为什么GCC使用Mov而不是推入函数调用?

时间:2014-03-08 09:52:26

标签: c gcc assembly compilation stack

所以我有这个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将参数推送到堆栈的新方法吗?如果有的话,我可以使用编译器标志来切换它吗?

2 个答案:

答案 0 :(得分:7)

GCC manual说,

-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这样的编译器是由那些非常仔细考虑如何使经常使用的代码片段(如函数调用/返回)尽可能高效的人编写的。当然,他们的解决方案针对一般情况,在特殊情况下可能会有更好的选择。