I'm currently playing around, examining stack frames, trying to get an idea of how this works. After reading a few articles that always explained that the general structure would be:
local vars <--- SP
low address
old BP
<--- BP
ret addr args high address
I have an example program that calls a function with three arguments and has two buffers as local variables:
#include <stdio.h>
void function(int a, int b, int c);
int main()
{
function(1, 2, 3);
return 0;
}
void function(int a, int b, int c)
{
char buffer1[5];
char buffer2[10];
}
I took a look at the assembler code of the program and was surprised not to find what I expect when the function is called. I expected something along the lines of:
# The arguments are pushed onto the stack:
push 3
push 2
push 1
call function # Pushes ret address onto stack and changes IP to function
...
# In function:
# Push old base pointer onto stack and set current base pointer to point to it
push rbp
mov rbp, rsp
# Reserve space for stack frame etc....
So that the structure of the frame, when executing the function, would be something like:
buffers <--- SP low address
old BP <--- BP
ret Addr
1
2
3 high address
But instead what happens is the following:
The function call:
mov edx, 3
mov esi, 2
mov edi, 1
call function
Why use the registers here when we can just push to the stack??? And in the actual function that we call:
.cfi_startproc
push rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
mov rbp, rsp
.cfi_def_cfa_register 6
sub rsp, 48
mov DWORD PTR [rbp-36], edi
mov DWORD PTR [rbp-40], esi
mov DWORD PTR [rbp-44], edx
mov rax, QWORD PTR fs:40
mov QWORD PTR [rbp-8], rax
xor eax, eax
mov rax, QWORD PTR [rbp-8]
xor rax, QWORD PTR fs:40
je .L3
call __stack_chk_fail
As far as I can see, 48 bytes are reserved for the stack frame right? And afterwards, using the registers from the function call, the arguments to the function are copied to the end of the stack. So it would look something like this:
3 <--- SP
2
1
??
??
old BP <--- BP
return Address
??
I assume the buffers are somewhere between the args and the old BP
. But I'm really not sure where exactly...since they are both only 15 bytes in total and 48 bytes where reserved...won't there be a bunch of unused space in there?
Can someone help me outline what is happening here? Is this something that is processor dependant? I'm using an intel i7.
Cheers, Brick