随便在读取示例C程序的汇编列表时,我注意到在调用函数foo之前堆栈指针不是16位对齐:
void foo() { }
int func(int p) { foo(); return p; }
int main() { return func(1); }
func:
pushq %rbp
movq %rsp, %rbp
subq $8, %rsp ; See here
movl %edi, -4(%rbp)
movl $0, %eax
call foo
movl -4(%rbp), %eax
leave
ret
subq $8, %rsp
指令在调用foo之前使RSP不对齐(它应该是“subq $ 16,%rsp”)。
在System V ABI中,参数。 3.2.2,我读到:“当控制转移到功能入口点时,值(%rsp - 8)总是16的倍数。”
有人可以帮我理解为什么gcc没有放subq $16, %rsp
?
提前谢谢。
编辑:
我忘了提及我的操作系统和编译器版本:
Debian wheezy,gcc 4.7.2
答案 0 :(得分:1)
假设在输入 func
时堆栈指针是16字节对齐的,那么
pushq %rbp ; <- 8 bytes
movq %rsp, %rbp
subq $8, %rsp ; <- 8 bytes
将保持16字节对齐,以便随后调用foo()
。
击>
似乎因为编译器知道foo()
的实现并且它是一个noop,所以它不会对堆栈对齐感到困扰。如果foo()
仅被视为编译func()
的翻译单元中的声明或原型,您将看到预期的堆栈对齐。