据说"离开"指令类似于:
movl %ebp, %esp
popl %ebp
Run Code Online (Sandbox Code Playgroud)
我理解这movl %ebp, %esp部分,并且它用于释放存储的内存(如本问题中所讨论的).
但是popl %ebp代码的目的是什么?
Mic*_*ael 34
LEAVE是对应的ENTER.该ENTER指令通过首先推EBP入堆栈然后复制ESP到堆栈帧来设置堆栈帧EBP,因此LEAVE必须执行相反的操作,即复制EBP到堆栈中ESP然后EBP从堆栈中恢复旧堆栈.
见评为部分过程调用块结构语言在英特尔的软件开发人员手册第1卷,如果你想了解更多关于如何ENTER和LEAVE工作.
enter n,0 完全等同于(并应替换为)
push %ebp
mov %esp, %ebp # ebp = esp, mov ebp,esp in Intel syntax
sub $n, %esp # allocate space on the stack. Omit if n=0
Run Code Online (Sandbox Code Playgroud)
leave 完全等同于
mov %ebp, %esp # esp = ebp, mov esp,ebp in Intel syntax
pop %ebp
Run Code Online (Sandbox Code Playgroud)
enter非常慢,编译器不使用它,但leave很好.(http://agner.org/optimize).编译器在使用leave堆栈框架时会使用(至少gcc 会这样做).但如果esp已经相等ebp,那么它的效率最高pop ebp.
的popl指令恢复基指针,并且movl指令恢复堆栈指针。基指针在栈底,栈指针在栈顶。在 leave 指令之前,堆栈如下所示:
----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)
Run Code Online (Sandbox Code Playgroud)
在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)
Run Code Online (Sandbox Code Playgroud)
在popl %ebp, 恢复调用者的堆栈之后,堆栈看起来像这样:
----Bottom of Caller's stack---- (%ebp)
...
Caller's
Variables
...
Function Parameters
----Top of Caller's Stack---- (%esp)
Run Code Online (Sandbox Code Playgroud)
该enter指令保存调用者堆栈的底部并设置基指针,以便被调用者可以分配他们的堆栈。
另请注意,虽然大多数 C 编译器以这种方式分配堆栈(至少关闭优化),但如果您编写汇编语言函数,您可以根据需要使用相同的堆栈框架,但您必须一定要pop一切从堆栈,你push就可以了,否则当你回到你会跳转到一个垃圾地址(这是因为call <somewhere>手段push <ret address>[或push %eip]jmp <somewhere>和ret手段跳转到地址堆栈[或顶部pop %eip。 %eip是保存当前指令地址的寄存器)。