按照C編譯器的約定調用函數時壓棧的順序是從右向左,並且返回值是保存在eax寄存器當中。這個命題本該是成立的,下麵用一個小程式來反彙編觀察執行過程: 代碼解釋一下,asm的代碼中movl %%eax, %0的意思是把寄存器eax的值賦值給咱們程式的eax變數當中。但為什麼執行結果卻是: z is 11 ...
按照C編譯器的約定調用函數時壓棧的順序是從右向左,並且返回值是保存在eax寄存器當中。這個命題本該是成立的,下麵用一個小程式來反彙編觀察執行過程:
#include<stdio.h> int add(int x, int y){ return x+y; } int main(){ int eax=0; int z =0; int x =6; int y =5; z=add(x,y); __asm__( "movl %%eax, %0" :"+b"(eax) :"m"(x) ); printf("z is %d\n", z); printf("eax is %d\n", eax); return 0; }
代碼解釋一下,asm的代碼中movl %%eax, %0的意思是把寄存器eax的值賦值給咱們程式的eax變數當中。但為什麼執行結果卻是:
z is 11
eax is 0
理論上應該是x和y相加返回的結果才對啊。反彙編一下此exe程式:
上面是main函數
[esp+1ch]對應的是eax,[esp+18h]對應的是z,[esp+10h]對應的是x,[esp+14h]對應的是y。再看下圖
esp自減了20h,說明開闢了20h也就是32位元組的棧空間,再看下圖:
先把[esp+10h]的值也就是x的值賦給eax,再把[esp+14h]的值也就是y的值賦給edx,再分別把它們賦給[esp+4]和[esp]處,註意這裡沒用push指令壓棧,但原理卻是一樣,因為用的是棧指針esp,還需要註意的是因為不是使用push指令,所以不是說誰先執行誰就先壓棧,而是觀察esp指向的位置來確定壓棧的先後順序,因為[esp]指向的是棧低。所以這裡就解釋了先把y壓棧,再把x壓棧,確實是從右向左壓棧。
接下來再看add調用:
先取了y的值再取x的值,相加後結果保存在eax里。然後再回到main函數
調用完add後把eax的值賦值給了z,這就說明函數的返回值確實是保存在eax中。但為什麼列印出來的eax卻是0呢。
接著往下看,
首先把程式中eax變數的值賦給了eax寄存器,那當然就是0了。所以現在深入理解了C語言嵌入彙編的執行過程,就算指定了"+b"賦給ebx寄存器,但編譯器還是會先把變數的值賦給eax寄存器,再賦值給ebx,返回也是一樣的原理,如下圖: