Mastering the GCC Toolchain: From Source Code to ELF Executable

This article explains how high‑level C/C++ programs are transformed into processor‑executable binaries on Linux, covering preprocessing, compilation, assembly, linking, the GCC and Binutils utilities, and how to inspect the resulting ELF file.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
Mastering the GCC Toolchain: From Source Code to ELF Executable

Programming Language Categories

Computer programming languages are typically divided into machine language, assembly language, and high‑level languages. High‑level languages must be translated into machine code, either by a compiler (e.g., C, C++, Java) or an interpreter (e.g., Python, Ruby, MATLAB, JavaScript).

From C/C++ Source to Binary

The conversion process consists of four steps:

Preprocessing

Compilation

Assembly

Linking

GCC Toolchain Overview

GCC (GNU Compiler Collection) is the standard compiler suite on Linux. The toolchain includes GCC, Binutils, and the C runtime library (CRT).

GCC

GCC performs the compilation of C/C++ source files into executable binaries.

Binutils

Binutils provides a set of binary handling tools such as addr2line, ar, objcopy, objdump, as, ld, ldd, readelf, and size. Brief descriptions: addr2line: maps program addresses to source files and line numbers. as: assembles assembly code. ld: links object files. ar: creates static libraries; static libraries have .a extension on Linux, while shared libraries use .so. ldd: lists shared library dependencies of an executable. objcopy: converts object files between formats. objdump: disassembles binaries. readelf: displays ELF file information. size: shows the size of each section in an executable.

C Runtime Library

The C standard defines syntax and a standard library. The library provides function prototypes (e.g., printf in stdio.h) but not implementations; the CRT supplies the actual code. C++ has a similar runtime library.

Preparation

We use a simple Hello World program as the example source:

#include <stdio.h>
// This program simply prints a Hello World string.
int main(void) {
    printf("Hello World! 
");
    return 0;
}

Compilation Process

1. Preprocessing

Preprocessing expands macros, includes header files, removes comments, and adds line directives. The command:

$ gcc -E hello.c -o hello.i   // -E stops after preprocessing

The resulting hello.i can be viewed as plain text.

2. Compilation

Compilation translates the preprocessed file into assembly code:

$ gcc -S hello.i -o hello.s   // -S stops after compilation

3. Assembly

Assembly converts the assembly file into an object file ( .o):

$ gcc -c hello.s -o hello.o   // -c stops after assembly
# or directly using Binutils
$ as -c hello.s -o hello.o

The object file is in ELF format.

4. Linking

Linking combines object files and libraries into a final executable. Both static and dynamic linking are possible.

Static linking incorporates library code into the executable, producing a larger file.

Dynamic linking records library references; the libraries are loaded at runtime.

Example commands:

$ gcc hello.c -o hello               // dynamic linking
$ size hello
$ ldd hello

$ gcc -static hello.c -o hello       // static linking
$ size hello
$ ldd hello   // reports "not a dynamic executable"

Analyzing the ELF File

1. ELF Sections

Typical ELF sections include:

.text – executable code

.rodata – read‑only data (constants)

.data – initialized global/static variables

.bss – uninitialized global/static variables

.debug – debugging symbols

Use readelf -S hello to list section headers.

$ readelf -S hello
There are 31 section headers, starting at offset 0x19d8:
[ 0] NULL ...
[11] .init ...
[14] .text ...
[15] .fini ...

2. Disassembling ELF

Since ELF files are binary, use objdump to view instructions.

$ objdump -D hello
0000000000400526 <main>:
  400526: 55                push %rbp
  400527: 48 89 e5          mov %rsp,%rbp
  ...

To interleave source code with disassembly, use objdump -S:

$ gcc -o hello -g hello.c
$ objdump -S hello
0000000000400526 <main>:
# include <stdio.h>
int main(void) {
  400526: 55                push %rbp
  printf("Hello World!
");
  400527: 48 89 e5          mov %rsp,%rbp
  ...
}
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

CompilationELFToolchaingcc
MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.