= ELF header
Running:
``
readelf -h hello_world.o
``
outputs:
``
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 64 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 64 (bytes)
Number of section headers: 7
Section header string table index: 3
``
Running:
``
readelf -h hello_world.out
``
outputs:
``
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x4000b0
Start of program headers: 64 (bytes into file)
Start of section headers: 272 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 2
Size of section headers: 64 (bytes)
Number of section headers: 6
Section header string table index: 3
``
Bytes in the object file:
``
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 01 00 3e 00 01 00 00 00 00 00 00 00 00 00 00 00 |..>.............|
00000020 00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 |........@.......|
00000030 00 00 00 00 40 00 00 00 00 00 40 00 07 00 03 00 |....@.....@.....|
``
Executable:
``
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
00000010 02 00 3e 00 01 00 00 00 b0 00 40 00 00 00 00 00 |..>.......@.....|
00000020 40 00 00 00 00 00 00 00 10 01 00 00 00 00 00 00 |@...............|
00000030 00 00 00 00 40 00 38 00 02 00 40 00 06 00 03 00 |....@.8...@.....|
``
Structure represented:
``
# define EI_NIDENT 16
typedef struct {
unsigned char e_ident[EI_NIDENT];
Elf64_Half e_type;
Elf64_Half e_machine;
Elf64_Word e_version;
Elf64_Addr e_entry;
Elf64_Off e_phoff;
Elf64_Off e_shoff;
Elf64_Word e_flags;
Elf64_Half e_ehsize;
Elf64_Half e_phentsize;
Elf64_Half e_phnum;
Elf64_Half e_shentsize;
Elf64_Half e_shnum;
Elf64_Half e_shstrndx;
} Elf64_Ehdr;
``
Manual breakdown:
* 0 0: `EI_MAG` = `7f 45 4c 46` = `0x7f 'E', 'L', 'F'`: ELF magic number
* 0 4: `EI_CLASS` = `02` = `ELFCLASS64`: 64 bit elf
* 0 5: `EI_DATA` = `01` = `ELFDATA2LSB`: little endian data
* 0 6: `EI_VERSION` = `01`: format version
* 0 7: `EI_OSABI` (only in 2003 Update) = `00` = `ELFOSABI_NONE`: no extensions.
* 0 8: `EI_PAD` = 8x `00`: reserved bytes. Must be set to 0.
* 1 0: `e_type` = `01 00` = 1 (big endian) = `ET_REl`: relocatable format
On the executable it is `02 00` for `ET_EXEC`.
Another important possibility for the executable is `ET_DYN` for PIE executables and shared libraries.
`ET_DYN` tells the Linux kernel that the code is position independent, and can loaded at a random memory location with ASLR.
This is explained further at:
* https://stackoverflow.com/questions/2463150/what-is-the-fpie-option-for-position-independent-executables-in-gcc-and-ld/51308031#51308031
* https://stackoverflow.com/questions/34519521/why-does-gcc-create-a-shared-object-instead-of-an-executable-binary-according-to/55704865#55704865
* 1 2: `e_machine` = `3e 00` = `62` = `EM_X86_64`: AMD64 architecture
* 1 4: `e_version` = `01 00 00 00`: must be 1
* 1 8: `e_entry` = 8x `00`: execution address entry point, or 0 if not applicable like for the object file since there is no entry point.
On the executable, it is `b0 00 40 00 00 00 00 00`. The kernel puts the RIP directly on that value when executing. It can be configured by the linker script or `-e`. But it will segfault if you set it too low: https://stackoverflow.com/questions/2187484/why-is-the-elf-execution-entry-point-virtual-address-of-the-form-0x80xxxxx-and-n
* 2 0: `e_phoff` = 8x `00`: program header table offset, 0 if not present.
`40 00 00 00` on the executable, i.e. it starts immediately after the ELF header.
* 2 8: `e_shoff` = `40` 7x `00` = `0x40`: section header table file offset, 0 if not present.
* 3 0: `e_flags` = `00 00 00 00` Arch specific. `i386` docs say:
> The Intel386 architecture defines no flags; so this member contains zero.
* 3 4: `e_ehsize` = `40 00`: size of this elf header. TODO why this field needed? Isn't the size fixed?
* 3 6: `e_phentsize` = `00 00`: size of each program header, 0 if not present.
`38 00` on executable: it is 56 bytes long
* 3 8: `e_phnum` = `00 00`: number of program header entries, 0 if not present.
`02 00` on executable: there are 2 entries.
* 3 A: `e_shentsize` and `e_shnum` = `40 00 07 00`: section header size and number of entries
* 3 E: `e_shstrndx` (`Section Header STRing iNDeX`) = `03 00`: index of the `.shstrtab` section.
Back to article page