为什么gcc使用movl而不是push-to-pass函数args?

为什么gcc使用movl而不是push-to-pass函数args?,c,gcc,assembly,callstack,calling-convention,C,Gcc,Assembly,Callstack,Calling Convention,请注意以下代码: #include <stdio.h> void a(int a, int b, int c) { char buffer1[5]; char buffer2[10]; } int main() { a(1,2,3); } 该命令在汇编中显示我们的源代码 现在我们可以在main函数中看到,我们从不使用“push”命令来推送 将函数插入堆栈中。它用“movel”代替了那个 main: pushl %ebp movl %esp, %ebp

请注意以下代码:

#include <stdio.h>
void a(int a, int b, int c)
{
    char buffer1[5];
    char buffer2[10];
}

int main()
{
    a(1,2,3); 
}
该命令在汇编中显示我们的源代码

现在我们可以在main函数中看到,我们从不使用“push”命令来推送 将函数插入堆栈中。它用“movel”代替了那个

main:
 pushl %ebp
 movl %esp, %ebp
 andl $-16, %esp
 subl $16, %esp
 movl $3, 8(%esp)
 movl $2, 4(%esp)
 movl $1, (%esp)
 call a
 leave
为什么会这样?
它们之间有什么区别?

该代码只是直接将常量(1、2、3)放置在(更新的)堆栈指针(esp)的偏移位置。编译器选择手动执行“推送”,结果相同


“push”设置数据并更新堆栈指针。在本例中,编译器将其简化为堆栈指针的一次更新(而不是三次)。一个有趣的实验是,尝试将函数“a”更改为只接受一个参数,并查看指令模式是否发生变化。

gcc进行各种优化,包括根据要优化的特定CPU的执行速度选择指令。你会注意到,像
x*=n
这样的东西经常被SHL、ADD和/或SUB的组合所代替,尤其是当n是一个常数时;而MUL仅在SHL-ADD-SUB组合的平均运行时间(和缓存/等封装外形)超过MUL时使用,或者
n
不是常数(因此,将循环与SHL-ADD-SUB一起使用会更昂贵)


在函数参数的情况下:MOV可以被硬件并行化,而PUSH不能。(由于esp寄存器的更新,第二次推送必须等待第一次推送完成。)在函数参数的情况下,MOV可以并行运行。

这在OS X上可能吗?我在某个地方读到,它要求堆栈指针在16字节边界对齐。这可能解释了这种代码生成

我找到了这篇文章:

以下是我对它的看法:

-mpush参数
-mno推送参数
使用推送操作存储传出参数。这种方法比较短,而且通常
与使用SUB/MOV操作的方法速度相同,默认情况下启用。
在某些情况下,禁用它可能会由于调度的改进而提高性能
减少依赖性。
-maccumulate传出args
如果启用,传出参数所需的最大空间量将为
在函数序言中计算。这在大多数现代CPU上更快,因为
减少依赖性,改进调度,减少首选时的堆栈使用
堆栈边界不等于2。缺点是代码大小显著增加。
此开关表示-mno push args。
显然,默认情况下启用了
-maccumulate传出参数
,覆盖了
-mpush参数
。使用
-mno累计传出args进行显式编译
会返回到此处的
PUSH
方法


2019更新:从奔腾M开始,现代CPU就有了高效的推送/弹出功能。

-mno累计传出参数(并使用push)最终在2014年1月成为
-mtune=generic
的默认值。

为什么需要先将常量放入寄存器?x86支持立即常量的推送。更清楚的是,OS X ABI只要求堆栈指针在外部函数调用点对齐16字节。我明白了,谢谢你指出这一点。通过阅读其他答案,我现在了解到movl代码生成与改进的调度相关。andl指令似乎只用于堆栈对齐。一个更好的问题是为什么
-maccumulate outgoing args
不会自动被
-Os
@R禁用此膨胀生成选项。。那么你知道为什么吗?@Tony:显然,因为在决定为每个特定的-O选项启用/禁用许多(~200)个优化标志中的哪一个时,有时会出现问题。更新:
-maccumulate outgoing args
在2014年1月被默认禁用,现在没有的CPU非常少见。(可能应该早点完成)。
main:
 pushl %ebp
 movl %esp, %ebp
 andl $-16, %esp
 subl $16, %esp
 movl $3, 8(%esp)
 movl $2, 4(%esp)
 movl $1, (%esp)
 call a
 leave