2

根据一些教科书,编译器会使用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没有任何addqand subq。为什么?的作用是addq $16, %rsp什么?

感谢您的任何意见。

4

1 回答 1

5

您的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 异常)。

上面的代码也显示了它。看,这四条mov指令只使用了 8 个字节的内存,而addandsub指令将堆栈增长和收缩了 16 个字节。

于 2012-10-14T19:35:41.400 回答