3

I am trying to understand how assembly is generated for c. I wrote a sample program and disassembled it for the same.

int main()
{
int a = 100;
}

Assembly generated:

pushq   %rbp     #
movq    %rsp, %rbp   #,
subq    $48, %rsp    #,
call    __main   #
movl    $100, -4(%rbp)   #, a
leave
ret

That is pretty straight forward for me. But i dont understand the assembly when i include a pointer in it.

C Program:

int main()
{
int a = 100;
int *p = &a;
}

Assembly generated:

pushq   %rbp     #
movq    %rsp, %rbp   #,
subq    $48, %rsp    #,
call    __main   #
movl    $100, -12(%rbp)  #, a
leaq    -12(%rbp), %rax  #, tmp59
movq    %rax, -8(%rbp)   # tmp59, p
leave
ret

I dont understand why the local variable a is now pushed to a different offset with in the stack compared to tha earlier snip which doesnt have a pointer in it.

Question #2: If i have 4 local variables my stack frame is subq $48, %rsp, but if i convert one of the local variable to pointer it is subq $64. why is it so.

C code:

int main()
{
int a = 100;
int *p = &a;
int b = 10;
int c = 20;
}

Assembly:

pushq   %rbp     #
movq    %rsp, %rbp   #,
subq    $64, %rsp    #,
call    __main   #
movl    $100, -20(%rbp)  #, a
leaq    -20(%rbp), %rax  #, tmp59
movq    %rax, -8(%rbp)   # tmp59, p
movl    $10, -12(%rbp)   #, b
movl    $20, -16(%rbp)   #, c
leave
ret

Also it would be helpful, if you guys can explain why the stack frame is 2 * 16 bytes aligned (32 bytes) for a main function with no local variables. Guess it should be for some book keeping exercise, but whats the exact reason?

Thanks,

nrz
  • 10,435
  • 4
  • 39
  • 71
trialyogi
  • 41
  • 3
  • 4
    The compiler is free to put the variables anywhere on the stack it wants. – Mysticial Apr 28 '13 at 18:32
  • Thanks Mystical. Still i have one more question on this. I have posted as a question in the same thread. Still it is too large to add as a comment. – trialyogi Apr 28 '13 at 18:38
  • @trialyogi ? you have two local variables: `a` and `p`. The 100 is a compile time constant and the address of `a` is used in an assignment... but on the right hand side (not the left). You can see in the assembly that the compiler allocated 8 bytes at the highest address in the stack frame for `p` and then 4 bytes below that for `a`. – rliu Apr 28 '13 at 18:39
  • 2
    The compiler can put them anywhere it wants. If you have more variables, it may feel that it wants to rearrange them a little so they fit better. (or whatever reason) You'll also find that if you turn on optimizations, everything gets optimized out and no stack is needed. – Mysticial Apr 28 '13 at 18:40
  • Got it, why we are going for subq $64, since the pointer size here is 8 bytes. – trialyogi Apr 28 '13 at 18:59

2 Answers2

0

The compiler does not simply convert code line by line from c to assembly. Optimizing compilers will do a bunch of analysis on the code attempting to do things like remove code that will never be executed, optimize loop performance, and optimize stack/memory usage. By the time the compiler is deciding where to allocate memory and where to store variables, it knows about both a and p and will put them wherever it thinks is best.

underrun
  • 6,713
  • 2
  • 41
  • 53
0

Well, in x86_64, the stack pointer is always kept with 16-byte alignment (so use of sse 16 byte load/store instructions will be most efficient). Pointers are 8 bytes and only require 8 byte alignment while ints are 4 bytes and only require 4 byte alignment. The order of local vars in the stack frame is completely unspecified, but generally compilers will lay out those with the greatest alignment restrictions first, followed by those that are more flexible (in order to pack most efficiently). The compiler may also reserve space for other things (spilling registers and space for outgoing arguments in calls), and rely on having the optimizer dead-code eliminate things that are not needed (so if you compile without optimization, you'll see a lot of apparently unused space in the stack frame).

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226