C++函數有參調用有幾種傳參方式: 函數
一.傳值 編碼
二.傳指針(地址) spa
三.傳引用 指針
其中參數可被const修飾,也能夠有默認值。下面分狀況討論: code
爲了簡潔,省略main函數的彙編碼而直接給出func函數的彙編碼。 ip
一.傳值調用 內存
有源代碼: class
void func(int a,char b){ int c; c=a+b; } int main(int argc,char *argv[]) { //call func func(10,'a'); return 0; }下面看看彙編碼:
調用發生時: 變量
//call func func(10,'a'); //進行參數壓棧操做,首先是'a'壓入棧,而後是10壓棧,而後call跳轉表,再由調轉表call函數 00F1141E push 61h 00F11420 push 0Ah 00F11422 call 00F1113B //函數調用完成後,棧減少8字節,兩個dword,由於CPU對棧的操做都是雙字操做,這裏兩個參數就是兩個雙字 00F11427 add esp,8具體內存中的表現是這樣的(先讓func把棧初始化):
顯然不在func的stack內,注意兩個參數前面還有兩個DWORD, 引用
一個是00f1 1427,另外一個是00dd f794;這兩個DWORD的產生應該是在PUSH兩個參數以後,
又有的兩個PUSH,顯然,第一個PUSH 00f1 1427是在call 時將ip壓棧致使的:
這個ip是當前這條call 指令的下一條指令(add)的地址,請參考上面的main函數。
第二個PUSH是在 func函數中完成的,能夠參考func函數的彙編碼:
void func(int a,char b){ 00F113D0 push ebp //這裏第二個PUSH,壓入ebp,顯然這個ebp的值能夠在main函數裏面看到, //有兩條: //## 00F11401 mov ebp,esp //## 00F11403 sub esp,0C0h //那麼ebp就是main的棧底 00F113D1 mov ebp,esp 00F113D3 sub esp,0CCh 00F113D9 push ebx 00F113DA push esi 00F113DB push edi 00F113DC lea edi,[ebp+FFFFFF34h] 00F113E2 mov ecx,33h 00F113E7 mov eax,0CCCCCCCCh 00F113EC rep stos dword ptr es:[edi] int c; c=a+b; 00F113EE movsx eax,byte ptr [ebp+0Ch] 00F113F2 add eax,dword ptr [ebp+8] 00F113F5 mov dword ptr [ebp-8],eax } 00F113F8 pop edi 00F113F9 pop esi 00F113FA pop ebx 00F113FB mov esp,ebp 00F113FD pop ebp 00F113FE ret調用發生時,壓入兩個參數後,必須再保存下一條指令的位置,所以有一個壓棧操做,這個操做是有call指令來完成的。 其次,func函數將ebp壓棧是爲了爲恢復堆棧作準備。由於CPU只有兩個寄存器用於堆棧操做:SS:SP,爲了調用func函數完成時能進入main的堆棧,必須先保存(push ebp)再恢復(pop ebp),這一點從func函數末尾也看得出。
此外,更直觀一點,從內存中看得出:第二個push 00ddf794和func的stack靠的很近:
剛好是指向了main的棧底。
再來看看func裏面:
int c; c=a+b; 00F113EE movsx eax,byte ptr [ebp+0Ch] 00F113F2 add eax,dword ptr [ebp+8] 00F113F5 mov dword ptr [ebp-8],eax //通過分析能夠知道: //&b = ebp+0ch //&a = ebp+8 //&c = ebp-8 //在上面的分析中咱們知道這個ebp是指向棧底的,局部變量c在棧內,參數a 和 b 是以前push進來的通過上述分析,能夠得出一些結論:
有參函數調用發生時:
1.先將參數從右向左依次壓棧
2.將下一條指令的地址壓棧
3.被調函數將主調函數的棧底位置壓棧
4.被調函數初始化本身的棧
5.取出參數進行運算(並非pop)
6.恢復棧指針
7.執行ret恢復(pop)ip,此時程序轉到call的下一條add esp
8.向下移動棧頂指針sp,所謂的釋放局部變量。
能夠看到局部變量的"釋放"實際上是在主調函數中完成的,而不是在被調用函數末尾。
"釋放"不是清除內存,而是修改棧指針使局部變量不能訪問。