I am currently looking at the ELF format, and especially at stripped ELF executable program files.
I know that, when stripped, the symbol table is removed, but some information are always needed to link against dynamic libraries. So, I guess that there are other symbols that are kept whatever the executable has been stripped or not.
For example, the dynamic symbol table seems to be always kept (actually this is part of my question). It contains all the names of functions coming from dynamic libraries that are used in the program.
Indeed, taking a stripped binary and looking at the output of readelf
on it will give you the following output:
Symbol table '.dynsym' contains 5 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (2)
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND perror@GLIBC_2.2.5 (2)
My question is, what are all the symbol tables that the system always need to keep inside the executable file, even after a strip (and what are they used for) ?
Another part of my question, would also be about how to use these dynamic symbols. Because, they are all pointing to zero and not to a valid address. You do we identify, as objdump
does, their respective links to the code stored in the PLT. For example, in the following dump I got from objdump -D
, we can see that the section .plt
is split, I assume that this is thanks to symbols, into subsections corresponding to each dynamic function, I would like to know if this is coming from another symbol table that I do not know or if objdump
rebuild this information (and, then, I would like to know how):
Disassembly of section .plt:
0000000000400400 <puts@plt-0x10>:
400400: ff 35 6a 05 20 00 pushq 0x20056a(%rip)
400406: ff 25 6c 05 20 00 jmpq *0x20056c(%rip)
40040c: 0f 1f 40 00 nopl 0x0(%rax)
0000000000400410 <puts@plt>:
400410: ff 25 6a 05 20 00 jmpq *0x20056a(%rip)
400416: 68 00 00 00 00 pushq $0x0
40041b: e9 e0 ff ff ff jmpq 400400 <puts@plt-0x10>
0000000000400420 <__libc_start_main@plt>:
400420: ff 25 62 05 20 00 jmpq *0x200562(%rip)
400426: 68 01 00 00 00 pushq $0x1
40042b: e9 d0 ff ff ff jmpq 400400 <puts@plt-0x10>
0000000000400430 <__gmon_start__@plt>:
400430: ff 25 5a 05 20 00 jmpq *0x20055a(%rip)
400436: 68 02 00 00 00 pushq $0x2
40043b: e9 c0 ff ff ff jmpq 400400 <puts@plt-0x10>
0000000000400440 <perror@plt>:
400440: ff 25 52 05 20 00 jmpq *0x200552(%rip)
400446: 68 03 00 00 00 pushq $0x3
40044b: e9 b0 ff ff ff jmpq 400400 <puts@plt-0x10>
Edit: Thanks to Igor's comment, I found the different offsets allowing to rebuild the information in .rela.plt
(but, what is .rela.dyn
used for ?).
Relocation section '.rela.dyn' at offset 0x368 contains 1 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000600960 000300000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0
Relocation section '.rela.plt' at offset 0x380 contains 4 entries:
Offset Info Type Sym. Value Sym. Name + Addend
000000600980 000100000007 R_X86_64_JUMP_SLO 0000000000000000 puts + 0
000000600988 000200000007 R_X86_64_JUMP_SLO 0000000000000000 __libc_start_main + 0
000000600990 000300000007 R_X86_64_JUMP_SLO 0000000000000000 __gmon_start__ + 0
000000600998 000400000007 R_X86_64_JUMP_SLO 0000000000000000 perror + 0
.rela.dyn
and.rela.plt
.