1

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?

fuz
  • 88,405
  • 25
  • 200
  • 352
Maras
  • 982
  • 9
  • 15
  • 1
    The 128 bytes below the stack pointer are called *red zone* and may be used without first decrementing the stack pointer. Let me close this as an appropriate duplicate. Space can be unused for various reasons, I think it's mainly because you did not allow the compiler to optimise the code. – fuz Mar 17 '19 at 14:11
  • Thanks a lot, I think that answers my question! :) – Maras Mar 17 '19 at 14:44

0 Answers0