汇编x86 - "离开"指令

ale*_*swo 16 c assembly

据说"离开"指令类似于:

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卷,如果你想了解更多关于如何ENTERLEAVE工作.


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.

  • 为了扩展这个答案,"LEAVE"或"ENTER"并不相互依赖.也就是说,您可以拥有一个没有另一个,但必须存在关联的ASM(使用这两个指令或明确包含等效指令). (4认同)
  • `EBP`和`ESP`都只是32位通用寄存器.虽然`ESP`有一个特殊的函数,它可以作为堆栈指针,但它会被某些指令隐式修改(例如`push`,`pop`,`call`).按惯例,"EBP"通常用作函数内的堆栈帧指针. (2认同)

Jus*_*nCB 5

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是保存当前指令地址的寄存器)。