The 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
y86 基于 x86。这x86指令集参考手册条目push说(正确):
PUSH ESP 指令将 ESP 寄存器的值压入指令执行前的值。
And pop:
POP ESP 指令在旧堆栈顶部的数据写入目标之前递增堆栈指针 (ESP)。
所以在pop %esp
这种情况下,增量就会丢失。尽管大多数真实的 CPU 可能会加载到临时内部存储器中,而不是在寻址模式中实际使用更新的 ESP 值,但该序列具有相同的效果。
add $4, %esp
movl -4(%esp), %esp
But pop %esp
这样做不需要更新 FLAGS,并且在 add 和 mov 之间不可能出现中断或信号处理程序。 (单独的添加/移动序列在任何低于当前值的上下文中并不安全%esp
可以被中断处理程序异步覆盖。)
y86 大概与 x86 做同样的事情。您可以轻松(并且应该)使用调试器进行检查看看你最喜欢的 y86 模拟器如何处理这个极端情况。push %esp
通过查看内存(或添加一个pop %eax
之后)。
同时测试两者会让人感到困惑,如果弹出的值与旧的堆栈指针相同,则无法区分。大概推一个0
(或存储一个0
to (%esp)
), then pop %esp
并使用调试器查看寄存器中的值。 (如果您的代码随后崩溃也没关系,您只是使用了调试器。)
我没有检查y86是否支持push $0
or movl $0, (%esp)
像x86。我想会是immovl $0, (%esp)
如果支持(立即记忆)。如果没有,则将寄存器归零并推送。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)