"目的为0x0(%rip),%xmm0"

时间:2015-08-03 18:25:47

标签: gcc assembly

我试图理解/调试我没有源代码的库。在这样做时,我遇到了以下函数(以及其他一些更复杂的函数,例如[0]):

0000000000000000 <old_bern_poly_power02(double, double)>:
       0:       66 0f 28 d0             movapd %xmm0,%xmm2
       4:       66 0f 28 c1             movapd %xmm1,%xmm0
       8:       f2 0f 59 d1             mulsd  %xmm1,%xmm2
       c:       f2 0f 5c 05 00 00 00    subsd  0x0(%rip),%xmm0        # 14 <old_bern_poly_power02(double, double)+0x14>
      13:       00
      14:       f2 0f 59 c2             mulsd  %xmm2,%xmm0
      18:       c3                      retq
      19:       0f 1f 80 00 00 00 00    nopl   0x0(%rax)

除了subsd指令之外,该函数的作用非常明显。但是,我对subsd指令正在做什么感到困惑。指向指令的值0x0(%rip)与此计算有什么关系?

所以,这是我的问题:&#34; subsd&#34;的目的是什么?上面的指示?我假设该函数是用GCC编译的。为什么GCC(或汇编语言程序员)会包含这样的指令? [1]

[0]这是另一个类似的例子:

0000000000000020 <old_bern_poly_power03(double, double)>:
      20:       66 0f 28 d0             movapd %xmm0,%xmm2
      24:       66 0f 28 d8             movapd %xmm0,%xmm3
      28:       66 0f 28 c1             movapd %xmm1,%xmm0
      2c:       f2 0f 59 15 00 00 00    mulsd  0x0(%rip),%xmm2        # 34 <old_bern_poly_power03(double, double)+0x14>
      33:       00
      34:       f2 0f 5c 05 00 00 00    subsd  0x0(%rip),%xmm0        # 3c <old_bern_poly_power03(double, double)+0x1c>
      3b:       00
      3c:       f2 0f 59 d9             mulsd  %xmm1,%xmm3
      40:       f2 0f 59 c3             mulsd  %xmm3,%xmm0
      44:       f2 0f 58 c2             addsd  %xmm2,%xmm0
      48:       f2 0f 59 c3             mulsd  %xmm3,%xmm0
      4c:       c3                      retq
      4d:       0f 1f 00                nopl   (%rax)

[1]注意:基于逐步执行gdb中的函数,当%xmm0远离0.0时,subsd指令似乎没有实际效果,因为0x0(%rip)很小(我不确定这是否正确):

(gdb) x $rip
0x4004e2 <old_bern_poly_power02+12>:    0x00000000055c0ff2
(gdb) p (double)(void *)(0x00000000055c0ff2)
$22 = 4.4426122995515177e-316

为了进一步研究subsd指令的效果,我创建了一个不包含subsd指令的old_bern_poly_power02函数的版本,但在其他方面与上面的列表相同。下表比较了给定各种输入的每个函数版本的返回值。

实际上,返回值是相同的,除非xmm1参数为0,在这种情况下,原始结果为-0(0x8000000000000000),没有subsd指令的版本为0(0x0)。

    xmm0     xmm1 ret_val_with_subsd           (as hex) ret_val_without_subsd           (as hex)
0.000000 0.000000      -0.0000000000 (8000000000000000)          0.0000000000 (               0)
0.000000 1.000000       0.0000000000 (               0)          0.0000000000 (               0)
0.000000 2.000000       0.0000000000 (               0)          0.0000000000 (               0)
0.000000 3.000000       0.0000000000 (               0)          0.0000000000 (               0)
1.000000 0.000000      -0.0000000000 (8000000000000000)          0.0000000000 (               0)
1.000000 1.000000       1.0000000000 (3ff0000000000000)          1.0000000000 (3ff0000000000000)
1.000000 2.000000       4.0000000000 (4010000000000000)          4.0000000000 (4010000000000000)
1.000000 3.000000       9.0000000000 (4022000000000000)          9.0000000000 (4022000000000000)
2.000000 0.000000      -0.0000000000 (8000000000000000)          0.0000000000 (               0)
2.000000 1.000000       2.0000000000 (4000000000000000)          2.0000000000 (4000000000000000)
2.000000 2.000000       8.0000000000 (4020000000000000)          8.0000000000 (4020000000000000)
2.000000 3.000000      18.0000000000 (4032000000000000)         18.0000000000 (4032000000000000)
3.000000 0.000000      -0.0000000000 (8000000000000000)          0.0000000000 (               0)
3.000000 1.000000       3.0000000000 (4008000000000000)          3.0000000000 (4008000000000000)
3.000000 2.000000      12.0000000000 (4028000000000000)         12.0000000000 (4028000000000000)
3.000000 3.000000      27.0000000000 (403b000000000000)         27.0000000000 (403b000000000000)

编辑1:Per Harold和Ross的评论,我将库链接到一个简单的可执行文件(生成上表的那个)并在GDB中反汇编函数,如下所示:

$ gdb ./tmp
[snp]
(gdb) b old_bern_poly_power02 
Breakpoint 1 at 0x400516
(gdb) r
Starting program: [...]/tmp 
    xmm0     xmm1 ret_val_with_subsd           (as hex) ret_val_without_subsd           (as hex)

Breakpoint 1, 0x0000000000400516 in old_bern_poly_power02 ()
(gdb) disassemble
Dump of assembler code for function old_bern_poly_power02:
=> 0x0000000000400516 <+0>:     movapd %xmm0,%xmm2
   0x000000000040051a <+4>:     movapd %xmm1,%xmm0
   0x000000000040051e <+8>:     mulsd  %xmm1,%xmm2
   0x0000000000400522 <+12>:    subsd  0x0(%rip),%xmm0        # 0x40052a <old_bern_poly_power02+20>
   0x000000000040052a <+20>:    mulsd  %xmm2,%xmm0
   0x000000000040052e <+24>:    retq   
   0x000000000040052f <+25>:    nopl   (%rax)
End of assembler dump.

这里似乎仍然对0-offset-to-%rip有相同的引用,尽管我仍然可能做错了?

编辑2:在上面的清单中,我正在反汇编我从未链接的静态库的反汇编中复制和粘贴的版本,然后汇编并链接到我上面的测试程序中。当我从原始静态库中反汇编函数时,链接到我的真实程序中,确实填补了偏移量:

(gdb) disassemble old_bern_poly_power02
Dump of assembler code for function _Z21old_bern_poly_power02dd:
   0x00007f65cf642a50 <+0>:     movapd %xmm0,%xmm2
   0x00007f65cf642a54 <+4>:     movapd %xmm1,%xmm0
   0x00007f65cf642a58 <+8>:     mulsd  %xmm1,%xmm2
   0x00007f65cf642a5c <+12>:    subsd  0x38cc(%rip),%xmm0        # 0x7f65cf646330
   0x00007f65cf642a64 <+20>:    mulsd  %xmm2,%xmm0
   0x00007f65cf642a68 <+24>:    retq   
End of assembler dump.

所以我猜这个subsd指令只是在这里引用表中的常量。

0 个答案:

没有答案