I have few questions about how stack is used in Assembly. As far as I know, the %rsp register is used as stack pointer. To allocate new memory on stack in Assembly code, you just subtract needed amount from %rsp, moving it backwards. Then you can access newly allocated memory by adding specific values to %rsp.
However, when I compile C code with GCC to Assembly, sometimes I get weird results.
When I make some function like this:
int fun(int arg1, int arg2)
{
return arg2;
}
I'd expect something like:
fun: pushq %rbp
movq %rsp, %rbp
sub $8, %rsp
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
movl -4(%rbp), %eax
addq $8, %rsp
popq %rbp
ret
Instead, I get this:
fun:
pushq %rbp
movq %rsp, %rbp
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
movl 16(%rbp), %eax
popq %rbp
ret
It's actually not moving the stack pointer, it just uses the space behind it. It's getting even weirder when I pass 7 arguments:
int fun(int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7)
{
return arg7;
}
Now the Assembly code:
fun:
pushq %rbp
movq %rsp, %rbp
movl %edi, -4(%rbp)
movl %esi, -8(%rbp)
movl %edx, -12(%rbp)
movl %ecx, -16(%rbp)
movl %r8d, -20(%rbp)
movl %r9d, -24(%rbp)
movl 16(%rbp), %eax
popq %rbp
ret
After the previous example I've expected the code not to subtract anything from %rsp. Using smaller addresses is perfectly fine, there's nothing there. But what about 16(%rsp)? It should point to a space already allocated in the stack, wouldn't it overwrite something?
And the last but not least, if I write that simple function:
void fun(int arr[], int n)
{
int i = 0;
while(i < n)
{
++arr[i++];
}
}
The Assembly code:
fun:
.LFB0:
pushq %rbp
movq %rsp, %rbp
movq %rdi, -24(%rbp)
movl %esi, -28(%rbp)
movl $0, -4(%rbp)
jmp .L2
.L3:
movl -4(%rbp), %eax
leal 1(%rax), %edx
movl %edx, -4(%rbp)
cltq
leaq 0(,%rax,4), %rdx
movq -24(%rbp), %rax
addq %rdx, %rax
movl (%rax), %edx
addl $1, %edx
movl %edx, (%rax)
.L2:
movl -4(%rbp), %eax
cmpl -28(%rbp), %eax
jl .L3
nop
popq %rbp
ret
As you can see, pointer to arr is stored in -24(%rsp) to -16(%rsp). Integer n is stored in -28(%rsp) to -24(%rsp) and integer i is stored in -4(%rsp) to (%rsp). What about the space between -16(%rsp) to -4(%rsp)? Why is it unused? Is there some particular reason behind it?