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:
esp
value eventualy change by itself? (I would bet it can't.)esp
value a mistake?Thank you in advance and excuse my ignorance.
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.