22

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
  • 2
    Print the relocations too. – Igor Skochinsky Jul 26 '13 at 17:37
  • Ah, I didn't notice it first ! I guess you are meaning .rela.dyn and .rela.plt. – perror Jul 26 '13 at 17:41
  • .rela.dyn may be related to dynamic linking -- you'd be interested in section 4/5 here uclibc.org/docs/SysV-ABI.pdf – Ditmar Wendt Aug 1 '13 at 22:25
22

To answer to this question, we have first to rephrase it a bit. The real question can be stated like this:

What are the symbols that cannot be removed from an ELF binary file ?

Indeed, strip removes quite a bit of information from the ELF file, but it could do a bit more (see the option --strip-unneeded from strip or the program sstrip for more about this). So, my original question was more about what symbols can be assumed to be in the executable file whatever modifications have been made on the ELF file.

In fact, there is only one type of symbols that you need to keep whatever happen, we call it dynamic symbols (as opposed at static symbols). They are a bit different from the static ones because we never know in advance where they will be pointing to in memory. Indeed, as they are supposed to point to external binary objects (libraries, plugin), the binary blob is dynamically loaded in memory while the process is running and we cannot predict at what address it will be located.

If the static symbols are stored in the .symbtab section, the dynamic ones have their own section called .dynsym. They are kept separate to ease the operation of relocation (the operation that will give a precise address to each dynamic symbol). The relocation operation also relies on two extra tables which are namely:

  • .rela.dyn : Relocation for dynamically linked objects (data or procedures), if PLT is not used.
  • .rela.plt : List of elements in the PLT (Procedure Linkage Table), which are liable to the relocation during the dynamic linking (if PLT is used).

Somehow, put all together, .dynsym, .rela.dyn and .rela.plt will allow to patch the initial memory (i.e. as mapped in the ELF binary), in order for the dynamic symbols to point to the right object (data or procedure).

Just to illustrate a bit more the process of relocation of dynamic symbols, I built examples in i386 and amd64 architectures.

i386

Symbol table '.dynsym' contains 6 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 00000000     0 FUNC    GLOBAL DEFAULT  UND perror@GLIBC_2.0 (2)
     2: 00000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.0 (2)
     3: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     4: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.0 (2)
     5: 080484fc     4 OBJECT  GLOBAL DEFAULT   15 _IO_stdin_used


Relocation section '.rel.dyn' at offset 0x28c contains 1 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
08049714  00000306 R_386_GLOB_DAT    00000000   __gmon_start__

Relocation section '.rel.plt' at offset 0x294 contains 4 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
08049724  00000107 R_386_JUMP_SLOT   00000000   perror
08049728  00000207 R_386_JUMP_SLOT   00000000   puts
0804972c  00000307 R_386_JUMP_SLOT   00000000   __gmon_start__
08049730  00000407 R_386_JUMP_SLOT   00000000   __libc_start_main

amd64

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)



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_SLOT 0000000000000000 puts + 0
000000600988  000200000007 R_X86_64_JUMP_SLOT 0000000000000000 __libc_start_main + 0
000000600990  000300000007 R_X86_64_JUMP_SLOT 0000000000000000 __gmon_start__ + 0
000000600998  000400000007 R_X86_64_JUMP_SLOT 0000000000000000 perror + 0

A few interesting web pages and articles about dynamic linking:

  • 1
    Thanks for the writeup. But, strictly speaking, isn't this dependent on whether you link to anything at all? I realize that with GCC you have to go through hoops to achieve this, but it's still possible. For all I know you could create an ELF file that will literally only use syscall instead of external libraries of any kind. Wouldn't that imply that you can leave out more of the functions you say have to be "always" in? – 0xC0000022L Aug 14 '13 at 19:58
  • 1
    Yes, you are right. But, in fact, even if you have no call to libc functions in your code, you will get the __libc_start_main function and all the usual framework. To achieve what you want, you need to pass the option -nostdlib to the compiler. Then, you will get a raw ELF binary with no external call to libc. – perror Aug 14 '13 at 21:51
  • You said in your answer about the dynamic symbol table "they are supposed to point to external binary objects". However, they can also define the positions of functions or data in your file which are exported for use by code that you link to or which links to you. Usually this is seen in dynamic libraries, but you can also see it in top-level executables - for example a lot of C++ programs will redefine "operator new" and "operator delete", and these will appear in the dynamic symbol table, overriding the ones provided by the standard C++ library. – sheltond Mar 16 '16 at 10:10
  • @sheltond: You are right. In fact, I do not manipulate C++ binaries a lot in my daily usage, so I tend to forget about their specificities, but, yes, they obviously do such things, I agree. – perror Mar 16 '16 at 11:53

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.