調用約定 壓參數入棧順序 把參數彈出棧者 函數修飾名
(Calling convention)
--------------------------------------------------------------------------------------------------------
__cdecl 右->左 被調用者 _function 微機
__cdecl 右->左 被調用者 _function UNIX
__fastcall 右->左 被調用者 @function@nnn
__stdcall 右->左 被調用者 _
__pascal 左->右 被調用者 _function@nnn
-----------------------------------------------------------------------------------------------------------
_cdecl
按從右至左的順序壓參數入棧,由調用者把參數彈出棧。對於“C”函數或者變量,修飾名是在函數名前加下劃線。對於“C++”函數,有所不同。
如函數void test(void)的修飾名是_test;對於不屬於一個類的“C++”全局函數,修飾名是?test@@ZAXXZ。
這是缺省調用約定。由於是調用者負責把參數彈出棧,所以可以給函數定義個數不定的參數,如printf函數。
_stdcall
按從右至左的順序壓參數入棧,由被調用者把參數彈出棧。對於“C”函數或者變量,修飾名以下劃線爲前綴,然後是函數名,然後是符號“@”及參數的字節數,如函數int func(int a, double b)的修飾名是_func@12。對於“C++”函數,則有所不同。
所有的Win32 API函數都遵循該約定。
_pascal
按從左至右的順序壓參數入棧 ...其它的與_stdcall相同;
_fastcall
頭兩個DWORD類型或者佔更少字節的參數被放入ECX和EDX寄存器,其他剩下的參數按從右到左的順序壓入棧。由被調用者把參數彈出棧,對於“C”函數或者變量,修飾名以“@”爲前綴,然後是函數名,接着是符號“@”及參數的字節數,如函數int func(int a, double b)的修飾名是@func@12。對於“C++”函數,有所不同。
未來的編譯器可能使用不同的寄存器來存放參數。
thiscall
僅僅應用於“C++”成員函數。this指針存放於CX寄存器,參數從右到左壓棧。thiscall不是關鍵詞,因此不能被程序員指定。
naked call
採用1-4的調用約定時,如果必要的話,進入函數時編譯器會產生代碼來保存ESI,EDI,EBX,EBP寄存器,退出函數時則產生代碼恢復這些寄存器的內容。naked call不產生這樣的代碼。
naked call不是類型修飾符,故必須和_declspec共同使用,如下:
__declspec( naked ) int func( formal_parameters )
{
// Function body
}
便於更好理解, 看下面例子(函數調用的過程以彙編代碼表示):
void cdecl fun1(int x,int y);
void stdcall fun2(int x,int y);
void pascal fun3(int x,int y);
****************************************
void cdecl fun1(int x,int y);
fun1(x,y);
調用 fun1 的彙編代碼
push y
push x
call fun1
add sp,sizeof(x)+sizeof(y) ;跳過參數區(x,y)
fun1 的彙編代碼:
fun1 proc
push bp
mov bp,sp
……
…
pop bp
ret ;返回,但不跳過參數區
fun1 endp
****************************************
void stdcall fun2(int x,int y);
fun2(x,y);
調用 fun2 的彙編代碼
push y
push x
call fun2
fun2 的彙編代碼:
fun2 proc
push bp
mov bp,sp
……
…
pop bp
ret sizeof(x)+sizeof(y) ;返回並跳過參數區(x,y)
fun2 endp
*****************************************
void pascal fun3(int x,int y);
fun3(x,y);
調用 fun3 的彙編代碼
push x
push y
call fun3
fun3 的彙編代碼:
fun3 proc
push bp
mov bp,sp
……
…
pop bp
ret sizeof(x)+sizeof(y) ;返回並跳過參數區(x,y)
fun3 endp