Inferensys

Glossary

Executable and Linkable Format (ELF)

The Executable and Linkable Format (ELF) is a common standard file format for executables, object code, shared libraries, and core dumps, used by many Unix-like operating systems to define the structure of binary files.
Developer building agentic RAG system, retrieval pipeline diagram on laptop, technical workspace with notes.
BINARY FORMAT

What is Executable and Linkable Format (ELF)?

The Executable and Linkable Format (ELF) is the standard binary file format used by most Unix-like operating systems, including Linux and BSD variants, to define the structure of executable programs, object code, shared libraries, and core dumps.

The Executable and Linkable Format (ELF) is a common standard file format for executables, object code, shared libraries, and core dumps. It defines the structure for binary files used by many Unix-like operating systems, including Linux and BSD variants. The format is organized into a header, program headers for execution, and section headers for linking and debugging. This structure allows the operating system's loader to map the file into memory and execute it correctly.

ELF is crucial for linkers and loaders during software compilation and execution. It supports dynamic linking, where shared library dependencies are resolved at runtime, and static linking, where all code is contained within a single executable. The format's flexibility enables features like position-independent code (PIC) and supports a wide range of processor architectures. In the context of NPU deployment, ELF files encapsulate compiled kernels and runtime libraries that are loaded onto the accelerator hardware for execution.

EXECUTABLE AND LINKABLE FORMAT

Key Structural Components of an ELF File

The Executable and Linkable Format (ELF) is a standard binary file format for executables, object code, shared libraries, and core dumps. Its modular structure is defined by a header, program headers, section headers, and data segments.

01

ELF Header

The ELF Header is located at the start of the file and serves as a roadmap. It defines the file's fundamental properties, including:

  • Magic Number: The initial bytes (0x7f 'E' 'L' 'F') that identify the file as ELF.
  • Class: Specifies the architecture as 32-bit (ELFCLASS32) or 64-bit (ELFCLASS64).
  • Data Encoding: Defines byte order as little-endian (ELFDATA2LSB) or big-endian (ELFDATA2MSB).
  • Type: Identifies the file type: relocatable object (ET_REL), executable (ET_EXEC), shared object (ET_DYN), or core file (ET_CORE).
  • Machine: Specifies the required CPU architecture (e.g., EM_X86_64 for x86-64).
  • Entry Point: The virtual address where the system transfers control to start the program.
  • Offsets: Pointers to the start of the Program Header Table and Section Header Table.
02

Program Header Table

The Program Header Table is an array of program headers, essential for the operating system's loader. It describes segments—contiguous chunks of the file that are mapped into memory at runtime. Key segment types include:

  • PT_LOAD: A loadable segment containing executable code (.text) or data (.data, .bss). A file typically has at least two: one for code (read-only, execute) and one for data (read-write).
  • PT_DYNAMIC: Contains dynamic linking information, such as the location of the symbol table and relocation entries.
  • PT_INTERP: Specifies the path to the program interpreter (e.g., /lib64/ld-linux-x86-64.so.2), which is the dynamic linker.
  • PT_PHDR: Points to the program header table itself, useful for the loader. Each header defines the segment's virtual address (Vaddr), physical address (Paddr), file offset, size in memory (Memsz), size in file (Filesz), and permission flags (read, write, execute).
03

Section Header Table

The Section Header Table is an array of section headers, primarily used by linkers and debugging tools. It describes sections—smaller, named blocks within segments that hold specific types of data. Common sections include:

  • .text: The executable machine instructions.
  • .data: Initialized global and static variables.
  • .rodata: Read-only data, such as string literals.
  • .bss: Block Started by Symbol; holds uninitialized global/static variables (occupies no space in the file, only size definition).
  • .symtab: The symbol table, a list of functions and variables with their names, addresses, and sizes.
  • .strtab: The string table holding null-terminated symbol names referenced by .symtab.
  • .rela.text / .rela.data: Relocation entries containing information for the linker to adjust addresses in code/data.
  • .dynamic: Contains dynamic linking information, mirroring the PT_DYNAMIC segment. While segments are for runtime execution, sections are for static analysis and linking.
04

Sections vs. Segments

A core concept in ELF is the distinction and mapping between sections and segments.

  • Sections are defined in the Section Header Table. They are logical views of the file's contents used by the linker (ld) and tools like objdump and readelf. Their purpose is organization and static analysis.
  • Segments are defined in the Program Header Table. They are runtime views used by the operating system loader to map parts of the file into memory. A segment is a container for one or more sections. The Mapping: When a program is executed, the loader reads the program headers. It ignores sections entirely. It maps each PT_LOAD segment from the file into memory at the specified virtual address. Multiple sections (like .text and .rodata) are packed into a single read-only, executable segment. The .data and .bss sections are packed into a single read-write segment. The strip command removes the section header table without affecting execution, proving segments are sufficient for the loader.
05

Dynamic Linking Metadata

For executables that use shared libraries, ELF files contain extensive metadata for the dynamic linker. This is primarily housed in the PT_DYNAMIC segment (.dynamic section). Key data structures include:

  • Dynamic Symbol Table (.dynsym): A subset of the full symbol table, containing only symbols needed for dynamic linking (e.g., printf from libc).
  • Dynamic String Table (.dynstr): String names for the dynamic symbols.
  • Global Offset Table (.got): A table of absolute addresses for global data. The Procedure Linkage Table (.plt), which contains stub code for function calls, interacts with the GOT to resolve external function addresses lazily at runtime.
  • Relocation Tables (.rela.dyn, .rela.plt): Instructions for the dynamic linker to patch addresses in the GOT and PLT once the actual memory addresses of shared library functions are known.
  • DT_NEEDED Entries: A list of required shared library names (e.g., libc.so.6).
  • DT_RPATH/DT_RUNPATH: Directories to search for shared libraries. This metadata enables position-independent code (PIC) and the lazy binding optimization, which defers symbol resolution until the first call.
06

Tooling and Inspection

A suite of standard Unix tools allows developers to inspect and manipulate ELF files, which is critical for debugging and optimization in deployment pipelines.

  • readelf: The primary tool for displaying comprehensive ELF information. Use readelf -h for the header, readelf -l for program headers (segments), and readelf -S for section headers.
  • objdump: Powerful for disassembly and detailed section analysis. objdump -d disassembles the .text section, while objdump -x shows all headers.
  • nm: Lists symbols from the symbol table (.symtab), showing their names, types, and virtual addresses.
  • ldd: Lists the shared library dependencies of a dynamic executable by reading the DT_NEEDED entries.
  • strip: Removes the symbol table (.symtab) and debugging sections to reduce file size for production deployment, without affecting the program headers needed for execution.
  • patchelf: A utility to modify various ELF properties, such as changing the RPATH or interpreter path, which is useful for creating portable binaries.
BINARY FORMAT OVERVIEW

How ELF Works: From Compilation to Execution

The Executable and Linkable Format (ELF) is the standard binary file structure used by most Unix-like operating systems. It defines how compiled code, data, and metadata are organized for execution, linking, and core dumps.

The Executable and Linkable Format (ELF) is a common standard file format for executables, object code, shared libraries, and core dumps, used by many Unix-like operating systems to define the structure of binary files. Its design separates the file into a header, program headers for execution, and section headers for linking. This modular structure allows a single file to serve multiple purposes, such as being a relocatable object file for the linker or a loadable executable for the operating system loader.

During compilation, a toolchain like GCC outputs a relocatable ELF object file (.o), containing code and data sections with relocation metadata. The linker combines multiple object files, resolves symbols, and applies relocations to create an executable or shared library. At load time, the OS dynamic linker uses the ELF's program header table to map segments into memory, resolve runtime dependencies, and transfer control to the entry point, enabling execution.

ELF FILE FORMAT

Primary Use Cases and File Types

The Executable and Linkable Format (ELF) is a versatile binary standard used across Unix-like systems. Its structure defines several distinct file types, each serving a specific stage in the software lifecycle.

01

Executable Files

ELF files containing a complete, ready-to-run program. The OS loader maps the segments defined in the program header table into memory and transfers control to the entry point.

  • Key Sections: .text (code), .data (initialized data), .rodata (read-only data).
  • Dynamic Linking: Most executables are dynamically linked, containing a .interp section pointing to the dynamic linker (e.g., /lib64/ld-linux-x86-64.so.2).
  • Entry Point: The e_entry field in the ELF header specifies the virtual address where execution begins.
02

Relocatable Object Files

The output of a compiler (.o files), containing code and data but not yet a final executable. These files are inputs to the linker.

  • Symbol Tables: Contain STT_NOTYPE, STT_OBJECT, and STT_FUNC symbols, many of which are unresolved (e.g., printf).
  • Relocation Sections: Sections like .rela.text contain relocation entries that instruct the linker how to patch addresses once final memory locations are known.
  • No Program Headers: Typically lack a program header table; the segment layout is the linker's responsibility.
03

Shared Libraries

Dynamically linked libraries (.so files) containing code intended to be shared among multiple processes. They are a hybrid of executable and relocatable features.

  • Position-Independent Code (PIC): Code is compiled to be loaded at any virtual address, using a Global Offset Table (GOT) and Procedure Linkage Table (PLT) for addressing.
  • Dynamic Section: Contains critical metadata for the runtime linker (DT_NEEDED, DT_SYMTAB, DT_HASH/DT_GNU_HASH).
  • Symbol Visibility: Controls which functions are exported (STB_GLOBAL) or kept internal (STB_LOCAL or STV_HIDDEN).
04

Core Dump Files

ELF files generated by the kernel when a process terminates due to a fatal signal (e.g., SIGSEGV). They contain a snapshot of the process's address space and register state at the time of crash.

  • Program Headers for Memory: Each PT_LOAD segment corresponds to a memory region (code, heap, stack) from the original process.
  • Note Sections: Contain auxiliary information like the prstatus structure (register values) and prpsinfo (process name, command line).
  • Debugging: Essential for post-mortem analysis with tools like gdb to diagnose crashes in production.
05

Kernel and Bootloader Use

ELF is the standard format for Linux kernel images (vmlinux) and many bootloaders (e.g., GRUB2's core image). The bootloader or firmware parses the ELF headers to load segments into specific physical memory addresses.

  • No Dynamic Linking: Kernel images are statically linked.
  • Custom Sections: May contain architecture-specific sections (e.g., .init.text for initialization code that can be discarded after boot).
  • Entry Point: For the kernel, the entry point is the start of architecture-specific assembly bootstrap code.
06

Firmware and Bare-Metal Binaries

In embedded systems, ELF is the primary output of cross-compilation toolchains. The ELF file is used for debugging with symbols, while a raw binary (.bin) or Intel HEX file is extracted for flashing.

  • Linker Scripts: Heavily used to define precise memory maps, placing .text in ROM and .data in RAM.
  • No OS Loader: The program headers (PT_LOAD) are read by the flashing tool, not a runtime loader.
  • Debugging: The ELF file, with its symbol table and debugging sections, is paired with the flashed binary for source-level debugging via JTAG/SWD.
COMPARISON

ELF vs. Other Binary File Formats

A technical comparison of the Executable and Linkable Format (ELF) against other common binary file formats, highlighting structural differences, use cases, and platform support relevant to system-level programming and deployment.

Feature / AspectELF (Executable and Linkable Format)Mach-O (Mach Object)PE (Portable Executable)a.out (Assembler Output)

Primary Use Case & Origin

Executables, shared libraries, object code, core dumps. Standard for Unix-like systems (Linux, BSD).

Executables, libraries, bundles. Native format for Apple's macOS and iOS (Darwin kernel).

Executables (EXE), Dynamic Link Libraries (DLL), drivers. Native format for Microsoft Windows.

Original Unix object & executable format. Largely historical, predecessor to COFF and ELF.

File Structure

Flexible, segmented into a header, program header table (segments for execution), and section header table (sections for linking).

Segmented into a header, load commands (describing segments), and data regions (sections within segments).

Based on COFF. Starts with a DOS stub, followed by PE header, optional header, and section tables. Data directories describe imports/exports.

Simple, monolithic structure with a header followed by text, data, and symbol table sections. Limited extensibility.

Support for Dynamic Linking

Cross-Architecture Support

Defined for multiple architectures (x86, ARM, PowerPC) but tied to Apple platforms.

Debugging & Symbol Information

Comprehensive support via dedicated sections (.debug_*, .symtab, .strtab).

Supports DWARF and stabs debugging formats within segments.

Supports CodeView and PDB (Program Database) formats, often stored externally.

Basic symbol table support. Limited standardized debugging format.

Relocation Types

Rich set of architecture-specific relocation types for complex symbol resolution.

Architecture-specific relocation types defined within load commands.

Extensive relocation types defined in the .reloc section for base address adjustments.

Simple, absolute relocations. Lacks complex PIC (Position Independent Code) support.

Modern Toolchain Support

Universal support by GCC, Clang, binutils (ld, objdump). Industry standard.

Fully supported by Apple's toolchain (Xcode, ld64). Required for Apple platforms.

Fully supported by Microsoft toolchain (MSVC, link.exe) and cross-compilers like MinGW.

Largely obsolete. Not supported by modern compilers as a primary target.

EXECUTABLE AND LINKABLE FORMAT (ELF)

Frequently Asked Questions

The Executable and Linkable Format (ELF) is the standard binary file format for executables, object code, shared libraries, and core dumps on Unix-like systems. This FAQ addresses its role in modern software deployment, particularly for NPU-accelerated workloads.

The Executable and Linkable Format (ELF) is a common standard file format for executables, object code, shared libraries, and core dumps, used by many Unix-like operating systems to define the structure of binary files. It serves as the universal container for compiled machine code and associated metadata, enabling the operating system's loader to prepare a program for execution. An ELF file is organized into a header, program headers (for execution), and section headers (for linking and debugging). This format is critical for NPU acceleration as it defines how optimized kernels and runtime libraries are packaged and loaded onto specialized hardware.

Prasad Kumkar

About the author

Prasad Kumkar

CEO & MD, Inference Systems

Prasad Kumkar is the CEO & MD of Inference Systems and writes about AI systems architecture, LLM infrastructure, model serving, evaluation, and production deployment. Over 5+ years, he has worked across computer vision models, L5 autonomous vehicle systems, and LLM research, with a focus on taking complex AI ideas into real-world engineering systems.

His work and writing cover AI systems, large language models, AI agents, multimodal systems, autonomous systems, inference optimization, RAG, evaluation, and production AI engineering.