14 April 2018

15.7 Dynamic Linking of Programming Language Pragmatics, Fourth Edition gives a high level description of linux dynamic linking. It is great treatment of the topic without involving much low-level details. One note is that the push GOT_main mains GOT[1] which can also be referred as GOT+8.

Linux Internals ~ Dynamic Linking Wizardry gives a good description of linux dynamic linking. But the post talks about i386 platform. Here I describe some parts of the post applied to x86-64 platform. My post can be use a complementary reading to the original post when you want to play along on x86-64 platform. .

name.c:

int main(void) {
  puts("Hey!");
  return 0;
}

gcc -o name name.c produces:

name.c: In function ‘main’:
name.c:2:3: warning: implicit declaration of function ‘puts’ [-Wimplicit-function-declaration]
   puts("Hey!");
   ^~~~

./name produces:

Hey!

callq 400400 <puts@plt> jumps to the first instruct of puts’s PLT entry whose address is 0x400400. A part of objdump- D name:

0000000000400507 <main>:
  400507: 55                    push   %rbp
  400508: 48 89 e5              mov    %rsp,%rbp
  40050b: bf a4 05 40 00        mov    $0x4005a4,%edi
  400510: e8 eb fe ff ff        callq  400400 <puts@plt>
  400515: b8 00 00 00 00        mov    $0x0,%eax
  40051a: 5d                    pop    %rbp
  40051b: c3                    retq
  40051c: 0f 1f 40 00           nopl   0x0(%rax)

The first instruction of puts PLT entry jumps to GOT[3] whose address is 0x601008. A part of objdump- D name:

Disassembly of section .plt:

00000000004003f0 <puts@plt-0x10>:
  4003f0: ff 35 12 0c 20 00     pushq  0x200c12(%rip)        # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
  4003f6: ff 25 14 0c 20 00     jmpq   *0x200c14(%rip)        # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
  4003fc: 0f 1f 40 00           nopl   0x0(%rax)

0000000000400400 <puts@plt>:
  400400: ff 25 12 0c 20 00     jmpq   *0x200c12(%rip)        # 601018 <_GLOBAL_OFFSET_TABLE_+0x18>
  400406: 68 00 00 00 00        pushq  $0x0
  40040b: e9 e0 ff ff ff        jmpq   4003f0 <_init+0x28>

readelf -r name produces:

Relocation section '.rela.dyn' at offset 0x380 contains 1 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000600ff8  000300000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0

Relocation section '.rela.plt' at offset 0x398 contains 2 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000601018  000100000007 R_X86_64_JUMP_SLO 0000000000000000 puts@GLIBC_2.2.5 + 0
000000601020  000200000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main@GLIBC_2.2.5 + 0

objdump -R name produces:

name:     file format elf64-x86-64

DYNAMIC RELOCATION RECORDS
OFFSET           TYPE              VALUE
0000000000600ff8 R_X86_64_GLOB_DAT  __gmon_start__
0000000000601018 R_X86_64_JUMP_SLOT  puts@GLIBC_2.2.5
0000000000601020 R_X86_64_JUMP_SLOT  __libc_start_main@GLIBC_2.2.5

puts@GLIBC_2.2.5 is puts’s GOT entry. Its type is R_X86_64_JUMP_SLOT.

06 04 40 starting from 601008 is 400406 in the little endian. So the first instruction of puts’ PLT entry jumps to the second instruction of puts’ PLT entry.

Disassembly of section .got.plt:

0000000000601000 <_GLOBAL_OFFSET_TABLE_>:
  601000: 28 0e                 sub    %cl,(%rsi)
  601002: 60                    (bad)
  ...
  601017: 00 06                 add    %al,(%rsi)
  601019: 04 40                 add    $0x40,%al
  60101b: 00 00                 add    %al,(%rax)
  60101d: 00 00                 add    %al,(%rax)
  60101f: 00 16                 add    %dl,(%rsi)
  601021: 04 40                 add    $0x40,%al
  601023: 00 00                 add    %al,(%rax)
  601025: 00 00                 add    %al,(%rax)
  ...