根据一些教科书,编译器将使用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
周围没有任何addq
和subq
。为什么? addq $16, %rsp
的功能是什么?
感谢您的任何意见。
答案 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个字节的内存,而add
和sub
指令使堆栈增加和缩小16个。