函式呼叫過程

2021-08-14 05:28:19 字數 3219 閱讀 2049

每乙個未執行完的函式都對應著乙個棧幀,系統為單個函式分配的那部分棧空間就叫做棧幀,棧幀儲存了函式的資訊。

以下面的**為例,通過彙編**的執行過程介紹棧幀建立和銷毀的過程

#include 

int add(int

x, int

y)

int main()

從main函式建立自己的棧幀開始(其他內容先忽略),初始狀態:

ebp和esp所表示的這一段記憶體空間叫棧幀,也就是粉色框框區域

10:    int a = 10

;00401078

mov dword ptr [ebp-4],0ah

11: int b = 20

;0040107f mov dword ptr [ebp-8],14h

12: int c = add(a, b);

00401086

mov eax,dword ptr [ebp-8]

00401089

push eax

0040108a mov ecx,dword ptr [ebp-4]

0040108d push ecx

0040108e call @ilt+0(_add) (00401005)

00401093

add esp,8

00401096

mov dword ptr [ebp-0ch],eax

13: printf("c = %d\n", c);

mov dword ptr [ebp-4],0aha的值是10,也就是0ah,將a賦值到ebp所指向空間的下乙個空間,dword ptr指明大小是雙字(4個位元組,也就是int的大小)

mov dword ptr [ebp-8],14h

同理把b的值放到ebp的下下個空間

mov eax,dword ptr [ebp-8]

把b賦值給eax

push eax

eax入棧,即剛剛的b入棧

push有兩個步驟:

(esp)=(esp)-4;

(esp)=(eax);

所以esp向下移動,b是棧頂第乙個元素

mov ecx,dword ptr [ebp-4]

push ecx

同理a入棧,現在a成了棧頂元素

call @ilt+0(_add) (00401005)

@ilt+0(_add) (00401005)是乙個標號,這裡標記著add函式的入口

執行這一步就進入add函式內部了

3:    

0040104b pop edi

0040104c pop esi

0040104d pop ebx

0040104e mov esp,ebp

00401050

pop ebp

00401051

ret

push ebp第一步先將main函式的ebp入棧,儲存呼叫函式的棧底指標

mov ebp,esp

sub esp,44h

將esp賦值給ebp(也就是說被呼叫函式的棧底指標其實是呼叫函式的棧頂指標),這裡修改了棧底指標ebp

然後esp=esp-44h,44h即為add函式棧幀的大小,esp向下移動了44h個位元組,現在add函式的棧幀形成了

mov dword ptr [ebp-4],0

相當於在ebp下面開闢了乙個新的空間,並賦值為0

mov eax,dword ptr [ebp+8]

add eax,dword ptr [ebp+0ch]

mov dword ptr [ebp-4],eax

將a+b賦值給剛剛定義的z

現在位址空間結構如下:

接著就要將返回值返回了,先將返回值賦值給eax

mov esp,ebp

pop ebp

ret將ebp賦值給esp,然後彈出棧頂元素賦值給ebp

即 ebp = main的ebp;

esp = esp+4;

ret

ret其實就是 pop eip

彈出棧頂元素賦值給eip,現在的棧頂元素是 call壓入的返回位址,同時esp上移

現在的位址空間結構如下:

然後回到了main函式

add esp,8

esp向上移動兩個int型大小,釋放掉了函式引數x和y

mov dword ptr [ebp-0ch],eax

ebp-0ch是b再往下的一塊空間,即此時定義了c變數,並同時把add函式的返回值賦值給c

現在main函式的棧幀恢復到剛開始的狀態,開始執行後面的**

函式add的呼叫過程結束了,它所使用的空間也全部釋放掉了

在查閱資料的過程中,我發現對於棧幀大家都有不同的理解,我也沒能找到最標準的定義,有人認為函式的棧幀是從形參的記憶體分配開始,也有人認為棧幀是從ebp的指向開始

我比較認可第二種,所以我覺得函式的引數是不在函式自己的棧幀中的,而是在呼叫這個函式的函式中。

。。。。過程。。。。

函式呼叫過程

c語言種有三種迴圈 do.while while for 初始化 條件判斷 步進 主函式 main 庫函式自定義函式函式的發明,使得變成可以以函式為單位進行模組化,叫做面向過程。軟體工程中,有 高內聚,低耦合 的要求。函式就是為了實現以上要求發明的產物。函式是面向過程的 介面 其介面包含了 引數 返...

函式呼叫過程

引數代入順序 引數入棧的順序是從右向左入棧的。8位元組的引數代入 push入棧的方式將引數傳遞 8位元組的引數代入 先在main函式的棧頂向上移動12位元組,然後將引數的資料拷貝到main函式棧頂開闢的記憶體。int fun1 int a,int b int main 第一步進行函式引數入棧,如圖 ...

函式呼叫過程

主要流程 呼叫前的準備 引數入棧,eip 入棧,ebp 入棧,eip跳轉 函式執行 恢復到呼叫前狀態 返回值 eax,恢復ebp,恢復 eip include intf intmain call f 0b711d6h pushl ebp movl esp,ebp subl 16,esp movl e...