Introduction
You have used GCC for years. You know what -O2 does, roughly. You have fought
cannot find crt1.o at two in the morning. You have built a cross toolchain by
copying somebody's shell script and changing the triple, and it worked, and you
never found out why.
This book is about what is actually in there.
It is not a manual. GCC already has excellent manuals — several of them — and where they cover a mechanism this book tells you which node to read. It is also not a wiki: there is an order to the chapters, each one assumes the ones before it, and each one is about a single mechanism named in its title.
What the book does that the manuals do not is show you the code. Every concrete claim here carries a link to the line of GCC source that proves it, so that when you disagree with a sentence you are one click from settling the argument. GCC's own comments are unusually good, and where a comment explains a decision better than prose could, the comment is quoted rather than paraphrased.
Who this is for
Someone comfortable with C, ELF, readelf, and the general shape of a linker.
You do not need to have read a compiler book. You do not need to know what SSA
is; when it matters, you will be told.
You do not need to build GCC to use most of this book. Nearly every mechanism
described has a command that lets you watch it happen on a compiler you already
have installed — -###, -v, -print-search-dirs, -dumpspecs,
-fdump-tree-all. Chapters that describe something you cannot observe from
outside say so explicitly.
How the source is cited
Every source reference in this book points at an immutable upstream release
tag on the official read-only mirror at github.com/gcc-mirror/gcc. At the
time of writing that tag is releases/gcc-15.2.0, and every line number was read
out of that tag rather than out of anybody's working tree.
Each chapter opens with a note naming its pin and ends with a reminder of it. That matters because line numbers rot: the code around them almost never does, but the numbers themselves move with every patch. If you are reading a GCC 12 tree, the file names alone will differ — see below.
When a mechanism genuinely changed between major releases, rather than merely shifting a few lines down, that is flagged inline, at the point of the claim, so a reader on an older compiler is warned by the sentence they are reading rather than by an appendix they will never reach.
If you are on GCC 11 or earlier, every filename in this book is wrong. GCC 12 renamed nearly every
.cfile in the compiler to.ccin a single commit,5c69acb3(Martin Liska, 2022-01-14). Sogcc.cbecamegcc.cc,gimplify.cbecamegimplify.cc,aarch64.cbecameaarch64.cc. Every pre-12 blog post, mailing-list thread and Stack Overflow answer on the internet uses the old names. Mentally add or drop the secondcas needed.
The shape of the book
Part I, "The driver is not the compiler", is about the program you actually
type. gcc compiles nothing at all; it is a program whose entire job is to
decide which other programs to run and to build each one's command line. That
single fact explains most of what looks arbitrary about GCC from outside, and
Part I is the longest part of the book because almost every path, prefix,
library and header decision lives there.
Part II is about configuring and building GCC itself, and Part III about the specific problem of bootstrapping a cross toolchain, where the compiler and the C library each need the other to exist first.
Part IV goes inside cc1 — the three intermediate representations, the pass
manager, and how a machine description becomes an instruction. Part V covers
the runtime libraries GCC ships. Part VI is about working on GCC as a
project: the testsuite, the conventions, and how a patch gets proposed.
Four things to keep straight from the start
These recur in every part and they are where most published explanations of GCC go wrong.
The driver never opens a library file. It emits -l and -L and lets ld
resolve them. A "library search path" in GCC's sense is a list of strings the
driver hands to the linker, nothing more.
Link-time search and run-time search are unrelated systems. A successful link
says nothing whatever about whether the resulting binary will start. That is
ld.so's business — DT_RUNPATH, ld.so.conf, LD_LIBRARY_PATH — and no
chapter in Part I touches it.
Header search and library search are separate mechanisms. They happen to be relocated by the same prefix, which makes them look like one thing. They are implemented in different files by different code with different sysroot rules.
Anything under libexec/gcc/ is a host program; anything under
<target>/lib/ is a target artifact. A host program runs on your machine. A
target artifact never runs at all on your machine; it only gets linked into what
your compiler produces. Blurring these two makes cross-compilation incoherent,
and Chapter 1.2 is largely about keeping them apart.