ELF Header

The structure looks something like this

#define EI_NIDENT 16
 
typedef struct {
    unsigned char   e_ident[EI_NIDENT];
    Elf32_Half      e_type;
    Elf32_Half      e_machine;
    Elf32_Word      e_version;
    Elf32_Addr      e_entry;
    Elf32_Off       e_phoff;
    Elf32_Off       e_shoff;
    Elf32_Word      e_flags;
    Elf32_Half      e_ehsize;
    Elf32_Half      e_phentsize;
    Elf32_Half      e_phnum;
    Elf32_Half      e_shentsize;
    Elf32_Half      e_shnum;
    Elf32_Half      e_shstrndx;
} Elf32_Ehdr;
 
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;

An example of raw bytes from a 32 bit ELF header

# exit32.dmp
#  -------------- ELF HEADER --------------
                # all numbers are in base 16
                # 00 number of bytes to be used in the ELF
7F 45 4C 46     # 04 e_ident[EI_MAG]: ELF magic bytes
01              # 05 e_ident[EI_CLASS]: 1=32-bit, 2=64-bit
   01           # 06 e_ident[EI_DATA]: 1=little-endian, 2=big=endian
      01        # 07 e_ident[EI_VERSION]: ELF header version
         00     # 08 e_ident[EI_OSABI]: Target OS ABI; should be 0 for System V
00              # 09 e_ident[EI_ABIVERSION]: ABI version; 0 is ok for Linux
   00 00 00     # 0C e_ident[EI_PAD]: unused, should be 0
00 00 00 00     # 10
 
02 00           # 12 e_type: object file type; 2=executable
      03 00     # 14 e_machine: instruction set architecture; 03=x86, 3E=amd64
01 00 00 00     # 18 e_version: ELF identification version; must be 1
54 80 04 08     # 1C e_entry: memory address of entry point (where process starts)
34 00 00 00     # 20 e_phoff: file offset where program headers begin
 
00 00 00 00     # 24 e_shoff: file offset where section headers begin
00 00 00 00     # 28 e_flags: 0 for x86
 
34 00           # 2A e_ehsize: size of this header (34: 32-bit, 40: 64-bit)
      20 00     # 2C e_phentsize: size of each program header (20: 32-bit, 38: 64-bit)
01 00           # 2E e_phnum: #program headers
      28 00     # 30 e_shentsize: size of each section header (28: 32-bit, 40: 64-bit)
 
00 00           # 32 e_shnum: #section headers
      00 00     # 34 e_shstrndx: index of section header containing section names
 
#  -------------- ELF HEADER --------------

e_ident

On an Ubuntu machine this looks something like this:

$ xxd -g 1 hello | head -1
00000000: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00  .ELF............

Notice this is actually the magic bytes of the elf

7f is followed by 45 4c 46 which mean ELF when converted into hexadecimal (ascii for ELF)

 
$ readelf -h /bin/ls
ELF Header:
  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:                              DYN (Position-Independent Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x55f0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          140224 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         14
  Size of section headers:           64 (bytes)
  Number of section headers:         28
  Section header string table index: 27

e_type

This identifies the object file type

NameValueMeaningNotes
ET_NONE0No file type
ET_REL1Relocatable file: object filesgcc -c foo.c -o foo.o
ET_EXEC2Executable file: -no-pie exegcc -no-pie foo.c -o foo
ET_DYN3Shared object file: exe and shared libsgcc foo.c -o foo
gcc -shared foo.c -o foo
ET_CORE4Core file

e_machine

This specifies the required architecture for an individual file

ValueMeaning
0x03x86 Intel Architecture
0x08MIPS
0x28ARM
0x3Eamd64
0xB7ARMv8
0xF3RISC-V

e_version

Always set to 1

e_entry

This store the entry point address for executable.

For shared libraries, this stores the constructor address.

Otherwise 0

For executables:

e_machinee_ident[EI_CLASS]e_entrylittle endian
0x0003 (x86)0x010x08048000 + offset (54 if 1 program header)54 80 04 08
0x003E (x86_64)0x020x40000000 + offset (78 if 1 program header)78 00 40 00 00 00 00 00.

Why is the ELF execution entry point virtual address of the form 0x80xxxx

e_phoff

This member holds the program header table’s file offset in bytes. If the file has no program header table, this member holds zero. (Segments)

8x 00: program header table offset, 0 if not present.

For executables:

e_machinee_ident[EI_CLASS]e_ehsizee_phoff
0x0003 (x86)0x010x003834 00 00 00
0x003E (x86_64)0x020x004040 00 00 00 00 00 00 00

e_shoff

This member holds the section header table’s file offset in bytes. If the file has no section header table, this member holds zero. (Sections)

Both of these offsets are relative to the beginning of the file

40 7x 00 = 0x40: section header table file offset, 0 if not present.

e_flags

Heavily architecture and OS dependent

e_ehsize

Size of the ELF header (0x34 for 32 bit, 0x40 for 64 bit)

e_phentsize

This member holds the size in bytes of one entry in the file’s program header table; all entries are the same size.

(0x20 for 32 bit, 0x38 for 64 bit)

e_phnum

This member holds the number of entries in the program header table. Thus the product of e_phentsize and e_phnum gives the table’s size in bytes. If a file has no program header table, e_phnum holds the value zero.

e_shentsize

This member holds a section header’s size in bytes. A section header is one entry in the section header table; all entries are the same size.

(0x34 for 32 bit, 0x40 for 64 bit)

e_shnum

This member holds the number of entries in the section header table. Thus the product of e_shentsize and e_shnum gives the section header table’s size in bytes. If a file has no section header table, e_shnum holds the value zero

e_shstrndx

This member holds the section header table index of the entry associated with the section name string table. If the file has no section name string table, this member holds the value SHN_UNDEF.

Continue to Program Header