VC 6.0 函數調用過程

目的: 本文要做的事就是通過一個最簡單的程序學習C代碼函數調用的內部實現。

環境:Windows XP + Visual C++ 6.0

C代碼如下:

  1. #include "stdafx.h"  
  2.  
  3. void test(int a)  
  4. {  
  5.     int  c = a;  
  6. }  
  7.  
  8. int main(int argc, char* argv[])  
  9. {  
  10.     test(argc);  
  11.  
  12.       
  13.     return 0;  
  14. }  

test函數只傳了一個參數,不驗證cdecl、stdcall 、fastcall等調用約定的差異。百度一下記錄在這: 

cdecl:參數入棧按從右至左的順序,調用者將參數彈出棧。可以給函數定義個數不定的參數,如print函數。

stdcall:參數入棧按從右至左的順序。由被調用者將參數彈出棧。WIN32 API遵循此約定。

fastcall:頭兩個DWORD類型或者佔更少字節的參數放入ECX和EDX寄存器,其他剩餘參數按從右至左的順序壓入棧。參數由被調用者彈出棧。

 彙編代碼如下:

  1. 11:   int main(int argc, char* argv[])  
  2. 12:   {  
  3. 0040B480 55                   push        ebp  
  4. 0040B481 8B EC                mov         ebp,esp  
  5. 0040B483 83 EC 40             sub         esp,40h  
  6. 0040B486 53                   push        ebx  
  7. 0040B487 56                   push        esi  
  8. 0040B488 57                   push        edi  
  9. 0040B489 8D 7D C0             lea         edi,[ebp-40h]  
  10. 0040B48C B9 10 00 00 00       mov         ecx,10h  
  11. 0040B491 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
  12. 0040B496 F3 AB                rep stos    dword ptr [edi]  
  13. 13:       test(argc);  
  14. 0040B498 8B 45 08             mov         eax,dword ptr [ebp+8]  
  15. 0040B49B 50                   push        eax  
  16. 0040B49C E8 69 5B FF FF       call        @ILT+5(test) (0040100a)  
  17. 0040B4A1 83 C4 04             add         esp,4  
  18. 14:  
  19. 15:  
  20. 16:       return 0;  
  21. 0040B4A4 33 C0                xor         eax,eax  
  22. 17:   }  

 

  1. @ILT+0(_main):  
  2. 00401005 E9 76 A4 00 00       jmp         main (0040b480)  
  3. 0040100A E9 01 00 00 00       jmp         test (00401010)  
  4. 0040100F CC                   int         3  

 

  1.     void test(int a)  
  2. 7:    {  
  3. 00401010 55                   push        ebp  
  4. 00401011 8B EC                mov         ebp,esp  
  5. 00401013 83 EC 44             sub         esp,44h  
  6. 00401016 53                   push        ebx  
  7. 00401017 56                   push        esi  
  8. 00401018 57                   push        edi  
  9. 00401019 8D 7D BC             lea         edi,[ebp-44h]  
  10. 0040101C B9 11 00 00 00       mov         ecx,11h  
  11. 00401021 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
  12. 00401026 F3 AB                rep stos    dword ptr [edi]  
  13. 8:        int  c = a;  
  14. 00401028 8B 45 08             mov         eax,dword ptr [ebp+8]  
  15. 0040102B 89 45 FC             mov         dword ptr [ebp-4],eax  
  16. 9:    }  
  17. 0040102E 5F                   pop         edi  
  18. 0040102F 5E                   pop         esi  
  19. 00401030 5B                   pop         ebx  
  20. 00401031 8B E5                mov         esp,ebp  
  21. 00401033 5D                   pop         ebp  
  22. 00401034 C3                   ret  

 

 1、main函數首先是將基址指針寄存器入棧,再將堆棧指針寄存器賦值給基址指針寄存器。

  1. 0040B480 55                   push        ebp  
  2. 0040B481 8B EC                mov         ebp,esp 

 

2、將ESP下移40H+0H(預留40H,局部變量0H,爲何預留40H暫時沒有搞清楚),用來存儲局部變量。

  1. 0040B483 83 EC 40             sub         esp,40h 

 

3、將寄存器入棧,用於函數返回時恢復現場。

  1. 0040B486 53                   push        ebx  
  2. 0040B487 56                   push        esi  
  3. 0040B488 57                   push        edi  

4、循環初始化局部變量部分內存爲0xCCCCCCCC。

  1. 0040B489 8D 7D C0             lea         edi,[ebp-40h]  
  2. 0040B48C B9 10 00 00 00       mov         ecx,10h  
  3. 0040B491 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
  4. 0040B496 F3 AB                rep stos    dword ptr [edi] 

5、入參入棧。

  1. 0040B498 8B 45 08             mov         eax,dword ptr [ebp+8]  
  2. 0040B49B 50                   push        eax  

 

6、調用test函數。ILT爲 Incremental   Linking   Table 的縮寫,關閉Link   Incrementally後,編譯器就不會產生ILT。ILT的作用是減少debug版的編譯時間。

  1. 0040B49C E8 69 5B FF FF       call        @ILT+5(test) (0040100a) 

7、test函數保存ebp、預留局部變量空間並初始化、保留現場。同main函數。

  1. 00401010 55                   push        ebp  
  2. 00401011 8B EC                mov         ebp,esp  
  3. 00401013 83 EC 44             sub         esp,44h  
  4. 00401016 53                   push        ebx  
  5. 00401017 56                   push        esi  
  6. 00401018 57                   push        edi  
  7. 00401019 8D 7D BC             lea         edi,[ebp-44h]  
  8. 0040101C B9 11 00 00 00       mov         ecx,11h  
  9. 00401021 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
  10. 00401026 F3 AB                rep stos    dword ptr [edi]  

8、int c = a;  ebp+4存的是函數調用前的ebp。ebp+8是入參a,ebp-4是局部變量c。

  1. 00401028 8B 45 08             mov         eax,dword ptr [ebp+8]  
  2. 0040102B 89 45 FC             mov         dword ptr [ebp-4],eax 

9、test執行完成,恢復現場。

  1. 0040102E 5F                   pop         edi  
  2. 0040102F 5E                   pop         esi  
  3. 00401030 5B                   pop         ebx  
  4. 00401031 8B E5                mov         esp,ebp  
  5. 00401033 5D                   pop         ebp  
  6. 00401034 C3                   ret  

10、釋放入參佔用的棧空間。

  1. 0040B4A1 83 C4 04             add         esp,4  

11、置返回值爲0。

  1. 0040B4A4 33 C0                xor         eax,eax 

12、main函數恢復堆棧返回。

  1. 0040B4A6 5F                   pop         edi  
  2. 0040B4A7 5E                   pop         esi  
  3. 0040B4A8 5B                   pop         ebx  
  4. 0040B4A9 83 C4 40             add         esp,40h  
  5. 0040B4AC 3B EC                cmp         ebp,esp  
  6. 0040B4AE E8 0D 00 00 00       call        __chkesp (0040b4c0)  
  7. 0040B4B3 8B E5                mov         esp,ebp  
  8. 0040B4B5 5D                   pop         ebp  
  9. 0040B4B6 C3                   ret  

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章