【发布时间】:2016-05-11 12:23:08
【问题描述】:
我有以下 C 代码:
#include <stdio.h>
void function(int a, int b, int c) {
int buff_1[5];
int buff_2[10];
buff_1[0] = 6;
buff_2[0] = 'A';
buff_2[1] = 'B';
}
int main(void) {
int i = 1;
function(1,2,3);
return 0;
}
现在我要分析相关的汇编代码: 根据我正在阅读的书,函数调用之前的汇编指令是:
pushl $3
pushl $2
pushl $1
call function
底层对象文件是使用gcc-5.3 -O0 -c functions.c 创建的。
但是,如果我使用 objdump 创建汇编代码,我会收到以下说明:
movl $3, %edx
movl $2, %esi
movl $1, %edi
据我了解汇编(我对它很陌生),第一个对我来说更有意义。
这本书是不是完全错了?或者是因为使用gcc 2.9而导致书籍输出过时了
【问题讨论】:
-
gcc 是否有特定的中间表示或字节码?您的第二个示例看起来像目标特定程序集。 IE。不是每个处理器都会有这些寄存器,那些是 x86 特定的(我可能错了,我通常不处理低级的东西)。此外,可能是一种优化并没有全部被“-O0”关闭,构造函数省略是我知道的不是。可能相关:stackoverflow.com/questions/4534791/…
-
这只是一个不同的调用约定——在寄存器中而不是在堆栈中传递前 N 个参数。但是,使用这些寄存器不是我认可的惯例,the Wikipedia page 也不是。这是 64 位电脑吗?尝试使用
-m32编译可能会得到 32 位约定,我认为默认情况下是堆栈。 -
它只是使用 x86_64 调用约定,使用寄存器 RDI、RSI 和 RDX 的下半部分(它们是 x86_64 调用约定中的前 3 个寄存器)
-
"这是转贴:为什么它使用 movl 而不是 push?" - 不,这不对。该问题涉及 GCC 3.x 通过保留一些空间然后写入该空间而不是使用推送指令将参数推送到堆栈的方式。 David 是正确的:这是因为您正在编译 64 位代码,这是标准的 64 位 Linux 调用约定。尝试
-m32来获得看起来像你的书的 32 位代码,或者至少像链接问题中的代码,这相当于你书中的代码(这部分是 gcc 2.95 与更现代的 GCC)。跨度> -
GCC 2.95.X Releases 发生在 1999 年 7 月 - 2001 年 3 月,并且已经过时了。 x86_64 那时还处于起步阶段。请参阅x86_64,因此看起来代码生成是使用 x86_64 调用约定来描述的,但要么使用寄存器的下半部分——要么只是错误地使用了 x86 寄存器名称。学习历史没有错,但是如果您打算使用当前代码,则需要更多更新的参考。