#include
int add(int a, int b)
int main()
我們使用visual studio 2017
編譯上面**,並在在工程配置中將函式呼叫約定設定為__cdecl
。
在程式除錯過程中,可以在visual studio
的反彙編視窗
中看到c++**對應的彙編**,以及暫存器
視窗中看到各個暫存器的值。
main
函式的反彙編**如下:
int main()
執行進入add
函式後,add
函式內的彙編**如下:
int add(int a, int b)
01191701 pop edi // 將edi的值還原到函式呼叫前
01191702 pop esi // 將esi的值還原到函式呼叫前
01191703 pop ebx // 將ebx的值還原到函式呼叫前
01191704 mov esp,ebp // 移動棧頂到ebp位置,從而跳過了區域性變數儲存區域
01191706 pop ebp // 將ebp的值還原到函式呼叫前
01191707 ret // ret指令等同於:彈出此時棧頂的值給eip,
// 因為此時棧頂儲存的剛好是函式返回位址,所以相當於將返回位址賦值給eip,從而實現了返回到函式呼叫的地方。
在上面**的注釋中已經包含了詳細的解釋,特別值得注意的幾個地方是:
1.rep stos dword ptr es:[edi]
結合edi
,ecx
來初始化區域性儲存區域。
2. 函式call
指令之前的引數壓棧順序。
3.call
指令相當於執行一條push
指令加一條jmp
指令,push
指令用於壓入該指令的下一條指令位址到棧中,用於執行完子函式之後返回來。jmp
指令用於跳轉到子函式所在位置開始執行子函式。
4. 因為是__cdecl
,函式呼叫完之後,呼叫方使用add esp,8
來平衡堆疊。
5.ret
指令等同於:彈出此時棧頂的值給eip,巧妙之處在於此時棧頂儲存的剛好是函式返回位址。
從彙編的角度分析函式呼叫過程(1)
函式的引數傳遞有2種方式 堆疊方式 暫存器方式。如果是堆疊方式傳遞的,就需要定義函式引數在堆疊中的傳遞順序,並約定函式被呼叫之後,由誰來平衡堆疊 如果是暫存器方式傳遞的,就需要確定引數存放在哪個暫存器中。每一種方式都有其優缺點,而且與使用的程式語言有關係,不存在哪種方式好與壞。我們在開發中經常遇到呼...
彙編看函式呼叫過程
分析下列原始碼 include dword stdcall function dword dwp1,pvoid p2 int main 轉彙編 vs2012 include dword stdcall function dword dwp1,pvoid p2 00fe1401 pop edi edi...
從彙編分析函式呼叫堆疊詳細過程
首先由下面簡單的 我們來考慮兩個問題 1.main函式呼叫sum,sum執行完以後,怎麼知道回到哪個函式中?2.sum函式執行完,回到main以後,怎麼知道從哪一行指令繼續執行的?int sum int a,int b intmain 首先,大家都知道函式執行的時候要在棧幀上開闢空間。乙個函式的呼叫...