1
votes

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?

1

1 Answers

1
votes

But why a character "@" is appended by readelf? And why the String "GLIBC_2.2.5" (at offset 0x22) is appended, too?

These are GNU-versioned symbols. readelf appends that info to make it clear, otherwise you'll see e.g. this:

  1232: 00000000000792d0   471 FUNC    GLOBAL DEFAULT   13 fmemopen
  1233: 0000000000078ed0   527 FUNC    GLOBAL DEFAULT   13 fmemopen

and will be confused by how there could be two separate fmemopens at different addresses.

Current output:

  1232: 00000000000792d0   471 FUNC    GLOBAL DEFAULT   13 fmemopen@GLIBC_2.2.5
  1233: 0000000000078ed0   527 FUNC    GLOBAL DEFAULT   13 fmemopen@@GLIBC_2.22

shows that these symbols have different version info attached to them, and that the GLIBC_2.22 version is the default one.

You can read more about GNU versioned symbols here.