【c++】函數調用約定

         函數的調用約定,當一個函數被調用時,參數的傳遞以及返回值以什麼樣的方式回到調用函數;函數的調用約定就是指參數和返回值是怎麼樣傳遞的,以及是由誰平衡堆棧的。

函數的調用約定主要針對三個問題:
1.函數符號的生成與編譯後的名稱
2.實參的入棧順序
3.形參的開闢與清理方式

 

一、__cdecl調用約定
cdecl是c標準的調用約定;聲明方式爲:
int function(int a,int b)                    //不加修飾就是採用默認的c調用約定
int __cdecl function(int a,int b)      //明確指出c調度約定

 __cdecl約定下的函數符號的生成:int __cdecl Sum(int,int)   =》  (?Sum@@YAHHH@Z)
?Sum@@YAHHH@Z     
Sum指的是函數名
A指的調用約定 __cdecl
第一個H返回值的類型,後面的H是參數的類型
 __cdecl約定下的函數編譯後的名稱:_Sum

具體的函數調用棧的指令,可見上一篇文章;在調用函數中,首先push 14h也就是20,後push 0Ah就是十進制的10,所以c標準調用約定中形參是調用函數中開棧,並且入棧順序是從右向左;從call函數進入被調函數中,返回值由寄存器eax帶出;ebp重新指向(指向棧底寄存器)調用函數的棧底;
00E843E7  add         esp,8     //調用函數中恢復棧頂指針esp
由調用函數中的彙編指令可以看出,__cdecl調用約定中,形參是由調用函數清理的;

二、__stdcall
__stdcall是windows標準調用約定,也被稱爲pascal調用約定,因爲使用pascal方式清棧c方式壓棧,在win32應用程序裏,宏APIENTRY,WINAPI,都表示_stdcall;聲明方式爲:
int  __stdcall(int a,int b);


__stdcall調用約定下函數符號的生成:int __stdcall Sum(int a, int b)  =》?Sum@@YGHHH@Z
?Sum@@YGHHH@Z     
Sum指的是函數名
G指的調用約定 __stdcall
第一個H返回值的類型,後面的H是參數的類型
__stdcall調用約定下編譯後的名稱:_Sum@4    @後跟參數類型的字節數

在調用函數的彙編指令中,先push14h將十進制數字20入棧,push 0Ah將十進制數字10入棧,所以在stdcall調用約定下形參是調用函數開闢棧的,形參入棧的順序是從右向左入棧;由call函數跳轉到被調函數,返回值由寄存器帶入調用函數中;注意在被調函數中有:
00A2297A  ret         8            //被調函數中
ret指令是對棧頂指針esp進行操作,所以__stdcall調用約定中形參是由被調函數清理的

三、__fastcall
        顧名思義,其特點就是快;_fastcall函數調用約定表明了參數應該放在寄存器中,而不是棧中,使用VC編譯器調用約定傳遞參數時,最左邊的兩個不大於4個字節(DEORD)的參數分別放在ecx和edx寄存器,像浮點值還是通過堆棧來傳遞


__fastcall調用約定下函數符號的生成:extern int __fastcall Sum(int , int ,int)  =》?Sum@@YIHHHH@Z
?Sum@@YIHHHH@Z
Sum指的是函數名
I指的調用約定 __fastcall
第一個H返回值的類型,後面的H是參數的類型
__fastcall調用約定下編譯後的名稱:@Sum@8

在調用函數中,參數有3個,push 1Eh將十進制的30入棧,將十進制的20與10分別放入edx和ecx寄存器中;所以在fastcall調用約定下,當參數個數不大於兩個,並且參數不大於32字節時,則形參只需要寄存器(edx與ecx)傳遞(也就是不需要開闢棧),如果參數個數大於兩個時,從第三個數起,從右往左進行入棧;在本例中有三個參數,所以第三個參數入棧;然後依舊從call函數跳轉到被調函數中,返回值放在eax寄存器中帶出,在被調函數中有:
00F12985  ret         4      //被調函數中
在被調函數中對esp進行操作,被調函數恢復棧頂指針,因爲只有一個int類型的數值入棧,所以這裏是4

四、__thiscall
      thiscall是唯一一個不能明確指明的函數修飾,因爲thiscall只能用於C++類成員函數的調用;由於成員函數調用還有一個this指針,因此必須特殊處理。thiscall意味着:
1.採用棧傳遞參數,參數從右向左入棧。如果參數個數確定,this指針通過ecx傳遞給被調用者;如果參數個數不確定,this指針在所有參數壓棧後被壓人堆棧;
2.對參數個數不確定的,調用者清理堆棧,否則由被調函數清理堆棧

 

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