1. cdecl: C的函數預設調用方式, 適用可變參數,這種方式由於是 函數調用者清理堆棧,所以又導致了產生代碼增長(因為每次函數調用之後都是實現清理功能的代碼,如果是函數自己清理,則只需要一份清理代碼就可以了) 2.
stdcall:
函數清理堆棧,不可用於可變參數。 3.
fastcall: 類似stdcall, 但把因為它是通過寄存器
來傳送參數的(實際上,它用ECX和EDX傳送前兩個單字(DWORD)或更小的參數,剩下的參數仍舊自右向左壓棧傳送,被調用的函數在返回前清理傳送參數的記憶體棧 )。
基於在不同函數調用方式下的彙編產生代碼作比較:(用VS反組譯碼產生,看標紅代碼即可)
int func(int val1,int val2,int val3){int a;a=val1;return a;}b=func(1,2,3); //調用語句
--------cdecl------------
func: ......... 004113BE mov eax,dword ptr [val1] 004113C1 mov dword ptr [a],eax
004113C4 mov eax,dword ptr [a] ......... 004113CD
ret
b=func(1,2,3): 004113FE push 3 00411400 push 2 00411402 push 1 00411404 call func (411028h) 00411409
add esp,0Ch 0041140C mov dword ptr [b],eax
說明:
cdecl是函數調用者清理參數(add esp,0Ch,把棧指標加3個int長度的位移,實現參數的清理,如果是類對象還要析構) --------cdecl------------ --------stdcall------------
func: ......... 004113BE mov eax,dword ptr [val1] 004113C1 mov dword ptr [a],eax
004113C4 mov eax,dword ptr [a] ......... 004113CD
ret 0Ch
b=func(1,2,3): 004113FE push 3 00411400 push 2 00411402 push 1 00411404 call func (411028h) 00411409 mov dword ptr [b],eax 說明:
stdcall是函數自己清理參數(注意此時堆棧指標esp是指向返回地址的,返回地址下面是參數,指令
ret OCh使
函數返回再給
esp加上3個int長度的位移來清理參數
) --------stdcall------------
--------fastcall------------
func: ......... 004113BF
pop ecx
004113C0
mov dword ptr [ebp-14h],edx 004113C3
mov dword ptr [ebp-8],ecx 004113C6 mov eax,dword ptr [val1] //這裡val1==ebp-8 004113C9 mov dword ptr [a],eax
004113CC mov eax,dword ptr [a] ......... 004113D5
ret 4
b=func(1,2,3): 0041140E push 3 00411410
mov edx,2 00411415
mov ecx,1 0041141A call func (4110B4h) 0041141F mov dword ptr [b],eax
說明:
fastcall是通過ecx和edx來傳遞前
兩個單字(DWORD)或更小的參數 ,如這裡用ecx傳遞1( mov ecx,1 ),edx傳遞2(mov edx,2 ), 它的棧中參數清理工作是跟stdcall一樣的,只是這裡只需要清理一個參數就可以了(ret 4 ) --------fastcall------------
總結: 1.cdecl和stdcall好理解,如果不需要可變參數的話,stdcall是好的選擇。 2.fastcall的作用有點不好理解,從上面的代碼看,看不出有多麼快速。。
待續。。