Search code examples
functionassemblyx86stackgnu-assembler

Assembly: function template meditation


I'm learning assembly now and I don't get one thing about the (presumably) standard function template.

So, based on this really nice book, "the form to remember for functions is as follows:"

function_label:
    pushl   %ebp
    movl    %esp, %ebp
    < normal function code goes here>
    movl    %ebp, %esp
    popl    %ebp
    ret

OK, I'm perfectly fine with it, but there is one small thing that I don't understand. After the "normal function code" we restore the initial (pre-call) value of esp, which was previously stored in ebp.

Now, I understand it clearly why we want to serve the esp value back to the calling context untouched. What I do not understand is under which conditions the esp value can be changed at all during the function's execution.

Is it some kind of protection against ourselves (in case we somehow corrupt the stack somewhere in our code) included in this template? Or maybe changing stack values inside a function is a normal practice? Or it is possible that the initial esp value may end up changed during execution even if we don't do anything with it? (I can't figure out how this can be, in fact.)

I felt rather silly while thinking about this and checked the esp value with gdb in this simple code:

.section .data
message:
    .asciz "> Hello from function #%d\n"

.section .text
.globl main

main:
    nop
    call    overhere
    pushl   $0
    call    exit
overhere:
    pushl   %ebp
    movl    %esp, %ebp
    pushl   $1
    pushl   $message
    call    printf
    add     $8, %esp
    movl    %ebp, %esp
    popl    %ebp
    ret 

And esp (as I actually expected) was untouched, so moving ebp to esp didn't actually change anything.

Now, I hope that it's clear what I want to find out:

  • Can esp value eventualy change by itself? (I would bet it can't.)
  • If it can't, then this template above, obviously, assumes that the programmer might change it somehow inside the function. But I can't figure out why on Earth one might need to do that, so - is changing esp value a mistake?

Thank you in advance and excuse my ignorance.


Solution

  • I am puzzled how you missed the instruction that explicitly changes esp: add $8, %esp. So the answer is clearly yes, it may change during a function and is not a mistake. Note that push and call also change it, in fact the add is to compensate for the two push instructions (the ret at the end of printf will balance the call). Other typical reason for changing esp is the allocation of local variables. This has been omitted from the function template you showed, it typically looks like sub $size_of_locals, %esp right after the movl %esp, %ebp.

    That said, you don't need to use ebp to remember the stack pointer, as long as you ensure it has the same value at the exit of the function as it had upon entry. Recent versions of gcc don't use ebp when optimization is enabled, otherwise you can use -fomit-frame-pointer to do so.