2

Y86 指令将pushl堆栈指针减 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
4

1 回答 1

1

y86 基于 x86。x86 指令集参考手册条目push说(正确):

PUSH ESP 指令压入 ESP 寄存器的值,因为它在指令执行之前就存在。

并且pop

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

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

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

但是pop %esp这样做没有更新 FLAGS,并且在 add 和 mov 之间没有中断或信号处理程序的可能性。%esp(单独的 add/mov 序列在低于当前的任何内容都可以被中断处理程序异步覆盖的上下文中是不安全的。)


大概 y86 和 x86 做同样的事情。 您可以轻松(并且应该)使用调试器检查您最喜欢的 y86 模拟器如何处理这种极端情况。 push %esp通过查看内存(或在其后添加)很容易测试pop %eax

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

我没有检查 y86 是否支持push $0movl $0, (%esp)喜欢 x86。我想immovl $0, (%esp)如果它受到支持(立即记忆)。如果不是,则将寄存器归零并推送。

于 2018-02-28T07:40:19.237 回答