• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            小明思考

            高性能服務器端計算
            posts - 70, comments - 428, trackbacks - 0, articles - 0
              C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

            今天研究了一下vc6函數調用,看看vc6調用函數時候都做了什么。有些意思。

            我寫下了如下代碼:
            int fun(int a,int b)
            {
                
            int i = 3;
                
            return a+b+i;
            }

            int main()
            {
                
            int a = 1,b=2;
                
            int result ;
                result 
            = fun(1,2);
                
            return result;
            }

            非常簡單。反匯編后(Debug版)變成這樣

            1:    int fun(int a,int b)
            2:    {
            00401020   push        ebp
            00401021   mov         ebp,esp
            00401023   sub         esp,44h
            00401026   push        ebx
            00401027   push        esi
            00401028   push        edi
            00401029   lea         edi,[ebp-44h]
            0040102C   mov         ecx,11h
            00401031   mov         eax,0CCCCCCCCh
            00401036   rep stos    dword ptr [edi]
            3:        int i = 3;
            00401038   mov         dword ptr [ebp-4],3
            4:        return a+b+i;
            0040103F   mov         eax,dword ptr [ebp
            +8]
            00401042   add         eax,dword ptr [ebp+0Ch]
            00401045   add         eax,dword ptr [ebp-4]
            5:    }
            00401048   pop         edi
            00401049   pop         esi
            0040104A   pop         ebx
            0040104B   mov         esp,ebp
            0040104D   pop         ebp
            0040104E   ret

            7:    int main()
            8:    {
            00401060   push        ebp
            00401061   mov         ebp,esp
            00401063   sub         esp,4Ch
            00401066   push        ebx
            00401067   push        esi
            00401068   push        edi
            00401069   lea         edi,[ebp-4Ch]
            0040106C   mov         ecx,13h
            00401071   mov         eax,0CCCCCCCCh
            00401076   rep stos    dword ptr [edi]
            9:        int a = 1,b=2;
            00401078   mov         dword ptr [ebp-4],1
            0040107F   mov         dword ptr [ebp
            -8],2
            10:       int result ;
            11:       result = fun(1,2);
            00401086   push        2
            00401088   push        1
            0040108A   call        @ILT
            +5(fun) (0040100a)
            0040108F   add         esp,
            8
            00401092   mov         dword ptr [ebp-0Ch],eax
            12:       return result;
            00401095   mov         eax,dword ptr [ebp-0Ch]
            13:   }
            00401098   pop         edi
            00401099   pop         esi
            0040109A   pop         ebx
            0040109B   add         esp,4Ch
            0040109E   cmp         ebp,esp
            004010A0   call        __chkesp (004010c0)
            004010A5   mov         esp,ebp
            004010A7   pop         ebp
            004010A8   ret

            我們主要來看看函數調用部分

            1.參數壓棧
            push 2
            push 1
            參數從右向左壓棧(__cdcel),esp遞減

            2.調用函數
             call        @ILT+5(fun) (0040100a)
            這條指令會把下一行代碼的地址壓棧,也就是函數返回地址。同時跳轉到函數入口處

            3.進入函數體
            push        ebp
            mov         ebp,esp
            首先保存ebp的地址,然后把esp保存到ebp中去
            00401023   sub         esp,44h
            00401026   push        ebx
            00401027   push        esi
            00401028   push        edi
            減小stack的指針(注意,stack是從內存的高端向低端生長的),為局部變量保留一些空間,這里的44h不是固定的,由編譯器計算得來
            00401029   lea         edi,[ebp-44h]
            0040102C   mov         ecx,11h
            00401031   mov         eax,0CCCCCCCCh
            00401036   rep stos    dword ptr [edi]
            用0xCC填充局部變量空間。這是Debug模式特有的,如果是字符串,你就看到被初始化成"燙燙燙燙燙燙"
            至此,整個堆棧變成
            |-----------------|
            |    局部變量2   |
            |-----------------|
            |    局部變量1    |<----ebp-4
            |-----------------|
            |    old ebp          |<----ebp
            |-----------------|
            | 函數返回地址| <----ebp+4
            |-----------------|
            |      參數1         | <----ebp+8
            |-----------------|
            |      參數2         |
            |-----------------|

            Next:
            int i = 3;
            00401038   mov         dword ptr [ebp-4],3
            這里你看到[ebp-4]就是第一個局部變量i了
            0040103F   mov         eax,dword ptr [ebp+8]
            00401042   add         eax,dword ptr [ebp+0Ch]
            00401045   add         eax,dword ptr [ebp-4]
            [ebp+8],[ebp+0Ch]分別是a和b了

            4.函數返回
            函數的結果都是放在eax中(ps:你可以在vc的watch窗口輸入@EAX,就可以直接看到函數返回值了)
            00401048   pop         edi
            00401049   pop         esi
            0040104A   pop         ebx
            0040104B   mov         esp,ebp
            0040104D   pop         ebp
            0040104E   ret
            把edi,esi,ebx恢復,然后恢復esp,ebp,這時函數的返回地址就在棧頂,調用ret就可以返回了。


            那如果改變函數的返回地址會怎樣?
            ok,我們修改一下代碼:
            #include <stdio.h>
            void fun2()
            {
                printf(
            "fun2() called");
            }

            int fun(int a,int b)
            {
                
            int i = 3;
                printf(
            "return address:0x%x\n",&i+2);
                printf(
            "fun2 address:0x%x\n",&fun2);
                
            /*int *p = (int*)&fun2;
                __asm
                {
                    mov ebx,p
                    mov dword ptr[ebp+4],ebx
                }
            */
                
            *(&i+2)=(int)&fun2; //modify return address
                return a+b+i;
            }

            int main()
            {
                
            int a = 1,b=2;
                
            int result ;
                result 
            = fun(1,2);
                
            return result;
            }

            Wow,這時,我們就會發現fun2被調用了。這就是Buffer overrun(緩沖溢出)所做的事情吧。


            5.最后一步,調用者調整堆棧指針
            call        @ILT+5(fun) (0040100a)
             add         esp,8
            為什么要調整呢,因為調用之前push兩個參數進入棧,現在要恢復它
             mov         dword ptr [ebp-0Ch],eax
            這句話就是享用函數調用的果實了(EAX保存了函數的返回值)

            ------end--------


            posted @ 2005-12-14 16:53 小明 閱讀(3397) | 評論 (5)編輯 收藏

            記得以前在程序員雜志上面,看見有人提到這個問題,試了很多種方法,結果是沒辦法將程序刪除。

            真的沒辦法刪除自身么?
            請運行下面的代碼:

            #include <windows.h>
            #include 
            <shlobj.h>

            BOOL SelfDelete()
            {
              SHELLEXECUTEINFO sei;
              TCHAR szModule [MAX_PATH], szComspec[MAX_PATH], szParams [MAX_PATH];

              
            // get file path names:
              if((GetModuleFileName(0,szModule,MAX_PATH)!=0&&
                 (GetShortPathName(szModule,szModule,MAX_PATH)
            !=0&&
                 (GetEnvironmentVariable(
            "COMSPEC",szComspec,MAX_PATH)!=0))
              {
                
            // set command shell parameters
                lstrcpy(szParams,"/c del ");
                lstrcat(szParams, szModule);
                lstrcat(szParams, 
            " > nul");

                
            // set struct members
                sei.cbSize       = sizeof(sei);
                sei.hwnd         
            = 0;
                sei.lpVerb       
            = "Open";
                sei.lpFile       
            = szComspec;
                sei.lpParameters 
            = szParams;
                sei.lpDirectory  
            = 0;
                sei.nShow        
            = SW_HIDE;
                sei.fMask        
            = SEE_MASK_NOCLOSEPROCESS;

                
            // increase resource allocation to program
                SetPriorityClass(GetCurrentProcess(),
                                 REALTIME_PRIORITY_CLASS);
                SetThreadPriority(GetCurrentThread(),
                                  THREAD_PRIORITY_TIME_CRITICAL);

                
            // invoke command shell
                if(ShellExecuteEx(&sei))
                {
                  
            // suppress command shell process until program exits
                  SetPriorityClass(sei.hProcess,IDLE_PRIORITY_CLASS);
                  SetProcessPriorityBoost(sei.hProcess,TRUE);

                  
            // notify explorer shell of deletion
                  SHChangeNotify(SHCNE_DELETE,SHCNF_PATH,szModule,0);
                  
            return TRUE;
                }
                
            else // if error, normalize allocation
                {
                  SetPriorityClass(GetCurrentProcess(),
                                   NORMAL_PRIORITY_CLASS);
                  SetThreadPriority(GetCurrentThread(),
                                    THREAD_PRIORITY_NORMAL);
                }
              }
              
            return FALSE;
            }

            int APIENTRY WinMain(HINSTANCE hInstance,
                                 HINSTANCE hPrevInstance,
                                 LPSTR     lpCmdLine,
                                 
            int       nCmdShow)
            {
                
            // on program exit
                
            // close all handles etc.
                if(!SelfDelete())
                {
                  
            // add error messaging
                }
                
            return 0;    // WinMain exit
              }


            程序的思想是通過創建一個另外的進程(ShellExecuteEx),再賦予本進程比較高的權限(SetPriorityClass),
            等這個程序退出以后,那個殺進程的進程就可以刪除程序了,另外程序通過
            SHChangeNotify通知Explorer:程序被刪除。

            具體API的使用方法請看MSDN.

            ps:這個程序是我在老外的網站上找到的,不是我寫的。我在VC6,Win2000 Professional上面調試通過

            posted @ 2005-12-07 10:21 小明 閱讀(1255) | 評論 (1)編輯 收藏

            這是小明我自編的題目。

            1.請在不運行程序的情況下,說出下面的程序運行后會崩潰么?如果是,在哪一行。

             1 #include <stdio.h>
             2 #include <memory.h>
             3 class Test 
             4 
             5 public
             6         Test() 
             7         { 
             8                 memset(this,0,sizeof(*this)); 
             9         } 
            10         int s; 
            11         void test() 
            12         { 
            13                 printf("test()\n"); 
            14         }
            15         void test1() 
            16         { 
            17                 printf("test1():%d\n",this->s); 
            18         }
            19         virtual void test2() 
            20         { 
            21                 printf("test2()\n"); 
            22         }
            23 }; 
            24 
            25 int main() 
            26 
            27         Test *s; 
            28         s->test(); 
            29         s->test2(); 
            30         s->test1(); 
            31         return 0
            32 }

            2 .修改一下,又是在哪一行呢?

             1 #include <stdio.h>
             2 #include <memory.h>
             3 class Test 
             4 
             5 public
             6         Test() 
             7         { 
             8                 memset(this,0,sizeof(*this)); 
             9         } 
            10         int s; 
            11         void test() 
            12         { 
            13                 printf("test()\n"); 
            14         }
            15         void test1() 
            16         { 
            17                 printf("test1():%d\n",this->s); 
            18         }
            19         virtual void test2() 
            20         { 
            21                 printf("test2()\n"); 
            22         }
            23 }; 
            24 
            25 int main() 
            26 
            27         Test *= new Test(); 
            28         s->test(); 
            29         s->test1(); 
            30         s->test2(); 
            31         return 0
            32 }

            3.再修改一下,情況會如何呢?
             1 #include <stdio.h>
             2 #include <memory.h>
             3 class Test 
             4 
             5 public
             6         Test() 
             7         { 
             8                 memset(this,0,sizeof(*this)); 
             9         } 
            10         int s; 
            11         void test() 
            12         { 
            13                 printf("test()\n"); 
            14         }
            15         void test1() 
            16         { 
            17                 printf("test1():%d\n",this->s); 
            18         }
            19         virtual void test2() 
            20         { 
            21                 printf("test2()\n"); 
            22         }
            23 }; 
            24 
            25 int main() 
            26 
            27         Test s ;
            28         s.test(); 
            29         s.test1(); 
            30         s.test2(); 
            31         return 0
            32 }




            最后說一下答案吧
            第一題是在29行,第二題在30行,最后一題不報錯。
            如果你不知道為什么,建議看看<<Inside the c++ Object Model>>

            posted @ 2005-12-06 09:34 小明 閱讀(2493) | 評論 (12)編輯 收藏

            當我回想起來我剛剛學習C語言,Turbo C2.0提供的豐富的函數,可以讓枯燥的文本界面,顯示出花花綠綠的文字界面。在windows時代,這些函數都不在標準庫中。不過WINAPI可以幫你實現。

            #include <windows.h>
            #include 
            <string>
            #include 
            <ctime>

            enum Colors
            {
                BLACK        
            = 0,
                BLUE         
            = 1,
                DARK_GREEN   
            = 2,
                LIGHT_BLUE   
            = 3,
                RED          
            = 4,
                PURPLE       
            = 5,
                ORANGE       
            = 6,
                GREY         
            = 7,
                DARKER_GREY  
            = 8,
                MEDIUM_BLUE  
            = 9,
                LIGHT_GREEN  
            = 10,
                TEAL         
            = 11,
                RED_ORANGE   
            = 12,
                LIGHT_PURPLE 
            = 13,
                YELLOW       
            = 14,
                WHITE        
            = 15
            };

            void set_cursor(short x, short y)
            {
                COORD point 
            = {x, y};
                ::SetConsoleCursorPosition(::GetStdHandle(STD_OUTPUT_HANDLE), point);
            }

            void set_color(unsigned short color)
            {
                ::SetConsoleTextAttribute(::GetStdHandle(STD_OUTPUT_HANDLE), color);
            }

            void delay(unsigned int delay)
            {
                ::Sleep(delay);
            }

            void set_title(std::string title)
            {
                ::SetConsoleTitle(title.c_str());
            }

            void show_cursor(bool show, int size = 25)
            {
                CONSOLE_CURSOR_INFO cci;
                
            if (size <= 0) size = 1;
                
            if (size > 100) size = 100;
                cci.dwSize 
            = size;
                cci.bVisible 
            = show;
                ::SetConsoleCursorInfo(::GetStdHandle(STD_OUTPUT_HANDLE), 
            &cci);
            }

            void clear_screen()
            {
                system(
            "cls");
            }

            代碼很簡單,不用多作解釋了

            posted @ 2005-12-05 10:49 小明 閱讀(928) | 評論 (0)編輯 收藏

            條件:不借助任何文件操作,輸出程序的source code.


            程序:
            #include <stdio.h>
            char c[] = {0x7d,0x3b,0xa,0x69,0x6e,0x74,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0xa,0x7b,0xa,0x20,0x20,0x20,0x20,0x70,0x72,0x69,0x6e,0x74,0x66,0x28,0x22,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,0x3c,0x73,0x74,0x64,0x69,0x6f,0x2e,0x68,0x3e,0x5c,0x6e,0x63,0x68,0x61,0x72,0x20,0x63,0x5b,0x5d,0x20,0x3d,0x20,0x7b,0x22,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x66,0x6f,0x72,0x28,0x69,0x6e,0x74,0x20,0x69,0x3d,0x30,0x3b,0x69,0x3c,0x73,0x69,0x7a,0x65,0x6f,0x66,0x28,0x63,0x29,0x3b,0x2b,0x2b,0x69,0x29,0xa,0x20,0x20,0x20,0x20,0x7b,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x70,0x72,0x69,0x6e,0x74,0x66,0x28,0x22,0x30,0x78,0x25,0x78,0x2c,0x22,0x2c,0x63,0x5b,0x69,0x5d,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x7d,0xa,0x20,0x20,0x20,0x20,0x70,0x72,0x69,0x6e,0x74,0x66,0x28,0x22,0x25,0x73,0x22,0x2c,0x63,0x29,0x3b,0xa,0x20,0x20,0x20,0x20,0x72,0x65,0x74,0x75,0x72,0x6e,0x20,0x30,0x3b,0xa,0x7d,};
            int main()
            {
                printf(
            "#include <stdio.h>\nchar c[] = {");
                
            for(int i=0;i<sizeof(c);++i)
                {
                    printf(
            "0x%x,",c[i]);
                }
                printf(
            "%s",c);
                
            return 0;
            }

            至于怎么做到的,大家可以自己琢磨

            不過不要以為只有C能做到,java也可以哦



            posted @ 2005-12-02 10:58 小明 閱讀(2604) | 評論 (21)編輯 收藏

            我接收到一個任務,是把公司的一個產品從vc6遷移到vs2005,結果發現了很多的warning和error

            warning 主要是使用了strcpy,strcat這樣的函數
            這些在2005中都是unsafe_api.
            在vs2005都推薦使用strcpy_s,strcat_s.
            我想微軟這么做固然跟C++ standard有偏差
            但是這些函數的使用確實造成了微軟產品經常有的漏洞
            微軟深受這些函數的危害阿
            所以在vs2005這些都是warning

            error的類型主要是以下幾種,多半和STL有關

            1.include 帶.h的舊式頭文件,比如 #include <iostream.h>改為include <iostream>

            2.vc6的string iterator的 char *,而vs2005中卻不是
            strcpy(s.begin(), str);是不能compile的,應改為strcpy((char *) s.c_str(),str);

            3.函數返回類型不支持缺省是int
            missing type specifier - int assumed. Note: c++ does not support default-int
            <Code>
                extern IsWindowsNT();

            <Fix>
                extern int IsWindowsNT();


            posted @ 2005-11-30 17:33 小明 閱讀(2963) | 評論 (3)編輯 收藏

            www.ogre3d.org
            OGRE: A 3D library for OpenGL and/or Direct3D

             

            template <typename T> class Singleton
            {
            protected:
            static T* ms_Singleton;

            public:
            Singleton( 
            void )
            {
                assert( 
            !ms_Singleton );
                ms_Singleton 
            = static_cast< T* >this );
            }
            ~Singleton( void )
                {  assert( ms_Singleton );  ms_Singleton 
            = 0;  }
            static T& getSingleton( void )
                {  assert( ms_Singleton );  
            return ( *ms_Singleton );  }
            static T* getSingletonPtr( void )
                {  
            return ( ms_Singleton );  }
            };

            //client端的代碼
            //Singleton的類
            //Root.h
            class Root:public Singleton<Root>
            {
               
            public:
                  
            void Use();
            };

            //初始化
            //Root.cpp
            Root * Singleton<Root>::ms_Singleton =0;
            Root g_root;
            //must declare once only

            //使用
            //Test.Cpp
            Root::getSingleton().Use();

            很簡單,使用的技巧是template base class
            這種實現方法的好處是復用性好。
            不過使用者要聲明Root * Singleton<Root>::ms_Singleton =0;挺討厭的

            改進方法:template static member function
            也就是改變聲明一個static T*在template class,換成使用靜態成員函數取出instance

            template <typename T> class Singleton
            {
            private:
            static T* & ms_Singleton()
                    {
                            
            static T* ms_Singleton_ =0 ;
                            
            return ms_Singleton_;
                    }
                    
            public:
            Singleton( 
            void )
            {
                assert( 
            !ms_Singleton() );
                ms_Singleton() 
            = static_cast< T* >this );
            }
            ~Singleton( void )
                    {  assert( ms_Singleton() );  ms_Singleton() 
            = 0;  }
            static T& getSingleton( void )
                    {  assert( ms_Singleton() );  
            return ( *ms_Singleton() );  }
            static T* getSingletonPtr( void )
                    {  
            return ( ms_Singleton() );  }
            };



             

            posted @ 2005-11-30 11:38 小明 閱讀(2434) | 評論 (1)編輯 收藏

            1.download ACE from: www.cs.wustl.edu/~schmidt/ACE.html

            2.build ACE in Visual Studio,generate ACE.lib(dll)[for release] & ACEd.lib(dll)[for debug]

            3.create a empty project named: ACETest

            4.add ACE path into Project Include Path and add ACE/lib into project lib path

            5.create a file(hello.cpp)

            #ifdef _DEBUG
            #pragma comment(lib,
            "ACED.lib")
            #else
            #pragma comment(lib,
            "ACE.lib")
            #endif

            #include 
            <ace/OS_main.h>
            #include 
            <ace/ACE.h>
            #include 
            <ace/Log_Msg.h>
            #include 
            <ace/SOCK_Connector.h>

            int main(int argc, char *argv[])
            {
             ACE_INET_Addr addr(
            1500,"127.0.0.1"); //remote address
             ACE_SOCK_Connector con; // connetor for socket client
             ACE_SOCK_Stream stream; // stream is for socket read/write

             
            if(con.connect(stream,addr)==-1//connect to remote address
             {
              ACE_DEBUG ((LM_DEBUG,
               ACE_TEXT (
            "(%P|%t) %p\n"),
               ACE_TEXT (
            "connection failed")));
              
            return 1;
             }

             
            const char msg[] = "Hello,ACE!";

             stream.send_n(msg,
            sizeof(msg)); // send_n function send exactly n bytes

             
            char buffer[1024= {0};

             
            if(stream.recv(buffer,sizeof(buffer)-1)==-1// just call socket recv
             {
              ACE_DEBUG ((LM_DEBUG,
               ACE_TEXT (
            "(%P|%t) %p\n"),
               ACE_TEXT (
            "recv failed")));
              
            return 1;
             }
             ACE_DEBUG ((LM_DEBUG,
              ACE_TEXT (
            "(%P|%t) recv:%s\n"),
              buffer));

             
            if (stream.close () == -1//close the connection
             {
              ACE_ERROR ((LM_ERROR,
               ACE_TEXT (
            "(%P|%t) %p\n"),
               ACE_TEXT (
            "close")));
              
            return 1;
             }

             
            return 0;
            }



            6.build & execute

            posted @ 2005-11-24 11:28 小明 閱讀(3604) | 評論 (8)編輯 收藏

                 摘要: 1.boost::any boost::any是一種通用的數據類型,可以將各種類型包裝后統一放入容器內最重要的它是類型安全的。有點象COM里面的variant. 使用方法:any::type() 返回包裝的類型any_cast可用于any到其他類型的轉化   #include <boost/any.hpp>void test_any(){ ...  閱讀全文

            posted @ 2005-11-23 09:39 小明 閱讀(10962) | 評論 (9)編輯 收藏

            僅列出標題
            共4頁: 1 2 3 4 
            久久99精品国产麻豆| 久久久久久精品久久久久| 精品人妻伦九区久久AAA片69| 国产精品嫩草影院久久| 久久精品aⅴ无码中文字字幕重口 久久精品a亚洲国产v高清不卡 | 久久免费的精品国产V∧| 99久久精品免费看国产一区二区三区| 久久精品视频91| 香蕉久久影院| 国产成人精品三上悠亚久久| 久久婷婷五月综合国产尤物app| 日韩十八禁一区二区久久| 中文字幕无码久久精品青草| 中文国产成人精品久久亚洲精品AⅤ无码精品| 狠狠久久综合| 亚洲国产小视频精品久久久三级| 三级韩国一区久久二区综合 | 色婷婷综合久久久久中文一区二区| 久久精品人人做人人爽电影 | 久久精品成人免费网站| 国产精品亚洲美女久久久| 美女久久久久久| 人妻丰满AV无码久久不卡| 国内精品久久国产大陆| 久久精品国产精品亚洲人人| 久久精品视频一| avtt天堂网久久精品| 久久精品国产精品亚洲| 亚洲av日韩精品久久久久久a| 精品无码久久久久久午夜| 国产亚洲精午夜久久久久久 | 亚洲国产成人久久综合一区77| 人妻无码αv中文字幕久久琪琪布| 亚洲级αV无码毛片久久精品| 伊人色综合久久天天| 久久精品国产久精国产果冻传媒| av无码久久久久不卡免费网站| 精品久久久久一区二区三区| 亚洲熟妇无码另类久久久| 久久97久久97精品免视看| 久久久久久午夜成人影院|