ELF File Format

The Executable and Linkable Format is used by Linux, the BSDs, Android, most embedded systems and firmware: executables, shared libraries (.so), object files (.o) and core dumps. This page walks through every structure with its offsets in 32 and 64-bit files, then annotates every byte of a small working executable.

Layout

An ELF file starts with a fixed header that points to two independent tables: the program header table describes segments, what the loader maps into memory, and the section header table describes sections, what the linker and the tools work with. Both views cover the same bytes.

Linker view: sections
ELF header
Program header table (optional in .o)
.text
.rodata
.data
.symtab, .rela.text, ...
.strtab, .shstrtab
Section header table

Used by ld, objdump, debuggers. Fine-grained, named, typed. Not needed to run the program: strip and packers can remove all of it.

Loader view: segments
PT_LOAD R-XELF header, program headers, .text, .rodata
PT_LOAD RW-.data, .bss (memsz > filesz)
PT_GNU_STACK RW-no file content, stack is not executable
.symtab, .strtab, .shstrtab
Section header table (not loaded)

Used by the kernel and ld.so. Coarse: one mapping per permission set. A segment contains zero or more sections, and the first PT_LOAD usually starts at offset 0 so the headers are mapped too.

Annotated sample (1008 bytes, x86-64)

A complete static executable that prints Hello, ELF! and exits: no libc, three program headers, eight sections and a symbol table. Every byte belongs to a field. Hover the dump or the structure list to see what it is.

0x0ELF headerElf64_Ehdr64 B
0x40Program header table3 × Elf64_Phdr168 B
0xe8.textcode40 B
0x110.rodatamessage12 B
0x120.datacounter8 B
0x128.symtab5 × Elf64_Sym120 B
0x1a0.strtab, .shstrtabnames80 B
0x1f0Section header table8 × Elf64_Shdr512 B
000000007f454c46020101000000000000000000.ELF............
0000001002003e0001000000e800400000000000..>.......@.....
000000204000000000000000f001000000000000@...............
0000003000000000400038000300400008000700....@.8...@.....
0000004001000000050000000000000000000000................
0000005000004000000000000000400000000000..@.......@.....
000000601c010000000000001c01000000000000................
0000007000100000000000000100000006000000................
0000008020010000000000002011400000000000 ....... .@.....
0000009020114000000000000800000000000000 .@.............
000000a010000000000000000010000000000000................
000000b051e57464060000000000000000000000Q.td............
000000c000000000000000000000000000000000................
000000d000000000000000000000000000000000................
000000e0100000000000000048ff0531100000b8........H..1....
000000f001000000bf01000000488d3510000000.........H.5....
00000100ba0c0000000f05b83c00000031ff0f05........<...1...
0000011048656c6c6f2c20454c46210a00000000Hello, ELF!.....
000001202a000000000000000000000000000000*...............
0000013000000000000000000000000000000000................
00000140010000000400f1ff0000000000000000................
0000015000000000000000000900000001000200................
0000016010014000000000000c00000000000000..@.............
000001700d000000010003002011400000000000........ .@.....
0000018008000000000000001500000012000100................
00000190e8004000000000002800000000000000..@.....(.......
000001a00068656c6c6f2e73006d736700636f75.hello.s.msg.cou
000001b06e746572005f737461727400002e7465nter._start...te
000001c07874002e726f64617461002e64617461xt..rodata..data
000001d0002e627373002e73796d746162002e73..bss..symtab..s
000001e07472746162002e736873747274616200trtab..shstrtab.
000001f000000000000000000000000000000000................
0000020000000000000000000000000000000000................
0000021000000000000000000000000000000000................
0000022001000000000000000000000000000000................
0000023001000000010000000600000000000000................
00000240e800400000000000e800000000000000..@.............
0000025028000000000000000000000000000000(...............
0000026010000000000000000000000000000000................
0000027007000000010000000200000000000000................
0000028010014000000000001001000000000000..@.............
000002900c000000000000000000000000000000................
000002a001000000000000000000000000000000................
000002b00f000000010000000300000000000000................
000002c020114000000000002001000000000000 .@..... .......
000002d008000000000000000000000000000000................
000002e008000000000000000000000000000000................
000002f015000000080000000300000000000000................
0000030028114000000000002801000000000000(.@.....(.......
0000031008000000000000000000000000000000................
0000032008000000000000000000000000000000................
000003301a000000020000000000000000000000................
0000034000000000000000002801000000000000........(.......
0000035078000000000000000600000004000000x...............
0000036008000000000000001800000000000000................
0000037022000000030000000000000000000000"...............
000003800000000000000000a001000000000000................
000003901c000000000000000000000000000000................
000003a001000000000000000000000000000000................
000003b02a000000030000000000000000000000*...............
000003c00000000000000000bc01000000000000................
000003d0340000000000000000000000000000004...............
000003e001000000000000000000000000000000................

Hover a byte or a field to see what it is. Click to pin it.

ELF header: e_ident 0x0
  • EI_MAG0..37f "ELF"
  • EI_CLASSELFCLASS64
  • EI_DATAELFDATA2LSB (little …
  • EI_VERSION1
  • EI_OSABIELFOSABI_NONE (Syste…
  • EI_ABIVERSION0
  • EI_PADzero
ELF header 0x10
  • e_typeET_EXEC
  • e_machineEM_X86_64
  • e_version1
  • e_entry0x4000e8
  • e_phoff0x40
  • e_shoff0x1f0
  • e_flags0
  • e_ehsize0x40
  • e_phentsize0x38
  • e_phnum3
  • e_shentsize0x40
  • e_shnum8
  • e_shstrndx7
Program header 0 (PT_LOAD) 0x40
  • p_typePT_LOAD
  • p_flagsR-X
  • p_offset0
  • p_vaddr0x400000
  • p_paddr0x400000
  • p_filesz0x11c
  • p_memsz0x11c
  • p_align0x1000
Program header 1 (PT_LOAD) 0x78
  • p_typePT_LOAD
  • p_flagsRW-
  • p_offset0x120
  • p_vaddr0x401120
  • p_paddr0x401120
  • p_filesz8
  • p_memsz0x10
  • p_align0x1000
Program header 2 (PT_GNU_STACK) 0xb0
  • p_typePT_GNU_STACK
  • p_flagsRW-
  • p_offset0
  • p_vaddr0
  • p_paddr0
  • p_filesz0
  • p_memsz0
  • p_align0x10
.text (_start) 0xe8
  • inc qword [rip+counter]inc qword [rip+count…
  • mov eax, 1mov eax, 1
  • mov edi, 1mov edi, 1
  • lea rsi, [rip+msg]lea rsi, [rip+msg]
  • mov edx, 12mov edx, 12
  • syscallsyscall
  • mov eax, 60mov eax, 60
  • xor edi, edixor edi, edi
  • syscallsyscall
.rodata 0x110
  • msg"Hello, ELF!\n"
Padding 0x11c
  • paddingzeros
.data 0x120
  • counter42
Symbol 0 (null) 0x128
  • st_name0
  • st_infoSTB_LOCAL STT_NOTYPE
  • st_other0
  • st_shndxSHN_UNDEF
  • st_value0
  • st_size0
Symbol 1 hello.s 0x140
  • st_name1 → "hello.s"
  • st_infoSTB_LOCAL STT_FILE
  • st_other0
  • st_shndxSHN_ABS
  • st_value0
  • st_size0
Symbol 2 msg 0x158
  • st_name9 → "msg"
  • st_infoSTB_LOCAL STT_OBJECT
  • st_other0
  • st_shndx2 (.rodata)
  • st_value0x400110
  • st_size0xc
Symbol 3 counter 0x170
  • st_name13 → "counter"
  • st_infoSTB_LOCAL STT_OBJECT
  • st_other0
  • st_shndx3 (.data)
  • st_value0x401120
  • st_size8
Symbol 4 _start 0x188
  • st_name21 → "_start"
  • st_infoSTB_GLOBAL STT_FUNC
  • st_other0
  • st_shndx1 (.text)
  • st_value0x4000e8
  • st_size0x28
.strtab 0x1a0
  • strings"hello.s" "msg" "cou…
.shstrtab 0x1bc
  • strings".text" ".rodata" ".…
Section header 0 (SHN_UNDEF) 0x1f0
  • sh_name0
  • sh_typeSHT_NULL
  • sh_flags0
  • sh_addr0
  • sh_offset0
  • sh_size0
  • sh_link0
  • sh_info0
  • sh_addralign1
  • sh_entsize0
Section header 1 (.text) 0x230
  • sh_name1 → ".text"
  • sh_typeSHT_PROGBITS
  • sh_flagsSHF_ALLOC | SHF_EXEC…
  • sh_addr0x4000e8
  • sh_offset0xe8
  • sh_size0x28
  • sh_link0
  • sh_info0
  • sh_addralign0x10
  • sh_entsize0
Section header 2 (.rodata) 0x270
  • sh_name7 → ".rodata"
  • sh_typeSHT_PROGBITS
  • sh_flagsSHF_ALLOC
  • sh_addr0x400110
  • sh_offset0x110
  • sh_size0xc
  • sh_link0
  • sh_info0
  • sh_addralign1
  • sh_entsize0
Section header 3 (.data) 0x2b0
  • sh_name15 → ".data"
  • sh_typeSHT_PROGBITS
  • sh_flagsSHF_WRITE | SHF_ALLOC
  • sh_addr0x401120
  • sh_offset0x120
  • sh_size8
  • sh_link0
  • sh_info0
  • sh_addralign8
  • sh_entsize0
Section header 4 (.bss) 0x2f0
  • sh_name21 → ".bss"
  • sh_typeSHT_NOBITS
  • sh_flagsSHF_WRITE | SHF_ALLOC
  • sh_addr0x401128
  • sh_offset0x128
  • sh_size8
  • sh_link0
  • sh_info0
  • sh_addralign8
  • sh_entsize0
Section header 5 (.symtab) 0x330
  • sh_name26 → ".symtab"
  • sh_typeSHT_SYMTAB
  • sh_flags0
  • sh_addr0
  • sh_offset0x128
  • sh_size0x78
  • sh_link6
  • sh_info4
  • sh_addralign8
  • sh_entsize0x18
Section header 6 (.strtab) 0x370
  • sh_name34 → ".strtab"
  • sh_typeSHT_STRTAB
  • sh_flags0
  • sh_addr0
  • sh_offset0x1a0
  • sh_size0x1c
  • sh_link0
  • sh_info0
  • sh_addralign1
  • sh_entsize0
Section header 7 (.shstrtab) 0x3b0
  • sh_name42 → ".shstrtab"
  • sh_typeSHT_STRTAB
  • sh_flags0
  • sh_addr0
  • sh_offset0x1bc
  • sh_size0x34
  • sh_link0
  • sh_info0
  • sh_addralign1
  • sh_entsize0

ELF header

At offset 0. Only e_ident is the same for all files; EI_CLASS and EI_DATA tell how to read the rest. In the tables below ElfN_Addr, ElfN_Off and ElfN_Xword are 4 bytes in ELF32 and 8 bytes in ELF64 (Xword fields are plain Elf32_Word in ELF32); ElfN_Half is 2 bytes and ElfN_Word 4 bytes in both.

Elf32_Ehdr / Elf64_Ehdr 52 (0x34) bytes / 64 (0x40) bytes

FieldOff. 32Off. 64Size 32Size 64TypeMeaning
e_ident0x000x001616uint8_t[16]Identification bytes, see below.
e_type0x100x1022ElfN_HalfObject type: ET_REL, ET_EXEC, ET_DYN (shared library or PIE executable), ET_CORE.
e_machine0x120x1222ElfN_HalfArchitecture: EM_386, EM_X86_64, EM_AARCH64...
e_version0x140x1444ElfN_WordAlways 1.
e_entry0x180x1848ElfN_AddrVirtual address of the entry point (_start); relative to the load base for ET_DYN. 0 if none.
e_phoff0x1c0x2048ElfN_OffFile offset of the program header table (loader view).
e_shoff0x200x2848ElfN_OffFile offset of the section header table (linker view). 0 if none.
e_flags0x240x3044ElfN_WordProcessor-specific flags (ARM EABI version, RISC-V float ABI, MIPS ISA...). 0 on x86.
e_ehsize0x280x3422ElfN_HalfSize of this header: 52 or 64.
e_phentsize0x2a0x3622ElfN_HalfSize of one program header: 32 or 56.
e_phnum0x2c0x3822ElfN_HalfNumber of program headers.
e_shentsize0x2e0x3a22ElfN_HalfSize of one section header: 40 or 64.
e_shnum0x300x3c22ElfN_HalfNumber of section headers (0 and the real count in sh_size of section 0 when ≥ 0xff00).
e_shstrndx0x320x3e22ElfN_HalfIndex of the section that holds section names (.shstrtab).

e_ident[16] 16 (0x10) bytes

FieldOffsetSizeTypeMeaning
EI_MAG0..30x004uint8_t[4]Magic: 7f 45 4c 46 ("\x7fELF").
EI_CLASS0x041uint8_t1 = ELFCLASS32, 2 = ELFCLASS64. Selects the layout of every other structure.
EI_DATA0x051uint8_t1 = little endian (ELFDATA2LSB), 2 = big endian (ELFDATA2MSB).
EI_VERSION0x061uint8_tAlways 1 (EV_CURRENT).
EI_OSABI0x071uint8_t0 = System V (ELFOSABI_NONE), 3 = Linux/GNU (ELFOSABI_LINUX). Linux binaries normally use 0; 3 marks GNU extensions (IFUNC, unique symbols).
EI_ABIVERSION0x081uint8_tABI version, normally 0. The kernel uapi header still calls byte 8 EI_PAD.
EI_PAD0x097uint8_t[7]Padding, zero.

e_type

NameValueMeaning
ET_NONE0No file type.
ET_REL1Relocatable object (.o).
ET_EXEC2Executable at a fixed address (non-PIE).
ET_DYN3Shared object, or position-independent executable (PIE, the default on modern distributions).
ET_CORE4Core dump.

e_machine (common values)

NameValueMeaning
EM_3863Intel 80386
EM_MIPS8MIPS
EM_PPC0x14PowerPC
EM_PPC640x15PowerPC 64-bit
EM_S3900x16IBM S/390 and z/Architecture
EM_ARM0x28ARM 32-bit (AArch32)
EM_SPARCV90x2bSPARC v9 64-bit
EM_IA_640x32Intel Itanium
EM_X86_640x3eAMD64 / Intel 64
EM_AARCH640xb7ARM 64-bit (AArch64)
EM_RISCV0xf3RISC-V (32 and 64-bit, class from EI_CLASS)
EM_BPF0xf7Linux eBPF
EM_LOONGARCH0x102LoongArch

Program headers

e_phnum entries of e_phentsize bytes at e_phoff. Each one describes a segment.

Elf32_Phdr 32 (0x20) bytes

FieldOffsetSizeTypeMeaning
p_type0x004Elf32_WordSegment type (PT_LOAD, PT_DYNAMIC, PT_INTERP...).
p_offset0x044Elf32_OffFile offset of the segment.
p_vaddr0x084Elf32_AddrVirtual address in memory.
p_paddr0x0c4Elf32_AddrPhysical address; unused on Linux, usually equal to p_vaddr.
p_filesz0x104Elf32_WordBytes in the file.
p_memsz0x144Elf32_WordBytes in memory; the part beyond p_filesz is zero-filled (.bss).
p_flags0x184Elf32_WordPermissions: PF_X 1, PF_W 2, PF_R 4.
p_align0x1c4Elf32_WordAlignment; p_offset % p_align == p_vaddr % p_align.
p_flags moves: it is the 7th field in Elf32_Phdr but the 2nd in Elf64_Phdr, so that the 64-bit fields stay 8-byte aligned.

Elf64_Phdr 56 (0x38) bytes

FieldOffsetSizeTypeMeaning
p_type0x004Elf64_WordSegment type.
p_flags0x044Elf64_WordPermissions: PF_X 1, PF_W 2, PF_R 4.
p_offset0x088Elf64_OffFile offset of the segment.
p_vaddr0x108Elf64_AddrVirtual address in memory (relative to the load base for ET_DYN).
p_paddr0x188Elf64_AddrPhysical address; unused on Linux.
p_filesz0x208Elf64_XwordBytes in the file.
p_memsz0x288Elf64_XwordBytes in memory; the excess over p_filesz is zero-filled.
p_align0x308Elf64_XwordAlignment, usually the page size (0x1000) or more for PT_LOAD.

p_type

NameValueMeaning
PT_NULL0Unused entry.
PT_LOAD1Loadable segment: mapped from p_offset to p_vaddr. The only type that creates memory.
PT_DYNAMIC2The .dynamic array, read by the dynamic linker.
PT_INTERP3Path of the program interpreter, e.g. /lib64/ld-linux-x86-64.so.2.
PT_NOTE4Notes (build ID, ABI tag, GNU properties).
PT_SHLIB5Reserved.
PT_PHDR6Location of the program header table itself.
PT_TLS7Thread-local storage template (.tdata + .tbss).
PT_GNU_EH_FRAME0x6474e550.eh_frame_hdr, binary search table for unwinding.
PT_GNU_STACK0x6474e551Only p_flags matters: stack is executable if PF_X is set. Absent = executable on some architectures.
PT_GNU_RELRO0x6474e552Range made read-only after relocation (RELRO): .got, .dynamic, .init_array...
PT_GNU_PROPERTY0x6474e553.note.gnu.property: CET IBT/SHSTK on x86, BTI/PAC on AArch64.
PT_AARCH64_MEMTAG_MTE0x70000002AArch64 MTE tags stored in core dumps.

p_flags

NameValueMeaning
PF_X1Execute
PF_W2Write
PF_R4Read

Section headers

e_shnum entries of e_shentsize bytes at e_shoff. Entry 0 is always null. Names are offsets in the section e_shstrndx.

Elf32_Shdr / Elf64_Shdr 40 (0x28) bytes / 64 (0x40) bytes

FieldOff. 32Off. 64Size 32Size 64TypeMeaning
sh_name0x000x0044ElfN_WordOffset of the name in .shstrtab.
sh_type0x040x0444ElfN_WordSection type (SHT_PROGBITS, SHT_SYMTAB, SHT_NOBITS...).
sh_flags0x080x0848ElfN_XwordAttributes: SHF_WRITE, SHF_ALLOC, SHF_EXECINSTR...
sh_addr0x0c0x1048ElfN_AddrVirtual address when the section is loaded (0 if not SHF_ALLOC).
sh_offset0x100x1848ElfN_OffFile offset of the content (meaningless for SHT_NOBITS).
sh_size0x140x2048ElfN_XwordSize in bytes.
sh_link0x180x2844ElfN_WordIndex of a related section: the string table of a symbol table, the symbol table of a relocation section...
sh_info0x1c0x2c44ElfN_WordExtra info: for SHT_REL/RELA the section the relocations apply to; for SHT_SYMTAB the index of the first non-local symbol.
sh_addralign0x200x3048ElfN_XwordRequired alignment.
sh_entsize0x240x3848ElfN_XwordSize of one entry for table sections (24 for an Elf64_Sym), else 0.

sh_type

NameValueMeaning
SHT_NULL0Inactive entry. Section 0 is always SHT_NULL.
SHT_PROGBITS1Program-defined content: code, data, .rodata, .got, .eh_frame...
SHT_SYMTAB2Full symbol table (.symtab); removed by strip.
SHT_STRTAB3String table (.strtab, .shstrtab, .dynstr).
SHT_RELA4Relocations with addend (.rela.text, .rela.dyn, .rela.plt).
SHT_HASH5SysV symbol hash table (.hash).
SHT_DYNAMIC6Dynamic linking array (.dynamic).
SHT_NOTE7Notes (.note.*).
SHT_NOBITS8Occupies no file space: .bss, .tbss.
SHT_REL9Relocations without addend.
SHT_SHLIB0xaReserved.
SHT_DYNSYM0xbDynamic symbol table (.dynsym), kept by strip.
SHT_INIT_ARRAY0xeConstructor pointers (.init_array).
SHT_FINI_ARRAY0xfDestructor pointers (.fini_array).
SHT_PREINIT_ARRAY0x10Pointers run before the constructors (executables only).
SHT_GROUP0x11Section group (COMDAT), used for C++ inline functions and templates in .o files.

sh_flags

NameValueMeaning
SHF_WRITE1Writable at run time.
SHF_ALLOC2Occupies memory at run time (part of a PT_LOAD).
SHF_EXECINSTR4Executable code.
SHF_MERGE0x10Identical entries may be merged (sh_entsize gives the size).
SHF_STRINGS0x20NUL-terminated strings (with SHF_MERGE: string pooling).
SHF_INFO_LINK0x40sh_info holds a section index.
SHF_LINK_ORDER0x80Keep the order of the section referenced by sh_link.
SHF_GROUP0x200Member of a section group.
SHF_TLS0x400Thread-local data.
SHF_EXCLUDE0x8000000Excluded from the link output.

Special section indexes

NameValueMeaning
SHN_UNDEF0Undefined: the symbol comes from another object or library.
SHN_ABS0xfff1Absolute value, not relative to any section.
SHN_COMMON0xfff2Uninitialized common block (-fcommon); st_value holds the alignment.

Common sections

SectionContent
.interpPath of the dynamic linker (covered by PT_INTERP).
.note.gnu.build-idUnique build ID, used to find debug symbols.
.gnu.hash / .hashHash tables to look up dynamic symbols.
.dynsym / .dynstrSymbols and names needed for dynamic linking.
.gnu.version, .gnu.version_rSymbol versioning (puts@GLIBC_2.2.5).
.rela.dyn / .rela.pltDynamic relocations: data and GOT / PLT slots.
.init, .finiLegacy constructor and destructor code.
.plt, .plt.got, .plt.secProcedure linkage table stubs used to call library functions.
.textCode.
.rodataRead-only data, string literals.
.eh_frame, .eh_frame_hdrUnwind tables (C++ exceptions, backtraces).
.tdata, .tbssThread-local storage template.
.init_array, .fini_arrayConstructor and destructor pointers.
.dynamicThe Elf64_Dyn array.
.got, .got.pltGlobal offset table: addresses filled by the dynamic linker.
.data, .bssInitialized and zero-initialized writable data.
.commentCompiler version strings.
.debug_*DWARF debug information.
.symtab, .strtab, .shstrtabFull symbol table and names, section names.

Symbols

Elf32_Sym 16 (0x10) bytes

FieldOffsetSizeTypeMeaning
st_name0x004Elf32_WordOffset of the name in the string table (sh_link of the symbol table).
st_value0x044Elf32_AddrValue: an address in executables, an offset in its section in ET_REL.
st_size0x084Elf32_WordSize of the object or function.
st_info0x0c1uint8_tBinding (high 4 bits) and type (low 4 bits): ELF_ST_BIND(i) = i >> 4, ELF_ST_TYPE(i) = i & 0xf.
st_other0x0d1uint8_tVisibility in the low 2 bits (STV_*).
st_shndx0x0e2Elf32_HalfIndex of the defining section, or SHN_UNDEF / SHN_ABS / SHN_COMMON.

Elf64_Sym 24 (0x18) bytes

FieldOffsetSizeTypeMeaning
st_name0x004Elf64_WordOffset of the name in the string table.
st_info0x041uint8_tBinding (high 4 bits) and type (low 4 bits).
st_other0x051uint8_tVisibility in the low 2 bits.
st_shndx0x062Elf64_HalfIndex of the defining section or a special index.
st_value0x088Elf64_AddrAddress (executables, shared objects) or section offset (ET_REL).
st_size0x108Elf64_XwordSize of the object or function.
The fields are reordered in Elf64_Sym (name, info, other, shndx, value, size) so that it packs into 24 bytes without padding.
Binding (st_info >> 4)
NameValueMeaning
STB_LOCAL0Not visible outside the object. Local symbols come first in the table.
STB_GLOBAL1Visible to all objects.
STB_WEAK2Global with lower precedence; may stay undefined (value 0).
Type (st_info & 0xf)
NameValueMeaning
STT_NOTYPE0No type (labels).
STT_OBJECT1Data object.
STT_FUNC2Function.
STT_SECTION3A section, used by relocations.
STT_FILE4Source file name (LOCAL, SHN_ABS).
STT_COMMON5Common block.
STT_TLS6Thread-local variable; st_value is an offset in the TLS template.
STT_GNU_IFUNC0xaGNU indirect function: the value is a resolver called at load time.
Visibility (st_other & 3)
NameValueMeaning
STV_DEFAULT0Visibility given by the binding; exported and preemptible.
STV_INTERNAL1Like hidden, with processor-specific meaning.
STV_HIDDEN2Not exported from the shared object or executable (-fvisibility=hidden).
STV_PROTECTED3Exported but not preemptible.

Relocations

Elf32_Rel / Elf64_Rel 8 (0x8) bytes / 16 (0x10) bytes

FieldOff. 32Off. 64Size 32Size 64TypeMeaning
r_offset0x000x0048ElfN_AddrWhere to apply the relocation: section offset in ET_REL, virtual address in executables and shared objects.
r_info0x040x0848ElfN_XwordSymbol index and type. 64-bit: sym = r_info >> 32, type = r_info & 0xffffffff. 32-bit: sym = r_info >> 8, type = r_info & 0xff.

Elf32_Rela / Elf64_Rela 12 (0xc) bytes / 24 (0x18) bytes

FieldOff. 32Off. 64Size 32Size 64TypeMeaning
r_offset0x000x0048ElfN_AddrWhere to apply the relocation.
r_info0x040x0848ElfN_XwordSymbol index and relocation type.
r_addend0x080x1048ElfN_SxwordConstant added to the computed value. Rel (no addend) stores it in the patched location instead; x86-64 and AArch64 use Rela, i386 and ARM use Rel.
In the formulas: S symbol value, A addend, P address of the patched location, B load base, G offset of the GOT entry, GOT address of the GOT, L address of the PLT entry.

x86-64

NameValueCalculationUse
R_X86_64_NONE0—No relocation.
R_X86_64_641S + AAbsolute 64-bit address (pointers in data).
R_X86_64_PC322S + A - P32-bit PC-relative (lea rax, [rip+sym]).
R_X86_64_GOT323G + A32-bit GOT offset.
R_X86_64_PLT324L + A - PPC-relative call through the PLT (call puts).
R_X86_64_COPY5—Dynamic: copy the initial value of a shared library variable into the executable.
R_X86_64_GLOB_DAT6SDynamic: fill a GOT entry with the symbol address.
R_X86_64_JUMP_SLOT7SDynamic: fill a .got.plt entry (lazy binding).
R_X86_64_RELATIVE8B + ADynamic: add the load base (PIE and shared library pointers).
R_X86_64_GOTPCREL9G + GOT + A - PPC-relative address of the GOT entry.
R_X86_64_3210S + AAbsolute 32-bit, zero-extended (non-PIE only).
R_X86_64_32S11S + AAbsolute 32-bit, sign-extended (non-PIE only).
R_X86_64_DTPMOD6416—Dynamic: TLS module ID.
R_X86_64_DTPOFF6417—Dynamic: offset in the TLS block.
R_X86_64_TPOFF6418—Dynamic: offset from the thread pointer (initial-exec TLS).
R_X86_64_TLSGD19—General dynamic TLS: PC-relative GOT entry for __tls_get_addr.
R_X86_64_GOTTPOFF22—Initial-exec TLS: PC-relative GOT entry holding a TP offset.
R_X86_64_TPOFF3223—Local-exec TLS: 32-bit offset from the thread pointer.
R_X86_64_PC6424S + A - P64-bit PC-relative.
R_X86_64_IRELATIVE37indirect(B + A)Dynamic: call the IFUNC resolver at B + A and store its result.
R_X86_64_GOTPCRELX41G + GOT + A - PLike GOTPCREL, the linker may relax the instruction to a direct lea/call.
R_X86_64_REX_GOTPCRELX42G + GOT + A - PSame, for instructions with a REX prefix (mov rax, [rip+sym@GOTPCREL]).

AArch64

NameValueCalculationUse
R_AARCH64_NONE256—No relocation (also 0).
R_AARCH64_ABS64257S + AAbsolute 64-bit address.
R_AARCH64_ABS32258S + AAbsolute 32-bit address.
R_AARCH64_PREL32261S + A - P32-bit PC-relative (.eh_frame).
R_AARCH64_ADR_PREL_PG_HI21275Page(S+A) - Page(P)adrp: 4 KiB page of the symbol.
R_AARCH64_ADD_ABS_LO12_NC277(S + A) & 0xfffadd: low 12 bits, pairs with ADR_PREL_PG_HI21.
R_AARCH64_LDST32_ABS_LO12_NC285(S + A) & 0xfff32-bit ldr/str low 12 bits (scaled by 4).
R_AARCH64_LDST64_ABS_LO12_NC286(S + A) & 0xfff64-bit ldr/str low 12 bits (scaled by 8).
R_AARCH64_JUMP26282S + A - Pb: 26-bit branch (±128 MiB).
R_AARCH64_CALL26283S + A - Pbl: 26-bit call, may go through a PLT or veneer.
R_AARCH64_ADR_GOT_PAGE311Page(G(GDAT(S+A))) - Page(P)adrp to the GOT entry page.
R_AARCH64_LD64_GOT_LO12_NC312G(GDAT(S+A)) & 0xff8ldr of the GOT entry.
R_AARCH64_TLSDESC_ADR_PAGE21562—TLS descriptor: adrp.
R_AARCH64_TLSDESC_LD64_LO12563—TLS descriptor: ldr.
R_AARCH64_TLSDESC_ADD_LO12564—TLS descriptor: add.
R_AARCH64_TLSDESC_CALL569—TLS descriptor: marks the blr.
R_AARCH64_COPY1024—Dynamic: copy relocation.
R_AARCH64_GLOB_DAT1025S + ADynamic: GOT entry.
R_AARCH64_JUMP_SLOT1026S + ADynamic: PLT GOT entry.
R_AARCH64_RELATIVE1027B + ADynamic: add the load base.
R_AARCH64_TLS_TPREL641030—Dynamic: offset from the thread pointer.
R_AARCH64_TLSDESC1031—Dynamic: TLS descriptor.
R_AARCH64_IRELATIVE1032indirect(B + A)Dynamic: IFUNC resolver result.

Dynamic section

The array covered by PT_DYNAMIC. It is how ld.so finds everything else: the needed libraries, the dynamic symbol table, the relocations, the constructors.

Elf32_Dyn / Elf64_Dyn 8 (0x8) bytes / 16 (0x10) bytes

FieldOff. 32Off. 64Size 32Size 64TypeMeaning
d_tag0x000x0048ElfN_SxwordEntry type (DT_*). The array ends with DT_NULL.
d_un0x040x0848ElfN_XwordValue (d_val) or address (d_ptr), depending on the tag.
NameValueMeaning
DT_NULL0End of the array.
DT_NEEDED1Name of a needed library (offset in DT_STRTAB).
DT_PLTRELSZ2Size of the PLT relocations (.rela.plt).
DT_PLTGOT3Address of .got.plt.
DT_HASH4SysV hash table.
DT_STRTAB5Dynamic string table (.dynstr).
DT_SYMTAB6Dynamic symbol table (.dynsym).
DT_RELA7Rela relocations (.rela.dyn).
DT_RELASZ8Size of DT_RELA.
DT_RELAENT9Size of one Rela entry (24).
DT_STRSZ0xaSize of DT_STRTAB.
DT_SYMENT0xbSize of one symbol (24).
DT_INIT0xcAddress of _init.
DT_FINI0xdAddress of _fini.
DT_SONAME0xeName of this shared object.
DT_RPATH0xfLibrary search path (deprecated, searched before LD_LIBRARY_PATH).
DT_SYMBOLIC0x10Resolve symbols in this object first.
DT_REL0x11Rel relocations.
DT_RELSZ0x12Size of DT_REL.
DT_RELENT0x13Size of one Rel entry.
DT_PLTREL0x14Type of the PLT relocations: DT_REL or DT_RELA.
DT_DEBUG0x15Filled by ld.so with &r_debug (debuggers walk the link map from it).
DT_TEXTREL0x16Relocations write to read-only segments.
DT_JMPREL0x17PLT relocations (.rela.plt), applied lazily unless BIND_NOW.
DT_BIND_NOW0x18Resolve all symbols at load time.
DT_INIT_ARRAY0x19Address of .init_array.
DT_FINI_ARRAY0x1aAddress of .fini_array.
DT_INIT_ARRAYSZ0x1bSize of .init_array.
DT_FINI_ARRAYSZ0x1cSize of .fini_array.
DT_RUNPATH0x1dLibrary search path, searched after LD_LIBRARY_PATH.
DT_FLAGS0x1eFlags (DF_BIND_NOW, DF_STATIC_TLS...).
DT_PREINIT_ARRAY0x20Address of .preinit_array.
DT_PREINIT_ARRAYSZ0x21Size of .preinit_array.
DT_GNU_HASH0x6ffffef5GNU hash table (.gnu.hash), replaces DT_HASH.
DT_VERSYM0x6ffffff0Symbol versions (.gnu.version).
DT_RELACOUNT0x6ffffff9Number of R_*_RELATIVE relocations at the start of DT_RELA.
DT_FLAGS_10x6ffffffbMore flags: DF_1_NOW, DF_1_PIE...
DT_VERNEED0x6ffffffeNeeded versions (.gnu.version_r).
DT_VERNEEDNUM0x6fffffffNumber of DT_VERNEED entries.

Notes

Elf32_Nhdr / Elf64_Nhdr 12 (0xc) bytes

FieldOffsetSizeTypeMeaning
n_namesz0x004ElfN_WordLength of the owner name, including the NUL ("GNU" = 4).
n_descsz0x044ElfN_WordLength of the descriptor.
n_type0x084ElfN_WordNote type, scoped by the owner (NT_GNU_BUILD_ID, NT_GNU_PROPERTY_TYPE_0 = 5...).
The name and then the descriptor follow the header, each padded to 4 bytes. The same 12-byte header is used by both classes.

What the Linux loader checks

FieldRead by load_elf_binary()?
e_ident[0..3]Yes: must be "\x7fELF".
e_ident[4..15]No. Class, endianness, version and OS ABI bytes are not checked by the native loader.
e_typeYes: ET_EXEC or ET_DYN.
e_machineYes: elf_check_arch(), e.g. EM_X86_64 or EM_AARCH64.
e_versionNo.
e_entryYes: where execution starts (plus the load bias for ET_DYN).
e_phoff, e_phnum, e_phentsizeYes: e_phentsize must equal sizeof(struct elf_phdr), and the table (e_phnum * e_phentsize) must be non-empty and at most 64 KiB.
e_shoff, e_shnum, e_shentsize, e_shstrndxNo. Section headers are never read.
e_flagsNot checked by the generic loader. Some architectures look at it in arch_check_elf() (MIPS floating-point ABI) or save it for core dumps.
e_ehsizeNo.
From fs/binfmt_elf.c of Linux 7.2. Program headers that matter: PT_LOAD, PT_INTERP, PT_GNU_STACK, PT_GNU_PROPERTY, and PT_LOPROC..PT_HIPROC passed to the architecture code. Everything else is ignored by the kernel, which is what makes room for tiny hand-made ELF files and for headers that confuse analysis tools. More details in Linux process execution and the useless ELF header fields.

Tools

TaskCommand
ELF headerreadelf -h a.out
Program headers and section to segment mappingreadelf -lW a.out
Section headersreadelf -SW a.out
Symbols (static / dynamic)readelf -sW a.out   nm -D a.out
Relocationsreadelf -rW a.out
Dynamic section, needed librariesreadelf -d a.out
Notes (build ID, GNU properties)readelf -n a.out
Hex dump of a sectionreadelf -x .rodata a.out
Disassembleobjdump -d -M intel a.out
Mitigations (PIE, RELRO, NX, canary)checksec --file=a.out