#include #include #include #include #include #include #include using namespace std;
int test(int a,int b)
int main()
我們在main函式第一行**處開始單步除錯。
ebp暫存器通常指向棧底,常用來定址當前函式內的區域性變數等。esp是指向堆疊棧頂的指標。x86/64 vc++的堆疊是從高位址向低位址生長,比如push乙個32位暫存器入棧後,esp - 04h。
第一行是push ebp,意思是將ebp入棧保護起來,雖然這個函式是main函式,但是流程和一般函式呼叫一樣,都是先將ebp入棧保護。
mov ebp,esp 是將當前棧頂指標給ebp,使其能夠定址區域性變數。
sub esp,0d8h 把棧頂指標esp移動到0d8h之後,這樣留出一塊隔離的空間,這個隔離空間的大小是由編譯器決定的。預設的隔離空間是192位元組。如果定義乙個int會在棧空間裡面占用12位元組?區域性變數也是存在隔離取內部的。
push esi
push edu
push ebx
是保護現場的3條彙編指令。
要理解lea edi,[ebp-0d8h] 的意思,先要搞清楚lea的意思。
假設:si=1000h , ds=5000h, (51000h)=1234h
執行指令 lea bx , [si]後,bx=1000h
執行指令 mov bx , [si]後,bx=1234h
實際上就是取內表示的資料的偏移位址。
lea edi,[ebp-108h]
mov ecx,42h
mov eax,0cccccccch
rep stos dword ptr es:[edi]
這四句結合在一起就是對留出的隔離區域和區域性變數所佔的空間進行清空,置為0xcccccccch。將每個位元組置為0xcch是有原因的,0xcch是int 3的位元組碼,int 3時斷點中斷指令。當意外的執行了棧中的內容時,會直接提示錯誤。
實際上是stos指令的作用是將eax中的值拷貝到es:edi指向的位址。rep指令是重複指令,重複次數存在暫存器ecx中。42h是10進製的66,就是重複66次。每次將乙個字的空間置為eax的值,重複66次就清空了264位元組。正好將隔離區和區域性變數所佔空間清空。
將立即數寫入棧空間。
下面是記憶體狀況。
因為下面要呼叫test函式,所以將a,b兩個int型變數入棧。
入棧順序為:
1.cdecl方式:c語言方式,引數從右邊開始入棧。
2.winapi方式:引數還是從右邊入棧。
上圖是test函式的彙編**。可以看出,與main函式的過程十分相似。首先也是將ebp入棧儲存,因為這個時候的ebp還是main函式的,所以儲存起來,然後把棧頂指標esp給ebp。現場保護和清空棧區域的**與main函式中的幾乎相同。
下一句是獲取引數資訊的。
mov eax,dword ptr [ebp+8]
這句ebp+8,實際上就是當前棧頂往棧底移動8個位元組。從這裡開始往後的4個位元組放入eax。下面那句彙編意思相同。
ebp+8的原因是,在呼叫call命令的時候會將當前的eip指標入棧。所以,這裡後移8位元組就能訪問到引數了。
mov dword ptr [ebp-8],eax 這句將計算結果放入ebp-8的位置,也就是區域性變數c所在的棧空間。
mov eax,dword ptr [ebp-8] 這句將[ebp - 8]棧的內容放入eax。函式的返回值就是通過eax暫存器返回的。
下面是記憶體狀況:
下面幾句恢復現場。
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
mov esp,ebp 這句將當前基指傳給棧頂指標。因為在test函式呼叫時,堆疊已經生長到這個地方了。
ret指令的內部操作是:棧頂字單元出棧,其值賦給ip暫存器。此時,ip指標就回到main函式繼續執行了。
最後返回main函式後會執行一句
add esp,8 這句的意思是平衡剛才有傳參占用的堆疊空間。從圖2中可知,ret後,esp會回到引數b的下面。此時,+8會使esp回到呼叫test前的位置,即恢復了棧頂指標。
簡單函式呼叫的彙編分析到此結束。下次分析new、malloc的區別。以及不同段的區別。
彙編看函式呼叫過程
分析下列原始碼 include dword stdcall function dword dwp1,pvoid p2 int main 轉彙編 vs2012 include dword stdcall function dword dwp1,pvoid p2 00fe1401 pop edi edi...
從彙編的角度分析函式呼叫過程(1)
函式的引數傳遞有2種方式 堆疊方式 暫存器方式。如果是堆疊方式傳遞的,就需要定義函式引數在堆疊中的傳遞順序,並約定函式被呼叫之後,由誰來平衡堆疊 如果是暫存器方式傳遞的,就需要確定引數存放在哪個暫存器中。每一種方式都有其優缺點,而且與使用的程式語言有關係,不存在哪種方式好與壞。我們在開發中經常遇到呼...
從彙編的角度分析函式呼叫過程(2)
include int add int a,int b int main 我們使用visual studio 2017編譯上面 並在在工程配置中將函式呼叫約定設定為 cdecl。在程式除錯過程中,可以在visual studio的反彙編視窗中看到c 對應的彙編 以及暫存器視窗中看到各個暫存器的值。m...