關於IA32的過程調用

在IA32的機器上,只提供了控制轉移的指令。至於一些局部變量以及數據傳遞則要靠棧來實現。

爲每一個過程分配的內存空間叫做棧幀,它包含兩個特殊的參數,棧指針和幀指針。一個指向棧頂一個指向棧低。

棧是向低地址增長的,也就是說,棧的底部在內存的高地址部分。

調用者棧的結束邊界是在執行call指令的時候將返回地址壓入棧中,被調用者棧的起始邊界是在保存禎指針ebp的值之後。

一般來說,數組等需要連續內存存儲的數據結構都需要在棧中進行存儲。在棧中擴展和回收空間其實都是靠移動棧指針來進行的。所謂的擴展空間,擴展的可能是其他程序剛剛用過的棧空間,但是現在可以進行覆蓋,回收空間只是把棧指針向高地址段移動,有數據仍然在你剛剛釋放的空間裏面。


1、關於IA32提供的轉移控制指令:

call

leave

ret

這三個指令是在每一次調用過程中都必須存在的,如果三個指令缺少其中一個,那麼很可能就不算是一個 調用過程。

call指令的具體 效果,是將返回地址壓入調用者的棧中,作爲它的棧裏面的最後一個元素,並且將程序計數器eip裏面的數值改變爲被調用者的地址。

ret指令是從棧中彈出這個返回地址,讓程序回到調用之前被調用函數下一條指令繼續進行。

leave指令一般在ret指令之前進行,它是爲回到返回地址進行一些準備工作,比如回收棧空間,並且重置棧指針和幀指針,因爲你調用完成之後是需要把兩個重要的指針復位的。

leave的指令 等價於這兩條指令 movl ebp esp , popl ebp。第一條指令的作用就是回收棧空間,把棧頂指針向上移動,和ebp指向同一條指令,ebp現在所指向的內存空間存儲的是調用者的 ebp,也就是舊的ebp的值。第二條指令,將舊的ebp值恢復到ebp的寄存器,也就是將幀指針 重新指向調用者的棧底,此時esp因爲彈出一個元素的原因 ,向上移動棧指針,正好指向了返回地址的那一塊內存空間,此時就可以利用ret命令進行返回了。


2、過程調用

首先要明確一點的就是,向被調用者傳遞的參數是存儲在調用者的棧中的。一般來說,一個被調用者的棧的起始點都是調用者ebp的值,爲了以後恢復方便。過程調用期間,會通過棧來分配一些自由的內存空間用於存儲一些臨時的變量,但是在這種類型的分配方式下,是要遵循分配的空間 必須是16字節整數倍這樣的 一個規定 ,這是X86編程的一個規定。所以你就會看到,在很多時候,明明分配了很多空間,但是都沒用到。


被調用過程在進行的時候,要先將舊的ebp壓入棧中,並且初始化兩個棧指針,之後要將一些被調用者保存的寄存器裏面的值壓入棧中保存,防止在之後的代碼中會覆蓋這些數據。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章