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.
Glossary
Executable and Linkable Format (ELF)

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.
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.
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.
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_64for 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.
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).
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 thePT_DYNAMICsegment. While segments are for runtime execution, sections are for static analysis and linking.
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 likeobjdumpandreadelf. 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_LOADsegment from the file into memory at the specified virtual address. Multiple sections (like.textand.rodata) are packed into a single read-only, executable segment. The.dataand.bsssections are packed into a single read-write segment. Thestripcommand removes the section header table without affecting execution, proving segments are sufficient for the loader.
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.,printffromlibc). - 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_NEEDEDEntries: 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.
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. Usereadelf -hfor the header,readelf -lfor program headers (segments), andreadelf -Sfor section headers.objdump: Powerful for disassembly and detailed section analysis.objdump -ddisassembles the.textsection, whileobjdump -xshows 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 theDT_NEEDEDentries.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 theRPATHor interpreter path, which is useful for creating portable binaries.
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.
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.
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
.interpsection pointing to the dynamic linker (e.g.,/lib64/ld-linux-x86-64.so.2). - Entry Point: The
e_entryfield in the ELF header specifies the virtual address where execution begins.
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, andSTT_FUNCsymbols, many of which are unresolved (e.g.,printf). - Relocation Sections: Sections like
.rela.textcontain 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.
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_LOCALorSTV_HIDDEN).
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_LOADsegment corresponds to a memory region (code, heap, stack) from the original process. - Note Sections: Contain auxiliary information like the
prstatusstructure (register values) andprpsinfo(process name, command line). - Debugging: Essential for post-mortem analysis with tools like
gdbto diagnose crashes in production.
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.textfor 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.
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
.textin ROM and.datain 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.
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 / Aspect | ELF (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. |
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.
Enabling Efficiency, Speed & Accuracy
Intelligent Analysis, Decision & Execution
We build AI systems for teams that need search across company data, workflow automation across tools, or AI features inside products and internal software.
Talk to Us
Search across company data
Give teams answers from docs, tickets, runbooks, and product data with sources and permissions.
Useful when people spend too long searching or get different answers from different systems.

Automate internal workflows
Use AI to route work, draft outputs, trigger actions, and keep approvals and logs in place.
Useful when repetitive work moves across multiple tools and teams.

Add AI to products and internal tools
Build assistants, guided actions, or decision support into the software your team or customers already use.
Useful when AI needs to be part of the product, not a separate tool.
Related Terms
ELF is a core component of the binary deployment toolchain. These related concepts define the interfaces, compilation strategies, and runtime environments that interact with ELF files in production systems.
Application Binary Interface (ABI)
An Application Binary Interface (ABI) is the low-level contract between an executable and the operating system or between different compiled modules. It defines the precise rules for:
- Calling conventions: How function arguments are passed (registers vs. stack) and values are returned.
- System call numbers: The mapping from library functions to kernel interrupts.
- Data representation: Size, alignment, and byte order of fundamental data types.
- Object file format: Often ELF itself, specifying how code and data are laid out. The ABI ensures binary compatibility; an ELF executable compiled for the Linux x86_64 ABI will not run on a system expecting the ARM ABI, even if the CPU architecture could theoretically execute the instructions.
Ahead-of-Time Compilation (AOT)
Ahead-of-Time Compilation (AOT) is a strategy where source code or an intermediate representation is fully compiled into a native machine binary before execution. This is the traditional model for creating ELF executables and shared libraries (.so files).
Key characteristics include:
- Produces a standalone ELF binary containing machine code for a specific target CPU and ABI.
- All symbol addresses and relocations are resolved at compile/link time, not at runtime.
- Enables maximum optimization by the compiler (e.g., GCC, Clang) with full program view.
- Contrasts with Just-in-Time (JIT) compilation, which happens during runtime. In NPU contexts, AOT compilation of a neural network graph into a vendor-specific NPU binary is critical for deploying optimized, low-latency models.
Link-Time Optimization (LTO)
Link-Time Optimization (LTO) is a compiler technique that postpones major optimization passes until the final linking stage. During compilation, modules are saved in an intermediate representation (IR) within the object files (e.g., in a special ELF section). The linker then merges all IR and performs whole-program optimizations.
Benefits for performance-critical deployment:
- Cross-module inlining: Functions from one
.ofile can be inlined into another. - Dead code elimination: Removal of functions and data unused across the entire program.
- Inter-procedural constant propagation. This results in a more optimized final ELF executable or shared library, which is especially valuable for large applications and runtime libraries where modularity traditionally limits compiler insight.
Dynamic Linking & Shared Libraries
Dynamic Linking is the process of resolving symbols and loading code from external shared libraries (ELF .so files) at runtime, rather than at build time. The main ELF executable contains a PT_INTERP program header pointing to the dynamic linker (e.g., /lib64/ld-linux-x86-64.so.2) and a .dynamic section listing required libraries.
Runtime process involves:
- The kernel loads the ELF executable and the dynamic linker.
- The dynamic linker loads the listed
.sofiles, performing relocation to resolve absolute addresses. - Lazy binding (via the Procedure Linkage Table, PLT) often defers resolution of individual function addresses until first call for speed. This enables code sharing, smaller binaries, and library updates without recompiling every dependent application.
Debugging With DWARF
DWARF is a standardized debugging data format, stored in specific sections (e.g., .debug_info, .debug_line) within an ELF file. It provides a comprehensive map between the executable machine code and the original source code, enabling symbolic debugging.
Information encoded in DWARF includes:
- Variable locations: Where a local variable is stored (register or stack offset) for each line of code.
- Data type descriptions: Structures, classes, and their members.
- Source file and line mapping: Which machine instruction corresponds to which source line.
- Call frame information: For unwinding the stack during exceptions. Tools like GDB and LLDB read the DWARF data from the ELF file to allow developers to step through code, inspect variables, and analyze crashes. Stripping these sections reduces file size but eliminates debug capability.
Executable Stack & Security
An executable stack is a memory region with both write and execute permissions, a historical feature that posed major security risks for buffer overflows. The ELF format controls this via the PT_GNU_STACK program header.
Modern hardening practices:
- No-execute (NX) bit: The linker marks the stack as non-executable (
-z noexecstack), which is signaled in the ELF header. The kernel enforces this, preventing code injection attacks from succeeding. - Position-Independent Executable (PIE): The entire executable is compiled as a shared library, allowing Address Space Layout Randomization (ASLR) to be fully effective, making memory addresses unpredictable.
- Relocation Read-Only (RELRO): Makes the Global Offset Table (GOT) read-only after dynamic linking, preventing GOT overwrite attacks. These security features are flags and metadata within the ELF file that instruct the operating system loader on how to apply modern exploit mitigations.

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.
Partnered with leading AI, data, and software stack.
How We Work
Custom AI workflows for your Business
One-fit-all AI don't work for modern businesses. At Inferensys, we aim to understand your business & custom requirements; which we use to define most efficient agentic workflows, the data, and the tools for your business.
01
Review the use case
We understand the task, the users, and where AI can actually help.
Read more02
Pick the right approach
We define what needs search, automation, or product integration.
Read more03
Build the first useful version
We implement the part that proves the value first.
Read more04
Improve from there
We add the checks and visibility needed to keep it useful.
Read moreThe first call is a practical review of your use case and the right next step.
Talk to Us