2010-04-28 39 views
5

我知道這個主題已被覆蓋ad nauseam在這裏,以及在互聯網上的其他地方 - 但希望這個問題是一個簡單的問題,因爲我試圖讓我的頭繞着程序集...程序集中的堆棧/基址指針

所以,如果我理解正確的ebp(基指針)將指向堆棧的頂部,並且ESP(堆棧指針)將指向底部 - 因爲堆棧向下增長。因此,指向'當前位置'。 因此,在函數調用中,一旦將ebp保存在堆棧中,您將爲該函數插入一個新的堆棧幀。所以對於下面的圖片來說,如果你從N-3開始,你可以通過函數調用來使用N-2。但是當你在N-2時 - 你的ebp == 25和esp == 24(至少在開始之前,在將任何數據放入堆棧之前)?

這是正確的還是我在這裏的切線?

謝謝!

http://upload.wikimedia.org/wikipedia/en/a/a7/ProgramCallStack2.png http://upload.wikimedia.org/wikipedia/en/a/a7/ProgramCallStack2.png

+0

我打算繼續並將其標記爲C,因爲它聽起來像是在試圖瞭解C編譯器生成的代碼是幹什麼的。如果這不正確,請隨時刪除該標記。 – Earlz 2010-04-28 01:30:16

回答

3

這實際上不僅取決於硬件體系結構和編譯器,而且還取決於calling convention,它只是一個協議的方式,在這種方式下函數與堆棧相互調用。換句話說,根據你的編譯器設置(和特殊的#pragma選項等等),函數可以把東西壓入堆棧的順序是不同的。

看起來您正在談論x86架構上的cdecl調用約定。在這種情況下,呼叫者的ebp通常會在返回地址後立即被壓入堆棧。因此,在您的示例的N-2中,位置25將包含一個指向調用函數N-3的指針(即,它將包含緊接在call之後的指令地址,將您引入N-2),而位置24將包含舊的ebp,並且在任何當地人被推入堆棧之前,您的esp將在調用後立即= 23。 (除了一些編譯器會在調用之後立即在堆棧上騰出空間,所以ESP將是20而不是在N-2函數內上下移動。)

然而注意,在x86有一個特殊的優化編譯器可有時候稱爲frame pointer omission,從而避免了推老ebp到堆棧乾脆在一定條件下。

0

這取決於平臺,但是這通常是如何工作的。

在我最熟悉的架構上,「調用」(又名返回)地址位於$ ra寄存器中,堆棧位於調用者留下的任何位置。因此,返回地址會像您的(調用者的)基址指針一樣被壓入堆棧,然後基指針被更新以指向堆棧所在的位置,並且堆棧不斷爬取。事情發生的準確順序以及我不記得時的設置順序,但通常取決於被調用者保存將被破壞的寄存器。這樣,如果被調用的函數只使用一個或兩個寄存器,則調用函數不需要保存所有內容。 (實際上,返回地址寄存器是相同的 - 如果函數沒有調用其他任何東西,它將不會被壓入堆棧。)

這實際上很容易遵循,如果你反彙編程序並採取偷看功能序言和結尾。它們都遵循很常見的「存儲所有內容」的模式,並在底部「恢復所有內容」。 (請注意,有些「特殊」寄存器永遠不會被存儲或恢復,並且編譯器知道只有在沒有函數調用的情況下,它才能計算出相關的值。在MIPS上,我認爲它們是S寄存器,和PPC調用它們?)

2
  1. 調入N-3後,ebp28,並且esp25
  2. 將舊的ebp推入,然後將 的ebp設置爲當前的 的值esp。現在espebp都是24
  3. 最後,調整esp以使 爲局部變量留出空間。 esp現在可能是 20,這取決於 函數在調用 N-2時的行爲。

瞭解你的頭腦的最好方法是閱讀function prologues,並熟悉x86實現。它也有助於接受使用espebp來定位每個函數中堆棧的使用,編譯器,體系結構和平臺之間有一些差異(並且與任何語言級別高於或等於C的用戶幾乎無關)。

+1

恥辱我不能接受兩個答案 - 謝謝你的指針! – malangi 2010-04-28 10:02:26