下面我們主要從棧的層面深入了解c語言中函式呼叫的過程。
下面我用乙個簡單的程式說明:
#include
#include
int add(int x, int y)
int main()
011e1880
pop edi
011e1881
pop esi
011e1882
pop ebx
011e1883
add esp,0e4h
011e1889 cmp ebp,esp
011e188b call __rtc_checkesp (011e112ch)
011e1890
mov esp,ebp
011e1892
pop ebp
011e1893
ret
add函式彙編**:
int add(int x, int y)
011e1731
pop edi
011e1732
pop esi
011e1733
pop ebx
011e1734
mov esp,ebp
011e1736
pop ebp
011e1737
ret
首先,我們在這裡必須的先了解倆個暫存器:
ebp
———棧底的位址
esp
———棧頂的位址
每乙個函式的呼叫都需要在棧上開闢空間,而開闢的空間都由ebp和esp維護
而且ebp和esp維護的是呼叫main函式的maincrtstartup函式的空間。
接下來我們進去main函式痕跡彙編**一步一步來了解函式呼叫的過程以及棧的建立和銷毀:
int main()
這裡add函式的呼叫同main函式呼叫過程相同,執行上端**後得到結果如圖示:
棧的銷毀:
011e1731 pop edi
011e1732 pop esi
011e1733 pop ebx
pop就相當於出棧的意思,esp此時指向ebx下面的空間,這三個位址相當於被**;
011e1734
mov esp,ebp
011e1736
pop ebp
011e1737
ret
這裡把ebp的值給esp,然後再將ebp出棧,這裡的ebp是main函式的ebp,ret指令要返回值,首先把棧頂call執行下一條指令的位址出棧,然後緊接著跳到下面這一行的位址。這也就是為什麼把之前的位址儲存起來,起一定的返回作用。
011e1850
add esp,8
esp+8直接把定義的形參跳了過去,到這一步的時候,add棧幀已經被銷毀了。
011e1853
movdword
ptr[ebp-0ch],eax
eax裡存放的是add函式裡的的值,把eax的值放入ebp-0ch,ret就把z的值返回了。
在棧幀銷毀的過程中返回值是通過暫存器返回的。
函式的呼叫及棧幀的建立和銷毀
函式在呼叫的過程中分為三步,第一步是函式的呼叫,第二步是執行函u數體,第三步是返回。第一步 函 數的呼叫 2.將實參從後往前依次入棧 3.跳轉到函式體處。第二部 函式體執行 1.如果函式體中定義了變數,將變數入棧 2.將每乙個形參用實參的值取代,執行函式體的功能 3.將函式體中的變數和儲存到棧中的實...
函式呼叫程序 棧楨
函式呼叫過程 棧楨 例 剖析 比較兩個數之間的大小關係,並把較大數返回 的呼叫原理 intmax intx,inty intmain 分析 圖一 main函式是被maincrtstartup呼叫的,所以main函式棧楨的ebp 1存放的是maincrtstartup棧楨ebp 觀察上圖maincrt...
函式的呼叫過程 棧幀的建立和銷毀
首先我們要了解一些概念。1.棧 stack 由編譯器自動分配釋放,存放為執行函式而分配的區域性變數 函式引數 返回函式 返回位址等。操作方式類似於資料結構中的棧。棧向下生成 先定義的位址高,後定義的位址低 2.堆 heap 由程式設計師分配釋放 若程式設計師不釋放,程式結束時可能由os 分配方式類似...