Dynamic symbol is a symbol whose address cannot be determined at compile time, but must be resolved at runtime. Section .dynsym contains the dynamic symbols. It works together with the .dynstr, .plt, .rela.plt, .got sections.
Section .dynstr is a string table that contains null-terminated strings. Each string represents a external symbol name.
$ readelf --string-dump=.dynstr main
String dump of section '.dynstr':
[ 22] puts#include <stdio.h>
int main(int argc, char** argv)
{
puts("hello");
return 0;
}# '-fcf-protection=none' to place puts@plt to .plt instead of .plt.sec.
$ gcc -fcf-protection=none main.c -o mainrela.plt is a relocation table that tells the runtime linker how to find addresses for dynamic symbols.
$ readelf --relocs main
Relocation section '.rela.plt' at offset 0x600 contains 1 entry:
Offset Info Type Sym. Value Sym. Name + Addend
000000003fd0 000300000007 R_X86_64_JUMP_SLO 0000000000000000 puts@GLIBC_2.2.5 + 0The .plt section contains a small executable code to find addresses for dynamic symbols. The .got section holds the dynamic symbol addresses.
┌──────────────────┐
┌──────────┐ ┌──────────────────────┐ │ ┌───────────┐ │ ┌─────────────────────────────┐
│ main() │ │.plt │ │ │.got │ │ │ runtime linker │
│ │ |──────────────────────| │ |───────────| │ |─────────────────────────────|
│ puts()─┼────┼► puts@plt() │ │ │ │ └───┼─►_dl_runtime_resolve() │
│ │ │ find puts in .got─┼────┼──►│ │ │ find puts │
│ │ │ │ │ │ │ │ │
└──────────┘ │ if not found │ │ │ │◄─────┼─── update puts addr to .got │
│ let linker find┼────┘ └───────────┘ └─────────────────────────────┘
│ call puts │
└──────────────────────┘(gdb) set stop-on-solib-events 1
(gdb) set auto-solib-add 0
(gdb) set environment LD_LIBRARY_PATH .
(gdb) file main
(gdb) start(gdb) disassemble main
Dump of assembler code for function main:
0x0000555555555139 <+0>: push %rbp
0x000055555555513a <+1>: mov %rsp,%rbp
0x000055555555513d <+4>: sub $0x10,%rsp
0x0000555555555141 <+8>: mov %edi,-0x4(%rbp)
0x0000555555555144 <+11>: mov %rsi,-0x10(%rbp)
0x0000555555555148 <+15>: lea 0xeb5(%rip),%rax # 0x555555556004
0x000055555555514f <+22>: mov %rax,%rdi
0x0000555555555152 <+25>: call 0x555555555030 <puts@plt>
0x0000555555555157 <+30>: mov $0x0,%eax
0x000055555555515c <+35>: leave
0x000055555555515d <+36>: ret(gdb) disassemble 0x555555555030
Dump of assembler code for function puts@plt:
0x0000555555555030 <+0>: jmp *0x2f9a(%rip) # 0x555555557fd0 <puts@got.plt>
0x0000555555555036 <+6>: push $0x0
0x000055555555503b <+11>: jmp 0x555555555020
(gdb) info symbol 0x555555557fd0
puts@got[plt] in section .got of /root/demo/main(gdb) x/a 0x555555557fd0
0x555555557fd0 <puts@got.plt>: 0x1036$ objdump --disassemble --section=.plt main
0000000000001030 <puts@plt>:
1030: ff 25 9a 2f 00 00 jmp *0x2f9a(%rip) # 3fd0 <puts@GLIBC_2.2.5>
1036: 68 00 00 00 00 push $0x0
103b: e9 e0 ff ff ff jmp 1020 <_init+0x20>(gdb) info files
0x0000555555557fb8 - 0x0000555555558000 is .got
(gdb) x/9a 0x0000555555557fb8
0x555555557fb8: 0x3dc8 0x0
0x555555557fc8: 0x0 0x1036
0x555555557fd8: 0x0 0x0
0x555555557fe8: 0x0 0x0
0x555555557ff8: 0x0Illustrate .plt, .got before the first call.
file: main file: main
section: .plt section: .got
function: puts@plt()
┌────────────────────┬─────────────────────┐ ┌────────────────┬────────────────┐
│ address │ value │ │ address │ value │
┼────────────────────┼─────────────────────┤ ┼────────────────┼────────────────┤
│ 0x0000555555555030 │ jump 0x555555557fd0┼───┐ │ │ │
│ │ │ │ │ │ │
│ 0x0000555555555036 │ push $0x0 ◄───────┼─┐ └──┼►0x555555557fd0 │ 0x1036 ──┐ │
│ │ │ │ │ │ │ │
│ 0x000055555555503b │ jmp 0x555555555020│ └────┼────────────────┼──────────┘ │
└────────────────────┴─────────────────────┘ └────────────────┴────────────────┘ (gdb) continue
Stopped due to shared library event:
Inferior loaded /lib/x86_64-linux-gnu/libc.so.6(gdb) x/9a 0x0000555555557fb8
0x555555557fb8: 0x3dc8 0x0
0x555555557fc8: 0x0 0x7ffff7e08e50 <__GI__IO_puts>
0x555555557fd8: 0x7ffff7db1dc0 <__libc_start_main_impl> 0x0
0x555555557fe8: 0x0 0x0
0x555555557ff8: 0x7ffff7dcd9a0 <__cxa_finalize>
(gdb) info symbol 0x7ffff7e08e50
puts in section .text of /lib/x86_64-linux-gnu/libc.so.6(gdb) disassemble 0x555555555030
Dump of assembler code for function puts@plt:
0x0000555555555030 <+0>: jmp *0x2f9a(%rip) # 0x555555557fd0 <puts@got.plt>
0x0000555555555036 <+6>: push $0x0
0x000055555555503b <+11>: jmp 0x555555555020
(gdb) x/a 0x555555557fd0
0x555555557fd0 <puts@got.plt>: 0x7ffff7e08e50 <__GI__IO_puts>Illustrate .plt, .got after the first call.
file: main file: main file: libc.so
section: .plt section: .got section: .text
function: puts@plt() function: puts
┌────────────────────┬─────────────────────┐ ┌────────────────┬────────────────┐ ┌────────────────┬────────────────┐
│ address │ value │ │ address │ value │ │ address │ value │
┼────────────────────┼─────────────────────┤ ┼────────────────┼────────────────┤ ┼────────────────┼────────────────┤
│ 0x0000555555555030 │ jump 0x555555557fd0┼───┐ │ │ │ ┌───┼►0x7ffff7e08e50 │ endbr64 │
│ │ │ │ │ │ │ │ │ │ │
│ 0x0000555555555036 │ push $0x0 │ └──┼►0x555555557fd0 │ 0x7ffff7e08e50─┼──┘ │ 0x7ffff7e08e54 │ push %r14 │
│ │ │ │ │ │ │ │ │
│ 0x000055555555503b │ jmp 0x555555555020│ │ │ │ │ 0x7ffff7e08e56 │ push %r13 │
└────────────────────┴─────────────────────┘ └────────────────┴────────────────┘ └────────────────┴────────────────┘