An executable file (or executable code) is the final, runnable product of the entire compilation and linking process. It contains not just the machine code for your program, but also all the necessary information for the operating system (OS) to load and execute it.
Think of it as the final, printed, and bound book. Your source code was the manuscript, the object files were the translated chapters, and the executable is the complete book, ready for the OS and CPU to "read" and act upon.
On Windows, these
files typically have a .exe
extension. On Unix-like systems (Linux, macOS), they often have no extension
but are marked with a special "executable" file permission.
What's Inside an Executable File?
An executable is a highly structured file (often in a format like ELF on Linux or PE on Windows) that contains several key components:
路聽聽聽聽聽聽聽聽 File Header: Metadata at the beginning of the file that describes its contents, such as the target architecture (e.g., x86-64), the memory address of the first instruction to execute (the entry point), and the locations of other sections.
路聽聽聽聽聽聽聽聽
Code Segment (.text
): Contains
the actual binary machine code instructions for all your functions, as well as
the functions from any statically linked libraries.
路聽聽聽聽聽聽聽聽 Data Segments:
o聽聽聽 .data
: Contains initialized global and static variables.
o聽聽聽 .rodata
: Contains read-only data like string literals and const
variables.
o聽聽聽 .bss
: A placeholder for uninitialized global and static
variables.
路聽聽聽聽聽聽聽聽
Startup Code: A small block of code from the C runtime library that
the OS runs before your main()
function. This code is responsible for setting up the
program's environment, such as initializing the stack and processing
command-line arguments.
路聽聽聽聽聽聽聽聽
Linkage
Information: For dynamically linked
programs, this section contains a list of the required shared libraries (e.g., .so
or .dll
files) and the symbols (functions/variables) the program needs to
import from them at runtime.
From Object Code to Executable: The Linker's Role
The linker is the tool that transforms one or more object files into a single executable file. Its two primary jobs are:
1.聽聽 Symbol Resolution: The linker scans the object files' symbol tables. When it sees an "undefined"
reference (like a call to printf
in your object file), it looks for a
"defined" symbol with that name in other object files or in the C
standard library. It resolves all these cross-references.
2.聽聽 Relocation:
The linker merges all the similar sections from the input object files (e.g.,
all .text
sections are combined into one large .text
section). It then assigns final memory addresses to
these sections and to all the symbols. Finally, it goes back through the code
and patches all the placeholder addresses left by the compiler with their
final, absolute addresses.
Example: Creating and Running an Executable
Let's take a simple C file and follow it to the final executable stage.
Source Code (main.c
):
C
#include <stdio.h>
聽
int main() {
聽聽聽
printf(
"This is an executable program!\n");
聽聽聽
return
0;
}
1.
Compilation and Linking Command The gcc
command, when not given any special flags like -c
, will automatically perform all four stages of
compilation to produce an executable.
Bash
# This command compiles and links main.c to create an executable named 'my_app'
gcc main.c -o my_app
2. Running the Executable Once created, you can run the program directly from your terminal.
路聽聽聽聽聽聽聽聽 On Linux or macOS:
Bash
./my_app
路聽聽聽聽聽聽聽聽 On Windows:
Bash
my_app.exe
Output:
聽聽聽聽聽聽聽聽聽聽聽 This is an executable program!
The
file my_app
is now a complete, self-contained program that the
operating system can load and execute.
聽
聽
An executable file is a highly structured binary file containing machine code and specific instructions (metadata) that tell the operating system how to load the program into memory and begin its execution.