所以我有这个C程序示例。
int worship(long john)
{
return 0 * john;
}
int main()
{
return worship(666);
}
程序集(基本上)看起来像这样:
worship(long):
pushq %rbp
movq %rsp, %rbp
movq %rdi, -8(%rbp)
movl $0, %eax
popq %rbp
ret
main:
pushq %rbp
movq %rsp, %rbp
movl $666, %edi
call worship(long)
popq %rbp
ret
我在阅读堆栈粉碎时遇到了这个问题。在汇编worship(long):
部分中,movq %rdi, -8(%rbp)
我希望它基于我到目前为止阅读的所有内容使用pushq
。这是GCC将参数推送到堆栈的新方法吗?如果有的话,我可以使用编译器标志来切换它吗?
答案 0 :(得分:7)
-mpush-args
推送指令将用于在调用函数时传递传出参数。默认情况下启用。
-mno-push-args
使用PUSH操作存储传出参数。这种方法通常较短 与使用SUB / MOV操作的方法一样快,默认情况下启用。 在某些情况下,由于改进了调度,禁用它可能会提高性能 并减少了依赖性。
-maccumulate-outgoing-args
如果启用,将在函数序言中计算传出参数所需的最大空间量。这在大多数现代CPU上更快,因为当优选的堆栈边界不等于2时,依赖性降低,调度改进并且堆栈使用减少。缺点是代码大小显着增加。这个开关意味着-mno-push-args。
默认情况下,即使-mpush-args
已启用,也会被默认启用的-maccumulate-outgoing-args
覆盖。明确地编译传递选项-mno-accumulate-outgoing-args
可能会将指令更改为push
。
答案 1 :(得分:1)
像GCC这样的编译器是由那些非常仔细考虑如何使经常使用的代码片段(如函数调用/返回)尽可能高效的人编写的。当然,他们的解决方案针对一般情况,在特殊情况下可能会有更好的选择。