Appendix C: ELF Format Quick Reference
ELF Header Fields
Every ELF file starts with a 64-byte header (for 64-bit) at offset 0.
+----------------+--------+------------------------------------------------+
| Field | Size | Description |
+----------------+--------+------------------------------------------------+
| e_ident[0..3] | 4 | Magic: 0x7f 'E' 'L' 'F' |
| e_ident[4] | 1 | Class: 1 = 32-bit, 2 = 64-bit |
| e_ident[5] | 1 | Data: 1 = little-endian, 2 = big-endian |
| e_ident[6] | 1 | Version: 1 (always) |
| e_ident[7] | 1 | OS/ABI: 0 = SYSV, 3 = Linux |
| e_ident[8..15] | 8 | Padding (zeroes) |
+----------------+--------+------------------------------------------------+
| e_type | 2 | ET_REL (1) = relocatable (.o) |
| | | ET_EXEC (2) = executable (fixed address) |
| | | ET_DYN (3) = shared object / PIE executable |
+----------------+--------+------------------------------------------------+
| e_machine | 2 | EM_X86_64 (0x3E), EM_AARCH64 (0xB7), etc. |
| e_version | 4 | 1 (current) |
| e_entry | 8 | Entry point virtual address (_start) |
| e_phoff | 8 | Program header table offset in file |
| e_shoff | 8 | Section header table offset in file |
| e_flags | 4 | Processor-specific flags |
| e_ehsize | 2 | ELF header size (64 for 64-bit) |
| e_phentsize | 2 | Size of one program header entry (56) |
| e_phnum | 2 | Number of program header entries |
| e_shentsize | 2 | Size of one section header entry (64) |
| e_shnum | 2 | Number of section header entries |
| e_shstrndx | 2 | Index of section name string table |
+----------------+--------+------------------------------------------------+
Common Sections
+-------------+-----------------------------------------------------------+
| Section | Contents |
+-------------+-----------------------------------------------------------+
| .text | Executable machine code |
| .data | Initialized global/static variables |
| .bss | Uninitialized globals (zero-filled at load, no file space)|
| .rodata | Read-only data (string literals, constants) |
| .symtab | Symbol table (functions, globals) — for linking/debugging |
| .strtab | String table for symbol names |
| .shstrtab | String table for section names |
| .rel / .rela| Relocation entries (fixups for the linker) |
| .plt | Procedure Linkage Table (lazy binding stubs) |
| .got | Global Offset Table (resolved dynamic addresses) |
| .got.plt | GOT entries specifically for PLT |
| .dynamic | Dynamic linking info (needed libraries, symbol tables) |
| .interp | Path to dynamic linker (/lib64/ld-linux-x86-64.so.2) |
| .init/.fini | Constructor/destructor code |
| .debug_* | DWARF debug information (line numbers, types, variables) |
| .eh_frame | Exception/stack unwinding tables |
| .note.* | Build ID, ABI tags |
| .comment | Compiler version string |
+-------------+-----------------------------------------------------------+
Common Segment Types (Program Headers)
Segments are the runtime view. The kernel reads these to load the program.
+----------------+----------------------------------------------------------+
| Type | Purpose |
+----------------+----------------------------------------------------------+
| PT_LOAD | Loadable segment. Mapped into memory. Usually two: |
| | 1) r-x: .text, .rodata (code + constants) |
| | 2) rw-: .data, .bss (writable data) |
+----------------+----------------------------------------------------------+
| PT_DYNAMIC | Points to .dynamic section. Used by the dynamic linker |
| | to find shared libraries and resolve symbols. |
+----------------+----------------------------------------------------------+
| PT_INTERP | Path to the dynamic linker (e.g., /lib64/ld-linux...) |
| | Kernel reads this to know which loader to invoke. |
+----------------+----------------------------------------------------------+
| PT_NOTE | Auxiliary info: build ID, ABI version. |
| | Not loaded into process memory. |
+----------------+----------------------------------------------------------+
| PT_GNU_STACK | Stack executability. If absent or flags=RW, stack is NX. |
| | If flags=RWX, stack is executable (rare, insecure). |
+----------------+----------------------------------------------------------+
| PT_GNU_RELRO | Read-only after relocation. The dynamic linker resolves |
| | GOT entries, then marks this region read-only. |
+----------------+----------------------------------------------------------+
| PT_PHDR | Points to the program header table itself. |
+----------------+----------------------------------------------------------+
Quick Inspection Commands
readelf -h binary # ELF header
readelf -S binary # Section headers
readelf -l binary # Program headers (segments)
readelf -s binary # Symbol table
readelf -d binary # Dynamic section
objdump -d binary # Disassemble .text
hexdump -C binary | head # Raw bytes (look for 7f 45 4c 46)