GCC


GCC 技术概览

前言

GCC(GNU Compiler Collection)是自由软件基金会旗下最负盛名的项目之一。自 1987 年诞生以来,它已从一个仅支持 C 语言的单一编译器,成长为支持数十种语言、数十个平台的编译器基础设施。作为 GNU 工具链的核心与 Linux 生态的基石,几乎所有 Linux 发行版上的系统软件和用户程序都由 GCC 编译生成。

第一章 历史与现状

1.1 诞生与早期发展

1987 年,Richard Stallman 启动了 GNU C Compiler 项目,为构建 GNU 操作系统提供核心编译工具。该编译器最初仅支持 C 语言,但因其性能优异、自由开放,迅速成为 Unix 世界中最重要的编译器之一。

1.2 EGCS 分叉与变革

1997 年,由于 GCC 官方开发流程过于封闭、代码合并缓慢,一群开发者发起 EGCS(Experimental/Enhanced GNU Compiler System)分叉。EGCS 采用了更开放的开发模式,积极接纳各类语言前端和优化改进。这次分叉深刻改变了 GCC 的命运——1999 年,EGCS 被正式采纳为官方版本,项目同时更名为 GNU Compiler Collection,标志着它从一个单一语言编译器转变为多语言编译器集合。此后 GCC 的发展模式持续开放至今,这直接塑造了其模块化、可扩展的架构设计。

1.3 关键版本里程碑

版本年份里程碑
GCC 1.01987首个公开发布版本
GCC 2.01992加入 C++ 支持
GCC 3.02001统一架构,整合所有语言前端
GCC 4.02005引入 SSA(静态单赋值)优化框架
GCC 5.02015默认 C++ ABI 切换至 C++11 标准
GCC 10.02020全面支持 C++20
GCC 14.02024持续演进中

1.4 版本发布策略

GCC 采用年度主版本发布策略,通常每年上半年发布一个新的主版本号(如 GCC 13、GCC 14)。每个主版本在发布后会进入维护期,持续接收 bug 修复和向后移植。版本号规则为 主版本.次版本.补丁版本,主版本号变化意味着新增语言标准支持、重大优化改进或架构适配。开发者可以通过 gcc -v 查看当前使用的 GCC 版本及其编译配置详情。


第二章 编译器家族

2.1 语言前端一览

GCC 是一个编译器集合,包含多个语言前端命令:

命令语言说明
gccCC 语言编译器
g++C++C++ 语言编译器(自动链接 libstdc++)
gfortranFortran取代旧的 g77
gnatAdaAda 语言编译器
gccgoGoGo 语言编译器
gdcDD 语言编译器
cc1objObjective-CObjective-C 编译器
cc1objplusObjective-C++Objective-C++ 编译器

2.2 支持的语言标准

每个语言前端支持多个版本的语言标准,通过 -std= 选项指定:

语言支持的标准
CC89, C99, C11, C17, C23
C++C++98, C++11, C++14, C++17, C++20, C++23
FortranF77, F90, F95, F2003, F2008, F2018
AdaAda 83, Ada 95, Ada 2005, Ada 2012
GoGo 1
DD 2.0

第三章 支持的平台

GCC 以其广泛的跨平台支持而闻名。通过前后端分离的设计,只需更换后端即可适配新架构。

3.1 处理器架构

  • x86 / x86_64:Intel 和 AMD 主流桌面/服务器处理器
  • ARM (32/64 位):移动设备和嵌入式领域的主导架构
  • AArch64:ARM 64 位架构
  • RISC-V:开源指令集架构,新兴生态系统
  • MIPS:历史悠久,广泛应用于嵌入式与网络设备
  • PowerPC:IBM 体系,用于服务器及嵌入式领域
  • SPARC:Sun/Oracle 服务器架构
  • s390x:IBM 大型机架构
  • LoongArch:国产自主指令集架构

3.2 操作系统

  • GNU/Linux:主要目标平台,支持所有主流发行版
  • Windows:通过 MinGW 或 Cygwin 环境运行
  • macOS:在 Apple 平台上进行本地编译
  • FreeBSD / OpenBSD / NetBSD:BSD 家族系统
  • Solaris:Oracle Solaris 系统

3.3 嵌入式与裸机开发

GCC 可用于裸机(bare-metal)环境下的嵌入式开发,生成不依赖操作系统的固件代码。通过配置适当的 --target 和链接脚本,开发者可以为微控制器等无操作系统环境编译程序。


第四章 核心架构

GCC 采用经典的前端-中端-后端三段式设计。这种模块化分离使其既能支持多种编程语言,又能生成多种目标平台的机器代码。

4.1 整体流程

源码 (Source Code)
前端: 词法分析 → 语法分析 → 语义分析 → 生成抽象语法树 (AST)
GENERIC: 语言无关的 AST 表示
中端优化第一阶段
GIMPLE: 三地址码,控制流简化
GIMPLE SSA: 静态单赋值形式,便于数据流分析
中端优化第二阶段(绝大多数优化在此完成)
RTL (Register Transfer Language): 低层中间表示
后端: 指令选择 → 指令调度 → 寄存器分配 → 汇编生成
汇编代码 (Assembly)

4.2 前端(Front End)

前端负责处理特定语言的源代码,执行词法分析、语法分析和语义分析。不同语言对应不同的前端程序:

前端程序语言
cc1C
cc1plusC++
f951Fortran
go1Go

前端将源代码解析为 AST,再逐步降级为 GENERIC,最终输出 GIMPLE 供中端处理。

4.3 中端(Middle End)

中端是 GCC 优化能力的核心所在。它在 GIMPLE SSA 形式上运行超过 200 个独立的优化 Pass,执行语言和架构无关的变换,包括:

  • 常量传播与折叠
  • 死代码与不可达代码消除
  • 循环优化(展开、向量化、融合、交换)
  • 函数内联
  • 公共子表达式消除
  • 尾调用优化
  • 值域传播与分支预测

4.4 后端(Back End)

后端将优化后的 RTL 映射为目标机器的指令。此阶段处理架构相关任务:

  • 指令选择:从目标指令集中选取最优指令序列
  • 指令调度:重排指令顺序以充分利用 CPU 流水线
  • 寄存器分配:将虚拟寄存器映射到物理寄存器
  • 汇编代码输出

第五章 编译原理基础概念

理解 GCC 的运作需要一些编译器理论基础知识。以下概念将在后续章节中频繁出现,此处做简要定义。

5.1 词法分析

将源代码字符流分解为有意义的 token 序列,如关键字(intreturn)、标识符(变量名、函数名)、字面量(42"hello")、运算符(+=)。

5.2 语法分析

根据语言语法规则,将 token 流组织成树状结构——抽象语法树(AST, Abstract Syntax Tree)。AST 保留了源代码的层级结构。

5.3 语义分析

检查程序的语义正确性:类型是否匹配、变量是否声明、函数调用参数是否合法等,并对 AST 进行必要的标注。

5.4 中间代码生成

将 AST 转换为编译器内部的中间表示(IR),逐步降级到接近机器指令的形式。

5.5 代码优化

在中间表示上进行等价变换,在不改变程序语义的前提下,提升执行效率或缩小代码体积。

5.6 目标代码生成

将优化后的中间表示转换为目标机器的汇编语言或直接生成机器码。


第六章 中间表示体系

GCC 内部使用三层递进式的中间表示,这是其架构的标志性特征。

6.1 GENERIC

GENERIC 是语言无关的 AST 表示。各语言前端将各自语言的 AST 统一转换为 GENERIC,屏蔽了语言差异。它保留了源代码的高层结构,是一个过渡性的表示。

6.2 GIMPLE

GIMPLE 是 GCC 的核心 IR,中端绝大多数优化在此运行。

三地址码:每条 GIMPLE 语句最多包含三个操作数,形式如 t1 = a + b。复杂的表达式被拆解为一系列简单的三地址操作。

控制流简化ifwhilefor 等高阶控制结构被分解为 goto 跳转和基本块。

查看 GIMPLEgcc -fdump-tree-gimple main.c 可将 GIMPLE 以文本形式输出,便于调试和分析优化过程。

6.3 GIMPLE SSA(静态单赋值形式)

SSA(Static Single Assignment)是现代编译器优化的基石。其核心规则是:程序中每个变量在静态文本上只被赋值一次。当控制流汇合时,通过 φ(phi)函数 合并来自不同路径的值。

SSA 的优势

  • 定义-使用链(def-use chain)变得直接且显式
  • 极大简化了死代码消除、常量传播、值域分析等优化算法的实现
  • 节省内存和计算开销

GCC 先将 GIMPLE 转换为 SSA 形式运行大量优化,优化完成后再退出 SSA 形式进入 RTL 阶段。

6.4 RTL(Register Transfer Language)

RTL 是 GCC 最低层的中间表示,接近机器指令。它采用 S-expression(类 Lisp 风格)描述数据从寄存器到寄存器的传输及操作。

RTL 阶段负责:

  • 指令选择(将操作映射为目标机指令)
  • 指令组合(合并相邻指令)
  • 寄存器分配
  • 指令调度

查看 RTLgcc -fdump-rtl-all main.c 可输出各 RTL Pass 的结果。


第七章 基本块与控制流图

7.1 基本块(Basic Block)

基本块是一段顺序执行的指令序列,只有一个入口(第一条指令)和一个出口(最后一条指令),中间不存在跳转指令进入或离开。

7.2 控制流图(CFG)

控制流图以基本块为节点,以跳转关系为有向边。GCC 绝大多数中端优化都构建在 CFG 之上,依赖它进行循环检测、支配关系分析和数据流分析。


第八章 Pass 系统

GCC 的优化不是由一个大型函数完成的,而是由超过 200 个独立的 Pass 组成的管道,按预定顺序依次在 IR 上运行。

8.1 GIMPLE Pass

运行在 GIMPLE SSA 上的优化,执行语言和架构无关的变换:

  • 函数内联、过程间优化(IPA)
  • 循环展开、向量化、融合
  • 公共子表达式消除
  • 死代码消除
  • 别名分析
  • 尾调用优化

8.2 RTL Pass

运行在 RTL 上的优化与准备工作:

  • 指令组合(合并相邻指令以利用复杂指令)
  • 寄存器分配(图着色)
  • 指令调度(流水线优化)
  • Peephole 优化(局部指令模式替换)
  • 延迟槽填充(部分架构)

8.3 查看与调试 Pass

  • 查看 Pass 执行顺序:gcc -O2 -fdump-passes main.c
  • 单独关闭某个 Pass:-fdisable-tree-vrp1-fdisable-rtl-combine
  • 查看某 Pass 前后的 IR 变化:-fdump-tree-all-fdump-rtl-all

第九章 寄存器分配

寄存器分配是将 IR 中无限的虚拟寄存器映射到目标机有限物理寄存器的过程,是编译器后端最关键也最复杂的步骤之一。

9.1 图着色法

将寄存器分配问题建模为图着色问题:构建寄存器冲突图,两个变量若同时存活则存在一条边。用不超过物理寄存器数量的颜色对图着色,若无法完成则需溢出。

9.2 溢出(Spilling)

当物理寄存器不足时,某些变量的值被暂存到栈内存中,使用时再取出。溢出点选择直接影响代码性能。

9.3 GCC 的实现

GCC 采用了改进型的寄存器分配器:

  • IRA(Integrated Register Allocator):集成寄存器分配器,使用优先图着色分配
  • LRA(Local Register Allocator):局部寄存器分配器,在处理复杂约束和溢出时更加鲁棒

第十章 指令选择与调度

10.1 指令选择

将 RTL 操作模式匹配到目标机的具体机器指令。GCC 使用机器描述文件(.md) 声明式地定义指令模板,通过自动工具生成模式匹配代码。

10.2 指令调度

重排指令执行顺序,以充分利用 CPU 的指令流水线,减少因数据冒险、结构冒险导致的停顿(stall)。

10.3 Peephole 优化

在已生成的指令序列上,滑动一个小的观察窗口,识别出低效的模式并替换为更优的等价序列。


第十一章 机器描述文件

GCC 后端不是用 C 代码硬编码的,而是通过机器描述文件(.md 文件)声明式描述目标架构。

机器描述文件包含

  • 指令模板:每条机器指令对应的 RTL 模式
  • 扩展模式:多条指令可合并为一条的优化规则
  • 属性定义:指令延迟、功能单元占用、指令长度等信息,供调度器和优化器使用

GCC 构建过程中会自动处理这些 .md 文件,生成后端代码的绝大部分。这一设计使移植 GCC 到新架构的工作量大幅降低。


第十二章 调用约定与 ABI

GCC 生成的代码必须遵循目标平台的 ABI(Application Binary Interface)和调用约定,以确保不同编译单元、不同语言编译的代码能够正确互操作。

12.1 寄存器使用约定

  • 参数传递寄存器:指定哪些寄存器用于传递函数参数
  • 调用者保存寄存器(caller-saved):调用前后可能被修改,调用者需自行保存
  • 被调用者保存寄存器(callee-saved):被调用者必须在使用前保存原值,返回前恢复

12.2 栈帧布局

  • 参数传递顺序(通常为从右向左压栈)
  • 返回值的存放位置(寄存器或栈)
  • 栈对齐要求(如 x86_64 要求 16 字节对齐)

12.3 名称修饰(Name Mangling)

C++ 的函数重载、模板、命名空间等特性要求将函数名编码为唯一的符号名。GCC 遵循 Itanium C++ ABI 规范进行名称修饰。

12.4 主要支持的 ABI

  • System V AMD64 ABI(x86_64 Linux)
  • ARM EABI / AArch64 ABI
  • 各架构的嵌入式 ABI 变体

第十三章 调试信息

GCC 可将源码级别的调试信息嵌入目标文件中,供 GDB 等调试器使用。

13.1 支持的标准

  • DWARF(主流标准,版本 2/3/4/5):功能丰富,支持复杂类型、宏信息等
  • STABS(老旧格式,已较少使用)
  • CTF / BTF:用于 BPF 等场景的紧凑调试格式

13.2 DWARF 包含的信息

  • 源代码行号到指令地址的映射
  • 变量类型信息及作用域
  • 栈帧描述(用于栈展开和回溯)
  • 调用约定信息

13.3 使用选项

  • -g:生成默认格式调试信息(通常为 DWARF)
  • -ggdb:生成包含 GDB 扩展的调试信息
  • -gdwarf-4:指定 DWARF 版本
  • -fno-omit-frame-pointer:保留帧指针,方便调试和分析

第十四章 异常处理机制

GCC 支持两种异常处理模型,用于 C++ 的 try/catch 及类似机制。

14.1 DWARF 零成本异常处理

正常执行路径完全无额外开销(“零成本”)。异常抛出时,通过 DWARF 的栈展开表(Call Frame Information)逐帧回溯调用栈,调用析构函数并寻找匹配的异常处理器。现代 Linux 平台默认使用此模型。

14.2 SjLj(setjmp/longjmp)异常

基于 C 标准库的 setjmp/longjmp 实现。实现简单,但在正常执行路径中也有记账开销。主要用于部分不支持 DWARF 展开的嵌入式平台。

14.3 栈展开(Stack Unwinding)

当异常被抛出时,运行时系统沿调用栈向上回溯,依次执行各栈帧中的析构函数,直到异常被某个 catch 捕获或程序终止。


第十五章 编译流程

gcc 命令实质是一个编译器驱动(Compiler Driver),它按顺序调用独立工具链组件完成四个阶段:

15.1 预处理

调用 cpp,处理 #include#define#ifdef 等预处理指令,展开宏和头文件。

gcc -E main.c -o main.i

输出:main.i(预处理后的源文件)

15.2 编译

调用语言前端(cc1 等),将预处理后的代码编译为汇编。

gcc -S main.c -o main.s

输出:main.s(汇编代码)

15.3 汇编

调用 as,将汇编代码转换为目标文件。

gcc -c main.c -o main.o

输出:main.o(目标文件)

15.4 链接

调用 collect2(它包装系统链接器 ld),将多个目标文件和库链接为可执行文件。

gcc main.o -o app

输出:app(可执行文件)


第十六章 输出格式

GCC 在编译各阶段可输出不同格式的中间产物:

选项输出文件内容
-E.i / .ii预处理后的源代码(展开所有宏和头文件)
-S.s汇编代码(文本格式)
-c.o目标文件(二进制)
-fdump-tree-gimple.gimpleGIMPLE 中间表示
-fdump-rtl-all.rtl.*RTL 中间表示各阶段

此外,GCC 默认输出的可执行文件为 ELF 格式(Linux),也可配置为 PE(Windows)、Mach-O(macOS)等格式。


第十七章 目标文件结构

目标文件(.o)遵循 ELF(Executable and Linkable Format)格式(Linux 平台),内部包含:

用途
.text编译后的机器指令代码
.data已初始化的全局变量和静态变量
.bss未初始化的全局变量(只在文件头记录大小,不占磁盘空间)
.rodata只读数据(字符串常量、const 全局变量)
符号表记录函数名、变量名及其对应的地址或偏移
重定位表记录需要链接器在最终链接时修正的地址占位符

第十八章 静态库与动态库

GCC 支持生成和使用两种共享代码的方式。

18.1 静态库(.a

将多个目标文件打包为一个存档文件,链接时复制所需代码到可执行文件中。

创建静态库

gcc -c math.c -o math.o
ar rcs libmath.a math.o

使用静态库

gcc main.c -L. -lmath -o app

18.2 动态库(.so

代码在运行时被加载,多个程序可以共享同一份库文件,节省内存和磁盘空间。

创建动态库

gcc -fPIC -c math.c -o math.o
gcc -shared math.o -o libmath.so

使用动态库

gcc main.c -L. -lmath -o app
LD_LIBRARY_PATH=. ./app

18.3 位置无关代码(PIC)与 PLT/GOT

动态库需被加载到不同进程的不同地址空间,因此必须编译为位置无关代码(Position Independent Code),不依赖绝对地址。GCC 通过 -fPIC 选项生成 PIC 代码。动态链接时,PLT(过程链接表)和 GOT(全局偏移量表)配合实现延迟符号绑定。


第十九章 链接过程

19.1 符号解析

链接器将每个符号引用(函数调用、全局变量访问)与其唯一定义进行匹配。未匹配到的引用导致 undefined reference 错误。

19.2 重定位

目标文件中的地址占位符在链接时被替换为最终运行时的绝对或相对地址。

19.3 动态链接

使用动态库时,链接器并不将库代码复制到可执行文件中,而是记录所依赖的共享库名称。程序启动时,动态链接器(ld.so)负责加载所需共享库并完成最终符号绑定。


第二十章 GCC 的自举构建

GCC 采用一种特殊的**三步构建(3-stage bootstrap)**方法编译自身:

  1. Stage 1:用系统已有的编译器编译 GCC 源码,得到初版 GCC
  2. Stage 2:用 Stage 1 编译出的 GCC 重新编译自己的源码,得到 Stage 2 的 GCC
  3. Stage 3:用 Stage 2 的 GCC 再次编译自己,并将输出与 Stage 2 的输出进行二进制对比

三步构建可确保编译器自身被正确编译,同时也能暴露编译器潜在的 bug。两次二进制对比的一致性也是判断构建成功的标志。


第二十一章 运行时库

GCC 生成的可执行文件在运行时依赖若干核心库。

21.1 libgcc

GCC 最底层的运行时库,提供目标 CPU 指令集未直接实现的功能:

  • 64 位整型在 32 位机器上的除法与取模
  • 浮点模拟(无硬件浮点单元时)
  • 异常处理与栈展开基础支持
  • 静态库版本 libgcc.a 和共享库版本 libgcc_s.so

21.2 libstdc++

C++ 标准库实现,g++ 自动链接。提供 STL 容器、算法、IO 流、字符串、线程支持等全部 C++ 标准设施。

21.3 libc

标准 C 库。Linux 上通常使用 GNU C Library(glibc),另有 musl、uClibc 等轻量级实现用于嵌入式场景。


第二十二章 高级特性

22.1 链接时优化(LTO)

传统编译以源文件为单位独立进行,跨文件的函数无法内联。LTO 解决了这一问题。

启用 LTO 时(-flto),编译器将 GIMPLE 中间表示与汇编代码一并存入 .o 文件。在最终链接阶段,链接器读取所有目标文件中的 GIMPLE,整合为一个完整单元,在全局范围内重新运行优化 Pass。

优点:跨文件内联、全局死代码消除、全程序常量传播等激进优化成为可能

缺点:显著增加链接时间和内存消耗

22.2 GCC 插件

GCC 提供插件接口,允许开发者在不修改 GCC 源码的情况下,向编译流水线中注入自定义逻辑。插件可以挂载到 GIMPLE Pass 或 RTL Pass 的各个节点。

典型应用

  • 自定义静态分析规则
  • 代码安全检查
  • 自动化插桩
  • 性能 Profiling 工具开发

22.3 运行时检查(Sanitizers)

通过编译时插入检测代码,在运行时捕获各类错误:

选项检测对象
-fsanitize=address内存错误(缓冲区溢出、use-after-free、内存泄漏)
-fsanitize=thread数据竞争(多线程环境中的竞态条件)
-fsanitize=undefined未定义行为(整数溢出、空指针解引用、非法类型转换等)
-fsanitize=leak内存泄漏检测
-fsanitize=memory未初始化内存读取

22.4 交叉编译

GCC 从设计之初即支持交叉编译,能在一种平台上编译生成在另一种平台上运行的程序。

GCC 区分三个平台概念:

  • 构建平台(build):运行编译器的机器
  • 主机平台(host):编译器自身运行的平台
  • 目标平台(target):生成的可执行文件运行的平台

在交叉编译场景中(build = host ≠ target),只需配置正确的目标后端即可。GCC 通过机器描述文件实现后端的快速移植,这使其成为嵌入式开发领域的工业标准。


第二十三章 配套工具链

23.1 编译过程调用的工具

工具作用
cppC 预处理器
cc1 / cc1plusC/C++ 语言编译器
asGNU 汇编器
collect2链接包装程序,调用 ld
ldGNU 链接器

23.2 二进制工具集(Binutils)

工具功能
ar创建静态库(.a 文件)
ranlib为静态库生成索引
nm列出目标文件中的符号
objdump反汇编目标文件或可执行文件
objcopy复制和转换目标文件格式
strip移除符号表和调试信息,减小体积
readelf解析并显示 ELF 文件详细信息
size显示 ELF 文件各段的大小
strings从二进制文件中提取可打印字符串

第二十四章 常用编译选项速查

24.1 优化级别

选项说明
-O0不优化(默认),编译速度最快
-O1基本优化,平衡编译时间与效果
-O2标准优化级别,包含绝大多数不增加体积的优化
-O3激进优化,包含循环展开、函数内联等
-Os优化代码体积
-Ofast极致优化,忽略严格标准合规(可能改变浮点语义)

24.2 调试与诊断

选项说明
-g生成调试信息
-ggdb生成 GDB 专用调试信息
-Wall启用大多数常见警告
-Wextra启用额外警告
-Werror将所有警告视为错误
-Wpedantic严格遵循语言标准,发出标准合规性警告
-fdiagnostics-color=always彩色输出诊断信息
-fno-omit-frame-pointer保留帧指针

24.3 语言标准

选项说明
-std=c11使用 C11 标准
-std=c++17使用 C++17 标准
-std=c++20使用 C++20 标准

24.4 预处理

选项说明
-I<dir>添加头文件搜索路径
-D<macro>定义宏
-D<macro>=<value>定义带值的宏
-U<macro>取消宏定义

24.5 链接

选项说明
-L<dir>添加库文件搜索路径
-l<lib>链接指定库(如 -lm 链接数学库)
-static静态链接
-shared生成动态库
-fPIC生成位置无关代码
-Wl,<option>向链接器传递选项
-Wl,-rpath=<dir>将运行时库搜索路径嵌入可执行文件

24.6 输出控制

选项说明
-o <file>指定输出文件名
-c只编译和汇编,不链接
-S只编译,生成汇编代码
-E只运行预处理器

第二十五章 常见编译错误速览

错误类型典型信息常见原因
预处理错误fatal error: xxx.h: No such file or directory找不到头文件,使用 -I 指定路径
编译错误expected ';' before ...语法错误,检查上一行代码
编译警告implicit declaration of function ...忘记包含相应头文件
链接错误undefined reference to 'func'函数有声明无定义,或缺少库/目标文件
链接错误multiple definition of ...同一符号被重复定义

第二十六章 与其他编译器的关系

26.1 Clang/LLVM

Clang 是基于 LLVM 后端的 C/C++/Objective-C 编译器。与 GCC 相比,Clang 编译速度通常更快,错误信息更友好,对 IDE 和静态分析工具的支持更好。GCC 的优势在于更成熟的优化能力、更广泛的架构支持以及在 Linux 内核编译等场景的不可替代性。

26.2 MSVC(Microsoft Visual C++)

微软的 C/C++ 编译器,是 Windows 生态的主要编译器。GCC 通过 MinGW 提供了 Windows 平台的替代选择。两者在语法扩展、ABI、标准库实现上存在差异。


第二十七章 与构建系统的配合

GCC 通常不是孤立使用的,它嵌入在更大的开发生态中:

  • make:经典的构建工具,通过 Makefile 组织编译规则
  • CMake:跨平台的元构建系统,可生成 Makefile、Ninja 等
  • Meson:现代、快速的构建系统
  • Autotools:GNU 项目的传统构建系统
  • GDB:GNU 调试器,消费 GCC 生成的 DWARF 调试信息
  • Valgrind:运行时内存分析工具,与 GCC 编译产物配合使用
  • perf / gprof:性能分析工具,利用 GCC 的 -pg-fprofile-arcs 选项生成数据

第二十八章 安装

28.1 通过包管理器安装(以 Ubuntu 为例)

sudo apt update
sudo apt install build-essential gdb binutils
  • build-essential:包含 gccg++makelibc-dev 等基础开发工具
  • gdb:GNU 调试器
  • binutils:包含 ldasobjdump 等二进制工具

验证安装:

gcc --version
g++ --version
gdb --version
ld --version

28.2 安装特定版本

sudo apt install gcc-15 g++-15
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-15 100
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-15 100
sudo update-alternatives --config gcc   # 切换默认版本

28.3 从源码编译安装

适用于需要最新版本或自定义编译配置的场景:

# 下载源码
wget https://ftp.gnu.org/gnu/gcc/gcc-15.1.0/gcc-15.1.0.tar.gz
tar -xzf gcc-15.1.0.tar.gz
cd gcc-15.1.0

# 安装构建依赖
./contrib/download_prerequisites

# 配置与编译
mkdir build && cd build
../configure --prefix=/usr/local/gcc-15.1.0 \
             --enable-languages=c,c++ \
             --disable-multilib
make -j$(nproc)        # 并行编译,充分利用多核
sudo make install

# 添加到 PATH
echo 'export PATH=/usr/local/gcc-15.1.0/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

第二十九章 文档与帮助

29.1 内置帮助

gcc --help                  # 查看所有选项概览
gcc --help=optimizers       # 优化选项
gcc --help=warnings         # 警告选项
gcc --help=target           # 目标平台相关选项
gcc --help=common           # 通用选项

29.2 查看当前启用的选项

gcc -Q -O2 --help=optimizers      # 查看 O2 级别启用的优化
gcc -Q -O3 --help=optimizers      # 与 O3 对比
gcc -Q --help=warnings | grep enabled   # 查看默认启用的警告

29.3 手册页与在线文档

man gcc     # 详尽的手册页
info gcc    # GNU Info 文档

在线文档:https://gcc.gnu.org/onlinedocs


第三十章 许可证与社区

30.1 许可证

GCC 本身使用 GNU 通用公共许可证第三版(GPLv3+)。同时,GCC 的运行时库(libgcc、libstdc++ 等)附带运行时库例外条款(GCC Runtime Library Exception),允许编译生成的非 GPL 程序链接这些库而不被 GPL 传染。

30.2 参与贡献

GCC 的开发依托于开放的社区:

  • 邮件列表gcc@gcc.gnu.org 为主要讨论渠道
  • Bug 跟踪:通过 GCC Bugzilla 报告和跟踪问题
  • 代码仓库:Git 仓库托管于 git://gcc.gnu.org/git/gcc.git
  • 编码规范:遵循 GCC Coding Conventions(主要是 C 语言的 GNU 风格)
  • 版权转让:贡献代码通常需要签署 FSF 版权转让文件

附录:参考资源

GCC Technical Overview

Preface

GCC (GNU Compiler Collection) is one of the most prestigious projects under the Free Software Foundation. Since its inception in 1987, it has grown from a single compiler supporting only the C language into a compiler infrastructure supporting dozens of languages and platforms. As the core of the GNU toolchain and the cornerstone of the Linux ecosystem, virtually all system software and user programs on Linux distributions are compiled by GCC.

Chapter 1: History and Current Status

1.1 Origins and Early Development

In 1987, Richard Stallman launched the GNU C Compiler project to provide a core compilation tool for building the GNU operating system. Initially supporting only the C language, the compiler quickly became one of the most important compilers in the Unix world due to its excellent performance and open, free nature.

1.2 The EGCS Fork and Transformation

In 1997, due to the overly closed official GCC development process and slow code merging, a group of developers initiated the EGCS (Experimental/Enhanced GNU Compiler System) fork. EGCS adopted a more open development model, actively accepting various language front ends and optimization improvements. This fork profoundly changed GCC’s destiny—in 1999, EGCS was officially adopted as the official version, and the project was simultaneously renamed the GNU Compiler Collection, marking its transformation from a single-language compiler to a multi-language compiler collection. Since then, GCC’s development model has remained open to this day, which has directly shaped its modular and extensible architectural design.

1.3 Key Version Milestones

VersionYearMilestone
GCC 1.01987First public release
GCC 2.01992Added C++ support
GCC 3.02001Unified architecture, integrating all language front ends
GCC 4.02005Introduced SSA (Static Single Assignment) optimization framework
GCC 5.02015Default C++ ABI switched to C++11 standard
GCC 10.02020Full C++20 support
GCC 14.02024Continued evolution

1.4 Version Release Strategy

GCC adopts an annual major version release strategy, typically releasing a new major version number (e.g., GCC 13, GCC 14) in the first half of each year. Each major version enters a maintenance period after release, continuously receiving bug fixes and backports. The versioning scheme is major.minor.patch, where a major version change signifies the addition of new language standard support, significant optimization improvements, or architecture adaptations. Developers can use gcc -v to view the currently used GCC version and its compilation configuration details.


Chapter 2: The Compiler Family

2.1 Language Front Ends at a Glance

GCC is a compiler collection that includes multiple language front-end commands:

CommandLanguageDescription
gccCC language compiler
g++C++C++ language compiler (automatically links libstdc++)
gfortranFortranReplaces the old g77
gnatAdaAda language compiler
gccgoGoGo language compiler
gdcDD language compiler
cc1objObjective-CObjective-C compiler
cc1objplusObjective-C++Objective-C++ compiler

2.2 Supported Language Standards

Each language front end supports multiple versions of language standards, specified through the -std= option:

LanguageSupported Standards
CC89, C99, C11, C17, C23
C++C++98, C++11, C++14, C++17, C++20, C++23
FortranF77, F90, F95, F2003, F2008, F2018
AdaAda 83, Ada 95, Ada 2005, Ada 2012
GoGo 1
DD 2.0

Chapter 3: Supported Platforms

GCC is renowned for its extensive cross-platform support. Through its front-end/back-end separation design, adapting to a new architecture only requires replacing the back end.

3.1 Processor Architectures

  • x86 / x86_64: Intel and AMD mainstream desktop/server processors
  • ARM (32/64-bit): Dominant architecture in mobile devices and embedded fields
  • AArch64: ARM 64-bit architecture
  • RISC-V: Open-source instruction set architecture, emerging ecosystem
  • MIPS: Historically significant, widely used in embedded and networking equipment
  • PowerPC: IBM architecture, used in servers and embedded fields
  • SPARC: Sun/Oracle server architecture
  • s390x: IBM mainframe architecture
  • LoongArch: Domestic independent instruction set architecture

3.2 Operating Systems

  • GNU/Linux: Primary target platform, supports all major distributions
  • Windows: Runs via MinGW or Cygwin environments
  • macOS: Native compilation on Apple platforms
  • FreeBSD / OpenBSD / NetBSD: BSD family systems
  • Solaris: Oracle Solaris system

3.3 Embedded and Bare-Metal Development

GCC can be used for bare-metal embedded development, generating firmware code that does not depend on an operating system. By configuring an appropriate --target and linker script, developers can compile programs for OS-less environments such as microcontrollers.


Chapter 4: Core Architecture

GCC adopts the classic front-end–middle-end–back-end three-stage design. This modular separation enables it to support multiple programming languages while generating machine code for multiple target platforms.

4.1 Overall Flow

Source Code
Front End: Lexical Analysis → Syntax Analysis → Semantic Analysis → Generate Abstract Syntax Tree (AST)
GENERIC: Language-independent AST representation
Middle-End Optimization Phase 1
GIMPLE: Three-address code, simplified control flow
GIMPLE SSA: Static Single Assignment form, facilitating data flow analysis
Middle-End Optimization Phase 2 (The vast majority of optimizations are completed here)
RTL (Register Transfer Language): Low-level intermediate representation
Back End: Instruction Selection → Instruction Scheduling → Register Allocation → Assembly Generation
Assembly Code

4.2 Front End

The front end is responsible for processing source code of a specific language, performing lexical analysis, syntax analysis, and semantic analysis. Different languages correspond to different front-end programs:

Front-End ProgramLanguage
cc1C
cc1plusC++
f951Fortran
go1Go

The front end parses source code into an AST, then gradually lowers it to GENERIC, and finally outputs GIMPLE for processing by the middle end.

4.3 Middle End

The middle end is the core of GCC’s optimization capabilities. It runs over 200 independent optimization passes on the GIMPLE SSA form, performing language- and architecture-independent transformations, including:

  • Constant propagation and folding
  • Dead code and unreachable code elimination
  • Loop optimizations (unrolling, vectorization, fusion, interchange)
  • Function inlining
  • Common subexpression elimination
  • Tail call optimization
  • Value range propagation and branch prediction

4.4 Back End

The back end maps the optimized RTL to instructions for the target machine. This stage handles architecture-dependent tasks:

  • Instruction selection: Selecting the optimal instruction sequence from the target instruction set
  • Instruction scheduling: Reordering instructions to fully utilize the CPU pipeline
  • Register allocation: Mapping virtual registers to physical registers
  • Assembly code output

Chapter 5: Fundamental Compilation Concepts

Understanding GCC’s operation requires some basic knowledge of compiler theory. The following concepts will frequently appear in subsequent chapters and are briefly defined here.

5.1 Lexical Analysis

Decomposes the source code character stream into a meaningful sequence of tokens, such as keywords (int, return), identifiers (variable names, function names), literals (42, "hello"), and operators (+, =).

5.2 Syntax Analysis

Organizes the token stream into a tree-like structure—the Abstract Syntax Tree (AST)—according to language grammar rules. The AST preserves the hierarchical structure of the source code.

5.3 Semantic Analysis

Checks the semantic correctness of the program: whether types match, whether variables are declared, whether function call arguments are legal, etc., and annotates the AST as necessary.

5.4 Intermediate Code Generation

Converts the AST into the compiler’s internal Intermediate Representation (IR), gradually lowering it to a form closer to machine instructions.

5.5 Code Optimization

Performs equivalent transformations on the intermediate representation to improve execution efficiency or reduce code size without changing program semantics.

5.6 Target Code Generation

Converts the optimized intermediate representation into assembly language for the target machine or directly generates machine code.


Chapter 6: Intermediate Representation System

GCC internally uses a three-tier progressive Intermediate Representation, which is a hallmark feature of its architecture.

6.1 GENERIC

GENERIC is a language-independent AST representation. Each language front end uniformly converts its language-specific AST into GENERIC, masking language differences. It retains the high-level structure of the source code and serves as a transitional representation.

6.2 GIMPLE

GIMPLE is GCC’s core IR, where the vast majority of middle-end optimizations run.

Three-Address Code: Each GIMPLE statement contains at most three operands, in the form t1 = a + b. Complex expressions are broken down into a series of simple three-address operations.

Control Flow Simplification: High-level control structures like if, while, and for are decomposed into goto jumps and basic blocks.

Viewing GIMPLE: gcc -fdump-tree-gimple main.c outputs GIMPLE in text form, facilitating debugging and analysis of the optimization process.

6.3 GIMPLE SSA (Static Single Assignment Form)

SSA (Static Single Assignment) is the cornerstone of modern compiler optimization. Its core rule is: each variable in the program is assigned exactly once statically in the text. When control flow merges, values from different paths are combined through φ (phi) functions.

Advantages of SSA:

  • Def-use chains become direct and explicit
  • Greatly simplifies the implementation of optimization algorithms such as dead code elimination, constant propagation, and value range analysis
  • Saves memory and computational overhead

GCC first converts GIMPLE into SSA form to run extensive optimizations, then exits SSA form after optimization is complete to enter the RTL phase.

6.4 RTL (Register Transfer Language)

RTL is GCC’s lowest-level intermediate representation, close to machine instructions. It uses S-expressions (Lisp-like style) to describe data transfers and operations from register to register.

The RTL phase is responsible for:

  • Instruction selection (mapping operations to target machine instructions)
  • Instruction combination (merging adjacent instructions)
  • Register allocation
  • Instruction scheduling

Viewing RTL: gcc -fdump-rtl-all main.c outputs the results of each RTL pass.


Chapter 7: Basic Blocks and Control Flow Graph

7.1 Basic Block

A basic block is a sequence of instructions executed sequentially, with only one entry (the first instruction) and one exit (the last instruction), with no jump instructions entering or leaving in the middle.

7.2 Control Flow Graph (CFG)

The Control Flow Graph uses basic blocks as nodes and jump relationships as directed edges. The vast majority of GCC’s middle-end optimizations are built upon the CFG, relying on it for loop detection, dominance relationship analysis, and data flow analysis.


Chapter 8: The Pass System

GCC’s optimizations are not performed by a single large function but by a pipeline of over 200 independent Passes run on the IR in a predetermined order.

8.1 GIMPLE Passes

Optimizations running on GIMPLE SSA, performing language- and architecture-independent transformations:

  • Function inlining, Inter-Procedural Analysis (IPA)
  • Loop unrolling, vectorization, fusion
  • Common subexpression elimination
  • Dead code elimination
  • Alias analysis
  • Tail call optimization

8.2 RTL Passes

Optimizations and preparations running on RTL:

  • Instruction combination (merging adjacent instructions to exploit complex instructions)
  • Register allocation (graph coloring)
  • Instruction scheduling (pipeline optimization)
  • Peephole optimization (local instruction pattern replacement)
  • Delay slot filling (on some architectures)

8.3 Viewing and Debugging Passes

  • View pass execution order: gcc -O2 -fdump-passes main.c
  • Disable a specific pass individually: -fdisable-tree-vrp1, -fdisable-rtl-combine
  • View IR changes before and after a pass: -fdump-tree-all, -fdump-rtl-all

Chapter 9: Register Allocation

Register allocation is the process of mapping the infinite virtual registers in the IR to the limited physical registers of the target machine. It is one of the most critical and complex steps in the compiler back end.

9.1 Graph Coloring Method

Models the register allocation problem as a graph coloring problem: build an interference graph, where two variables have an edge if they are simultaneously live. Color the graph using no more colors than the number of physical registers; if coloring is impossible, spilling is required.

9.2 Spilling

When physical registers are insufficient, the values of certain variables are temporarily stored in stack memory and retrieved when needed. The choice of spill points directly impacts code performance.

9.3 GCC’s Implementation

GCC employs improved register allocators:

  • IRA (Integrated Register Allocator): Uses priority-based graph coloring allocation
  • LRA (Local Register Allocator): More robust in handling complex constraints and spilling

Chapter 10: Instruction Selection and Scheduling

10.1 Instruction Selection

Matches RTL operation patterns to specific machine instructions for the target. GCC uses Machine Description files (.md) to declaratively define instruction templates, generating pattern matching code through automated tools.

10.2 Instruction Scheduling

Reorders instruction execution sequences to fully utilize the CPU’s instruction pipeline, reducing stalls caused by data hazards and structural hazards.

10.3 Peephole Optimization

Slides a small observation window over the generated instruction sequence, identifying inefficient patterns and replacing them with superior equivalent sequences.


Chapter 11: Machine Description Files

The GCC back end is not hardcoded in C; instead, the target architecture is declaratively described through Machine Description files (.md files).

Machine Description Files Contain:

  • Instruction Templates: RTL patterns corresponding to each machine instruction
  • Expansion Patterns: Optimization rules for merging multiple instructions into one
  • Attribute Definitions: Information such as instruction latency, functional unit occupation, and instruction length, used by the scheduler and optimizer

During the GCC build process, these .md files are automatically processed to generate the vast majority of the back-end code. This design significantly reduces the effort required to port GCC to a new architecture.


Chapter 12: Calling Conventions and ABI

Code generated by GCC must adhere to the target platform’s ABI (Application Binary Interface) and calling conventions to ensure correct interoperability between code compiled from different compilation units and different languages.

12.1 Register Usage Conventions

  • Parameter passing registers: Specifies which registers are used to pass function arguments
  • Caller-saved registers: May be modified across calls; the caller must save them if needed
  • Callee-saved registers: The callee must save the original values before use and restore them before returning

12.2 Stack Frame Layout

  • Parameter passing order (typically pushed right-to-left)
  • Location of the return value (register or stack)
  • Stack alignment requirements (e.g., x86_64 requires 16-byte alignment)

12.3 Name Mangling

C++ features such as function overloading, templates, and namespaces require encoding function names into unique symbol names. GCC follows the Itanium C++ ABI specification for name mangling.

12.4 Major Supported ABIs

  • System V AMD64 ABI (x86_64 Linux)
  • ARM EABI / AArch64 ABI
  • Various embedded ABI variants for different architectures

Chapter 13: Debug Information

GCC can embed source-level debugging information into object files for use by debuggers like GDB.

13.1 Supported Standards

  • DWARF (Mainstream standard, versions 2/3/4/5): Feature-rich, supports complex types, macro information, etc.
  • STABS (Older format, now less commonly used)
  • CTF / BTF: Compact debugging formats used in scenarios like BPF

13.2 Information Contained in DWARF

  • Mapping of source code line numbers to instruction addresses
  • Variable type information and scope
  • Stack frame descriptions (for stack unwinding and backtracing)
  • Calling convention information

13.3 Usage Options

  • -g: Generate default format debug information (usually DWARF)
  • -ggdb: Generate debug information including GDB extensions
  • -gdwarf-4: Specify DWARF version
  • -fno-omit-frame-pointer: Preserve the frame pointer, facilitating debugging and profiling

Chapter 14: Exception Handling Mechanisms

GCC supports two exception handling models, used for C++ try/catch and similar mechanisms.

14.1 DWARF Zero-Cost Exception Handling

The normal execution path has absolutely no additional overhead (“zero cost”). When an exception is thrown, the call stack is unwound frame by frame using DWARF Call Frame Information tables, calling destructors and searching for a matching exception handler. This is the default model on modern Linux platforms.

14.2 SjLj (setjmp/longjmp) Exceptions

Implemented based on the C standard library’s setjmp/longjmp. Simple to implement, but incurs bookkeeping overhead even on the normal execution path. Mainly used on some embedded platforms that do not support DWARF unwinding.

14.3 Stack Unwinding

When an exception is thrown, the runtime system traces back up the call stack, executing destructors in each stack frame in turn, until the exception is caught by a catch block or the program terminates.


Chapter 15: Compilation Process

The gcc command is essentially a Compiler Driver that sequentially invokes independent toolchain components to complete four stages:

15.1 Preprocessing

Invokes cpp, processing preprocessing directives like #include, #define, #ifdef, expanding macros and header files.

gcc -E main.c -o main.i

Output: main.i (preprocessed source file)

15.2 Compilation

Invokes the language front end (cc1, etc.) to compile the preprocessed code into assembly.

gcc -S main.c -o main.s

Output: main.s (assembly code)

15.3 Assembly

Invokes as to convert assembly code into an object file.

gcc -c main.c -o main.o

Output: main.o (object file)

15.4 Linking

Invokes collect2 (which wraps the system linker ld) to link multiple object files and libraries into an executable.

gcc main.o -o app

Output: app (executable file)


Chapter 16: Output Formats

GCC can output intermediate products in different formats during various compilation stages:

OptionOutput FileContent
-E.i / .iiPreprocessed source code (all macros and headers expanded)
-S.sAssembly code (text format)
-c.oObject file (binary)
-fdump-tree-gimple.gimpleGIMPLE intermediate representation
-fdump-rtl-all.rtl.*Various stages of RTL intermediate representation

Furthermore, the default executable format output by GCC is ELF (Linux), but it can also be configured for PE (Windows), Mach-O (macOS), and other formats.


Chapter 17: Object File Structure

Object files (.o) follow the ELF (Executable and Linkable Format) format (on Linux platforms), internally containing:

SectionPurpose
.textCompiled machine instruction code
.dataInitialized global and static variables
.bssUninitialized global variables (only records size in the file header, occupies no disk space)
.rodataRead-only data (string constants, const global variables)
Symbol TableRecords function names, variable names, and their corresponding addresses or offsets
Relocation TableRecords address placeholders that need the linker to fix during final linking

Chapter 18: Static and Dynamic Libraries

GCC supports generating and using code in two shared forms.

18.1 Static Libraries (.a)

Packages multiple object files into a single archive file; required code is copied into the executable during linking.

Creating a static library:

gcc -c math.c -o math.o
ar rcs libmath.a math.o

Using a static library:

gcc main.c -L. -lmath -o app

18.2 Dynamic Libraries (.so)

Code is loaded at runtime; multiple programs can share the same library file, saving memory and disk space.

Creating a dynamic library:

gcc -fPIC -c math.c -o math.o
gcc -shared math.o -o libmath.so

Using a dynamic library:

gcc main.c -L. -lmath -o app
LD_LIBRARY_PATH=. ./app

18.3 Position-Independent Code (PIC) and PLT/GOT

Dynamic libraries must be loaded into different address spaces of different processes, and thus must be compiled as Position-Independent Code, not relying on absolute addresses. GCC generates PIC code via the -fPIC option. During dynamic linking, the PLT (Procedure Linkage Table) and GOT (Global Offset Table) cooperate to implement lazy symbol binding.


Chapter 19: The Linking Process

19.1 Symbol Resolution

The linker matches each symbol reference (function call, global variable access) with its unique definition. Unmatched references result in an undefined reference error.

19.2 Relocation

Address placeholders in object files are replaced with final runtime absolute or relative addresses during linking.

19.3 Dynamic Linking

When using dynamic libraries, the linker does not copy library code into the executable but records the names of the dependent shared libraries. When the program starts, the dynamic linker (ld.so) is responsible for loading the required shared libraries and performing the final symbol binding.


Chapter 20: GCC’s Bootstrap Build

GCC uses a special 3-stage bootstrap method to compile itself:

  1. Stage 1: Compile GCC source code using the system’s existing compiler to produce an initial GCC
  2. Stage 2: Recompile its own source code using the GCC compiled in Stage 1 to produce the Stage 2 GCC
  3. Stage 3: Compile itself again using the Stage 2 GCC and compare the output binary with the Stage 2 output

The 3-stage build ensures the compiler itself is correctly compiled and can also expose potential compiler bugs. The consistency of the two binary comparisons is also a sign of a successful build.


Chapter 21: Runtime Libraries

Executables generated by GCC depend on several core libraries at runtime.

21.1 libgcc

GCC’s lowest-level runtime library, providing functionality not directly implemented by the target CPU instruction set:

  • 64-bit integer division and modulo on 32-bit machines
  • Floating-point emulation (when no hardware floating-point unit is present)
  • Basic support for exception handling and stack unwinding
  • Available in a static library version libgcc.a and shared library version libgcc_s.so

21.2 libstdc++

The C++ standard library implementation, automatically linked by g++. Provides all C++ standard facilities including STL containers, algorithms, IO streams, strings, and thread support.

21.3 libc

The standard C library. On Linux, GNU C Library (glibc) is commonly used, with lightweight implementations like musl and uClibc available for embedded scenarios.


Chapter 22: Advanced Features

Traditional compilation is performed independently per source file, preventing cross-file function inlining. LTO solves this problem.

When LTO is enabled (-flto), the compiler stores the GIMPLE intermediate representation alongside the assembly code in the .o file. During the final linking phase, the linker reads the GIMPLE from all object files, integrates them into a single whole unit, and re-runs optimization passes on a global scale.

Advantages: Enables aggressive optimizations such as cross-file inlining, global dead code elimination, and whole-program constant propagation

Disadvantages: Significantly increases linking time and memory consumption

22.2 GCC Plugins

GCC provides a plugin interface, allowing developers to inject custom logic into the compilation pipeline without modifying the GCC source code. Plugins can hook into various points of the GIMPLE passes or RTL passes.

Typical Applications:

  • Custom static analysis rules
  • Code security checks
  • Automated instrumentation
  • Performance profiling tool development

22.3 Runtime Checking (Sanitizers)

Catches various errors at runtime by inserting detection code during compilation:

OptionDetection Target
-fsanitize=addressMemory errors (buffer overflow, use-after-free, memory leaks)
-fsanitize=threadData races (race conditions in multi-threaded environments)
-fsanitize=undefinedUndefined behavior (integer overflow, null pointer dereference, illegal type casts, etc.)
-fsanitize=leakMemory leak detection
-fsanitize=memoryUninitialized memory reads

22.4 Cross-Compilation

GCC was designed from the start to support cross-compilation, capable of compiling programs on one platform to run on another.

GCC distinguishes three platform concepts:

  • Build platform: The machine running the compiler
  • Host platform: The platform the compiler itself runs on
  • Target platform: The platform the generated executable runs on

In cross-compilation scenarios (build = host ≠ target), only the correct target back end needs to be configured. GCC enables rapid back-end porting through Machine Description files, making it the industry standard in the embedded development field.


Chapter 23: Supporting Toolchain

23.1 Tools Invoked During Compilation

ToolFunction
cppC Preprocessor
cc1 / cc1plusC/C++ Language Compiler
asGNU Assembler
collect2Linker wrapper program, invokes ld
ldGNU Linker

23.2 Binary Utilities (Binutils)

ToolFunction
arCreate static libraries (.a files)
ranlibGenerate index for static libraries
nmList symbols in object files
objdumpDisassemble object files or executables
objcopyCopy and convert object file formats
stripRemove symbol table and debug information, reduce size
readelfParse and display detailed ELF file information
sizeDisplay the sizes of sections in an ELF file
stringsExtract printable strings from binary files

Chapter 24: Quick Reference for Common Compilation Options

24.1 Optimization Levels

OptionDescription
-O0No optimization (default), fastest compilation speed
-O1Basic optimization, balances compilation time and effect
-O2Standard optimization level, includes most optimizations that do not increase size
-O3Aggressive optimization, includes loop unrolling, function inlining, etc.
-OsOptimize for code size
-OfastExtreme optimization, disregards strict standard compliance (may alter floating-point semantics)

24.2 Debugging and Diagnostics

OptionDescription
-gGenerate debug information
-ggdbGenerate GDB-specific debug information
-WallEnable most common warnings
-WextraEnable extra warnings
-WerrorTreat all warnings as errors
-WpedanticStrictly follow the language standard, issue standard compliance warnings
-fdiagnostics-color=alwaysColored diagnostic output
-fno-omit-frame-pointerPreserve frame pointer

24.3 Language Standards

OptionDescription
-std=c11Use the C11 standard
-std=c++17Use the C++17 standard
-std=c++20Use the C++20 standard

24.4 Preprocessing

OptionDescription
-I<dir>Add header file search path
-D<macro>Define a macro
-D<macro>=<value>Define a macro with a value
-U<macro>Undefine a macro

24.5 Linking

OptionDescription
-L<dir>Add library search path
-l<lib>Link specified library (e.g., -lm links the math library)
-staticStatic linking
-sharedGenerate a dynamic library
-fPICGenerate Position-Independent Code
-Wl,<option>Pass an option to the linker
-Wl,-rpath=<dir>Embed runtime library search path into the executable

24.6 Output Control

OptionDescription
-o <file>Specify output file name
-cCompile and assemble only, do not link
-SCompile only, generate assembly code
-ERun only the preprocessor

Chapter 25: Common Compilation Errors at a Glance

Error TypeTypical MessageCommon Cause
Preprocessing Errorfatal error: xxx.h: No such file or directoryHeader file not found, use -I to specify the path
Compilation Errorexpected ';' before ...Syntax error, check the preceding line of code
Compilation Warningimplicit declaration of function ...Forgot to include the corresponding header file
Linker Errorundefined reference to 'func'Function declared but not defined, or missing library/object file
Linker Errormultiple definition of ...The same symbol was defined repeatedly

Chapter 26: Relationship with Other Compilers

26.1 Clang/LLVM

Clang is a C/C++/Objective-C compiler based on the LLVM back end. Compared to GCC, Clang typically compiles faster, provides friendlier error messages, and offers better support for IDEs and static analysis tools. GCC’s advantages lie in its more mature optimization capabilities, broader architecture support, and irreplaceability in scenarios like Linux kernel compilation.

26.2 MSVC (Microsoft Visual C++)

Microsoft’s C/C++ compiler, the primary compiler for the Windows ecosystem. GCC provides an alternative for the Windows platform through MinGW. The two differ in syntax extensions, ABI, and standard library implementations.


Chapter 27: Integration with Build Systems

GCC is typically not used in isolation; it is embedded within a larger development ecosystem:

  • make: The classic build tool, organizing compilation rules via Makefiles
  • CMake: A cross-platform meta-build system that can generate Makefiles, Ninja, etc.
  • Meson: A modern, fast build system
  • Autotools: The traditional build system for GNU projects
  • GDB: The GNU Debugger, consumes DWARF debug information generated by GCC
  • Valgrind: A runtime memory analysis tool, works with binaries compiled by GCC
  • perf / gprof: Performance analysis tools, utilize GCC’s -pg or -fprofile-arcs options to generate data

Chapter 28: Installation

28.1 Installation via Package Manager (using Ubuntu as an example)

sudo apt update
sudo apt install build-essential gdb binutils
  • build-essential: Includes basic development tools such as gcc, g++, make, libc-dev
  • gdb: GNU Debugger
  • binutils: Includes binary tools like ld, as, objdump

Verify installation:

gcc --version
g++ --version
gdb --version
ld --version

28.2 Installing a Specific Version

sudo apt install gcc-15 g++-15
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-15 100
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-15 100
sudo update-alternatives --config gcc   # Switch default version

28.3 Compiling and Installing from Source

Suitable for scenarios requiring the latest version or custom build configurations:

# Download source
wget https://ftp.gnu.org/gnu/gcc/gcc-15.1.0/gcc-15.1.0.tar.gz
tar -xzf gcc-15.1.0.tar.gz
cd gcc-15.1.0

# Install build dependencies
./contrib/download_prerequisites

# Configure and build
mkdir build && cd build
../configure --prefix=/usr/local/gcc-15.1.0 \
             --enable-languages=c,c++ \
             --disable-multilib
make -j$(nproc)        # Parallel build, fully utilizes multiple cores
sudo make install

# Add to PATH
echo 'export PATH=/usr/local/gcc-15.1.0/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

Chapter 29: Documentation and Help

29.1 Built-in Help

gcc --help                  # View overview of all options
gcc --help=optimizers       # Optimization options
gcc --help=warnings         # Warning options
gcc --help=target           # Target platform-related options
gcc --help=common           # Common options

29.2 Checking Currently Enabled Options

gcc -Q -O2 --help=optimizers      # View optimizations enabled at O2 level
gcc -Q -O3 --help=optimizers      # Compare with O3
gcc -Q --help=warnings | grep enabled   # View default enabled warnings

29.3 Man Pages and Online Documentation

man gcc     # Detailed man page
info gcc    # GNU Info documentation

Online documentation: https://gcc.gnu.org/onlinedocs


Chapter 30: License and Community

30.1 License

GCC itself uses the GNU General Public License version 3 (GPLv3+). Additionally, GCC’s runtime libraries (libgcc, libstdc++, etc.) come with the GCC Runtime Library Exception, allowing compiled non-GPL programs to link against these libraries without the GPL propagating.

30.2 Contributing

GCC’s development relies on an open community:

  • Mailing List: gcc@gcc.gnu.org is the primary discussion channel
  • Bug Tracking: Report and track issues via GCC Bugzilla
  • Code Repository: Git repository hosted at git://gcc.gnu.org/git/gcc.git
  • Coding Standards: Follow the GCC Coding Conventions (primarily GNU style for C)
  • Copyright Assignment: Submitting code usually requires signing an FSF copyright assignment

Appendix: Reference Resources