pushl%esp是否在存储之前或之后更新ESP?

时间:2018-02-28 06:07:25

标签: assembly y86

pushl Y86指令将堆栈指针递减4并将寄存器值写入存储器。因此,当执行指令pushl %esp时,处理器应该做什么并不清楚,因为正在按下的寄存器被同一指令改变。可能发生两种可能的事件:

(1)推送%esp的原始值,或(2)按下%esp的递减值。

鉴于此,我们如何修改此代码相当于pushl REG来解释和容纳这些歧义(REG可以是%esp以及任何其他寄存器)?:

subl $4,%esp                   Decrement stack pointer
movl REG,(%esp)                Store REG on stack

类似地,指令popl %esp可以将%esp设置为从内存读取的值或增加的堆栈指针。如何更改此代码以适应这些歧义?:

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

1 个答案:

答案 0 :(得分:0)

y86基于x86。 x86 instruction-set reference manual entry for push说(正确):

  

PUSH ESP指令按下执行指令之前存在的ESP寄存器的值。

And pop

  

POP ESP指令在堆栈旧堆栈的数据写入目标之前递增堆栈指针(ESP)。

所以在pop %esp的情况下,增量会丢失。此序列具有相同的效果,但大多数实际CPU可能会加载到临时内部存储器中,而不是在寻址模式下实际使用更新的ESP值。

add   $4, %esp
movl  -4(%esp), %esp

pop %esp在没有更新FLAGS的情况下做到了这一点,并且没有可能在add和mov之间产生中断或信号处理程序。 (单独的add / mov序列在上下文中不安全,其中当前%esp以下的任何内容都可以被中断处理程序异步覆盖。)

据推测,y86与x86完全相同。 您可以轻松(并且应该)使用调试器查看您最喜欢的y86模拟器如何处理此角落案例。通过查看内存(或在其后面添加push %esp)可以轻松测试pop %eax

同时测试两者会让人感到困惑,如果弹出的值与旧的堆栈指针相同,则无法区分。可能会推送0(或将0存储到(%esp)),然后pop %esp,并使用调试器查看寄存器中的值。 (如果您的代码在之后崩溃并不重要,那么您只需使用调试器。)

我没有检查y86是否支持x push $0movl $0, (%esp)。我想如果支持它会立即immovl $0, (%esp)(直接记忆)。如果没有,那么将寄存器归零并推送它。