Why doesn't the compiler allocate and deallocate local var with “sub*” and “add*” on the stack?

StackOverflow https://stackoverflow.com/questions/12883160

문제

According to some textbooks, the compiler will use sub* to allocate memory for local variables.

For example, I write a Hello World program:

int main()
{
    puts("hello world");
    return 0;
}

I guess this will be compiled to some assembly code on the 64 bit OS:

    subq    $8, %rsp
    movq    $.LC0, (%rsp)
    calq    puts
    addq    $8, %rsp

The subq allocates 8 byte memory (size of a point) for the argument and the addq deallocates it.

But when I input gcc -S hello.c (I use the llvm-gcc on Mac OS X 10.8), I get some assembly code.

.section    __TEXT,__text,regular,pure_instructions
.globl  _main
.align  4, 0x90
_main:
Leh_func_begin1:
       pushq    %rbp
Ltmp0:
    movq    %rsp, %rbp
Ltmp1:
    subq    $16, %rsp
Ltmp2:
    xorb    %al, %al
    leaq    L_.str(%rip), %rcx
    movq    %rcx, %rdi
    callq   _puts
    movl    $0, -8(%rbp)
    movl    -8(%rbp), %eax
    movl    %eax, -4(%rbp)
    movl    -4(%rbp), %eax
    addq    $16, %rsp
    popq    %rbp
    ret

   .......

L_.str:
      .asciz     "hello world!"

Around this callq without any addq and subq. Why? And what is the function of addq $16, %rsp?

Thanks for any input.

도움이 되었습니까?

해결책

You don't have any local variables in your main(). All you may have in it is a pseudo-variable for the parameter passed to puts(), the address of the "hello world" string.

According to your last disassembly, the calling conventions appear to be such that the first parameter to puts() is passed in the rdi register and not on the stack, which is why there isn't any stack space allocated for this parameter.

However, since you're compiling your program with optimization disabled, you may encounter some unnecessary stack space allocations and reads and writes to and from that space.

This code illustrates it:

subq    $16, %rsp ; allocate some space
...
movl    $0, -8(%rbp) ; write to it
movl    -8(%rbp), %eax ; read back from it
movl    %eax, -4(%rbp) ; write to it
movl    -4(%rbp), %eax ; read back from it
addq    $16, %rsp

Those four mov instructions are equivalent to just one simple movl $0, %eax, no memory is needed to do that.

If you add an optimization switch like -O2 in your compile command, you'll see more meaningful code in the disassembly.

Also note that some space allocations may be needed solely for the purpose of keeping the stack pointer aligned, which improves performance or avoids issues with misaligned memory accesses (you could get the #AC exception on misaligned accesses if it's enabled).

The above code shows it too. See, those four mov instructions only use 8 bytes of memory, while the add and sub instructions grow and shrink the stack by 16.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top