Every C (except some inline
functions, and not only C functions) function has it's beginning and ending. The beginning usually looks like this:
push ebp
mov ebp, esp
sub esp, x
The first line pushes old stack frames. As there are many functions called during program´s run, functions can save their stack frame on stack when calling another function. Stack frame (usually stored in EBP
register) is something that is base of every local variable addressing. Let's say you have this code:
int main() {
__volatile int localVariable = 0x10;
printf("%d");
}
Variable localVariable
can be stored somewhere statically (for example on address 0x410000
), but if there was main
called again, the value on that address would be overwirtten. Therefore there is need for something like dynamic allocation. That's what stack frame is used for; saves previous stack frame and 'allocates' place for local variables relatively to actual position of stack pointer. In this case, localVariable
should be always on position EBP-sizeof(int)
.
The second and third line are actually that piece of code that allocates 'new' memory. Third line substracts some value from ESP
(stack grows down) -> and that's why functions don't overwrite their variables; every function has it´s own place for them. Second line saves old stack pointer, so when called function returns from it's stack frame, it stack pointer of previous function.
Standard ending of function is
mov esp, ebp
pop ebp
ret
or
leave
ret
leave
in second example is alternative to first two lines in first example, as functions return to execution of previous function very often.
Addressing EBP - something
usually means accessing local variables of called (current) function.
Addressing EBP + someting
usually means accessing arguments passed to function.
I have to notice that address stored in EBP
actually doesn't point to argument, but to return address of function, which was pushed by call
instruction when calling function. Value stored on EBP + 4
can be first (old practice, used for example for functions with variable number of arguments, like printf
) as same as the last variable (typical for Java, which handles variable count arguments - Object... values
- by creating new array and passing only reference to it).