3
votes

I am struggling in understanding how a linker perform relocation. According on the ELF manual (Relocation section, pag 27) a relocation of type R_386_PC32 is performed by calculating the quantity S + A - P (see ELF manual at page 29).

Now, consider the following ELF header:

   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.

and the relative relocatable 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 

Given that the symbol printf has type R_386_PC32, the new offset has to be calculated as S + A - P. According the sym table S is equal to 0. The quantity A, according the ELF manual, is implicit in the location to be modified, therefore should be equal to 0xfffffffc (little endianess) and finally P should be r_offset, thus 0x24. It follows that the new offset should be equal to 0xffffffD8.

Instead, after linking the above program, I obtain:

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

My question is: how is calculated the value actually stored in the final executable file as argument of the printf call(i.e., 0xfffffead)?

1
S is not 0, it's whatever the address of printf in the plt is going to be.Jester
not according on the ELF manual. It says: 'S: This means the value of the symbol whose index resides in the relocation entry.'badnack
Except printf isn't in your object file, it's undefined. So yes, the specification is correct, it is going to be that address, but from your dump that address is not yet known. PS: also applies to your .rodata relocation.Jester
I see, and when the new value will be added to the symbol table?badnack
I believe they are talking about the totally filled in symbol table, which is produced during linking from all the objects and libraries. Obviously your module that references an external symbol can't have its address yet.Jester

1 Answers

0
votes

Except printf isn't in your object file, it's undefined. So yes, the specification is correct, it is going to be that address, but from your dump that address is not yet known. PS: also applies to your .rodata relocation. – Jester