函式的呼叫過程 函式呼叫棧幀的建立

2021-08-15 12:25:30 字數 1479 閱讀 1902

函式的呼叫過程:

我們知道每一次函式呼叫都是乙個過程,這個過程我們通常稱之為:

函式的呼叫過程。

而這個過程要為函式開闢棧空間,用於本次函式呼叫中臨時變數的儲存,現場保護,這塊棧空間我們稱之為

函式棧幀。

而函式棧幀的維護需要兩個暫存器:esp和ebp,在呼叫過程中,這兩個暫存器存放了維護這個棧的棧頂和棧底指標。

舉個例子:

呼叫main函式,我們為main函式分配棧幀空間,那麼棧幀的維護如下圖:

注意:ebp永遠指向棧底    esp永遠指向棧頂

下面通過乙個簡單的**詳細了解下函式的呼叫過程:

#include int add(int x, int y)

int main()

1.我們先從main函式的地方開始,要展開main函式的呼叫就必須為main函式建立棧幀,下面看看main函式棧幀的建立:

注:在呼叫main函式之前會先呼叫乙個__tmaincrtstartup()函式

首先將ebp(__tmaincrtstartup())壓棧處理(方便函式返回之後的現場恢復),然後使esp的值賦給ebp,產生新的ebp(為main函式開闢空間做準備),給esp減去乙個16進製制數字4ch,產生新的esp,此時,已為main函式開闢好空間。在該棧空間的棧頂進行壓棧,分別壓進去三個暫存器,分別是ebx,esi,edi(esp向上移動,指向新的棧頂),把棧幀預開闢的空間全部初始化成0xcccccccc,接下來處理區域性變數a,b的建立。

2.接下來是add函式的呼叫:

先進行傳參,引數壓棧,先壓b,再壓a(利用eax暫存器),call指令的呼叫,先要壓棧call指令下一條指令的位址(保護現場,函式需要返回),然後跳轉到add函式的地方。

將ebp(main函式)進行壓棧,將esp的值賦值給ebp,給esp減去乙個十六進製制的數字44h,產生新的esp,此時為add函式預開闢好棧空間,把預開闢的棧空間全部初始化成0xcccccccc,建立變數z,獲取形參a和b相加,將結果儲存到z中,再次將結果儲存到eax暫存器中,通過暫存器帶回函式的返回值。

3.函式的返回部分:

三次pop出棧,使得esp(add函式)向下移動,將ebp的值賦值給esp,出棧,將出棧的內容內容儲存到ebp中,回到main函式的棧幀,接下來利用ret指令將程式跳轉到call指令下一條指令的位址處(ret指令會使得出棧一次,並將出棧的內容當作位址,將程式執行跳轉到該位址處)。

附:1.把運算結果放到z中,但是z不能返回給main(),所以又將z的值存到eax中,由eax帶回。

2.在函式呼叫時實參和形參並不在同乙個空間,而函式呼叫會直接去拿形參,對實參不會有影響。

3.儲存上乙個函式的ebp,是因為在函式呼叫完之後它需要返回上乙個函式的棧底4.

函式呼叫完之後,應返回call指令的下一條指令繼續執行程式。

函式的呼叫過程(函式棧幀)

乙個完整的能實現一些基本功能的程式總要或多或少的呼叫一些函式,但函式的具體呼叫過程是怎樣的,從列印出來的結果來看,顯然是無法得知的,這就需要對函式的呼叫過程有乙個深入地研究。從簡單的 開始 include intadd int x,int y intmain 進行程式除錯,檢視 呼叫堆疊 如下 可以...

函式呼叫過程(棧幀)

眾所周知,程式每呼叫乙個函式,系統都會為其開闢一塊空間,當它返回時,才收回這塊空間。程式崩潰有一部分原因就是因為無限制的呼叫函式,卻沒有及時返回,導致記憶體空間不夠。為了更好的維護這一塊空間 通常稱為棧空間 我們需要了解兩個暫存器,乙個為 esp 指向棧頂的指標 乙個為 ebp 指向棧底的指標 棧空...

函式棧幀(呼叫過程)

函式棧幀就是在呼叫函式是為其在棧空間上開闢了一段空間,指向過程呼叫,乙個過程呼叫包括將資料 以過程引數和返回值的形式 和控制從 的一部分傳遞到另一部分。我們以以下 為例講解整個函式呼叫過程 int my add int x,int y int main 一 呼叫main 函式 我們從main 函式的...