C語言在x86上使用堆疊的方式

2021-10-05 17:16:05 字數 1759 閱讀 8291

堆疊區是同一片空間,但堆向上生長,棧向下生長,中間是空閒區域。

esp棧指標暫存器,其內存放著乙個指標,該指標永遠指向系統棧最上面乙個棧幀(當前正在使用的棧幀)的棧頂(邏輯上是棧頂,但物理上是最低的位置。)

在該堆疊保留區域中該位置以下的所有內容都是空閒的。

將值壓入堆疊需要減少棧指標,然後將值寫入棧指標指向的位置。

從棧中彈出乙個值需要讀取棧指標指向的值,然後增加棧指標。

在32位模式下,棧只能儲存32位值,並且esp始終可被4整除。

ebp:基址指標暫存器(extended base pointer),其內存放著乙個指標,該指標永遠指向系統棧最上面乙個棧幀的底部(物理上最高的位置)。

在通常情況下esp是可變的,隨著棧的增長而逐漸變小,而ebp暫存器是固定的,只有發生函式呼叫後才會改變。

修正:圖中下面乙個ebp+4應該為ebp-4,而ebp-4及下面的部分指向的是儲存的暫存器、區域性變數以及臨時值。

函式呼叫過程如下:

被呼叫函式開始執行

push    ebp  ;以便於在執行完畢後恢復現場是還原ebp的值。

mov ebp,esp ;新的ebp

即通過將前乙個函式的基址指標壓入堆疊來儲存該基址指標,然後將當前esp值複製到ebp中,並在當前函式執行時間內保持不變。

如果程式中的所有函式都遵守該約定,則在程式執行過程中的任何給定時間點,都可以通過儲存的ebp鏈來追溯整個棧並確定當前巢狀函式呼叫順序。

為它的區域性變數分配空間,同時,也必須為它可能用到的一些臨時變數分配空間。

sub esp,

0cch;減去的值根據程式而定

根據情況看是否儲存某些特定的暫存器(ebx,esi和edi)

ebp的值會保持固定。此後區域性變數和臨時儲存都可以通過基準指標ebp加偏移量找到了

函式執行完畢,控制流返回到呼叫者的函式(caller)之前會進行下述操作

pop         edi

pop esi

pop ebx

mov esp,ebp

pop ebp

ret

c語言引數壓棧順序是從右到左,這是為了支援可變長引數的函式。

以cprintf()函式為例。

在我做過的jos作業系統中,該函式原型是

int

cprintf

(const

char

*format,...);

這就是乙個可變長引數形式,引數的具體個數由format中的佔位符%決定。

format最先入棧,然後把其他引數入棧。

那麼format上面就壓著未知個數的引數。

要想確定引數的個數,就必須找到format的位置,但是要想找到format的位置,又必須已經知道引數的個數,顯然陷入了死迴圈。

函式呼叫時,先把若干個引數都壓入棧中,再壓format。

format最**棧,在棧頂,可以通過ebp加上相應偏移量直接取出,再通過format中的%確定引數的個數,從而正確獲取屬於該函式的所有引數。

在x86彙編中使用C語言的全域性變數

在閱讀于淵 乙個作業系統的實現 時,遇到如下乙個問題 在 chapter6 r kernel kernel.asm中,有這樣一段彙編 357 restart 358 mov esp,p proc ready 359 lldt esp p ldt sel 360 lea eax,esp p stack...

X86上4系統的安裝

x86上4系統的安裝 0.x86 pc 配置 cpu p4 2ghz ram 1gb hdd ide 120gb nic rt8139 video i865g sound ac97 1.分割槽布局 format grub win lin macosx sunos os name kenerl ver...

X86架構上函式呼叫過程的堆疊

理解呼叫棧最重要的兩點是 棧的結構,ebp暫存器的作用。首先要認識到這樣兩個事實 1 乙個函式呼叫動作可分解為 零到多個push指令 用於引數入棧 乙個call指令。call指令內部其實還暗含了乙個將返回位址 即call指令下一條指令的位址 壓棧的動作。2 幾乎所有本地編譯器都會在每個函式體之前插入...