Assembly popl%esp的替代方案
在第3.4.2节中,IA32 popl指令被描述为从 堆栈的顶部到目标寄存器,然后递增堆栈 指针。所以,如果我们有一个形式为popl REG的指令,它将是等价的 对于代码序列:Assembly popl%esp的替代方案,assembly,stack,cpu-registers,x86,Assembly,Stack,Cpu Registers,X86,在第3.4.2节中,IA32 popl指令被描述为从 堆栈的顶部到目标寄存器,然后递增堆栈 指针。所以,如果我们有一个形式为popl REG的指令,它将是等价的 对于代码序列: movl (%esp),REG //Read REG from stack addl $4,%esp //Increment stack pointer A.根据问题4.7中的分析,该代码顺序是否正确 描述指令popl%esp的行为?解释一下 B.如何重写代码序列,使其正确描述两者 REG为%esp以及任何其他寄存器的
movl (%esp),REG //Read REG from stack
addl $4,%esp //Increment stack pointer
A.根据问题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指令在旧堆栈顶部的数据写入目标之前递增堆栈指针。” 如果是这种情况,那么esp的增量4应该在将值放入目标寄存器之前发生,使
movl (%esp),REG //Read REG from stack
addl $4,%esp //Increment stack pointer
popl%esp的表示不正确
有人能澄清一下它是否真的没有正确地描述行为或popl%esp吗?事实上,这对于
pop
来说是一个错误的等价物。有趣的是,这也是英特尔在官方指令集参考中使用的。但至少他们在课文中说得很清楚。更好的等效代码是:
leal 4(%esp), %esp ; use lea to preserve flags (thanks to @Sparky)
movl -4(%esp), REG
然而,这只是一个逻辑等价物,因为实际上有人(如中断或信号处理程序)可以破坏两条指令之间堆栈上的值。原始代码没有遇到这个问题
请注意,这也适用于内存操作数,手册中说:“如果将ESP寄存器用作基址寄存器来寻址内存中的目标操作数,POP指令将在递增ESP寄存器后计算操作数的有效地址。”。我们也涵盖了该案例。除了已经被列为潜在问题的问题外,“addl$4,%esp”还影响eflags登记册。为了补偿这一点,“leal4(%esp),%esp”可以用在它的位置。@Jester对于
push%esp
?@bluejamesbond:那将是movl%esp,-4(%esp);leal-4(%esp),%esp
,但有相同的警告。