链接器如何确定符号被调用到哪一行?

时间:2013-12-20 19:40:39

标签: linker ld portable-executable objdump relocation

我想知道链接器如何确定printf被称为@ 0xd1: 如果我查看符号表中的_printf地址,我看到它是0x0,因为这个函数还没有重新定位。但是链接器和objdump如何知道地址 1e 重定位应该怎么做? Objdump说DISP32 _printf,但我找不到objfile中的一个条目,在地址1e处应该重新定位。

objdump -d -r -t test.obj输出:

test.obj:     file format pe-i386

SYMBOL TABLE:
[  0](sec -2)(fl 0x00)(ty   0)(scl 103) (nx 1) 0x00000000 test.c
File 
[  2](sec  1)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x00000000 _main
[  3](sec  1)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .text
AUX scnlen 0x29 nreloc 3 nlnno 0
[  5](sec  2)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .data
AUX scnlen 0x0 nreloc 0 nlnno 0
[  7](sec  3)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .bss
AUX scnlen 0x0 nreloc 0 nlnno 0
[  9](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .rdata
AUX scnlen 0x3 nreloc 0 nlnno 0
[ 11](sec  5)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .eh_frame
AUX scnlen 0x38 nreloc 1 nlnno 0
[ 13](sec  0)(fl 0x00)(ty  20)(scl   2) (nx 1) 0x00000000 ___main
AUX tagndx 0 ttlsiz 0x0 lnnos 0 next 0
[ 15](sec  0)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x00000000 _printf

Disassembly of section .text:

00000000 <_main>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   83 e4 f0                and    $0xfffffff0,%esp
   6:   83 ec 10                sub    $0x10,%esp
   9:   e8 00 00 00 00          call   e <_main+0xe>
            a: DISP32   ___main
   e:   c7 44 24 04 05 00 00    movl   $0x5,0x4(%esp)
  15:   00 
  16:   c7 04 24 00 00 00 00    movl   $0x0,(%esp)
        19: dir32   .rdata
  1d:   e8 00 00 00 00          call   22 <_main+0x22>
            1e: DISP32  _printf
  22:   b8 00 00 00 00          mov    $0x0,%eax
  27:   c9                      leave  
  28:   c3                      ret    
  29:   90                      nop
  2a:   90                      nop
  2b:   90                      nop

2 个答案:

答案 0 :(得分:1)

在我研究了PE / COFF - 格式并查看了OBJ-Code之后,我找到了一个重定位条目表:

0x160:14 00 19 00 00 00 09 00 00 00 06 00 1E 00 00 00  ................
0x170:0F 00 00 00 14 00 2D 00 00 00 09 00 00 00 06 00  ......-.........

@ 0x16C是 _printf 的条目。 0x1E 是调用指令的地址部分的地址。链接器在此位置插入重定位的符号。这是一个32位字。 在0x174,您可以找到重定位的类型。类型id为14,并表示链接器应使用printf的相对地址替换此部分:

  

IMAGE_REL_I386_REL32   0x0014   目标的32位相对位移。这支持x86相对分支和调用指令。

答案 1 :(得分:0)

当我上次查看Windows中的动态链接时,系统调用被编译为对“thunk”的调用,这是一个执行远程调用的2行子例程。所以对printf的所有调用都将调用同一个thunk。符号表给出了thunk的位置,并且链接器只需要替换thunk中的一个地址,以便在加载包含printf的库时将所有调用链接到正确的far地址。我无法想象这已经发生了很大变化。