VC++函式引數壓棧順序
阿新 • • 發佈:2019-02-09
今天閒來無事寫了一段程式碼: 這是因為EBP + 8本身也需要一條指令來計算,所以不能跟MOV寫在一條指令裡。但是彙編指令中記憶體地址符可以做算術運算,所以對於指令MOV
EAX, [EBP + 8]完全是合法的。接下來繼續跟下一條指令:
int Func1(int x,int y){
return (x&y)+((x^y)>>1);
}
void main(){
int Array[] = {1,2,3,4,5};
int *ptr = Array;
int c = Func1(*ptr,*(++ptr));
printf("%d\n",c);
}
原本預想輸出結果應該為1,誰知竟然為2,百思不得姐之後,就除錯了下進入反彙編檢視其中奧妙:
這個過程就不用解釋了,預先計算陣列大小,陣列按記憶體地址從低位到高位分配,接下來:55: int Array[] = {1,2,3,4,5}; 00401088 mov dword ptr [ebp-14h],1 0040108F mov dword ptr [ebp-10h],2 00401096 mov dword ptr [ebp-0Ch],3 0040109D mov dword ptr [ebp-8],4 004010A4 mov dword ptr [ebp-4],5
56: int *ptr = Array;
004010AB lea eax,[ebp-14h]
004010AE mov dword ptr [ebp-18h],eax
注意mov和lea的區別,如果你認為lea eax,[ebp-18h]是將記憶體地址為ebp-14h中的內容賦給eax那就錯了,lea只是將記憶體地址賦給eax,也就是此時eax的內容是ebp-14h。對於指令mov eax,[ebp-14h]自然是將記憶體中的地址壓入eax。說到這裡就囉嗦一下,mov的右值必須為常量不能為表示式,如,可以寫MOV
EAX, EBP,但不能寫MOV EAX, EBP + 8根據以上指令我們可以判斷該函式引數的入棧順序為從右至左,所以先執行了++ptr指令,我們繼續往下跟:57: int c = Func1(*ptr,*(++ptr)); 004010B1 mov ecx,dword ptr [ebp-18h] //ecx賦值為ebp-14h 004010B4 add ecx,4 //ecx值為ebp-10h,指向Array[1] 004010B7 mov dword ptr [ebp-18h],ecx 004010BA mov edx,dword ptr [ebp-18h] 004010BD mov eax,dword ptr [edx] //Array[1]壓入eax 004010BF push eax //2 004010C0 mov ecx,dword ptr [ebp-18h] 004010C3 mov edx,dword ptr [ecx] //ecx值為ebp-10h,指向Array[1] 004010C5 push edx //2 004010C6 call @ILT+0(Func1) (00401005) 004010CB add esp,8 004010CE mov dword ptr [ebp-1Ch],eax
58: printf("%d\n",c);
004010D1 mov eax,dword ptr [ebp-1Ch]
004010D4 push eax
004010D5 push offset string "%d\n" (0043101c)
004010DA call printf (004081f0)
004010DF add esp,8
很明顯,ebp-1Ch為區域性變數c的地址,在printf中居然也是先將c壓棧,然後才是那一串格式控制字串,這個平時居然沒有注意,那麼對於以下程式碼該輸出多少呢?int i=0;printf("%d,%d,%d",++i,i,--i);輸出該是0,-1,-1,而不是想當然的1,1,0。這個問題可以繼續深入的探討下去,通過查閱資料,得到如下結論:
1. 引數入棧順序是和具體 編譯器實現相關的。比如,Pascal語言中引數就是從左到右入棧的,有些語言中還可以通過修飾符進行指定,如Visual C++。
2. Pascal語言不支援可變長引數,而C語言支援這種特色,正是這個原 因使得C語言函式引數入棧順序為從右至左。具體原因為:C方式引數入棧順序(從右至左)的好處就是可以動態變化引數個數。
3. 這裡面還牽涉到一個新的問題:標準呼叫_stdcall和C呼叫_cdecl,這兩種呼叫方式可等到以後用到時在仔細區別。
最後,對於Func1函式的功能做個說明,這是個面試據說會考到的問題,它的作用是求兩輸入引數的平均值。
完-----------------------------^o^