ELF标准和重定位偏移计算

3
我在理解链接器如何执行重定位方面遇到了困难。根据 ELF 手册(重定位部分,第27页)说明,类型为R_386_PC32的重定位是通过计算量S + A - P来实现的(请参见第29页的ELF手册)。
现在,考虑以下ELF头:
   ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          560 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           40 (bytes)
  Number of section headers:         13
  Section header string table index: 10

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00000000 000034 000038 00  AX  0   0  1
  [ 2] .rel.text         REL             00000000 0001b8 000010 08   I 11   1  4
  [ 3] .data             PROGBITS        00000000 00006c 000000 00  WA  0   0  1
  [ 4] .bss              NOBITS          00000000 00006c 000000 00  WA  0   0  1
  [ 5] .rodata           PROGBITS        00000000 00006c 00000f 00   A  0   0  1
  [ 6] .comment          PROGBITS        00000000 00007b 000035 01  MS  0   0  1
  [ 7] .note.GNU-stack   PROGBITS        00000000 0000b0 000000 00      0   0  1
  [ 8] .eh_frame         PROGBITS        00000000 0000b0 000044 00   A  0   0  4
  [ 9] .rel.eh_frame     REL             00000000 0001c8 000008 08   I 11   8  4
  [10] .shstrtab         STRTAB          00000000 0001d0 00005f 00      0   0  1
  [11] .symtab           SYMTAB          00000000 0000f4 0000b0 10     12   9  4
  [12] .strtab           STRTAB          00000000 0001a4 000013 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

There are no section groups in this file.

There are no program headers in this file.

Relocation section '.rel.text' at offset 0x1b8 contains 2 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
0000001f  00000501 R_386_32          00000000   .rodata
00000024  00000a02 R_386_PC32        00000000   printf

Relocation section '.rel.eh_frame' at offset 0x1c8 contains 1 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00000020  00000202 R_386_PC32        00000000   .text

The decoding of unwind sections for machine type Intel 80386 is not currently supported.

Symbol table '.symtab' contains 11 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS asd.c
     2: 00000000     0 SECTION LOCAL  DEFAULT    1 
     3: 00000000     0 SECTION LOCAL  DEFAULT    3 
     4: 00000000     0 SECTION LOCAL  DEFAULT    4 
     5: 00000000     0 SECTION LOCAL  DEFAULT    5 
     6: 00000000     0 SECTION LOCAL  DEFAULT    7 
     7: 00000000     0 SECTION LOCAL  DEFAULT    8 
     8: 00000000     0 SECTION LOCAL  DEFAULT    6 
     9: 00000000    56 FUNC    GLOBAL DEFAULT    1 main
    10: 00000000     0 NOTYPE  GLOBAL DEFAULT  UND printf

No version information found in this file.

还有相关的可重定位文件:

asd.o:     file format elf32-i386


Disassembly of section .text:

00000000 <main>:
   0:   8d 4c 24 04             lea    0x4(%esp),%ecx
   4:   83 e4 f0                and    $0xfffffff0,%esp
   7:   ff 71 fc                pushl  -0x4(%ecx)
   a:   55                      push   %ebp
   b:   89 e5                   mov    %esp,%ebp
   d:   51                      push   %ecx
   e:   83 ec 14                sub    $0x14,%esp
  11:   c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%ebp)
  18:   83 ec 08                sub    $0x8,%esp
  1b:   ff 75 f4                pushl  -0xc(%ebp)
  1e:   68 00 00 00 00          push   $0x0
  23:   e8 fc ff ff ff          call   24 <main+0x24>
  28:   83 c4 10                add    $0x10,%esp
  2b:   b8 00 00 00 00          mov    $0x0,%eax
  30:   8b 4d fc                mov    -0x4(%ebp),%ecx
  33:   c9                      leave  
  34:   8d 61 fc                lea    -0x4(%ecx),%esp
  37:   c3                      ret 

考虑到符号printf的类型为R_386_PC32,新偏移量必须计算为S + A - P。根据符号表,S等于0。根据ELF手册,数量A隐含在要修改的位置中,因此应该等于0xfffffffc(小端序),最后P应该是r_offset,因此为0x24。因此,新的偏移量应该等于0xffffffD8。
然而,在链接上述程序后,我得到了:
0804840b <main>:
 804840b:       8d 4c 24 04             lea    0x4(%esp),%ecx
 804840f:       83 e4 f0                and    $0xfffffff0,%esp
 8048412:       ff 71 fc                pushl  -0x4(%ecx)
 8048415:       55                      push   %ebp
 8048416:       89 e5                   mov    %esp,%ebp
 8048418:       51                      push   %ecx
 8048419:       83 ec 14                sub    $0x14,%esp
 804841c:       c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%ebp)
 8048423:       83 ec 08                sub    $0x8,%esp
 8048426:       ff 75 f4                pushl  -0xc(%ebp)
 8048429:       68 d0 84 04 08          push   $0x80484d0
 804842e:       e8 ad fe ff ff          call   80482e0 <printf@plt>
 8048433:       83 c4 10                add    $0x10,%esp
 8048436:       b8 00 00 00 00          mov    $0x0,%eax
 804843b:       8b 4d fc                mov    -0x4(%ebp),%ecx
 804843e:       c9                      leave  
 804843f:       8d 61 fc                lea    -0x4(%ecx),%esp
 8048442:       c3                      ret    
 8048443:       66 90                   xchg   %ax,%ax
 8048445:       66 90                   xchg   %ax,%ax
 8048447:       66 90                   xchg   %ax,%ax
 8048449:       66 90                   xchg   %ax,%ax
 804844b:       66 90                   xchg   %ax,%ax
 804844d:       66 90                   xchg   %ax,%ax
 804844f:       90                      nop

我的问题是:printf调用的参数(即0xfffffead)在最终可执行文件中实际存储的值是如何计算的?

S 不是 0,而是 printfplt 中地址的值。 - Jester
2
不是根据 ELF 手册。它说:“S:这意味着重定位条目中索引所在的符号的值。” - badnack
1
除了 printf 不在你的目标文件中,它是未定义的。所以是的,规范是正确的,它将是那个地址,但从你的转储中,该地址尚未知道。PS:也适用于你的 .rodata 重定位。 - Jester
2
我明白了,那么新值将何时添加到符号表中? - badnack
我认为他们在谈论完全填充的符号表,这是从所有对象和库链接时产生的。显然,引用外部符号的模块还不能有其地址。 - Jester
我明白了,这很有道理。 - badnack
1个回答

0
除非 printf 不在您的目标文件中,否则它未定义。所以是的,规范是正确的,它将成为那个地址,但从您的转储中尚不知道该地址。PS:也适用于您的 .rodata 重定位。 - Jester

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接