Your disassembled program looks like this on my system:
gcc -m32 -c -o stackexample.o stackexample.c
objdump -d -M intel stackexample.o
test_function:
push ebp
mov ebp,esp
sub esp,0x10
mov DWORD PTR [ebp-0x4],0x7a69
mov BYTE PTR [ebp-0xe],0x41
leave
ret
main:
push ebp
mov ebp,esp
sub esp,0x10
mov DWORD PTR [esp+0xc],0x4
mov DWORD PTR [esp+0x8],0x3
mov DWORD PTR [esp+0x4],0x2
mov DWORD PTR [esp],0x1
call test_function
leave
ret
Let's start from the beginning.
Stack is arranged from top to bottom in memory. The top of the stack has the lowest address.
esp
is the Stack Pointer. It always points to the top of the stack.
ebp
is the Base Pointer. It points to the bottom of current stack frame. It is used for referencing current function's arguments and local variables.
These instructions
push ebp
mov ebp,esp
can be found at the top of every function. They do the following:
- save caller's Base Pointer
- setup current function's Base Pointer by assigning it to Stack Pointer. At this point Stack Pointer points to bottom of current stack frame, so by assigning Base Pointer to it, Base Pointer will show current bottom. Stack Pointer can increase/decrease during function's execution, so you use Base Pointer to reference the variables. Base Pointer also servers for saving/storing caller's Stack Pointer.
leave
is equivalent to
mov esp, ebp
pop ebp
which is the exact opposite of the instructions above:
- restore caller's Stack Pointer
- restore caller's Base Pointer
Now to answer your questions
in which stack frame the arguments are ???
Arguments are stored in caller's stack frame. However you can use Base Pointer to access them. info locals
does not display the information about the function arguments as part of gdb's specification:
http://visualgdb.com/gdbreference/commands/info_locals
How come and RET to main is on top (into a lower address) than the arguments ? Shouldnt ret address be in the start of the new stack frame
That's because arguments are stored in caller's frame. When test_function
is called, the stack already has the arguments stored, so the returned address is stored higher (aka lower address) than the arguments.
reference for the local variables is happening through $esp+(offset).
As far as I know, referencing local variables can happen both using the Base Pointer and the Stack Pointer - whichever is convenient for your compiler (not really sure).
Does the value of esp is always depending on the "current" stack frame that the execution is?
Yes. Stack Pointer is THE most important stack register. It points to the top of the stack.