昨天和海洋一塊研究了下函式呼叫棧,順便寫兩句。不足或錯誤之處請包涵!
理解呼叫棧最重要的兩點是:棧的結構,ebp暫存器的作用。
首先要認識到這樣兩個事實:
2、幾乎所有本地編譯器都會在每個函式體之前插入類似如下指令:push ebp; mov ebp esp;
+| (棧底方向,高位位址) |
| .................... |
| .................... |
| 引數3 |
| 引數2 |
| 引數1 |
| 返回位址 |
-| 上一層[ebp] | <-------- [ebp]
「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;
__a** _ebp, ebp;
while (not stack bottom)
如果要寫乙個簡單的偵錯程式的話,注意需在被除錯程序(而非當前程序——偵錯程式程序)中讀取記憶體資料。
函式呼叫棧比較有意思
理解呼叫棧最重要的兩點是 棧的結構,ebp暫存器的作用。首先要認識到這樣兩個事實 2 幾乎所有本地編譯器都會在每個函式體之前插入類似如下指令 push ebp mov ebp esp 棧底方向,高位位址 引數3 引數2 引數1 返回位址 上一層 ebp ebp push ebp mov ebp es...
函式呼叫棧比較有意思
昨天和海洋一塊研究了下函式呼叫棧,順便寫兩句。不足或錯誤之處請包涵!理解呼叫棧最重要的兩點是 棧的結構,ebp暫存器的作用。首先要認識到這樣兩個事實 2 幾乎所有本地編譯器都會在每個函式體之前插入類似如下指令 push ebp mov ebp esp 棧底方向,高位位址 引數3 引數2 引數1 返回...
程式設計是比較有意思的事情
這些天一直在實驗室幹活,忙得不行,所以也沒時間來寫部落格,今天有時間了,先寫點對程式設計的體會。最近逐漸感覺程式設計是比較有意思的事情,它有意思在於讓我們比較有創造力。記得上個學期一來,由於深感教育網上國外 要上 上國內網 特別是教育網的 為了速度又要去掉 的麻煩,於是就寫了乙個ie的 指令碼,到網...