据说“离开”指令类似于:
movl %ebp, %esp
popl %ebp
我理解movl %ebp, %esp
部分,并且它用于释放已存储的内存(如this question中所述)。
但是popl %ebp
代码的目的是什么?
答案 0 :(得分:2)
popl
指令恢复基指针,movl
指令恢复堆栈指针。基指针是堆栈的底部,堆栈指针是顶部。在离开指令之前,堆栈如下所示:
----Bottom of Caller's stack----
...
Caller's
Variables
...
Function Parameters
----Top of Caller's Stack/Bottom of Callee's stack---- (%ebp)
...
Callee's
Variables
...
---Bottom of Callee's stack---- (%esp)
在释放被调用者堆栈的movl %ebp %esp
之后,堆栈看起来像这样:
----Bottom of Caller's stack----
...
Caller's
Variables
...
Function Parameters
----Top of Caller's Stack/Bottom of Callee's stack---- (%ebp) and (%esp)
在恢复调用者堆栈的popl %ebp
之后,堆栈如下所示:
----Bottom of Caller's stack---- (%ebp)
...
Caller's
Variables
...
Function Parameters
----Top of Caller's Stack---- (%esp)
enter
指令保存调用者堆栈的底部并设置基指针,以便被调用者可以分配其堆栈。
另请注意,虽然大多数C编译器都以这种方式分配堆栈(至少在优化时关闭),但如果编写汇编语言函数,则可以根据需要使用相同的堆栈帧,但是你必须确保pop
堆放你push
的所有东西,否则当你返回时你会跳转到垃圾邮件地址(这是因为call <somewhere>
意味着{{1} }} [或push <ret address>
],push %eip
和jmp <somewhere>
表示跳转到堆栈顶部的地址[或ret
]。pop %eip
是保存当前指令地址的寄存器)。