I came across an interesting article a senior sent over about how your executable is a sqlite database. Curious, I open it, only for it to begin with explaining why the ELF is a database of sorts. But what is an ELF??
Executable and Linkable Format¶
The Executable and Linkable Format (ELF) is the standard binary format used across Unix-like systems (including Linux, BSD, and Solaris) for executables, object code (.o), shared libraries (.so), and core dumps.
It was designed to be highly flexible, extensible, and cross-platform, and does so without tying itself down to any CPU architecture!
The Two Views of an ELF File¶
An ELF file serves two distinct purposes in the lifecycle of software, offering two different "views" into the same binary:
- The Linkable View (Section Header Table)
- When the compiler produces object files (
.o), the linker needs to know about the symbols, relocations, functions, and data blocks. - The data is organized into Sections, like
.textfor code,.datafor initialized variables,.bssfor uninitialized memory,.symtabfor symbols.
- The Executable View (Program Header Table)
- When the OS kernel or dynamic linker (
ld.so) loads the binary into memory, it cares more about the read, write and execute permissions of chunks of memory, rather than the individual sections. - Thus these sections are bundled into Segments (e.g., a Loadable Segment containing
.textand.rodatawith Read+Execute permissions).
By Surueña - Own work, CC BY-SA 3.0, Link
The ELF Header at the beginning of the file contains metadata like the magic number (\x7fELF, used to identify that the file is an ELF file), target architecture, 32-bit vs 64-bit class, endianness, entry point address, and byte offsets to the Header Tables.
Below is an image from Wikipedia that I think better explains the ELF format:-
By Ange Albertini - Corkami, CC BY 1.0, Link
The ELF file defines the container format, which includes the layout of bytes, headers, and sections on disk. But how do two compiled ELF binaries actually talk to each other?
ABI (Application Binary Interface)¶
The ABI defines how binary code interacts with hardware and the operating system at the machine level. It is analogous to how an API works for source code interacting with each other, but for compiled binaries. The ABI defines various aspects of interactions, such as:-
- Calling Conventions: Which CPU registers are used to pass function arguments, where return values are stored, and who cleans up the stack (caller vs. callee).
- Data Layout & Alignment: How structs, primitive data types, and unions are padded and laid out in memory.
- System Call Interface: Exactly how user-space programs trap into the kernel to make syscalls (
syscallinstruction, register assignments for syscall numbers and parameters). - Object File & Linkage Conventions: Standard symbol naming/mangling, relocation formats, and dynamic linking semantics defined on top of the ELF spec (e.g., System V AMD64 ABI).
The ABI of a system is determined by a number of factors, including the CPU architecture, the operating system, and the compiler. For example, the ABI for a 64-bit x86 system running Linux is different from the ABI for a 64-bit ARM system running Linux.