popl%esp的替代方案

时间:2014-10-15 18:30:31

标签: assembly x86 stack cpu-registers ia-32

在3.4.2节中,IA32 popl指令被描述为复制结果 堆栈顶部到目标寄存器,然后递增堆栈 指针。所以,如果我们有一个popl REG形式的指令,它将是等价的 到代码序列:

movl (%esp),REG //Read REG from stack
addl $4,%esp //Increment stack pointer

一个。根据问题4.7中的分析,此代码序列是否正确 描述指令popl%esp的行为?解释

B中。你怎么能重写代码序列,以便正确地描述它们 REG是%esp以及任何其他寄存器的情况?

问题4.7:

以下汇编代码函数可让我们确定指令的行为 IA32的popl%esp:

1 .text
2 .globl poptest
3 poptest:
4 pushl %ebp
5 movl %esp, %ebp
6 pushl $0xabcd Push test value
7 popl %esp Pop to stack pointer
8 movl %esp, %eax Set popped value as return value
9 leave Restore stack and frame pointers
10 ret

我们发现此函数始终返回0xabcd。这对popl%esp的行为意味着什么?什么其他Y86指令会有完全相同的行为?


我对第一个问题中的代码序列是否正确描述了popl%esp指令的行为感到不知所措。起初我认为是的,因为它从堆栈中获取REG就像popl一样会返回值(我可能错了),然后它将esp递增4以从堆栈中删除该实例。

然后我遇到了声明" popl%esp指令在堆栈旧堆栈的数据写入目标之前递增堆栈指针。"

如果是这种情况,那么在将值放入目标寄存器之前,应该将4增加到esp,这样做

movl (%esp),REG //Read REG from stack
addl $4,%esp //Increment stack pointer

popl%esp。

的错误表示

有人可以澄清它是否真的没有正确描述行为或popl%esp?

1 个答案:

答案 0 :(得分:3)

确实这是pop的错误等价物。有趣的是,这也是英特尔在官方指令集参考中使用的。但至少他们确实在文中说清楚了。更好的等效代码是:

leal 4(%esp), %esp ; use lea to preserve flags (thanks to @Sparky)
movl -4(%esp), REG

然而,这只是一个逻辑等价物,因为实际上有人(例如中断或信号处理程序)可能会破坏两个指令之间的堆栈上的值。原始代码不会遇到这个问题。

请注意,这也适用于内存操作数,手册中说:“如果ESP寄存器用作寻址内存中目标操作数的基址寄存器,则POP指令计算操作数的有效地址在它增加ESP寄存器之后。“。我们也涵盖了这个案例。