【发布时间】:2017-07-17 09:30:13
【问题描述】:
GCC 和 Clang 编译器似乎使用了一些黑魔法。 C 代码只是否定 double 的值,但汇编指令涉及按位 XOR 和指令指针。有人可以解释发生了什么以及为什么它是最佳解决方案。谢谢。
test.c的内容:
void function(double *a, double *b) {
*a = -(*b); // This line.
}
生成的汇编指令:
(gcc)
0000000000000000 <function>:
0: f2 0f 10 06 movsd xmm0,QWORD PTR [rsi]
4: 66 0f 57 05 00 00 00 xorpd xmm0,XMMWORD PTR [rip+0x0] # c <function+0xc>
b: 00
c: f2 0f 11 07 movsd QWORD PTR [rdi],xmm0
10: c3 ret
(clang)
0000000000000000 <function>:
0: f2 0f 10 06 movsd xmm0,QWORD PTR [rsi]
4: 0f 57 05 00 00 00 00 xorps xmm0,XMMWORD PTR [rip+0x0] # b <function+0xb>
b: 0f 13 07 movlps QWORD PTR [rdi],xmm0
e: c3 ret
地址0x4 的汇编指令代表“这一行”,但我不明白它是如何工作的。 xorpd/xorps 指令应该是逐位的 XOR 和 PTR [rip] 是指令指针。
我怀疑在执行时rip 指向了0f 57 05 00 00 00 0f 字节带附近的某个位置,但我不太明白这是如何工作的,以及为什么两个编译器都选择这种方法。
附:我应该指出这是使用-O3编译的
【问题讨论】:
-
我无法重现这个。两个编译器都与一个表示 -0.0 的常量进行异或,它们从内存中加载。这对RIP-relative offsetting 有意义。没有意义的是,您的反汇编显示它们将下一条指令的字节加载为浮点常量。那是不对的。您是否有可能以某种方式从拆卸中剥离了偏移量?还是你的反汇编程序很困惑?
-
我绝对不会手动更改任何内容。使用上面的逐字代码和命令
gcc test.c -c -O3 -o test.o和objdump -S -M intel test.o这是我得到的输出。我将重申我知道PTR [rip]是什么,并且您可以通过更改双精度位的前导位来反转符号。我问的原因是因为这两个想法并没有在我的脑海中混合。 -
您越确定自己没有犯错,您犯错的可能性就越大。从控制台复制了错误的部分。抱歉,汇编列表现在应该是正确的。奇怪的
xor和rip仍然存在。 -
这看起来像未链接的代码,其中偏移量尚未修复。因此
[rip + 0x0]part。这是 RIP 相对寻址,但偏移量还没有被链接器放置到位。请参阅接受的答案,这显然使用了正确链接的代码。
标签: gcc assembly x86-64 sse magic-numbers