2012-09-19 27 views

回答

1

它不應該被用作通用寄存器。請適當謹慎地將其用作堆棧指針。例如。您可以使用'sub esp,...'指令爲堆棧上的本地變量保留一些內存,但是必須在ret指令之前恢復其原始值

+0

從你的回答我發現,它的值必須恢復,因爲這是唯一的寄存器指向哪裏將數據存儲在堆棧儀式>?所以是他們阻止它搞亂事情的原因? – archies50

+0

是的,絕對正確。 – Serge

0

在x86上,ESP是堆棧指針。最初,在16位8088和8086處理器上,寄存器簡稱爲SP,對於S大頭針P ointer。當在386處理器中添加32位支持時,E前綴(用於「擴展」)被添加到所有寄存器名稱,因此它變成了ESP。在當前模式下,堆棧指針始終具有與處理器本機字大小相同的位寬。也就是說,如果您在32位保護模式下執行,堆棧指針將爲32位寬,並存儲在ESP中。如果你在16位實模式下執行,堆棧指針將是16位寬,並存儲在SP中。

x86體系結構(不同地稱爲AMD64,x86-64或僅64位)的64位擴展將寄存器擴展爲64位,並添加了前綴R。因此,RSP寄存器包含堆棧指針,它在長(64位)模式下執行時爲64位寬。

雖然這個寄存器在概念上類似於其他寄存器(EAXECXEDXEBXESIEDI,和EBP),它不能以同等的方式使用。它被設計爲只有來保存堆棧指針,不能用作通用寄存器。

你沒有明確推送或彈出堆棧指針的原因是因爲這是由其他指令隱式完成的。實際上,PUSHPOP指令是操縱堆棧指針的指令,因爲它們將東西壓入堆棧並將其彈出。

在x86,堆棧總是在存儲器向下增長,所以PUSH將減去(根據操作數的大小)從堆棧指針字節的適當數目,而POP將添加字節的適當數目。

CALLRET指令還隱式地操縱堆棧指針。通過閱讀Intel x86體系結構手冊available here可以找到更多的細節。 標記wiki中還有很多其他資源可用。

您將看到ESP寄存器被明確操作的唯一時間是當它被用作ADDSUB指令中的目標操作數時。這些通常通過優化編譯器,根據需要遞增或遞減堆棧指針,以便騰出空間來存儲值或清理堆棧,從而插入到函數的序言和尾聲中。它們的功能類似於PUSHPOP,只是它們可以具有連續多次推送和彈出的效果。例如:

push eax 
push eax 
push eax 
push eax 
... 
pop eax 
pop eax 
pop eax 
pop eax 

可以簡單地進行更換:

sub eax, 16 
... 
add eax, 16 

(假設你沒有真正試圖EAX值並只使用PUSH使在房間堆棧)。

相關問題