Skip to content
ELF Header
step 1/5

Reading — step 1 of 5

Read

~1 min readELF Format

ELF Header

The first 64 bytes of an ELF (for 64-bit) is the header:

struct ElfHeader {
    char     ident[16];         // magic + class + data + version + ...
    uint16_t type;              // ET_REL (1), ET_EXEC (2), ET_DYN (3), ET_CORE (4)
    uint16_t machine;           // EM_X86_64 (62), EM_AARCH64 (183), ...
    uint32_t version;
    uint64_t entry;             // virtual address of entry point
    uint64_t phoff;             // offset to program header table
    uint64_t shoff;             // offset to section header table
    uint32_t flags;
    uint16_t ehsize;            // size of this header (52 for 32-bit, 64 for 64)
    uint16_t phentsize;
    uint16_t phnum;
    uint16_t shentsize;
    uint16_t shnum;
    uint16_t shstrndx;          // section header string table index
};

ident breakdown:

  • bytes 0-3: magic \x7fELF.
  • byte 4: class — 1 = 32-bit, 2 = 64-bit.
  • byte 5: data — 1 = little-endian, 2 = big-endian.
  • byte 6: version (1).
  • byte 7: OS/ABI — 0 = System V, 3 = Linux, 9 = FreeBSD.
  • byte 8: ABI version.
  • bytes 9-15: padding.

Type:

  • ET_REL: relocatable object file (.o).
  • ET_EXEC: legacy executable (fixed load addr).
  • ET_DYN: shared object OR position-independent executable (PIE).
  • ET_CORE: core dump.

Modern Linux: most "executables" are ET_DYN (PIE) for ASLR.

Entry point: where the kernel jumps after loading. For dynamic executables, it's the dynamic linker's entry, not main(). For static: _start.

Section vs program headers:

  • Section: how the LINKER sees it (logical, named).
  • Program: how the LOADER sees it (physical, mapped).

Static linker uses sections; loader uses program headers.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…