呼叫約定決定了以下內容:函式引數的壓棧順序、由呼叫者還是被呼叫者平衡堆疊。
3.1 __cdecl
__cdecl是c和c++程式的預設呼叫約定:引數通過堆疊來傳遞,從右向左依次入棧,由呼叫者平衡堆疊。
同樣的**,我們在addint函式前面加上__cdecl呼叫約定
int __cdecl addint(int a, int b)
f5執行斷下後,按「alt+f8」開啟反彙編視窗,沒有任何變化,和沒加__cdecl一樣,說明預設呼叫約定就是__cdecl。
3.2 __stdcall
同樣的**,我們在addint函式前面加上__stdcall呼叫約定
int __stdcall addint(int a, int b)
再反彙編看看main函式裡,呼叫的過程如下
9: int x = addint(1, 3);
00401078 push 3
0040107a push 1
0040107c call @ilt+10(addint) (0040100f)
引數還是一樣從右向左依次入棧,但是沒有了add esp,8這句,那誰來平衡堆疊呢?看看addint函式的反彙編的最後一條指令:
0040104a ret 8
這一句就相當於
ret
add esp,8
所以__stdcall的呼叫約定是引數通過堆疊來傳遞,從右向左依次入棧,由被呼叫者平衡堆疊。
一般windows api函式都是__stdcall,在windef.h中可以找到如下的定義:
#define winapi __stdcall
3.3 __fastcall
同樣的**,我們在addint函式前面加上__fastcall呼叫約定
int __fastcall addint(int a, int b)
再反彙編看看main函式裡,呼叫的過程如下
9: int x = addint(1, 3);
00401078 mov edx,3
0040107d mov ecx,1
00401082 call @ilt+0(addint) (00401005)
可以看到,兩個引數分別用ecx和edx傳遞。如果更多引數會怎麼樣呢?
int __fastcall addint(int a, int b, int c, int d)
呼叫的過程如下:
9: int x = addint(1, 3, 7, 9);
00401078 push 9
0040107a push 7
0040107c mov edx,3
00401081 mov ecx,1
00401086 call @ilt+15(addint) (00401014)
可以看出來,__fastcall的呼叫約定是:第乙個引數通過ecx傳遞,第二個引數通過edx傳遞,第三個引數起從右向左依次入棧,由被呼叫者平衡堆疊。
3.4 類的成員函式
對於類的成員函式來說,除了要傳遞普通的引數,還有乙個隱藏的引數——this指標。
class example
};int main()
反彙編看一下呼叫的過程:
16: a.addint(1, 3);
0040b468 push 3
0040b46a push 1
0040b46c lea ecx,[ebp-4]
0040b46f call @ilt+5(example::addint) (0040100a)
在呼叫之前,多了乙個指令lea ecx,[ebp-4],這一句實際上就是將this指標傳遞給ecx,可以看出來,類成員函式的預設呼叫約定是:引數通過堆疊來傳遞,從右向左依次入棧,由被呼叫者平衡堆疊棧,this指標通過ecx傳遞。除了this指標,其他都和__stdcall相同。
所以我們只要看到call呼叫前,某個位址傳遞給了ecx,就可以知道十有**呼叫的是乙個類成員函式。
值得注意的是vc編譯器預設使用ecx傳遞this指標,但是borland c++編譯器卻是用eax,不同的編譯器處理的方式不一樣。
更進一步,如果指定類的成員函式呼叫約定為__cdecl、__stdcall或者是__fastcall,會是什麼情況呢?
3.4.1 __cdecl
15: a.addint(1, 3);
00401038 push 3
0040103a push 1
0040103c lea eax,[ebp-4]
0040103f push eax
00401040 call @ilt+20(example::addint) (00401019)
00401045 add esp,0ch
3.4.2 __stdcall15: a.addint(1, 3);
00401038 push 3
0040103a push 1
0040103c lea eax,[ebp-4]
0040103f push eax
00401040 call @ilt+0(example::addint) (00401005)
3.4.3 __fastcall15: a.addint(1, 3);
00401038 push 3
0040103a mov edx,1
0040103f lea ecx,[ebp-4]
00401042 call @ilt+10(example::addint) (0040100f)
可以看出,如果指定了呼叫約定,實際上編譯器把this指標當成函式的第乙個引數進行處理了。 反彙編 函式巢狀呼叫
實現的功能 兩層函式呼叫,外層函式的傳入的兩個引數再傳到子函式中相加,實現四個數相加返回 004010e8 6a 03 push 3 壓入3 004010ea 6a 02 push 2 壓入2 004010ec 6a 01 push 1 壓入1 004010ee e8 12ffffff call s...
通過VC學習反彙編 彙編初步
因工作中經常用到反彙編解一些演算法,故對次有一定的接觸,為了更進一步理解c c vc等他們的特性,記下一些東西,就當自娛自樂了。1.1 暫存器 32位cpu所含有的暫存器分類簡介 1.1.1 資料暫存器 eax ebx ecx和edx 資料暫存器主要用來儲存運算元和運算結果等資訊。暫存器的低16位分...
反彙編之簡單函式呼叫
簡單的函式呼叫,通過反彙編可以清楚了解 舉例 include int add int a,int b int main void 這是乙個簡單的通過呼叫函式計算兩數之和的程式 vc6.0生成的彙編 如下 ebp 棧低 高位址 esp 棧頂 低位址 add函式 push ebp ebp 1000 es...