函式呼叫堆疊

2021-08-06 01:10:45 字數 3509 閱讀 7766

一、函式呼叫堆疊

認真體會每一行指令位址!!!

#include 

intsum(int a, int b)

//mov ebp,esp 讓esp回退到ebp的位置,回退棧幀的過程中,沒有對棧幀中的值進行清0的操作

//pop ebp 出棧並把出棧的值賦給ebp

int main()

下圖為上面示例函式,程式在sum函式中,棧的記憶體布局情況:

二、函式的返回值:

<=4byte eax

<4 <=8 eax,edx

8 產生臨時量

驗證返回值小於等於8位元組的時候,返回值是怎麼帶回去的:

#include

typedef struct data

data;

data

sum(data a, data b)

; tmp.a = a.a + b.a;

return tmp;

}int main()

; data b = ;

data ret = ;

ret =

sum(a,b);

return

0;}

以上**在sum返回時,對應的彙編指令為:

return

tmp;

008c16cd

moveax,dword

ptr[tmp]

008c16d0

movedx,dword

ptr[ebp-0ch]

所以,大於4位元組,小於等於8位元組的函式返回值是由兩個暫存器eax、edx返回給呼叫方的;

那麼大於8位元組的呢???

函式產生臨時量的三種情況:

<1>函式呼叫之前;

<2>函式呼叫return的時候;

<3>函式呼叫接受返回值的時候,當呼叫函式的時候,需要判斷返回值是否大於8位元組,如果大於,那麼就需要傳入呼叫方的一塊臨時量位址,所以這個時候已經產生臨時量了;

驗證返回值大於8位元組的時候,返回值是怎麼帶回去的:

#include

typedef struct data

data;

data

sum(data a, data b)

; tmp.a = a.a + b.a;

return tmp;

}int main()

; data b = ;

data ret = ;

ret =

sum(a,b);

return

0;}

以下為呼叫sum是,產生的臨時變數:

ret = sum(a,b);

012f1785 sub esp,0ch //把變數b的值拷貝乙份,作為sum的引數

012f1788 mov eax,esp

012f178a mov ecx,dword ptr [b]

012f178d mov dword ptr [eax],ecx

012f178f mov edx,dword ptr [ebp-24h]

012f1792 mov dword ptr [eax+4],edx

012f1795 mov ecx,dword ptr [ebp-20h]

012f1798 mov dword ptr [eax+8],ecx

012f179b sub esp,0ch //拷貝a的值,作為sum的形參

012f179e mov edx,esp

012f17a0 mov eax,dword ptr [a]

012f17a3 mov dword ptr [edx],eax

012f17a5 mov ecx,dword ptr [ebp-10h]

012f17a8 mov dword ptr [edx+4],ecx

012f17ab mov eax,dword ptr [ebp-0ch]

012f17ae mov dword ptr [edx+8],eax

012f17b1 lea ecx,[ebp-124h]//由於返回值大於8位元組,所以在main的棧空間中開闢一塊臨時量位址,壓入sum的棧中;

012f17b7 push ecx

012f17b8 call sum (012f108ch)

當sum函式返回的時候,將sum中的區域性變數的值,拷貝到了ebp+8的地方,這是main函式中臨時量的記憶體位址;

return tmp;

012f16d0 mov eax,dword ptr [ebp+8]

012f16d3 mov ecx,dword ptr [tmp]

012f16d6 mov dword ptr [eax],ecx

012f16d8 mov edx,dword ptr [ebp-10h]

012f16db mov dword ptr [eax+4],edx

012f16de mov ecx,dword ptr [ebp-0ch]

012f16e1 mov dword ptr [eax+8],ecx

012f16e4 mov eax,dword ptr [ebp+8]

三、函式的呼叫約定_cdecl c呼叫約定

_stdcall windows標準的呼叫約定

_fastcall 快速呼叫約定

_thiscall c++成員函式的呼叫約定

呼叫約定影響函式的三個方面:

1、函式產生的符號名字不同;

2、函式引數入棧順序不同; 右—->左

3、誰來清理形參的記憶體;

_cdecl 由呼叫方開闢形參記憶體,呼叫方釋放形參記憶體;

_stdcall 呼叫方開闢形參記憶體,被呼叫方自己釋放形參記憶體;

_fastcall 呼叫方開闢形參記憶體,但是把最左邊(也就是最後的8個位元組通過兩個暫存器帶到被呼叫方的函式棧中)被呼叫方自己釋放形參記憶體;

函式呼叫堆疊

一 棧 1 傳統的棧 被定義為乙個特殊的容器,使用者可以將資料壓入棧中,也可以將壓入 棧中的資料彈出,但必須遵守一條規則 先進後出。2 計算機系統中的棧 是乙個有以上屬性的動態記憶體區域,壓棧操作使得棧增大,彈出操作使棧減小。棧通常是向下增長的。3 最重要的是棧儲存了乙個函式呼叫所需的維護資訊,這通...

函式呼叫堆疊

乙個函式的執行在棧上開闢記憶體。在函式呼叫時,第乙個進棧的是主函式呼叫語句的下一條可執行語句的位址,然後是函式的各個引數。在大多編譯器中,引數是由右往左入棧的,然後再是函式中的區域性變數。下面給乙個例項 int sum int a,int b int main 其中,main函式的反彙編指令 其中,...

函式呼叫堆疊

1.函式呼叫堆疊 壓棧 呼叫函式 1.壓入形參變數的位址和值 2.壓入函式呼叫返回後要執行的指令的位址 被呼叫函式 1.壓入呼叫函式的棧底指標,把棧底指標暫存器指向被呼叫函式的棧底 2.開闢被呼叫函式的棧幀大小,並初始化為cc 清棧 被呼叫函式 1.清理被呼叫函式開闢的棧幀大小 2.回退棧底指標到呼...