2014-11-22 74 views
2

考慮x86指令ENTER。來自英特爾的指令集參考。x86 ENTER指令有什麼問題?

爲過程創建堆棧幀。第一個操作數(大小爲 操作數)指定堆棧幀的大小(即,爲該過程在堆棧上分配的動態存儲器的字節數 )。 第二個操作數(嵌套級別操作數)給出了過程的詞法嵌套 級別(0到31)。嵌套級別確定從前一幀複製到新堆棧幀的「顯示區域」 中的堆棧幀指針的數量。這兩個 操作數都是立即值。

我想知道ENTER指令如何作爲第二個操作數傳遞非零嵌套級別。在這種情況下,根據英特爾的手冊,處理器應該在堆棧上添加額外的幀指針。聽起來很簡單,但我不明白爲什麼它在示例程序中無法按預期工作。

我用FASM編譯了下面的例子,並用OllyDbg進行調試。

format PE 

section '.text' code readable executable 
entry start 
start: 
    enter 16, 8 
    push 0 
    call ExitProcess 
... 

ENTER指令發出的堆棧幀如下所示。

000CFF58 00000000 ; new esp 
000CFF5C 00000000 
000CFF60 00000000 
000CFF64 00000000 
000CFF68 000CFF88 ; value of new ebp 
000CFF6C 7EFDE000 ; ? 
000CFF70 000CFF94 ; value of old ebp 
000CFF74 76AD338A ; ? 
000CFF78 7EFDE000 ; ? 
000CFF7C 000CFF94 ; value of old ebp 
000CFF80 76AD338A ; ? 
000CFF84 7EFDE000 ; ? 
000CFF88 000CFF94 ; value of old ebp 
000CFF8C 76AD338A ; old esp 

結果很奇怪。讓我們用gcc做同樣的事情。

> cat enter.s 
.globl _start 

.text 
_start: 
    enter $16, $8 
    movl $1, %eax 
    movl $0, %ebx 
    int $0x80 

> gcc -m32 -g -c enter.s && ld -melf_i386 enter.o 
> gdb a.out 
... 
(gdb) r 
... 
Program received signal SIGSEGV, Segmentation fault. 
_start() at enter.s:5 
5   enter $16, $8 

Errr,確定...

我可能誤解它如何工作。我唯一的猜測是ENTER指令是由OS以某種方式處理的,但這幾乎肯定是錯誤的。

+4

'進入'是x86指令集中許多壞主意之一,比如'loop [cc]'。很遺憾,AMD在定義x86-64時沒有清除它。 – EOF 2014-11-22 17:11:55

回答

5

enter指令的嵌套格式假定您已在ebp中有一個有效的幀指針,在進程開始時並非如此。想必這就是你爲什麼會犯錯的原因。

試試這個:

_start: 
    enter $0, $0  # set up initial stack frame 
    push $1 
    push $2    # simulate two previous frame pointers 
    enter $16, $3  # nested proc level 3, esp should be 32 less 
    movl (%ebp), %eax # should be previous ebp 
    movl -4(%ebp), %eax # should be 1 
    movl -8(%ebp), %eax # should be 2 
    movl $1, %eax 
    movl $0, %ebx 
    int $0x80 

另請參見6.5.1 ENTER指令英特爾®64和IA-32架構軟件開發人員手冊卷1:基本架構

+0

明智的答案!謝謝! – newbie 2014-11-22 17:15:38