explanation about push ebp and pop ebp instruction in assembly

bunty picture bunty · Sep 3, 2010 · Viewed 75.5k times · Source

i used stack in assembly but i didn't got idea about push ebp and pop ebp.

.intel_syntax noprefix

.include "console.i"

.text

askl:   .asciz  "Enter length: "
askb:   .asciz  "Enter breadth: "
ans:    .asciz  "Perimeter = "

_entry:

    push    ebp     # establishing stack-frame
    mov ebp, esp
    sub esp, 12

    Prompt  askl
    GetInt  [ebp-4]     # length
    Prompt  askb
    GetInt  [ebp-8]     # breadth

    mov eax, [ebp-4]    # eax = l
    add eax, [ebp-8]    # eax = l + b
    add eax, eax    # eax = 2 * (l + b)
    mov [ebp-12], eax

    Prompt  ans
    PutInt  [ebp-12]
    PutEoL

    mov esp, ebp
    pop ebp     # unwinding stack-frame
    ret

.global _entry

.end

Answer

jyz picture jyz · Sep 3, 2010

Maybe you're wondering about this:

push    ebp
mov ebp, esp
sub esp, 12

These lines are known as the assembly function prologue. The first 2 instructions save the previous base pointer (ebp) and set EBP to point at that position on the stack (right below the return address). This sets up EBP as a frame pointer.

The sub esp,12 line is saving space for local variables in the function. That space can be addressed with addressing modes like [ebp - 4]. Any push/pop of function args, or the call instruction itself pushing a return address, or stack frames for functions we call, will happen below this reserved space, at the current ESP.

At the end you have:

mov esp, ebp         ; restore ESP
pop ebp              ; restore caller's EBP
ret                  ; pop the return address into EIP

This is the inverse the prologue does (i.e. the epilogue), so the previous context can be restored. This is sometimes called "tearing down" the stack frame.

(EBP is non-volatile aka call-preserved in all standard x86 calling conventions: if you modify it, you have to restore your caller's value.)

The leave instruction does exactly what these two instructions do, and is used by some compilers to save code size. (enter 0,0 is very slow and never used (https://agner.org/optimize/); leave is about as efficient as mov + pop.)


Note that using EBP as a frame pointer is optional, and compilers don't do it for most functions in optimized code. Instead they save separate metadata to allow stack unwinding / backtrace.