【问题标题】:Does pushl %esp update ESP before or after storing?pushl %esp 在存储之前还是之后更新 ESP?
【发布时间】:2018-08-07 22:40:01
【问题描述】:

pushlY86 指令将堆栈指针减 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

【问题讨论】:

  • 我记得这在 8086 的步进之间发生了变化,但与 y86 无关。

标签: assembly y86


【解决方案1】:

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 是否像 x86 一样支持 push $0movl $0, (%esp)。我想如果它受支持(立即记忆),它将是immovl $0, (%esp)。如果没有,则将寄存器归零并推送。

【讨论】:

猜你喜欢
  • 2013-02-04
  • 2013-02-07
  • 2017-09-21
  • 1970-01-01
  • 2016-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-16
相关资源
最近更新 更多