问题描述
让我们采用以下基本C函数以及它产生的有意未优化的程序集:
int main() {
int i = 4;
return 3;
}
它产生以下(未优化的)程序集,这对我来说都是有意义的:
main:
pushq %rbp
movq %rsp,%rbp
movl $4,-4(%rbp)
movl $3,%eax
popq %rbp
ret
但是,一旦添加函数调用,就会有两条我不太了解的指令:
void call() {};
int main() {
int i = 4;
call();
return 3;
}
main:
pushq %rbp
movq %rsp,%rbp
subq $16,%rsp <-- why is it subtracting 16?
movl $4,-4(%rbp)
movl $0,%eax <-- why is it first clearing the %eax register?
call call
movl $3,%eax
leave
ret
如果堆栈帧需要对齐16字节,subq $16,%rsp
对此有何帮助?最初的pushq %rbp
指令是否已经将其偏移8,而现在为+24?还是上面有问题的这两行的要点是什么?
解决方法
第一个变体将局部变量存储在红色区域中,该区域位于堆栈指针下方的128个字节区域中,signal处理程序不会更改该区域。第二种变体不能使用红色区域,因为callq
指令写入(原始)红色区域,从而破坏了存储在其中的局部变量。 (当然,被调用的函数也可以写入原始的红色区域。)
%eax
设置为零,因为函数定义未声明任何原型,因此编译器必须假定它是可变参数函数。 %eax
(实际上是%al
)用于optimize the implementation of variadic functions。