pushl%esp在存储之前或之后会更新ESP吗? [英] Does pushl %esp update ESP before or after storing?
问题描述
Y86指令pushl
都将堆栈指针减4,并将寄存器值写入内存.因此,尚不清楚处理器执行指令pushl %esp
时应执行的操作,因为要推送的寄存器正在由同一条指令更改.可能发生两个事件:
The pushl
Y86 instruction both decrements the stack pointer by 4 and writes a register value to memory. So it's not clear what the processor should do when it executes the instruction pushl %esp
, since the register being pushed is being changed by the same instruction. Two possible events can occur:
(1)按下%esp
的原始值,或(2)按下%esp
的减小值.
(1) push the original value of %esp
, or (2) push the decremented value of %esp
.
有鉴于此,我们如何修改等同于pushl REG
的代码,以解决并容纳这些歧义(因为REG可以是%esp以及任何其他寄存器)?
In light of this, how could we modify this code-equivalent of pushl REG
to account for, and accomdate, these ambiguities (being that REG can be %esp as well as any other register)?:
subl $4,%esp Decrement stack pointer
movl REG,(%esp) Store REG on stack
类似地,指令popl %esp
可以将%esp
设置为从内存读取的值或递增的堆栈指针.如何更改此代码以适应这些歧义?
Similarly, the instruction popl %esp
could either set %esp
to the value read from memory or to the incremented stack pointer. How could this code be changed to accommodate for these ambiguities?:
movl (%esp),REG Read REG from stack
addl $4,%esp Increment stack pointer
推荐答案
y86基于x86. push
的 x86指令集参考手册说(正确) :
y86 is based on x86. The x86 instruction-set reference manual entry for push
says (correctly):
PUSH ESP指令将执行该指令之前存在的ESP寄存器的值压入.
The PUSH ESP instruction pushes the value of the ESP register as it existed before the instruction was executed.
和pop
:
POP ESP指令在将堆栈顶部的旧数据写入目标之前将堆栈指针(ESP)递增.
The POP ESP instruction increments the stack pointer (ESP) before data at the old top of stack is written into the destination.
因此,在pop %esp
情况下,增量丢失.尽管大多数实际的CPU可能会加载到临时内部存储中,而不是在寻址模式下实际使用更新的ESP值,但此顺序具有相同的效果.
So in the pop %esp
case, the increment is lost. This sequence has the same effect, although most real CPUs probably load into temporary internal storage instead of actually using an updated ESP value in the addressing mode.
add $4, %esp
movl -4(%esp), %esp
但是pop %esp
这样做不需要更新FLAGS,并且在add和mov之间没有中断或信号处理程序的可能性. (单独的添加/移动序列在上下文中不安全,在当前上下文中,低于%esp
的任何内容都可以被中断处理程序异步覆盖.)
But pop %esp
does that without updating FLAGS, and without a possibility of an interrupt or signal-handler between the add and mov. (The separate add/mov sequence isn't safe in contexts where anything below the current %esp
can be asynchronously overwritten by an interrupt handler.)
大概y86与x86的功能相同. 您可以轻松(并且应该)与调试器联系,以了解您最喜欢的y86模拟器如何处理这种极端情况.通过查看内存(或在其后添加pop %eax
),可以轻松测试push %esp
.
Presumably y86 does the same thing as x86. You can easily (and should) check with a debugger to see how your favourite y86 simulator handles this corner case. push %esp
is easy to test by looking at memory (or adding a pop %eax
after it).
同时测试这两者会造成混淆,并且如果您弹出的值与旧的堆栈指针相同,您将无法分辨出两者之间的区别.可能先按0
(或将0
存储到(%esp)
),然后按pop %esp
,然后使用调试器查看寄存器中的值. (之后是否崩溃代码都没有关系,您只是在使用调试器.)
Testing both at once would get confusing, and if the value you pop is the same as the old stack pointer, you can't tell the difference. Probably push a 0
(or store a 0
to (%esp)
), then pop %esp
and see what value is in the register with a debugger. (It doesn't matter if your code crashes afterwards, you're just using a debugger.)
我没有检查y86是否支持x86之类的push $0
或movl $0, (%esp)
.我想如果它被支持(直接到内存),它将是immovl $0, (%esp)
.如果不是,则将寄存器清零并将其推入.
I didn't check if y86 supports push $0
or movl $0, (%esp)
like x86. I guess it would be immovl $0, (%esp)
if it's supported (immediate to memory). If not, then zero a register and push that.
这篇关于pushl%esp在存储之前或之后会更新ESP吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!