從彙編的角度分析函式呼叫過程(2)

2021-08-15 14:48:36 字數 1372 閱讀 9291

#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 首先,大家都知道函式執行的時候要在棧幀上開闢空間。乙個函式的呼叫...