1

考虑以下代码:

$ cat foo.c
static int foo = 100;

int function(void)
{
    return foo;
}

我了解libfoo.so的反汇编

$ gcc -m32 -fPIC -shared -o libfoo.so foo.c
$ objdump -D libfoo.so

000004cc <function>:
 4cc:   55                      push   %ebp
 4cd:   89 e5                   mov    %esp,%ebp
 4cf:   e8 0e 00 00 00          call   4e2 <__x86.get_pc_thunk.cx>
 4d4:   81 c1 c0 11 00 00       add    $0x11c0,%ecx
 4da:   8b 81 18 00 00 00       mov    0x18(%ecx),%eax
 4e0:   5d                      pop    %ebp
 4e1:   c3                      ret    

000004e2 <__x86.get_pc_thunk.cx>:
 4e2:   8b 0c 24                mov    (%esp),%ecx
 4e5:   c3                      ret    
 4e6:   66 90                   xchg   %ax,%ax
...

000016ac <foo>:
    16ac:   64 00 00                add    %al,%fs:(%eax)

function地址中foo计算为 0x4d4(ecx调用后的值__x86.get_pc_thunk.cx)+ $0x11c0 + 0x18 = 0x16ac。0x16ac 是foo.

但是我不明白的拆卸

$ gcc -m32 -fPIC -shared -c foo.c
$ objdump -D foo.o
00000000 <function>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   e8 fc ff ff ff          call   4 <function+0x4>
   8:   81 c1 02 00 00 00       add    $0x2,%ecx
   e:   8b 81 00 00 00 00       mov    0x0(%ecx),%eax
  14:   5d                      pop    %ebp
  15:   c3                      ret    

00000000 <foo>:
   0:   64 00 00                add    %al,%fs:(%eax)

00000000 <__x86.get_pc_thunk.cx>:
   0:   8b 0c 24                mov    (%esp),%ecx
   3:   c3                      ret 

为什么call 4 <function+0x4>和为什么add $0x2,%ecx

更新:(将 -r 标志添加到 objdump,-R 标志会产生错误not a dynamic object, Invalid operation

$ objdump -D -r foo.o
00000000 <function>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   e8 fc ff ff ff          call   4 <function+0x4>
        4: R_386_PC32   __x86.get_pc_thunk.cx
  8:    81 c1 02 00 00 00       add    $0x2,%ecx
        a: R_386_GOTPC  _GLOBAL_OFFSET_TABLE_
  e:    8b 81 00 00 00 00       mov    0x0(%ecx),%eax
        10: R_386_GOTOFF    .data
 14:    5d                      pop    %ebp
 15:    c3                      ret    

现在4在 中是有意义的call 4 <function+0x4>,因为该指令在文本部分的偏移量是 4。我仍然不知道为什么0x2在 中add $0x2,%ecx

4

1 回答 1

2

链接器将执行重定位,使得final value= symbol+ offset- PC。请注意,PC此公式中的 是重定位本身的地址,而不是指令的地址,因为链接器不知道指令边界。然而,汇编器知道它们并且可以创建适当的偏移量。

让我们看看它是如何call __x86.get_pc_thunk.cx工作的。在 x86 上,该call指令使用相对寻址,但 的值PC已经递增以指向下一条指令。您可以在第一次转储中验证这一点:

 4cf:   e8 0e 00 00 00          call   4e2 <__x86.get_pc_thunk.cx>
 4d4:   81 c1 c0 11 00 00       add    $0x11c0,%ecx

注意指令中的偏移量是0e。已经增加PC4d4肯定是跳转的目标4e2= 4d4+ 0e(所有数字均为十六进制)。

现在对于带有重定位的版本:

   3:   e8 fc ff ff ff          call   4 <function+0x4>
        4: R_386_PC32   __x86.get_pc_thunk.cx

它使用R_386_PC32但那是在指令的第二个字节,而call需要从更新的偏移量,PC这显然是4更多的字节。这意味着正确的结果4更少,因此指令包含fffffffcwhich is -4。请注意,无论 的地址call是什么,此偏移量始终为-4。反汇编程序会自动将其添加到更新PC的内容中,在本例中是8这样,因此它call 4通过做8-4

好的,进入R_386_GOTPC.

   3:   e8 fc ff ff ff          call   4 <function+0x4>
        4: R_386_PC32   __x86.get_pc_thunk.cx
  8:    81 c1 02 00 00 00       add    $0x2,%ecx
        a: R_386_GOTPC  _GLOBAL_OFFSET_TABLE_

__x86.get_pc_thunk.cx函数只是将堆栈中的返回地址加载到寄存器ecx中。在这种情况下,这个返回地址是8。实现的目标是拥有_GLOBAL_OFFSET_TABLE_in的地址ecx。我们需要知道它与PC已有参考的ecx距离并添加该距离。为此,R_386_GOTPC使用了重定位,但这将给出地址的偏移量,0a因为那是重定位条目所在的位置。与地址的偏移量8当然会2更多。这2是指令中编码的内容。

总结:指令中存储的重定位偏移量是重定位地址和所需参考点的差:offset= PC- reference。在第一种情况下,这个参考点是4更高的字节,在第二种情况下,2更低的字节分别给出-4和的偏移量2

于 2012-12-19T03:07:40.820 回答