A minimal, complete and correct ELF file

As part of the compiler for my homebrew language, Garlic, I've been exploring what's in an ELF file. This is so I can output a binary file, ready for execution, instead of depending on an external compiler like GCC to do that last step. As a first step, I've hand-generated, byte-by-byte, a small ELF file that can be run on a 64-bit x86-64 Linux installation.

There are some great resources out there (truly minimal ELF files for 32-bit architectures, a 64-bit tiny ELF file, a more comprehensive tutorial), but I still struggled with this exercise. The reason was that either the article tried to minimize the data in the file—omitting pieces that are going to exist in real-world ELF files a compiler would generate—or the article was too detailed. Another issue was that even when the high-level structure was clear, the individual bytes were not discussed. I had to go back and forth between these articles and the Linux ELF documentation (man elf).

So here is my attempt, with an additional twist: each byte in the explanation is clickable, with references to related bytes elsewhere in the file.

Diagram of the different parts of the ELF file. The structure is as described in the following File Overview section.

File overview

In this minimal ELF file, I will be constructing a statically linked executable for an x86-64 Linux installation.

First, an overview, which is something I found very hard to understand from any of the resources I looked at. The ELF file always starts with a fixed-size header, which states the locations of the other parts of the file. The diagram shows all these references:

  1. The ELF header states where the section and program header tables are, as well as which entry in the section header table is the section header string table.

  2. Both the .text section header and the executable program segment header state where the .text section is.

  3. The .shstrtab section header states where the section header string table is.

  4. The various section headers index into the section header string table for the names of the sections.

By changing the references, you can place any of these sections anywhere in the file! For example, I could have avoided the crossing of the arrows on the right if I put the .shstrtab section header before the .text section header 🙂

Technically, the section header table and the section header string table are not needed, but having them sets the stage for adding more sections in the future, namely dynamic linking and debug symbol sections.

ELF header

As mentioned in the overview, the ELF header is a fixed-size section of bytes that specifies how what this file is and how the rest of the file is laid out. Because the structure of the header is so rigid, it can be read without concerns such as endianness or what other sections are present in the file.

Magic number

"ELF" in ASCII. Identifies this file as an ELF file.

Type (architecture)

64-bit architecture

Processor data format

Two's complement, little-endian

ELF version

Current ELF specfication version

OS ABI

"None", evquivalent to UNIX - System-V, default version

Padding

Padding until 16 bytes, for future compatibility

Object file type

Static executable, as opposed to something like a shared object (.so file)

Machine type

AMD x86-64

File version

"Current" version

Entry point

Where the system should transfer control when starting the process. Needed for executables. Expressed as a virtual memory address; see both the executable segment in the program headers table and the .text section header in the section headers table below for more details.

Program header table start

The byte offset, in this file, of the start of the program header table

Section header table start

The byte offset, in this file, of the start of the section header table

Processor-specific flags

None defined by the ELF specifications at this time

ELF header size

The size of the ELF header in bytes

Program header entry size

The size of each program header in the program header table, in bytes. For 64-bit architectures, this size is 56 bytes.

Number of program headers

The number of program headers in the program header table

Section header entry size

The size of each section header in the section header table, in bytes. For 64-bit architectures, this size is 64 bytes.

Number of section headers

The number of section headers in the section header table

Section name string table index

Which of the section headers points to the section name string table, indexed from zero.

The section name string table is itself a section, which means a corresponding header shows up in the section header table. This index points out which section header that header is, because the section name string table is a special section.

Section header table

An ELF file is broken up into multiple sections, each with a different type and therefore a different structure. The section header table lays out the different sections in the file, where they are and what type they are. The sections don't need to appear right after the table, nor do they need to appear in the same order as in the table. The table will reference the data for each section by offset into the file.

Typical sections in an ELF file include the .text section (containing the code that will be executed), debug symbols and relocation symbols (for dynamic linking). There is a special section type, the section header name table, that contains strings with the names of the sections. Only the .text and the section header name table are included in this file.

.text section: section name

The .text section is the section of the ELF file containing the executable code that will be loaded into the executable program segment. This section is defined by the following fields:

Field Value Notes
Name 1 (".text") Defined by an index into the section name string table, pointing to a null-terminated ASCII string.
Type PROGBITS The loaded program will determine what these bytes mean. The data is opaque to the ELF file.
Flags Allocatable + executable Loaded into memory during process execution
Address 0x4000F8 Where the data from this section will end up in memory once it is loaded. Notice this is the same as the address of the executable program segment. This is defined because the segment is allocatable.
Offset 0xF8 Where the data for this section resides within this file
Size 14 How many bytes the section takes up in this file
Link N/A Links to another section header by index. The interpretation of this field depends on the section type. For this .text section, there is no link because this file represents a static binary.
Info N/A Any extra information, subject to interpretation based on the section type. No extra information for this section.
Address alignment 0x1000 Any alignment constraint, in bytes, for the data in this section. The alignment here is the same as that of the executable program segment.
Entry size N/A For sections that contain a table of fixed-size entries (such as a symbol table), this field states the size of those entries in bytes.

.text section: section type

The .text section is the section of the ELF file containing the executable code that will be loaded into the executable program segment. This section is defined by the following fields:

Field Value Notes
Name 1 (".text") Defined by an index into the section name string table, pointing to a null-terminated ASCII string.
Type PROGBITS The loaded program will determine what these bytes mean. The data is opaque to the ELF file.
Flags Allocatable + executable Loaded into memory during process execution
Address 0x4000F8 Where the data from this section will end up in memory once it is loaded. Notice this is the same as the address of the executable program segment. This is defined because the segment is allocatable.
Offset 0xF8 Where the data for this section resides within this file
Size 14 How many bytes the section takes up in this file
Link N/A Links to another section header by index. The interpretation of this field depends on the section type. For this .text section, there is no link because this file represents a static binary.
Info N/A Any extra information, subject to interpretation based on the section type. No extra information for this section.
Address alignment 0x1000 Any alignment constraint, in bytes, for the data in this section. The alignment here is the same as that of the executable program segment.
Entry size N/A For sections that contain a table of fixed-size entries (such as a symbol table), this field states the size of those entries in bytes.

.text section: section flags

The .text section is the section of the ELF file containing the executable code that will be loaded into the executable program segment. This section is defined by the following fields:

Field Value Notes
Name 1 (".text") Defined by an index into the section name string table, pointing to a null-terminated ASCII string.
Type PROGBITS The loaded program will determine what these bytes mean. The data is opaque to the ELF file.
Flags Allocatable + executable Loaded into memory during process execution
Address 0x4000F8 Where the data from this section will end up in memory once it is loaded. Notice this is the same as the address of the executable program segment. This is defined because the segment is allocatable.
Offset 0xF8 Where the data for this section resides within this file
Size 14 How many bytes the section takes up in this file
Link N/A Links to another section header by index. The interpretation of this field depends on the section type. For this .text section, there is no link because this file represents a static binary.
Info N/A Any extra information, subject to interpretation based on the section type. No extra information for this section.
Address alignment 0x1000 Any alignment constraint, in bytes, for the data in this section. The alignment here is the same as that of the executable program segment.
Entry size N/A For sections that contain a table of fixed-size entries (such as a symbol table), this field states the size of those entries in bytes.

.text section: section address

The .text section is the section of the ELF file containing the executable code that will be loaded into the executable program segment. This section is defined by the following fields:

Field Value Notes
Name 1 (".text") Defined by an index into the section name string table, pointing to a null-terminated ASCII string.
Type PROGBITS The loaded program will determine what these bytes mean. The data is opaque to the ELF file.
Flags Allocatable + executable Loaded into memory during process execution
Address 0x4000F8 Where the data from this section will end up in memory once it is loaded. Notice this is the same as the address of the executable program segment. This is defined because the segment is allocatable.
Offset 0xF8 Where the data for this section resides within this file
Size 14 How many bytes the section takes up in this file
Link N/A Links to another section header by index. The interpretation of this field depends on the section type. For this .text section, there is no link because this file represents a static binary.
Info N/A Any extra information, subject to interpretation based on the section type. No extra information for this section.
Address alignment 0x1000 Any alignment constraint, in bytes, for the data in this section. The alignment here is the same as that of the executable program segment.
Entry size N/A For sections that contain a table of fixed-size entries (such as a symbol table), this field states the size of those entries in bytes.

.text section: section offset

The .text section is the section of the ELF file containing the executable code that will be loaded into the executable program segment. This section is defined by the following fields:

Field Value Notes
Name 1 (".text") Defined by an index into the section name string table, pointing to a null-terminated ASCII string.
Type PROGBITS The loaded program will determine what these bytes mean. The data is opaque to the ELF file.
Flags Allocatable + executable Loaded into memory during process execution
Address 0x4000F8 Where the data from this section will end up in memory once it is loaded. Notice this is the same as the address of the executable program segment. This is defined because the segment is allocatable.
Offset 0xF8 Where the data for this section resides within this file
Size 14 How many bytes the section takes up in this file
Link N/A Links to another section header by index. The interpretation of this field depends on the section type. For this .text section, there is no link because this file represents a static binary.
Info N/A Any extra information, subject to interpretation based on the section type. No extra information for this section.
Address alignment 0x1000 Any alignment constraint, in bytes, for the data in this section. The alignment here is the same as that of the executable program segment.
Entry size N/A For sections that contain a table of fixed-size entries (such as a symbol table), this field states the size of those entries in bytes.

.text section: section size

The .text section is the section of the ELF file containing the executable code that will be loaded into the executable program segment. This section is defined by the following fields:

Field Value Notes
Name 1 (".text") Defined by an index into the section name string table, pointing to a null-terminated ASCII string.
Type PROGBITS The loaded program will determine what these bytes mean. The data is opaque to the ELF file.
Flags Allocatable + executable Loaded into memory during process execution
Address 0x4000F8 Where the data from this section will end up in memory once it is loaded. Notice this is the same as the address of the executable program segment. This is defined because the segment is allocatable.
Offset 0xF8 Where the data for this section resides within this file
Size 14 How many bytes the section takes up in this file
Link N/A Links to another section header by index. The interpretation of this field depends on the section type. For this .text section, there is no link because this file represents a static binary.
Info N/A Any extra information, subject to interpretation based on the section type. No extra information for this section.
Address alignment 0x1000 Any alignment constraint, in bytes, for the data in this section. The alignment here is the same as that of the executable program segment.
Entry size N/A For sections that contain a table of fixed-size entries (such as a symbol table), this field states the size of those entries in bytes.

.text section: link

The .text section is the section of the ELF file containing the executable code that will be loaded into the executable program segment. This section is defined by the following fields:

Field Value Notes
Name 1 (".text") Defined by an index into the section name string table, pointing to a null-terminated ASCII string.
Type PROGBITS The loaded program will determine what these bytes mean. The data is opaque to the ELF file.
Flags Allocatable + executable Loaded into memory during process execution
Address 0x4000F8 Where the data from this section will end up in memory once it is loaded. Notice this is the same as the address of the executable program segment. This is defined because the segment is allocatable.
Offset 0xF8 Where the data for this section resides within this file
Size 14 How many bytes the section takes up in this file
Link N/A Links to another section header by index. The interpretation of this field depends on the section type. For this .text section, there is no link because this file represents a static binary.
Info N/A Any extra information, subject to interpretation based on the section type. No extra information for this section.
Address alignment 0x1000 Any alignment constraint, in bytes, for the data in this section. The alignment here is the same as that of the executable program segment.
Entry size N/A For sections that contain a table of fixed-size entries (such as a symbol table), this field states the size of those entries in bytes.

.text section: additional information

The .text section is the section of the ELF file containing the executable code that will be loaded into the executable program segment. This section is defined by the following fields:

Field Value Notes
Name 1 (".text") Defined by an index into the section name string table, pointing to a null-terminated ASCII string.
Type PROGBITS The loaded program will determine what these bytes mean. The data is opaque to the ELF file.
Flags Allocatable + executable Loaded into memory during process execution
Address 0x4000F8 Where the data from this section will end up in memory once it is loaded. Notice this is the same as the address of the executable program segment. This is defined because the segment is allocatable.
Offset 0xF8 Where the data for this section resides within this file
Size 14 How many bytes the section takes up in this file
Link N/A Links to another section header by index. The interpretation of this field depends on the section type. For this .text section, there is no link because this file represents a static binary.
Info N/A Any extra information, subject to interpretation based on the section type. No extra information for this section.
Address alignment 0x1000 Any alignment constraint, in bytes, for the data in this section. The alignment here is the same as that of the executable program segment.
Entry size N/A For sections that contain a table of fixed-size entries (such as a symbol table), this field states the size of those entries in bytes.

.text section: addresss alignment

The .text section is the section of the ELF file containing the executable code that will be loaded into the executable program segment. This section is defined by the following fields:

Field Value Notes
Name 1 (".text") Defined by an index into the section name string table, pointing to a null-terminated ASCII string.
Type PROGBITS The loaded program will determine what these bytes mean. The data is opaque to the ELF file.
Flags Allocatable + executable Loaded into memory during process execution
Address 0x4000F8 Where the data from this section will end up in memory once it is loaded. Notice this is the same as the address of the executable program segment. This is defined because the segment is allocatable.
Offset 0xF8 Where the data for this section resides within this file
Size 14 How many bytes the section takes up in this file
Link N/A Links to another section header by index. The interpretation of this field depends on the section type. For this .text section, there is no link because this file represents a static binary.
Info N/A Any extra information, subject to interpretation based on the section type. No extra information for this section.
Address alignment 0x1000 Any alignment constraint, in bytes, for the data in this section. The alignment here is the same as that of the executable program segment.
Entry size N/A For sections that contain a table of fixed-size entries (such as a symbol table), this field states the size of those entries in bytes.

.text section: section entry size

The .text section is the section of the ELF file containing the executable code that will be loaded into the executable program segment. This section is defined by the following fields:

Field Value Notes
Name 1 (".text") Defined by an index into the section name string table, pointing to a null-terminated ASCII string.
Type PROGBITS The loaded program will determine what these bytes mean. The data is opaque to the ELF file.
Flags Allocatable + executable Loaded into memory during process execution
Address 0x4000F8 Where the data from this section will end up in memory once it is loaded. Notice this is the same as the address of the executable program segment. This is defined because the segment is allocatable.
Offset 0xF8 Where the data for this section resides within this file
Size 14 How many bytes the section takes up in this file
Link N/A Links to another section header by index. The interpretation of this field depends on the section type. For this .text section, there is no link because this file represents a static binary.
Info N/A Any extra information, subject to interpretation based on the section type. No extra information for this section.
Address alignment 0x1000 Any alignment constraint, in bytes, for the data in this section. The alignment here is the same as that of the executable program segment.
Entry size N/A For sections that contain a table of fixed-size entries (such as a symbol table), this field states the size of those entries in bytes.

.shstrtab section: section name

The .shstrtab section is the section of the ELF file containing the names of the section headers, as null-terminated ASCII strings. This section is defined by the following fields:

Field Value Notes
Name 1 (".shstrtab") Defined by an index into the section name string table, pointing to a null-terminated ASCII string.
Type STRTAB A string table. There can be other string tables in the file as well, though this one (by virtue of being referenced in the ELF header) is specifically the one used when looking up section names.
Flags N/A None of these fields apply to a string table section.
Address
Offset 0x106 Where the data for the string table is in the file.
Size 17 The number of bytes the string table occupies in the file.
Link N/A None of these fields apply to a string table section.
Info
Address alignment
Entry size N/A Even though this section is a table, the entries are not fixed-width.

.shstrtab section: section type

The .shstrtab section is the section of the ELF file containing the names of the section headers, as null-terminated ASCII strings. This section is defined by the following fields:

Field Value Notes
Name 1 (".shstrtab") Defined by an index into the section name string table, pointing to a null-terminated ASCII string.
Type STRTAB A string table. There can be other string tables in the file as well, though this one (by virtue of being referenced in the ELF header) is specifically the one used when looking up section names.
Flags N/A None of these fields apply to a string table section.
Address
Offset 0x106 Where the data for the string table is in the file.
Size 17 The number of bytes the string table occupies in the file.
Link N/A None of these fields apply to a string table section.
Info
Address alignment
Entry size N/A Even though this section is a table, the entries are not fixed-width.

.shstrtab section: non-applicable fields

The .shstrtab section is the section of the ELF file containing the names of the section headers, as null-terminated ASCII strings. This section is defined by the following fields:

Field Value Notes
Name 1 (".shstrtab") Defined by an index into the section name string table, pointing to a null-terminated ASCII string.
Type STRTAB A string table. There can be other string tables in the file as well, though this one (by virtue of being referenced in the ELF header) is specifically the one used when looking up section names.
Flags N/A None of these fields apply to a string table section.
Address
Offset 0x106 Where the data for the string table is in the file.
Size 17 The number of bytes the string table occupies in the file.
Link N/A None of these fields apply to a string table section.
Info
Address alignment
Entry size N/A Even though this section is a table, the entries are not fixed-width.

.shstrtab section: section offset

The .shstrtab section is the section of the ELF file containing the names of the section headers, as null-terminated ASCII strings. This section is defined by the following fields:

Field Value Notes
Name 1 (".shstrtab") Defined by an index into the section name string table, pointing to a null-terminated ASCII string.
Type STRTAB A string table. There can be other string tables in the file as well, though this one (by virtue of being referenced in the ELF header) is specifically the one used when looking up section names.
Flags N/A None of these fields apply to a string table section.
Address
Offset 0x106 Where the data for the string table is in the file.
Size 17 The number of bytes the string table occupies in the file.
Link N/A None of these fields apply to a string table section.
Info
Address alignment
Entry size N/A Even though this section is a table, the entries are not fixed-width.

.shstrtab section: section size

The .shstrtab section is the section of the ELF file containing the names of the section headers, as null-terminated ASCII strings. This section is defined by the following fields:

Field Value Notes
Name 1 (".shstrtab") Defined by an index into the section name string table, pointing to a null-terminated ASCII string.
Type STRTAB A string table. There can be other string tables in the file as well, though this one (by virtue of being referenced in the ELF header) is specifically the one used when looking up section names.
Flags N/A None of these fields apply to a string table section.
Address
Offset 0x106 Where the data for the string table is in the file.
Size 17 The number of bytes the string table occupies in the file.
Link N/A None of these fields apply to a string table section.
Info
Address alignment
Entry size N/A Even though this section is a table, the entries are not fixed-width.

.shstrtab section: non-applicable fields

The .shstrtab section is the section of the ELF file containing the names of the section headers, as null-terminated ASCII strings. This section is defined by the following fields:

Field Value Notes
Name 1 (".shstrtab") Defined by an index into the section name string table, pointing to a null-terminated ASCII string.
Type STRTAB A string table. There can be other string tables in the file as well, though this one (by virtue of being referenced in the ELF header) is specifically the one used when looking up section names.
Flags N/A None of these fields apply to a string table section.
Address
Offset 0x106 Where the data for the string table is in the file.
Size 17 The number of bytes the string table occupies in the file.
Link N/A None of these fields apply to a string table section.
Info
Address alignment
Entry size N/A Even though this section is a table, the entries are not fixed-width.

.shstrtab section: section entry size

The .shstrtab section is the section of the ELF file containing the names of the section headers, as null-terminated ASCII strings. This section is defined by the following fields:

Field Value Notes
Name 1 (".shstrtab") Defined by an index into the section name string table, pointing to a null-terminated ASCII string.
Type STRTAB A string table. There can be other string tables in the file as well, though this one (by virtue of being referenced in the ELF header) is specifically the one used when looking up section names.
Flags N/A None of these fields apply to a string table section.
Address
Offset 0x106 Where the data for the string table is in the file.
Size 17 The number of bytes the string table occupies in the file.
Link N/A None of these fields apply to a string table section.
Info
Address alignment
Entry size N/A Even though this section is a table, the entries are not fixed-width.

Program header table

Each program header describes some piece of information that's needed to prepare the program for execution. Typically, this will be something like a "program segment" that will go somewhere inside the virtual memory space. Unlike the sections referenced by the section header, the program segments are more about what's in the process after it's been loaded into memory, not what's in the ELF file. That said, the data that goes into memory might be present in this file, but generally, the focus is on the runtime, not the compile and link time.

Note: the order of the data in each program header depends on whether the ELF file targets a 32-bit or a 64-bit architecture. For example, the segment flags directly follows the segment type for 64-bit architectures but comes later for 32-bit architectures. Because this file is configured to target a 64-bit architecture, the bytes below will assume the corresponding layout.

Segment type

This segment is a "loadable" segment. This tells the system that N bytes from this file (at a defined offset) will be loaded into a memory location (at another defined offset) occupying M bytes. If N is less than M, then the remaining bytes in memory will be initialized to zero.

In this file, we've set it up so that N and M are equivalent.

Segment flags

Readable and executable, which is the standard for executable segments. Avoiding writes allows a level of security, where it`s guaranteed the code being executed will not suddenly change during execution. (Allowing self-modifying code or JIT compilation requires some additional thought.)

Offset in file

The offset, in bytes, where the data for this segment resides in this file. For this executable segment, the data should be loaded from 0xF8, which is where the .text section is located.

Virtual memory address

The virtual memory address where this segment will reside once it is loaded. Notice that this is the same address as the "entry point" defined in the ELF header, as this segment is where the executable code will reside for the executable to jump to once the process is started.

Physical memory address

The physical memory address where this segment will reside once it is loaded. Only relevant for systems where physical addressing is relevant, so for most usages, this value is irrelevant.

Segment size in file

The number of bytes the segment data takes up in this file.

Segment size in memory

The number of bytes the segment data takes up in memory after the data has been loaded.

Segment aligmnent

The alignment of the segment, in bytes, for both the data in this file and the segment in the virtual memory space after it has been loaded. The fact that the alignment applies to both is important, as it is required that the offset in the file is equal to the virtual memory address, modulo the alignment. This is indeed the case, as 0x4000F8 == 0xF8 (modulo 0x1000).

Program code: .text section

The actual machine code that will be executed. Recall:

With the combination of these directives, the code in this section is exactly what gets executed when this program is run!

See an x86-64 opcode reference guide for more information regarding how these opcodes correspond to specific instructions.

Program code

This code makes the exit system call (number 60) with an argument of 42. Essentially, this causes the process to return the status code 42.

mov  $60, %rax
mov  $42, %edi
syscall

Program code

This code makes the exit system call (number 60) with an argument of 42. Essentially, this causes the process to return the status code 42.

mov  $60, %rax
mov  $42, %edi
syscall

Program code

This code makes the exit system call (number 60) with an argument of 42. Essentially, this causes the process to return the status code 42.

mov  $60, %rax
mov  $42, %edi
syscall

Section name string table

This section is a string table, of which there may be others in the file. This particular string table is what's used to look up names of the sections, and therefore, these strings are referenced by the section header table. Each entry of this table is an ASCII, null-terminated string, with the very first entry in the table being just the null-terminator.

A reference into this table is a zero-indexed byte offset into this section's data. For example, to reference the first non-empty string in the table, the reference would be 1 for byte 1. By referencing into the middle of another string, it's possible to reuse common suffixes, as is done with section names like .text and .rel.text. This optimization is not needed for the minimal file, but is common in compiler-generated ELF files.

NULL

Just the null terminator. This is required to be the zero byte by the ELF specification.

".text"

The name of the .text section.

".shstrtab"

The name of this section! Stands for section header string table.