An ELF file is a standard format that tells your computer how to run a program on Linux, Unix, and similar operating systems.
ELF stands for Executable and Linkable Format. It is a file structure that contains machine code — the actual instructions your processor understands — along with metadata that tells the operating system how to load and run that code. When you download a program for Linux or run a command-line tool on Mac or Android, you are usually working with an ELF file, even if you never see the .elf extension.
The format was standardized in the 1990s and is now used across nearly every Unix-like system. Windows uses a different format called PE (Portable Executable), and older Mac systems used Mach-O, but ELF became the default almost everywhere else. Understanding what an ELF file is helps explain why a program compiled for Linux will not run on Windows without translation, and why the same compiled program often works across different Linux distributions.
Key Takeaways
- ELF files contain executable code and instructions that tell your operating system how to run a program on Linux, Unix, Android, and similar systems.
- An ELF file includes both the machine code itself and metadata sections that describe memory layout, required libraries, and entry points for execution.
- You can view basic information about an ELF file using command-line tools like file, readelf, or objdump without needing special software.
- ELF files are not human-readable text — they are binary files designed for computers to parse, which is why they appear as gibberish if you open them in a text editor.
- The same ELF file usually works across different Linux distributions and Unix variants because they all follow the same ELF standard.
The structure inside an ELF file
An ELF file is organized into distinct sections, each serving a specific purpose. At the very beginning is the ELF header, which is a fixed-size block of data that identifies the file as ELF, specifies whether it is 32-bit or 64-bit, and points to where the rest of the file's important information is located. Think of it as a table of contents that the operating system reads first.
After the header come the actual program sections. The .text section holds the executable machine code. The .data section contains variables that are initialized when the program starts. The .bss section reserves space for uninitialized variables. There are also sections for symbol tables (which map variable and function names to their locations), relocation information (which tells the system how to adjust addresses when loading the program), and string tables (which store text like function names and error messages).
At the end of the file is the section header table, which is a map describing where each section is located and how large it is. This allows tools and the operating system to quickly find what they need without reading the entire file sequentially.
How your operating system uses an ELF file
When you run an ELF program on Linux, the operating system does not simply copy the entire file into memory. Instead, it reads the ELF header and the program header table, which describe how the file should be laid out in memory. The kernel then creates a process, reserves the necessary memory regions, and copies the appropriate sections into place.
The operating system also checks whether the program depends on shared libraries — code libraries that multiple programs use, like the C standard library. The ELF file contains a list of these dependencies, and the kernel uses a program called the dynamic linker to load those libraries and resolve references to functions and variables within them. This is why you sometimes see error messages like "error while loading shared libraries" — the ELF file expected a library that is not installed on your system.
Once everything is loaded and linked, the kernel jumps to the entry point address specified in the ELF header, and your program begins executing. The entire process happens in milliseconds, but it is why ELF files need all that metadata — the operating system needs a precise blueprint to set up the program correctly.
Why ELF files are binary, not text
ELF files are binary files, meaning they contain raw bytes that represent machine instructions and data structures, not human-readable text. If you open an ELF file in a text editor, you will see mostly gibberish — random characters, symbols, and control codes — because the editor is trying to display binary data as if it were text.
This binary format is intentional. Machine code is already in the form your processor understands, so storing it as text would be wasteful and slow. A text representation would require converting every instruction into ASCII characters, making the file much larger and forcing the operating system to parse and convert it back to binary before execution. By keeping the file binary, ELF files are compact and fast to load.
If you need to read what is inside an ELF file, you use specialized tools rather than a text editor. The file command tells you basic information like architecture and whether it is statically or dynamically linked. The readelf tool displays the ELF header, sections, and symbols in human-readable form. The objdump tool can disassemble the machine code back into assembly language, which is closer to human-readable but still requires technical knowledge to understand.
Statically linked versus dynamically linked ELF files
An ELF file can be built in two ways: statically linked or dynamically linked. A statically linked ELF file contains all the code it needs to run, including copies of library functions. When you run it, the operating system loads the file and starts executing — no additional dependencies.
A dynamically linked ELF file, by contrast, contains only references to external libraries. When you run it, the dynamic linker loads those libraries from your system and connects the references. This approach saves disk space and memory because multiple programs can share the same library code, but it means the program will not run if a required library is missing or incompatible.
Most programs you use are dynamically linked because it is more efficient. Statically linked programs are larger and less flexible, but they are sometimes used for tools that need to run in minimal environments or be distributed as a single file without dependencies. You can check which type a file is using the file command — it will say "dynamically linked" or "statically linked" in the output.
ELF files across different systems
One of ELF's strengths is portability within the Unix ecosystem. An ELF file compiled for one Linux distribution usually runs on another Linux distribution without recompilation, as long as the required libraries are installed and the architecture matches. A 64-bit ELF binary for x86-64 processors will work on Ubuntu, Fedora, Debian, and other distributions because they all use the same ELF standard and the same processor instruction set.
However, ELF files are not portable across operating systems. An ELF file compiled for Linux will not run on Windows or macOS without special translation software. Windows uses the PE format, and modern macOS uses Mach-O. Android uses ELF files, but Android's runtime environment adds extra layers on top, so an ELF file compiled for desktop Linux will not work on Android either.
Architecture also matters. An ELF file compiled for ARM processors (common in mobile devices and embedded systems) will not run on x86-64 processors (common in desktops and servers), even if both systems are Linux. The ELF header specifies the target architecture, and the operating system checks this before attempting to execute the file.
Tools for examining ELF files
If you work with Linux or Unix systems, you may need to inspect an ELF file to understand what it does or troubleshoot problems. The file command is the simplest starting point — run file /path/to/program and it will tell you whether the file is ELF, what architecture it targets, whether it is statically or dynamically linked, and whether it has debugging symbols.
The readelf command provides detailed information about the ELF structure itself. You can use readelf -h to see the ELF header, readelf -S to list all sections, or readelf -d to see dynamic dependencies. The ldd command specifically shows which shared libraries a program depends on and where the system found them.
For more advanced analysis, objdump can disassemble the machine code into assembly language, and nm lists all symbols (function and variable names) in the file. These tools are part of the standard GNU binutils package and are available on nearly every Linux system.
Frequently Asked Questions
Can I run an ELF file on Windows?
Not directly. Windows uses the PE format, not ELF. However, you can use compatibility layers like Windows Subsystem for Linux (WSL) or virtual machines to run Linux and execute ELF files. Some tools like Cygwin also provide partial compatibility, but they are not true ELF execution.
What does it mean if I get a "not found" error when running an ELF file?
This usually means the file depends on a shared library that is not installed on your system. Run ldd /path/to/file to see which libraries it needs and which ones are missing. You may need to install additional packages or ensure the library versions match what the program expects.
Why does the same ELF file work on different Linux distributions?
Because they all follow the ELF standard and use the same kernel and processor instruction sets. As long as the required libraries are installed and compatible, the operating system can load and run the file the same way. Distribution differences are mostly in package management and default software, not in how ELF files are executed.
Can I edit an ELF file with a text editor?
Technically yes, but you should not. ELF files are binary, and changing random bytes will corrupt the file structure and make it unrunnable. If you need to modify a program, you should modify the source code and recompile it into a new ELF file.
What is the difference between an ELF file and a script file?
An ELF file contains compiled machine code that the processor executes directly. A script file (like a shell script or Python script) contains human-readable text that an interpreter reads and executes line by line. ELF files are faster because the code is already in machine form, but scripts are more portable and easier to modify.