MODULE 2

The ELF Header

Every ELF file begins with a 64-byte header. This small region is the most important part of the binary: it tells the operating system what kind of file this is, what architecture it targets, where to find the program headers and section headers, and where execution should begin. Without a valid ELF header, the kernel will refuse to load the file.

The ELF header is defined by the C struct Elf64_Ehdr. Every field has a precise offset, size, and meaning. What you see below is the actual content of a real ELF binary, decoded field by field. Hover over any field in the struct viewer to see it highlighted in the hex dump.

Load a binary to view hex data
No binary loaded

The Magic Number

The first four bytes of every ELF file are always 7f 45 4c 46, which is 0x7f followed by the ASCII characters E, L, F. This magic number is how the kernel, dynamic linker, and tools like file identify that a file is an ELF binary rather than a script, a JPEG, or random data.

💡Why magic bytes matter
Magic bytes are a convention used across all binary file formats. PNG files start with 89 50 4e 47, Java class files with ca fe ba be, and Mach-O binaries (macOS) with fe ed fa ce. The leading 0x7f byte in ELF is deliberately a non-printable character, ensuring that if you accidentally cat a binary to the terminal, it will not be interpreted as a shell script.

Class: 32-bit vs 64-bit

Byte offset 4 (e_ident[EI_CLASS]) tells the system whether this is a 32-bit or 64-bit ELF. A value of 0x01 means ELFCLASS32 (32-bit), and 0x02 means ELFCLASS64 (64-bit). This single byte determines the size of address fields throughout the entire file. In a 64-bit ELF, addresses and offsets are 8 bytes wide. In 32-bit, they are 4 bytes. This means the ELF header itself is 64 bytes for ELF64 and 52 bytes for ELF32.

Endianness

Byte offset 5 (e_ident[EI_DATA]) specifies the byte order for all multi-byte fields in the file. 0x01 means little-endian (least significant byte first), the standard for x86 and ARM in LE mode. 0x02 means big-endian (most significant byte first), used by some MIPS and PowerPC systems. Getting the endianness wrong means every multi-byte field you read will have its bytes reversed.

ELF Type

The e_type field at offset 16 identifies the kind of ELF file. The four most common types are:

ET_REL (1)
Relocatable
Object files (.o) produced by the assembler, not yet linked
ET_EXEC (2)
Executable
Statically addressed executables with fixed virtual addresses
ET_DYN (3)
Shared Object
Shared libraries (.so) and position-independent executables (PIE)
ET_CORE (4)
Core Dump
Memory snapshot from a crashed process for post-mortem debugging

Modern Linux distributions compile most executables as ET_DYN (type 3) with position-independent code, even though they are executables. This enables ASLR (Address Space Layout Randomization) as a security measure.

Machine Architecture

The e_machine field at offset 18 identifies the target instruction set architecture. Common values include EM_X86_64 (0x3e) for AMD64/Intel 64, EM_AARCH64 (0xb7) for 64-bit ARM, and EM_RISCV (0xf3) for RISC-V. The kernel will refuse to execute a binary whose machine type does not match the current CPU architecture.

Entry Point

The e_entry field at offset 24 holds the virtual address where execution begins after the kernel loads the program. This is not main(). In a typical C program, the entry point is _start, a small stub provided by the C runtime library (crt1.o) that sets up the stack, initializes the C library, and then calls main(). For relocatable object files, this field is zero because they have no entry point.

Table Offsets

The final group of fields tells the system where to find two critical data structures:

e_phoff / e_phentsize / e_phnum

The file offset, entry size, and count for the Program Header Table. Program headers define segments that describe how the file should be mapped into memory. Without them, the kernel cannot load the executable.

e_shoff / e_shentsize / e_shnum

The file offset, entry size, and count for the Section Header Table. Section headers provide the linker's view of the binary: named regions like .text, .data, .rodata. These are optional for execution but essential for debugging and tooling.

e_shstrndx

The index of the section that contains the section name strings. Section names like ".text" and ".data" are stored in a dedicated string table section, and this field points to it.

Challenge

What does the value 0x02 at offset 4 (e_ident[EI_CLASS]) mean?