cdecl, stdcall, pascal,fastcall的區(qū)別和調(diào)用約定
調(diào)用約定 壓參數(shù)入棧順序 把參數(shù)彈出棧者 函數(shù)修飾名
(Calling convention)
--------------------------------------------------------------------------------------------------------
__cdecl 右->左 調(diào)用者 _function
__fastcall 右->左 被調(diào)用者 @function@nnn
__stdcall 右->左 被調(diào)用者 _function@nnn
__pascal 左->右 被調(diào)用者 _function@nnn
-----------------------------------------------------------------------------------------------------------
_cdecl
按從右至左的順序壓參數(shù)入棧,由調(diào)用者把參數(shù)彈出棧。對于“C”函數(shù)或者變量,修飾名是在函數(shù)名前加下劃線。對于“C++”函數(shù),有所不同。
如函數(shù)void test(void)的修飾名是_test;對于不屬于一個類的“C++”全局函數(shù),修飾名是?test@@ZAXXZ。
這是缺省調(diào)用約定。由于是調(diào)用者負責把參數(shù)彈出棧,所以可以給函數(shù)定義個數(shù)不定的參數(shù),如printf函數(shù)。
_stdcall
按從右至左的順序壓參數(shù)入棧,由被調(diào)用者把參數(shù)彈出棧。對于“C”函數(shù)或者變量,修飾名以下劃線為前綴,然后是函數(shù)名,然后是符號“@”及參數(shù)的字節(jié)數(shù),如函數(shù)int func(int a, double b)的修飾名是_func@12。對于“C++”函數(shù),則有所不同。
所有的Win32 API函數(shù)都遵循該約定。
_pascal
按從左至右的順序壓參數(shù)入棧 ...其它的與_stdcall相同;
_fastcall
頭兩個DWORD類型或者占更少字節(jié)的參數(shù)被放入ECX和EDX寄存器,其他剩下的參數(shù)按從右到左的順序壓入棧。
由被調(diào)用者把參數(shù)彈出棧,對于“C”函數(shù)或者變量,修飾名以“@”為前綴,然后是函數(shù)名,接著是符號“@”及參數(shù)的字節(jié)數(shù),如函數(shù)int
func(int a, double b)的修飾名是@func@12。對于“C++”函數(shù),有所不同。
未來的編譯器可能使用不同的寄存器來存放參數(shù)。
thiscall
僅僅應(yīng)用于“C++”成員函數(shù)。this指針存放于CX寄存器,參數(shù)從右到左壓棧。thiscall不是關(guān)鍵詞,因此不能被程序員指定。
naked call
采用1-4的調(diào)用約定時,如果必要的話,進入函數(shù)時編譯器會產(chǎn)生代碼來保存ESI,EDI,EBX,EBP寄存器,退出函數(shù)時則產(chǎn)生代碼恢復(fù)這些寄存器的內(nèi)容。naked call不產(chǎn)生這樣的代碼。
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);
調(diào)用 fun1 的匯編代碼
push y
push x
call fun1
add sp,sizeof(x)+sizeof(y) ;跳過參數(shù)區(qū)(x,y)
fun1 的匯編代碼:
fun1 proc
push bp
mov bp,sp
……
…
pop bp
ret ;返回,但不跳過參數(shù)區(qū)
fun1 endp
****************************************
void stdcall fun2(int x,int y);
fun2(x,y);
調(diào)用 fun2 的匯編代碼
push y
push x
call fun2
fun2 的匯編代碼:
fun2 proc
push bp
mov bp,sp
……
…
pop bp
ret sizeof(x)+sizeof(y) ;返回并跳過參數(shù)區(qū)(x,y)
fun2 endp
*****************************************
void pascal fun3(int x,int y);
fun3(x,y);
調(diào)用 fun3 的匯編代碼
push x
push y
call fun3
fun3 的匯編代碼:
fun3 proc
push bp
mov bp,sp
……
…
pop bp
ret sizeof(x)+sizeof(y) ;返回并跳過參數(shù)區(qū)(x,y)
fun3 endp