每乙個未執行完的函式都對應著乙個棧幀,系統為單個函式分配的那部分棧空間就叫做棧幀,棧幀儲存了函式的資訊。
以下面的**為例,通過彙編**的執行過程介紹棧幀建立和銷毀的過程
#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],0ah
a的值是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...