Dissecting ELF with readelf

readelf is a powerful tool that can be leveraged to dissect and understand ELF files. It can further help to understand how the linker and loader make use of the information present in it to load the executable into the memory. In this cheatsheet kind of self-reference post, the most important functions of this tool are described.

Reading file header

Run the tool with -h or --file-header displays the ELF header.

The header section of the ELF file contains the information about the ELF file itself. The tool parses the header section into separate attributes and displays them in a human readable format.

The header section of an object file is shown below.

$ readelf -h hello_math.o
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          832 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           64 (bytes)
  Number of section headers:         12
  Section header string table index: 11

The header section of an executable file is shown below:

readelf -h hello                                                                                                                                                                              
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x1060
  Start of program headers:          64 (bytes into file)
  Start of section headers:          14832 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         13
  Size of section headers:           64 (bytes)
  Number of section headers:         31
  Section header string table index: 30

Displaying section headers

Running the tool with -S or --sections or --section-headers displays the section header, if it has any.

$ readelf -S hello_math.o
There are 12 section headers, starting at offset 0x340:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         0000000000000000  00000040
       0000000000000045  0000000000000000  AX       0     0     1
  [ 2] .data             PROGBITS         0000000000000000  00000085
       0000000000000000  0000000000000000  WA       0     0     1
  [ 3] .bss              NOBITS           0000000000000000  00000085
       0000000000000000  0000000000000000  WA       0     0     1
  [ 4] .comment          PROGBITS         0000000000000000  00000085
       000000000000002c  0000000000000001  MS       0     0     1
  [ 5] .note.GNU-stack   PROGBITS         0000000000000000  000000b1
       0000000000000000  0000000000000000           0     0     1
  [ 6] .note.gnu.propert NOTE             0000000000000000  000000b8
       0000000000000020  0000000000000000   A       0     0     8
  [ 7] .eh_frame         PROGBITS         0000000000000000  000000d8
       0000000000000078  0000000000000000   A       0     0     8
  [ 8] .rela.eh_frame    RELA             0000000000000000  00000290
       0000000000000048  0000000000000018   I       9     7     8
  [ 9] .symtab           SYMTAB           0000000000000000  00000150
       0000000000000120  0000000000000018          10     9     8
  [10] .strtab           STRTAB           0000000000000000  00000270
       000000000000001a  0000000000000000           0     0     1
  [11] .shstrtab         STRTAB           0000000000000000  000002d8
       0000000000000067  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)

Brief description of the sections (src):

  • .text: code of the executable
  • .data: initialized data
  • .rodata: read-only data
  • .bss: uninitialized data
  • .plt: Procedure Linkage Table
  • .got: GOT entried dedicated to dynamically linked global variables
  • .got.plt: GOT entries dedicated to dynamically linked functions
  • .symtab: global symbol table
  • .dynamic: holds all the needed information for dynamic linking
  • .dynsym: symbol tables dedicated to dynamically linked symbols
  • .strtab: striing table of .symtab section
  • .dynstr: string table of .dynsym section
  • .interp: RTLD embedded string
  • .rel.dyn: global variable relocation table
  • .rel.plt: function relocation table

Displaying Symbols

Running the tool with flag -s or --symbols displays the symbol table of the ELF file. Symbols (like function names) are stored under the section .symtab (symbol table). Symbol table holds the information needed to relocate a program’s symbolic definitions and references. Typically this section is not allocable and thus will not be loaded in the memory.

$ readelf -s hello_math.o

Symbol table '.symtab' contains 12 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS hello_math.c
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    2 
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
     8: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     9: 0000000000000000    24 FUNC    GLOBAL DEFAULT    1 add
    10: 0000000000000018    22 FUNC    GLOBAL DEFAULT    1 sub
    11: 000000000000002e    23 FUNC    GLOBAL DEFAULT    1 mul

In the above output, add, sub and mul are the functions present in the file hello_math.c.

Displaying section specific information

Running the tool with -p <number or name>/--string-dump=<number or name>, displays the content of the indicated section as printable strings. The argument can either be the section name or the index itself. Running the tool with -x <number or name>/--hex-dump=<number or name>, displays the content of the indicated section in hexadecimal. The argument can either be the section name or the index itself. Running the tool with -R <number or name>/--relocated-dump=<number or name>, the working is the same as above, but the content of the section will be relocated before they are displayed.

Displaying program headers

These flags display the program header, if it has any. These headers contain the execution information for the ELF file. If the ELF file is object file, it doesn’t contain any program headers. ~WIP~.

References

1 2

Written on September 23, 2023