2014-11-22 96 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