54

It's said that the "leave" instruction is similar to:

movl %ebp, %esp
popl %ebp

I understand the movl %ebp, %esp part, and that it acts to release stored up memory (as discussed in this question).

But what is the purpose of the popl %ebp code?

Community
  • 1
  • 1
alexswo
  • 539
  • 1
  • 4
  • 3
  • 34
    It pops `ebp` . – user253751 Apr 22 '15 at 08:47
  • 2
    I'm voting to close this because it's confusing what's being asked. You specifically ask about `pop %ebp` and that has a meaning outside of `LEAVE` making this question very compound. Your question on `LEAVE` is also a definite dupe. So we need to know what exactly is the question here and to keep it atomic. – Evan Carroll Oct 09 '18 at 18:58
  • Interestingly this is almost a direct dupe of this question https://stackoverflow.com/questions/41907672/need-some-explanations-about-leave-instruction-in-assembly-language – Evan Carroll Oct 09 '18 at 19:00
  • FYI: `movl %ebp, %esp` is AT&T syntax and means esp=ebp. `movl %esp, %ebp` would be the Intel syntax equivalent. – Thomas Nov 27 '21 at 14:15

2 Answers2

95

LEAVE is the counterpart to ENTER. The ENTER instruction sets up a stack frame by first pushing EBP onto the stack and then copies ESP into EBP, so LEAVE has to do the opposite, i.e. copy EBP to ESP and then restore the old EBP from the stack.

See the section named PROCEDURE CALLS FOR BLOCK-STRUCTURED LANGUAGES in Intel's Software Developer's Manual Vol 1 if you want to read more about how ENTER and LEAVE work.


enter n,0 is exactly equivalent to (and should be replaced with)

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

leave is exactly equivalent to

mov   %ebp, %esp     # esp = ebp,  mov  esp,ebp in Intel syntax
pop   %ebp

enter is very slow and compilers don't use it, but leave is fine. (http://agner.org/optimize). Compilers do use leave if they make a stack frame at all (at least gcc does). But if esp is already equal to ebp, it's most efficient to just pop ebp.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Michael
  • 57,169
  • 9
  • 80
  • 125
  • It seems like I don't understand the concept of EBP and ESP. Could you please explain both of these terms for me? – alexswo Apr 22 '15 at 07:20
  • 2
    `EBP` and `ESP` are both just 32-bit general-purpose registers. Although `ESP` has a special function, which is to act as the stack pointer, and it gets implicitly modified by certain instructions (e.g. `push`, `pop`, `call`). `EBP` by convention is typically used as a stack frame pointer within functions. – Michael Apr 22 '15 at 07:28
  • 1
    [What does ebp and esp in a dissembly code means?](http://stackoverflow.com/questions/26684506/what-does-ebp-and-esp-in-a-dissembly-code-means) [What are the ESP and the EBP registers?](http://stackoverflow.com/questions/21718397/what-are-the-esp-and-the-ebp-registers?rq=1) – phuclv Apr 22 '15 at 09:28
  • 6
    To expand on this answer, `LEAVE` or `ENTER` are not dependent on each other. That is, you can have one without the other, but the associated ASM must be present (either using these two instructions or explicitly including equivalent instructions). – sherrellbc Aug 13 '17 at 16:38
  • So, I'm not sure I'm understanding this right. Isn't it redundant to say leave is movl %ebp, %esp, followed by popl %ebp? Doesn't the popl instruction itself move the stack pointer to where it needs to be, without a need for the movl instruction? – John L. Mar 25 '18 at 04:19
  • 1
    No(see my answer). The base pointer is the bottom of the stack, & the stack pointer is the top. – JustinCB Apr 27 '18 at 00:11
  • @LewisKelsey That's why he put the Intel syntax in comments. The GCC ecosystem(& most similar C compiler ecosystems) use AT&T syntax(although, I think there is a `.intel` directive in recent versions). – JustinCB Oct 10 '19 at 14:21
  • BTW, I tested on Skylake and `leave` does cost 1 uop more (total of 3) than `mov %ebp, %esp` / `pop %ebp` (total of 2) even when used as part of a function call / ret. The 3 uops isn't including a stack-sync uop or something. It's still maybe worth using for code-size reasons, though, because small code size for more L1i hits is not a bad thing. GCC uses `leave` when the stack point isn't already pointing to the right place for `pop %ebp`. – Peter Cordes Jul 07 '20 at 07:55
9

The popl instruction restores the base pointer, and the movl instruction 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:

----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:

----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:

----Bottom of Caller's stack----    (%ebp)
...
Caller's
Variables
...
Function Parameters
----Top of Caller's Stack----   (%esp)

The enter instruction saves the bottom of the caller's stack and sets the base pointer so that the callee can allocate their stack.

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 pop everything off the stack that you push on 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 ret means jump to the address on the top of the stack[or pop %eip]. %eip is the register that holds the address of the current instruction).

JustinCB
  • 513
  • 4
  • 12
  • A code block would probably look better for your ASCII diagrams than ragged back-tick lines. You have some HTML elements inside backticks in the last paragraph. And BTW most C compilers don't waste instructions making stack frames at all; `-fomit-frame-pointer` has been gcc's default for years even on 32-bit x86 (with optimization enabled of course). – Peter Cordes Apr 27 '18 at 00:19
  • I didn't say it wasted instructions, just pointing out that you don't have to(a lot of C references say it's done that way). Also, I did use tags for the ASCII diagrams. – JustinCB Apr 27 '18 at 00:35
  • No, I mean Stack Overflow code formatting: select your block and hit control-k, or click the `{}` icon. Re: compilers: I was commenting on your *while C compilers almost always allocate the stack this way*, that *compilers* don't do that. And BTW, you probably shouldn't use code formatting for *`pop` everything off the stack*, because you shouldn't use the `pop` instruction just to increment `esp` by more than 4, just `add $12, %esp` or whatever. `pop %ecx` is often good if you only need it once, though. – Peter Cordes Apr 27 '18 at 00:39
  • I fixed the formatting for you to use Stack Overflow's markdown. It supports some HTML, but for example `<` isn't processed within backticks, and might not be processed at all. Welcome to SO :) – Peter Cordes Apr 27 '18 at 00:43