18

注意这段代码:

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

int main()
{
    a(1,2,3); 
}

之后 :

gcc -S a.c

该命令在汇编中显示我们的源代码。

现在我们可以看到在 main 函数中,我们从不使用“push”命令将 a 函数的参数压入堆栈。它使用“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

为什么会这样?他们之间有什么区别?

4

4 回答 4

19

以下是gcc 手册对此的说明:

-mpush-args
-mno-push-args
    Use PUSH operations to store outgoing parameters. This method is shorter and usually
    equally fast as method using SUB/MOV operations and is enabled by default. 
    In some cases disabling it may improve performance because of improved scheduling
    and reduced dependencies.

 -maccumulate-outgoing-args
    If enabled, the maximum amount of space required for outgoing arguments will be
    computed in the function prologue. This is faster on most modern CPUs because of
    reduced dependencies, improved scheduling and reduced stack usage when preferred
    stack boundary is not equal to 2. The drawback is a notable increase in code size.
    This switch implies -mno-push-args. 

显然-maccumulate-outgoing-args是默认启用的,覆盖-mpush-args. 显式编译-mno-accumulate-outgoing-args确实恢复到PUSH方法,here。


2019 年更新
-mno-accumulate-outgoing-args:自从 Pentium M (并使用推送)最终成为 2014 年 1 月的默认设置以来,现代 CPU 就具有高效的推送/弹出功能-mtune=generic

于 2010-12-27T00:20:16.903 回答
8

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

“push”既设置数据又更新堆栈指针。在这种情况下,编译器将其减少为仅更新堆栈指针(相对于三个)。一个有趣的实验是尝试将函数“a”更改为只接受一个参数,并查看指令模式是否发生变化。

于 2010-12-26T17:45:59.210 回答
6

gcc 会进行各种优化,包括根据要优化的特定 CPU 的执行速度来选择指令。你会注意到类似x *= n的东西经常被 SHL、ADD 和/或 SUB 的混合所取代,尤其是当 n 是一个常数时;而 MUL 仅在 SHL-ADD-SUB 组合的平均运行时间(和缓存/等足迹)超过 MUL 或n不是常数时使用(因此使用带有 shl-add-sub 的循环会出现)更贵)。

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

于 2010-12-26T19:05:31.833 回答
2

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

我找到了这篇文章:http: //blogs.embarcadero.com/eboling/2009/05/20/5607

于 2010-12-26T19:05:39.123 回答