函式呼叫時的棧狀態

2021-05-24 09:19:21 字數 2139 閱讀 7463

右側的紅色部分,寫出了引發棧結構變化的對應的指令

+| (棧底方向,高位位址) |

| ....................|

| ....................|// call somefun(...)-->修改esp,棧向下增長,引數入棧,返回值入棧

| 引數3                |

| 引數2                |

| 引數1                |

| 返回位址             |

-| 上一層[ebp]         |              // push ebp   --->修改esp,棧向下增長

| 區域性變數1            |                 // sub esp 區域性變數占用空間 -->修改esp,棧向下增長

| 區域性變數2            |

|.....................|

補充:棧一直隨著函式呼叫的深入,一直想棧頂方向壓下去。每次呼叫函式時候,先壓函式引數(從右往左順序壓),再壓入函式呼叫下條指令的位址(由call 完成)。接著進入呼叫函式體中先執行push ebp; mov ebp esp;(一般已經由編譯器加入到函式頭中了),接著就是吧函式體中的區域性變數壓入棧中。再遇到函式的呼叫的巢狀則依此類推。(added by smsong)

「push ebp」「mov ebp esp」這兩條指令實在大有深意:首先將ebp入棧,然後將棧頂指標esp賦值給ebp。「mov ebp esp」這條指令表面上看是用esp把ebp原來的值覆蓋了,其實不然——因為給ebp賦值之前,原ebp值已被壓棧(位於棧頂),而新的ebp又恰恰指 向棧頂。

此時ebp暫存器就已處於乙個很重要的地位,該暫存器中儲存著棧中的乙個位址(原ebp入棧後的棧頂),從該位址為基準,向上(棧底方向)能獲取返回位址、引數值,向下(棧頂方向)能獲取函式區域性變數值,而該位址處又儲存著上一層函式呼叫時的ebp值!

一般而言,ss:[ebp+4]處為返回位址,ss:[ebp+8]處為第乙個引數值(最後乙個入棧的引數值,此處假設其占用4位元組記憶體),ss:[ebp-4]處為第乙個區域性變數,ss:[ebp]處為上一層ebp值。

由於ebp中的位址處總是「上一層函式呼叫時的ebp值」,而在每一層函式呼叫中,都能通過當時的ebp值「向上(棧底方向)能獲取返回位址、引數值,向下(棧頂方向)能獲取函式區域性變數值」。

如此形成遞迴,直至到達棧底。這就是函式呼叫棧。

編譯器對ebp的使用實在太精妙了。

從當前ebp出發,逐層向上找到任何的ebp是很容易的:

unsigned int _ebp;

__asm _ebp, ebp;

while (not stack bottom)

假如要寫乙個簡單的偵錯程式的話,注意需在被除錯程序(而非當前程序——偵錯程式程序)中讀取記憶體資料。

首先要認識到這樣兩個事實:

1、乙個函式呼叫動作可分解為:零到多個push指令(用於引數入棧),乙個call指令。call指令內部其實還暗含了乙個將返回位址(即call指令下一條指令的位址)壓棧的動作。

2、幾乎任何本地編譯器都會在每個函式體之前插入類似如下指令:push ebp; mov ebp esp;

即,在程式執行到乙個函式的真正函式體時,已有以下資料順序入棧:引數,返回位址,ebp。

由此得到類似如下的棧結構(引數入棧順序跟呼叫方式有關,這裡以c語言預設的cdecl為例):

注意以下幾個事實

1) 棧的變化僅當esp的值被改變

2)esp的值得變化僅當

1.1 發生在 push,pop的時候。

1.2 sub esp ,add esp eg: 剛進入乙個函式時,為了給區域性變數分配棧空間

3) push發生在

1)**中顯式的push,pop

2)call指令會讓引數入棧呼叫push,會讓返回值入棧,呼叫push       

4) ebp的值發生僅在 剛進入乙個函式時 push ebp esp

函式呼叫時的開銷

問題引入 在學習c語言時,老師強調過呼叫函式時會有開銷,但是函式呼叫的開銷體現在哪幾個方面並不十分清楚!舉例說明 寫乙個兩數求和的 此 中不呼叫函式 include int main 該程式對應的反彙編如下 include int main 00ba1419 pop edi 00ba141a pop...

列印函式呼叫時間

raii可以實現,通過new delete控制呼叫前後,很懶,只想加幾個字元,不想換行 snippet mlt include define mllog printf ifndef mllog error please define mllog endif struct mlt template m...

複製建構函式的呼叫時機

每日心得 獨上高樓,望盡天涯路 日期 12.14 學習內容 複製建構函式的呼叫時機 重點 1 用已知變數 去複製 新定義的變數 2 值傳遞的方式給函式引數傳值 3 以值的方式返回區域性物件 4 呼叫複製建構函式後,系統不提供預設建構函式 定義類的時候,需要構造和複製都有 include using ...