How does the linker determine at which line a symbol is called?

414 views Asked by At

I want to know, how the linker determines that printf is called @ 0xd1: If I look into the symbol table for the address of _printf I see it's 0x0, because this function is not already relocated. But how does the linker and objdump know that at address 1e relocation should be done? Objdump says DISP32 _printf, but I can't find an entry in the objfile that says at address 1e relocation should be done.

objdump -d -r -t test.obj Output:

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

There are 2 answers

0
Sebi2020 On BEST ANSWER

After I studied the PE / COFF - Format and looked into the OBJ-Code I've found a table for the relocation entries:

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 is the entry for _printf. 0x1E is the address of the address part of the call instruction. The linker inserts the relocated symbol at this position. It's a 32 Bit Word. At 0x174 you find the type of the relocation. The type id is 14 and says the linker should replace this part with the relative address of printf:

IMAGE_REL_I386_REL32 0x0014 The 32-bit relative displacement of the target. This supports the x86 relative branch and call instructions.

3
stark On

When I last looked at dynamic linking in Windows, system calls were compiled as calls to a "thunk", a 2-line subroutine that did a far call. So all calls to printf will call this same thunk. The symbol table gives the location of the thunk, and the linker only has to replace the one address in the thunk to link all calls to the correct far address when the library containing printf is loaded. I can't imagine that has changed much.