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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pushl%esp是否在存储之前或之后更新ESP?相关的知识,希望对你有一定的参考价值。

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 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)。如果没有,那么将寄存器归零并推送它。

以上是关于pushl%esp是否在存储之前或之后更新ESP?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 pushl %ebp 和 movl %esp, %ebp 在每个 ASM 函数的开头?

分配的堆栈空间没用?

函数调用栈维护过程

函数调用栈维护过程

数据压入堆栈时,ESP寄存器的指向?

课程学习总结报告