用于双重否定的奇怪的SSE汇编程序指令

RuR*_*uRo 0 assembly gcc sse x86-64 magic-numbers

GCC和Clang编译器似乎采用了一些黑暗魔法.该C代码只是否定了双重的价值,但汇编指令涉及逐位XOR和指令指针.有人可以解释发生了什么,为什么它是一个最佳解决方案.谢谢.

test.c的内容:

void function(double *a, double *b) {
    *a = -(*b); // This line.
}
Run Code Online (Sandbox Code Playgroud)

生成的汇编程序指令:

(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 
Run Code Online (Sandbox Code Playgroud)
(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    
Run Code Online (Sandbox Code Playgroud)

地址处的汇编指令0x4代表"此行",但我无法理解它是如何工作的.该xorpd/xorps指令被认为是逐位XORPTR [rip]是指令指针.

我怀疑在执行的那一刻rip指向了接近0f 57 05 00 00 00 0f字节的区域,但我无法弄清楚,这是如何工作的以及为什么两个编译器都选择这种方法.

PS我应该指出这是使用编译的 -O3

saj*_*oie 7

对我来说,gcc使用-S -O3相同代码的选项的输出是:

    .file   "test.c"
    .text
    .p2align 4,,15
    .globl  function
    .type   function, @function
function:
.LFB0:
    .cfi_startproc
    movsd   (%rsi), %xmm0
    xorpd   .LC0(%rip), %xmm0
    movsd   %xmm0, (%rdi)
    ret
    .cfi_endproc
.LFE0:
    .size   function, .-function
    .section    .rodata.cst16,"aM",@progbits,16
    .align 16
.LC0:
    .long   0
    .long   -2147483648
    .long   0
    .long   0
    .ident  "GCC: (Ubuntu 6.3.0-12ubuntu2) 6.3.0 20170406"
    .section    .note.GNU-stack,"",@progbits
Run Code Online (Sandbox Code Playgroud)

这里xorpd指令使用指令指针相对寻址,偏移量指向.LC0带有64位值的标签0x8000000000000000(第63位设置为1).

.LC0:
    .long   0
    .long   -2147483648
Run Code Online (Sandbox Code Playgroud)

如果你的编译器是big endian这些swaped的行.

对double值进行xoring,0x8000000000000000将符号位(第63位)设置为负值.

clang使用xorps指令的方式与double值的前32位相同.

如果使用-r选项运行对象转储,它将显示在运行之前应该对程序执行的重定位.

objdump -d test.o -r

test.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <function>:
   0:   f2 0f 10 06             movsd  (%rsi),%xmm0
   4:   66 0f 57 05 00 00 00    xorpd  0x0(%rip),%xmm0        # c <function+0xc>
   b:   00 
            8: R_X86_64_PC32    .LC0-0x4
   c:   f2 0f 11 07             movsd  %xmm0,(%rdi)
  10:   c3                      retq   

Disassembly of section .text.startup:

0000000000000000 <main>:
   0:   31 c0                   xor    %eax,%eax
   2:   c3                      retq   
Run Code Online (Sandbox Code Playgroud)

在这里,<function + 0xb>我们有一个R_X86_64_PC32类型的重定位.

PS:我正在使用gcc 6.3.0