readelf Command Linux: Complete Guide to ELF File Analysis and Debugging

August 25, 2025

The readelf command is an essential tool for Linux developers, system administrators, and security analysts who need to examine Executable and Linkable Format (ELF) files. This powerful utility allows you to inspect the internal structure of executables, shared libraries, object files, and core dumps without executing them.

What is the readelf Command?

readelf is a GNU binutils program that displays information about ELF (Executable and Linkable Format) files. Unlike other tools like objdump, readelf is specifically designed to read ELF files and provides detailed information about their structure, headers, sections, symbols, and more.

Key Features of readelf:

  • Display ELF file headers and section information
  • Show symbol tables and relocation entries
  • Examine program headers and segments
  • Analyze dynamic linking information
  • Inspect debugging information
  • Cross-platform compatibility

Basic Syntax and Options

The basic syntax of the readelf command is:

readelf [options] elf-file(s)

Essential Options:

Option Long Form Description
-h --file-header Display ELF file header
-S --section-headers Display section headers
-s --symbols Display symbol table
-l --program-headers Display program headers
-d --dynamic Display dynamic section
-r --relocs Display relocations
-a --all Display all available information

Examining ELF File Headers

The ELF header contains crucial metadata about the file. Use the -h option to display this information:

readelf -h /bin/ls

Sample Output:

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:               0x6b30
  Start of program headers:          64 (bytes into file)
  Start of section headers:          137568 (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:         28
  Section header string table index: 27

Understanding Header Fields:

  • Magic: ELF file signature (7f 45 4c 46 = DEL + “ELF”)
  • Class: 32-bit (ELF32) or 64-bit (ELF64) architecture
  • Data: Byte order (little or big endian)
  • Type: File type (executable, shared library, object file)
  • Machine: Target architecture
  • Entry point: Address where execution begins

Analyzing Section Headers

Sections contain the actual data and code. Use -S to examine section headers:

readelf -S /bin/ls

Sample Output:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000000318  00000318
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.gnu.property NOTE             0000000000000338  00000338
       0000000000000020  0000000000000000   A       0     0     8
  [ 3] .note.gnu.build-i NOTE             0000000000000358  00000358
       0000000000000024  0000000000000000   A       0     0     4
  [ 4] .note.ABI-tag     NOTE             000000000000037c  0000037c
       0000000000000020  0000000000000000   A       0     0     4
  [ 5] .gnu.hash         GNU_HASH         00000000000003a0  000003a0
       0000000000000038  0000000000000000   A       6     0     8

Important Section Types:

  • .text: Contains executable code
  • .data: Initialized global variables
  • .bss: Uninitialized global variables
  • .rodata: Read-only data (constants)
  • .symtab: Symbol table
  • .strtab: String table
  • .dynamic: Dynamic linking information

Inspecting Symbol Tables

Symbol tables contain information about functions, variables, and other symbols. Use -s to display them:

readelf -s /bin/ls

Sample Output:

Symbol table '.dynsym' contains 140 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND strcoll@GLIBC_2.2.5
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_finalize@GLIBC_2.2.5
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND endgrent@GLIBC_2.2.5
     4: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND strcmp@GLIBC_2.2.5

Symbol Information Fields:

  • Value: Symbol address or offset
  • Size: Symbol size in bytes
  • Type: FUNC (function), OBJECT (variable), etc.
  • Bind: LOCAL, GLOBAL, or WEAK binding
  • Vis: Symbol visibility
  • Ndx: Section index where symbol is defined

Examining Program Headers

Program headers describe how the program should be loaded into memory. Use -l to view them:

readelf -l /bin/ls

Sample Output:

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                 0x00000000000002d8 0x00000000000002d8  R      0x8
  INTERP         0x0000000000000318 0x0000000000000318 0x0000000000000318
                 0x000000000000001c 0x000000000000001c  R      0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000003010 0x0000000000003010  R      0x1000

Program Header Types:

  • LOAD: Loadable segment
  • DYNAMIC: Dynamic linking information
  • INTERP: Program interpreter path
  • NOTE: Auxiliary information
  • PHDR: Program header table

Analyzing Dynamic Section

The dynamic section contains information needed for dynamic linking. Use -d to examine it:

readelf -d /bin/ls

Sample Output:

Dynamic section at offset 0x1de20 contains 30 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libselinux.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000001d (RUNPATH)            Library runpath: [/usr/lib/x86_64-linux-gnu]
 0x000000000000000c (INIT)               0x5000
 0x000000000000000d (FINI)               0x1a554

Advanced readelf Usage

Examining Relocations

Relocations show how addresses are adjusted during linking:

readelf -r program.o

Displaying Notes

Notes contain additional metadata:

readelf -n /bin/ls

Showing All Information

Use -a for comprehensive analysis:

readelf -a /bin/ls | less

Practical Use Cases

1. Debugging Linking Issues

Identify missing libraries and symbols:

# Check required libraries
readelf -d myprogram | grep NEEDED

# Find undefined symbols
readelf -s myprogram | grep UND

2. Security Analysis

Examine security features:

# Check for stack canaries and position independence
readelf -s /bin/ls | grep -E "(stack_chk|__stack_smash)"

# Verify ASLR support
readelf -h /bin/ls | grep Type

3. Architecture Verification

Confirm target architecture:

readelf -h binary_file | grep -E "(Class|Machine)"

4. Analyzing Core Dumps

Extract information from core dumps:

readelf -n core.dump

Comparing readelf with Other Tools

Tool Best For Key Difference
readelf ELF structure analysis ELF-specific, detailed headers
objdump Disassembly and code analysis Multi-format support, assembly output
nm Symbol listing Simple symbol extraction
ldd Dynamic dependencies Runtime dependency resolution

Tips and Best Practices

Efficient Analysis Workflow:

  1. Start with readelf -h for basic file information
  2. Use readelf -S to understand section layout
  3. Examine symbols with readelf -s for specific issues
  4. Check dynamic dependencies with readelf -d
  5. Use grep and less for filtering large outputs

Common Troubleshooting Commands:

# Find entry point and architecture
readelf -h binary | grep -E "(Entry|Machine|Class)"

# List all shared library dependencies
readelf -d binary | grep NEEDED

# Find specific symbols
readelf -s binary | grep "symbol_name"

# Check section sizes
readelf -S binary | grep -E "(\.text|\.data|\.bss)"

Conclusion

The readelf command is an indispensable tool for understanding ELF file structure and behavior. Whether you’re debugging linking problems, analyzing security features, or examining binary compatibility, readelf provides the detailed information needed for effective troubleshooting and analysis.

By mastering the various options and understanding ELF file structure, you can leverage readelf to solve complex system programming challenges, optimize application performance, and ensure binary security. Remember to combine readelf with other tools like objdump, nm, and ldd for comprehensive binary analysis.

Practice using readelf on different types of ELF files—executables, shared libraries, and object files—to become proficient in binary analysis and debugging techniques that are essential for advanced Linux system administration and software development.