为什么编译器在堆栈上没有“sub *”和“add *”来分配和释放本地var?

时间:2012-10-14 14:29:33

标签: c macos assembly compiler-construction llvm-gcc

根据一些教科书,编译器将使用sub*为局部变量分配内存。

例如,我写了一个Hello World程序:

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

我想这将被编译为64位操作系统上的一些汇编代码:

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

subq为参数分配8字节内存(点的大小),addq解除分配。

但是当我输入gcc -S hello.c(我在Mac OS X 10.8上使用llvm-gcc)时,我得到了一些汇编代码。

.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!"

callq周围没有任何addqsubq。为什么? addq $16, %rsp的功能是什么?

感谢您的任何意见。

1 个答案:

答案 0 :(得分:4)

您的main()中没有任何本地变量。您可能拥有的只是传递给puts()的参数的伪变量,"hello world"字符串的地址。

根据您的上一次反汇编,调用约定似乎是puts()的第一个参数在rdi寄存器中传递而不在堆栈中传递,这就是为什么没有为此参数分配的堆栈空间。

但是,由于您在禁用优化的情况下编译程序,因此可能会遇到一些不必要的堆栈空间分配以及对该空间的读写操作。

此代码说明了这一点:

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

这四条mov指令只相当于一个简单的movl $0, %eax,不需要内存来执行此操作。

如果在编译命令中添加-O2之类的优化开关,您将在反汇编中看到更有意义的代码。

另请注意,可能仅需要一些空间分配用于保持堆栈指针对齐,这样可以提高性能或避免未对齐内存访问的问题(如果启用了未对齐的访问,则可能会出现#AC异常)。 / p>

上面的代码也显示了它。请注意,这四个mov指令仅使用8个字节的内存,而addsub指令使堆栈增加和缩小16个。