【发布时间】:2017-05-25 05:14:28
【问题描述】:
在linux上反汇编write(1,"hi",3),用gcc -s -nostdlib -nostartfiles -O3构建会导致:
ba03000000 mov edx, 3 ; thanks for the correction jester!
bf01000000 mov edi, 1
31c0 xor eax, eax
e9d8ffffff jmp loc.imp.write
我不参与编译器开发,但由于移入这些寄存器的每个值都是常量并且已知编译时间,我很好奇为什么 gcc 不使用 dl、dil 和 al。
有些人可能会争辩说,这个特性不会对性能产生任何影响,但是当我们谈论程序中的数千个寄存器访问时,mov $1, %rax => b801000000 和mov $1, %al => b001 之间的可执行文件大小存在很大差异。体积小不仅是软件优雅的一部分,而且对性能也有影响。
有人可以解释为什么“GCC 决定”它无关紧要吗?
【问题讨论】:
-
如果你只加载部分寄存器,其余的将包含随机垃圾,被调用者将使用整个寄存器(根据数据类型而定)。它还会导致部分寄存器停顿。请注意,写入低 32 位将自动将高 32 位归零。 PS:你反汇编错了,所有这些指令实际上都是32位的(没有rex前缀)。
-
它与GCC没有任何关系,每个C编译器都需要这样做。谷歌“C 整数提升”以了解更多信息。
-
@HansPassant 整数提升是否适用于原型函数的函数参数?据我所知,只有default argument promotions 适用于函数调用。引用:“整数提升仅适用于:作为通常算术转换的一部分,适用于某些参数表达式 [ndr:上面的默认 arg 提升],适用于一元 +、- 和 ~ 运算符的操作数,以及移位运算符的两个操作数,由它们各自的子条款指定"
-
@MargaretBloom 传递给参数的值通过赋值转换为参数类型。请参见第 7 段。无论哪种方式,这意味着常量
3和1,已经是signed int,仍然是signed int。 -
@MargaretBloom 对于它的价值,
xor eax, eax表明调用是在没有原型的范围内进行的。它不知道函数是否为可变参数,因此将 AL 设置为 0 表示在 SSE 寄存器中传递的参数为 0。您的奇怪案例实际上是一个 ABI 问题,只要双方同意,“好像”规则就允许任一实现。
标签: assembly gcc x86 x86-64 cpu-architecture