I'm learning ELF file and using a C HelloWorld program built by GCC on x86_64 CentOS 7 as an example to investigate the executable.
I can understand how the name of a symbol is found for every symbol in the executable except two in dynamic symbol table (.dynsym).
Take symbol "main" in symbol table (.symtab) for example:
$ readelf -s HelloWorld
...
Symbol table '.symtab' contains 84 entries:
Num: Value Size Type Bind Vis Ndx Name
...
80: 0000000000400586 21 FUNC GLOBAL DEFAULT 13 main
...
Its original value is:
Name of this symbol
^^ ^^ ^^ ^^
00001e20 00 00 00 00 00 00 00 00 fb 03 00 00 12 00 0d 00 |................|
00001e30 86 05 40 00 00 00 00 00 15 00 00 00 00 00 00 00 |..@.............|
The value is 0x0000 03fb (small edian). It is actually an offset in section .strtab with the following content:
$ readelf -p .strtab HelloWorld
String dump of section '.strtab':
...
[ 3fb] main
...
So it is easy to understand that the name of this symbol is "main". And every symbol which is in either .symtab or .dynsym and has a name follows this rule, except two in .dynsym. The two exceptions are:
$ readelf -s HelloWorld
Symbol table '.dynsym' contains 6 entries:
Num: Value Size Type Bind Vis Ndx Name
...
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (2)
3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
...
Take symbol #2 for example, its original value is:
Name of the symbol
^^ ^^ ^^ ^^
000002e0 00 00 00 00 00 00 00 00 0b 00 00 00 12 00 00 00 |................|
000002f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
Offset of the symbol name 0x0000 000b. By looking at .dynstr:
$ readelf -p .dynstr HelloWorld
String dump of section '.dynstr':
[ 1] libc.so.6
[ b] puts
[ 10] __libc_start_main
[ 22] GLIBC_2.2.5
[ 2e] _ITM_deregisterTMCloneTable
[ 4a] __gmon_start__
[ 59] _ITM_registerTMCloneTable
I can see the the String at offset 0xb is "puts". But why a character "@" is appended by readelf? And why the String "GLIBC_2.2.5" (at offset 0x22) is appended, too?