通過VC學習反彙編 函式呼叫 呼叫約定

2021-06-01 02:31:35 字數 3375 閱讀 1088

呼叫約定決定了以下內容:函式引數的壓棧順序、由呼叫者還是被呼叫者平衡堆疊。

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 __stdcall
15:       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 __fastcall
15:       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...