2010-10-14 51 views
2

儘管看着教科書試圖抓住這一點,但我遇到了麻煩。設置後幀指針指向哪裏?

0x08048b29 <func+0>: push %ebp 
    0x08048b2a <func+1>: mov %esp,%ebp 
    0x08048b2c <func+3>: push %ebx 
    ... 
    0x08048b30 <phase_2+7>: lea -0x28(%ebp),%eax 

在lea指令中,我明白%eax在%ebp之前得到的值是0x28,但究竟在哪裏呢?它是0x8048b29 - 0x28(函數開始之前的0x28)還是什麼?

回答

1

ebp寄存器通常用於函數內部以訪問傳遞給該函數的任何參數。在調用此函數之前,任何未通過寄存器傳遞的參數都會被壓入堆棧。在該函數開始時,調用函數的基址指針被保存。

(1)0x08048b29 <func+0>: push %ebp

堆棧的頂部新被複制到EBP以用作在該功能的基指針。

(2)0x08048b2a <func+1>: mov %esp,%ebp

最後,EBX被保存,這是有可能傳遞給該函數在寄存器中的變量。

(3)0x08048b2c <func+3>: push %ebx

所有這些函數入口代碼後,EBP寄存器指向入堆棧的中部。在棧上方(朝向最新推送的項目)是在上面#3中推送的ebx值。在堆棧下面是來自調用函數的舊ebp(保存在上面#1中),最重要的是...通過堆棧傳遞給此函數的任何參數(在函數調用之前完成)。

(4)lea -0x28(%ebp),%eax

最終指令參照的由堆棧傳遞這些參數之一。 ebp最終指向堆棧,而不是任何函數的代碼地址。這對於ebp來說是非常正常的,它通常用作指向堆棧的指針。

+0

他們這樣做的原因是,參數總是可以被相同的ebp偏移量引用。您不能使用esp來達到此目的,因爲此功能可能需要使用堆棧指針來執行臨時推/拉指令。 – 2010-10-14 22:38:40

1

的上下文看這個函數調用那個函數。它執行的代碼,以便看起來像:

caller+...: push argN 
caller+...: ... 
caller+...: push arg0 
caller+...: call func 

即參數被放入堆棧在這樣的順序是,在進入func(),堆棧將具有以下佈局:

[esp+(N*4)] : argN 
...   : arg(N-1)...arg2 
[esp+4 ] : arg1 
[esp  ] : <return address to caller()+...> 

然後您執行push %ebp; mov %esp, %ebp序列,改變%esp(由-4),以使您的佈局現在是:

[ebp+4+(N*4)][esp+(N*4)] : argN 
...      : arg(N-1)...arg2 
[ ebp+8  ][esp+8 ] : arg1 
[ ebp+4  ][esp+4 ] : <return address to caller()+...> 
[ ebp  ][esp  ] : <saved %ebp of caller> 

代碼然後繼續推動堆棧上的更多寄存器 - 因爲每次%esp被更改爲-4時向下增長。最終(你沒有在你的反彙編中顯示,但它會在那裏),你會得到一條指令subl $..., %esp。這就是爲你的局部變量分配空間的原因。最終的堆棧佈局是一樣的東西:

[ebp+4+(N*4)][   ] : argN 
...      : arg(N-1)...arg2 
[ ebp+8  ][   ] : arg1 
[ ebp+4  ][   ] : <return address to caller()+...> 
[ ebp  ][   ] : <saved %ebp of caller> 
[ ebp-4  ][   ] : <saved %ebx of caller> 
[ ebp-8  ][   ] : ... 
...      : region for local variables 
[ ebp-?? ][ esp  ] : end of stack for func() 

[esp ... ebp-4]之間的任何地址內什麼要求你的函數的棧幀,它包含無論是在的情況下保存代表調用(如ebx的寄存器反彙編顯示你)或局部變量。

因此,如果您在代碼中看到對%ebp - XX的任何訪問權限,那麼它位於本地變量空間中,如果您看到%ebp + YY它位於包含函數參數的空間內。