C++程式中不同函式呼叫方式的彙編碼比較

看雪資料發表於2015-11-15

其實看雪的書中已經提到這個問題了,只不過少了thiscall和fastcall,而thiscall是VC++類成員預設的函式呼叫方式、fastcall是C++Builder預設的呼叫方式,所以我在這裡做一個補充,方便大家查閱。

例子:
假設我們的函式為:
int sumExample (int a, int b)
{
return a + b;
}
呼叫程式碼為: int c = sum (2, 3);

現在分別來看幾種不同的呼叫方式,呼叫者彙編程式碼和函式體彙編程式碼:

(1)_cdecl (C語言的呼叫方式)  ---------------
呼叫者程式碼>>>:
; // push arguments to the stack, from right to left
push        3    
push        2    
; // call the function
call        _sumExample
; // cleanup the stack by adding the size of the arguments to ESP register
add         esp,8
; // copy the return value from EAX to a local variable (int c)
mov         dword ptr [c],eax

函式體程式碼>>>:
; // function prolog
 push        ebp  
 mov         ebp,esp
 sub         esp,0C0h
 push        ebx  
 push        esi  
 push        edi  
 lea         edi,[ebp-0C0h]
 mov         ecx,30h
 mov         eax,0CCCCCCCCh
 rep stos    dword ptr [edi]
 
; //return a + b;
 mov         eax,dword ptr [a]
 add         eax,dword ptr [b]

; // function epilog
 pop         edi  
 pop         esi  
 pop         ebx  
 mov         esp,ebp
 pop         ebp  
 ret              

(2)__stdcall (Windows API 的呼叫方式) -----------------------
呼叫者程式碼>>>:
; // push arguments to the stack, from right to left
 push        3    
 push        2    
 
; // call the function
 call        _sumExample@8

; // copy the return value from EAX to a local variable (int c)  
 mov         dword ptr [c],eax

函式體程式碼>>>:
; // function prolog goes here (the same code as in the __cdecl example)

; //return a + b;
 mov         eax,dword ptr [a]
 add         eax,dword ptr [b]

; // function epilog goes here (the same code as in the __cdecl example)

; // cleanup the stack and return
 ret         8


(3)__fastcall(暫存器呼叫方式) -----------------------
呼叫者程式碼>>>:
; // put the arguments in the registers EDX and ECX
 mov         edx,3
 mov         ecx,2
 
; // call the function
 call        @fastcallSum@8
 
; // copy the return value from EAX to a local variable (int c)  
 mov         dword ptr [c],eax

函式體程式碼>>>:
; // function prolog

 push        ebp  
 mov         ebp,esp
 sub         esp,0D8h
 push        ebx  
 push        esi  
 push        edi  
 push        ecx  
 lea         edi,[ebp-0D8h]
 mov         ecx,36h
 mov         eax,0CCCCCCCCh
 rep stos    dword ptr [edi]
 pop         ecx  
 mov         dword ptr [ebp-14h],edx
 mov         dword ptr [ebp-8],ecx
; // return a + b;
 mov         eax,dword ptr [a]
 add         eax,dword ptr [b]
;// function epilog  
 pop         edi  
 pop         esi  
 pop         ebx  
 mov         esp,ebp
 pop         ebp  
 ret              


(4)thiscall(C++類成員函式呼叫方式) -----------------------
這個比較特殊,函式是某個類的成員,所以我們這樣定義:
class CSum //類定義
{
int sum ( int a, int b) {return a+b;}
};

呼叫者程式碼>>>:
push        3    
push        2    
lea         ecx,[sumObj]
call        ?sum@CSum@@QAEHHH@Z; CSum::sum
mov         dword ptr [s4],eax

函式體程式碼>>>:
 push        ebp  
 mov         ebp,esp
 sub         esp,0CCh
 push        ebx  
 push        esi  
 push        edi  
 push        ecx  
 lea         edi,[ebp-0CCh]
 mov         ecx,33h
 mov         eax,0CCCCCCCCh
 rep stos    dword ptr [edi]
 pop         ecx  
 mov         dword ptr [ebp-8],ecx
 mov         eax,dword ptr [a]
 add         eax,dword ptr [b]
 pop         edi  
 pop         esi  
 pop         ebx  
 mov         esp,ebp
 pop         ebp  
 ret         8    


總結: 這4種call基本上是C++程式(Visual C++ ,C++Builder)最常見的呼叫方式,熟練掌握這幾種call的呼叫者與函式體的彙編程式碼格式有助於更快分析演算法,寫序號產生器。所以我簡單列舉在這裡,不足的地方還請大家補充,錯誤的地方還請批評指正!
                                             WinHack  QQ: 85436  於2003-07-24
                                      屬於:CCG,OCN,FCG,YCG,轉載請保持完整


相關文章