C语言 汇编 x86 - “离开”指令
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29790175/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Assembly x86 - "leave" Instruction
提问by alexswo
It's said that the "leave" instruction is similar to:
据说“离开”指令类似于:
movl %ebp, %esp
popl %ebp
I understand the movl %ebp, %esppart, and that it acts to release stored up memory (as discussed in this question).
我理解这movl %ebp, %esp部分,它的作用是释放存储的内存(如本问题所述)。
But what is the purpose of the popl %ebpcode?
但是popl %ebp代码的目的是什么?
回答by Michael
LEAVEis the counterpart to ENTER. The ENTERinstruction sets up a stack frame by first pushing EBPonto the stack and then copies ESPinto EBP, so LEAVEhas to do the opposite, i.e. copy EBPto ESPand then restore the old EBPfrom the stack.
LEAVE是 的对应物ENTER。该ENTER指令通过首先压EBP入堆栈然后复制ESP到来设置堆栈帧EBP,因此LEAVE必须执行相反的操作,即复制EBP到堆栈ESP然后EBP从堆栈中恢复旧的。
See the section named PROCEDURE CALLS FOR BLOCK-STRUCTURED LANGUAGESin Intel's Software Developer's ManualVol 1 if you want to read more about how ENTERand LEAVEwork.
请参见命名过程调用块结构语言在英特尔的软件开发人员手册第1卷,如果你想了解更多关于如何ENTER和LEAVE工作。
enter n,0is exactly equivalent to (and should be replaced with)
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
leaveis exactly equivalent to
leave完全等同于
mov %ebp, %esp # esp = ebp, mov esp,ebp in Intel syntax
pop %ebp
enteris very slow and compilers don't use it, but leaveis fine. (http://agner.org/optimize). Compilers do use leaveif they make a stack frame at all (at least gcc does). But if espis already equal to ebp, it's most efficient to just pop ebp.
enter很慢,编译器不使用它,但leave很好。(http://agner.org/optimize)。编译器确实会使用,leave如果他们制作了一个堆栈框架(至少 gcc 是这样)。但是如果esp已经等于ebp,则仅是最有效pop ebp。
回答by JustinCB
The poplinstruction restores the base pointer, and the movlinstruction restores the stack pointer. The base pointer is the bottom of the stack, and the stack pointer is the top. Before the leave instruction, the stack looks like this:
的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)
After the movl %ebp %esp, which deallocates the callee's stack, the stack looks like this:
在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)
After the popl %ebp, which restores the caller's stack, the stack looks like this:
在popl %ebp, 恢复调用者的堆栈之后,堆栈看起来像这样:
----Bottom of Caller's stack---- (%ebp)
...
Caller's
Variables
...
Function Parameters
----Top of Caller's Stack---- (%esp)
The enterinstruction saves the bottom of the caller's stack and sets the base pointer so that the callee can allocate their stack.
该enter指令保存调用者堆栈的底部并设置基指针,以便被调用者可以分配他们的堆栈。
Also note, that, while most C compilers allocate the stack this way(at least with optimization turn'd off), if you write an assembly language function, you can just use the same stack frame if you want to, but you have to be sure to popeverything off the stack that you pushon it or else you'll jump to a junk address when you return(this is because call <somewhere>means push <ret address>[or push %eip], jmp <somewhere>, and retmeans jump to the address on the top of the stack[or pop %eip]. %eipis the register that holds the address of the current instruction).
另请注意,虽然大多数 C 编译器以这种方式分配堆栈(至少关闭优化),但如果您编写汇编语言函数,您可以根据需要使用相同的堆栈框架,但您必须一定要pop一切从堆栈,你push就可以了,否则当你回到你会跳转到一个垃圾地址(这是因为call <somewhere>手段push <ret address>[或push %eip]jmp <somewhere>和ret手段跳转到地址堆栈[或顶部pop %eip。 %eip是保存当前指令地址的寄存器)。

