Exploring ELF: Understanding ELF Fields and Headers

If you're new to Linux internals, ELF files can look scary. Strange hex numbers, weird names like .shstrndx, and definitions hidden deep inside /usr/include/elf.h.

Most students avoid this topic because it feels like learning a secret language.
I was also like you — avoiding everything ELF-related because it “felt too low-level.
Image:AI Generated 

But here’s the truth:

ELF is not magic. It’s just a structured file format.
And once you understand the header, you suddenly understand how Linux loads executables.

This article will walk you through ELF in the simplest, most human-friendly way possible.
No jargon. No showing off. Only clarity.

Let’s start small and build up

What Is ELF?

ELF stands for:

Executable and Linkable Format

It is the standard format for:

  • Executable programs (like /bin/ls)
  •  Shared libraries (.so)
  •  Object files (.o)
  •  Core dumps

Think of ELF like a container with instructions telling Linux:

  • how to load the program,
  • where to start running,
  •  which parts of the file belong to code or data.

When you run a program, Linux doesn’t “guess” how the file works
it reads the ELF header, which acts as the “table of contents.

Why Is This Topic So Scary?

Because it feels abstract:

  • binary data,
  • offsets,
  • headers,
  • structures,
  • unusual terminology.

But with the right breakdown, it becomes a fun puzzle.

You only need to understand one file:
/usr/include/elf.h.

This file contains the official structure of ELF files.
Your compiled program must match this structure exactly.

And guess what?
Once you see the connection between the ELF header definition and your real program, it suddenly "clicks.

1. What Is Inside an ELF File?

You can imagine an ELF file like a book with a table of contents:

  1. ELF Header – tells the OS how to read the rest of the file
  2. Program Header Table – tells how to load the program into memory
  3. Section Header Table – describes code, data, symbols, relocation info
  4. Sections / Segments – actual contents: machine code, data, etc

2. ELF Header – The Very First Structure

This is what the ELF header structure looks like (simplified from elf.h):

typedef struct {
    unsigned char e_ident[16]; // Magic number + metadata
    uint16_t e_type;       // Type: executable? object file?
    uint16_t e_machine;   // Target architecture (x86? ARM?)
    uint32_t e_version;  // ELF version
    uint64_t e_entry;   // Entry point address
    uint64_t e_phoff;  // Program header table offset
    uint64_t e_shoff; // Section header table offset
    uint32_t e_flags; // Architecture-specific flags
    uint16_t e_ehsize; // ELF header size
    uint16_t e_phentsize; // Program header table entry size
    uint16_t e_phnum;   // Number of program header entries
    uint16_t e_shentsize;  // Section header table entry size
    uint16_t e_shnum;     // Number of section header entries
    uint16_t e_shstrndx;  // Index of section name string table
} Elf64_Ehdr;

calc Results

$readelf -h calc

Magic:7f 45 4c 46 02 01 01 00 ... Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: DYN (PIE executable) Machine: X86-64 Version: 0x1 Entry point address: 0x1050 Start of program headers: 64 Start of section headers: 14016 Flags: 0 Size of this header: 64 Size of program headers: 56 Number of program headers: 13 Size of section headers: 64 Number of section headers: 31 Section header string table index: 30

Now let’s verify each one with the structure.

Let’s map calc program’s header to the fields in Elf64_Ehdr.

1. e_ident[16] — ELF Identity

This includes:

  • Magic bytes (7f 45 4c 46)
  • ELF class (ELF64)
  • Endianness (Little Endian)
  • ELF version (1)
  • OS ABI (System V)

✔ The calc program matches exactly.

2. e_type — File Type

readelf shows:

Type: DYN (Position Independent Executable)

In elf.h:

#define ET_DYN 3

This is a PIE executable, standard on modern Linux.

✔ Perfect match with calc program.

3. e_machine — Architecture

Machine: Advanced Micro Devices X86-64

elf.h defines:

#define EM_X86_64 62

✔ Exact match with calc.

4. e_entry — Entry Point

Calc program starts at:

0x1050

This is the address where the CPU begins execution after loading the binary.

Exactly how ELF expects it.

5. e_phoff — Program Header Offset

Start of program headers: 64

The ELF header size (e_ehsize) is also:

64 bytes

So the program headers start immediately after the ELF header.

✔ Matches elf.h perfectly.

6. e_shoff — Section Header Offset

Start of section headers: 14016

This offset varies depending on compilation.
It simply must exist — and it does.

✔ Valid with calc.

7. e_phentsize & e_phnum

Size of program headers: 56 Number of program headers: 13

elf.h defines that each Elf64_Phdr is 56 bytes.

✔ Perfect match with calc.

8. e_shentsize & e_shnum

Size of section headers: 64 Number of section headers: 31

Elf64_Shdr is 64 bytes.

✔ Correct.

9. e_shstrndx — Section Name String Table Index

30

Index 30 stores the names of sections like .text, .data, .bss, etc.

✔ Valid.

Conclusion

The calc program perfectly matches the ELF structure defined in elf.h.

There is:

  • no mismatch
  • no corruption
  • nothing strange 
  • nothing mysterious

It is a standard, clean, Linux-friendly ELF64 PIE executable.

Once you learn to “map” the output of readelf to the fields in elf.h, ELF becomes less like black magic and more like reading a blueprint.

Why This Matters

Understanding ELF helps you learn:

  • how Linux loads executables
  • how memory is mapped in processes
  • how loaders and dynamic linkers work
  • how debuggers inspect binaries
  • how malware hides
  • how reverse-engineering works

Once you understand the ELF header, the rest becomes much easier.

Final Thoughts

If ELF scared you before, that is completely normal.
Most learners step back when they see hex values and low-level structures.

But now you’ve:

  • compared a real ELF file with its official structure
  • matched field-by-field
  • understood what each part means