轉 函式呼叫約定

2022-01-19 16:26:41 字數 2036 閱讀 3971

談到函式,一般首先要分析一下各種函式呼叫約定,比如_cdecl、 _stdcall等。這兩種呼叫約定呼叫時都是最右側的引數先進棧,棧最上面的就是函式的第乙個引數。不同之處在於,_cdecl由呼叫者清理引數占用的 棧空間,而_stdcall由被呼叫者清理引數占用的棧空間。很明顯,對於接受可變引數的函式,如printf,被呼叫函式是無法知道到底有幾個引數的, 所以只能採用由呼叫者清理引數棧的方式。_stdcall呼叫方式生成的**會小一點。 下面的分析採用vc++6.0進行。

一.函式內部的彙編**

view plain

void func()  

int main()  

對應的彙編**是:

1:    void func()

2:   

00401038   pop         edi

00401039   pop         esi

0040103a   pop         ebx

0040103b   mov         esp,ebp

0040103d   pop         ebp

0040103e   ret

5:    int main()

6:   

0040106f   pop         edi

00401070   pop         esi

00401071   pop         ebx

00401072   add         esp,40h

00401075   cmp         ebp,esp

00401077   call        __chkesp (00401090)

0040107c   mov         esp,ebp

0040107e   pop         ebp

0040107f   ret

一般來說,函式開頭的**如下:

push        ebp           //儲存ebp

mov         ebp,esp     //將esp的值送ebp,在函式內部可能還會使用push、pop等操作,這時esp的值會不斷變化,如果採用esp來定址局 部變數或者引數的話,可能要不斷修正偏移量,而採用ebp定址變數就方便很多。當然,這樣會浪費乙個暫存器,編譯器可以優化。

sub          esp,40h     //為區域性變數分配空間,這裡的40h大小是vc預設分配的。

而結尾**如下:

mov         esp,ebp  //恢復esp,其實相當於把棧裡區域性變數的空間**了 

pop         ebp

ret

可以看到,即使函式沒有定義任何區域性變數,編譯器仍然為我們非配了0x40大小的空間,並全部初始化0xcccccccc。有時候我們會見到燙燙€這樣的字串資訊,就是這部分內存在作怪。

二 帶引數和區域性變數的函式

view plain

#include 

void func(int a,int b)  

int main()  

反彙編**:

main中呼叫func的**是:

00401088   push        20h  //32壓棧

0040108a   push        10h  //16壓棧

0040108c   call        @ilt+10(func) (0040100f)

00401091   add         esp,8  //呼叫完畢後清理引數占用的棧空間,這裡採用的是_cdecl呼叫約定。

再看func的**:

2:    void func(int a,int b)

3:   

……00401047   mov         esp,ebp

00401049   pop         ebp

0040104a   ret

函式中通過ebp加偏移量的方式來定址區域性變數,很容易看出,棧布局如下圖所示:

圖中,位址從上到下增加。因為這裡是near呼叫,所以沒有儲存ecs暫存器的內容。

函式呼叫約定

函式呼叫約定有多種,這裡簡單說一下 1 stdcall 呼叫約定相當於16位動態庫中經常使用的 pascal 呼叫約定。在32位的vc 5.0中pascal呼叫約定不再被支援 實際上它已被定義為 stdcall。除了 pascal外,fortran和 syscall也不被支援 取而代之的是 stdc...

函式呼叫約定

函式呼叫約定1.stdcall是pascal程式的預設呼叫方式,通常用於win32 api中,函式採用從右到左的壓棧方式,自己在退出時清空堆疊。vc將函式編譯後會在函式名前面加上下劃線字首,在函式名後加上 和引數的位元組數。2 c呼叫約定 即用 cdecl關鍵字說明 按從右至左的順序壓引數入棧,由呼...

函式呼叫約定

1.stdcall是pascal程式的預設呼叫方式,通常用於win32 api中,函式採用從右到左的壓棧方式,自己在退出時清空堆疊。vc將函式編譯後會在函式名前面加上下劃線字首,在函式名後加上 和引數的位元組數。2 c呼叫約定 即用 cdecl關鍵字說明 按從右至左的順序壓引數入棧,由呼叫者把引數彈...