【嵌入式】GNU/GCC vs LLVM/Clang

目录

    • [1. GCC vs LLVM/Clang ------ 对比表](#1. GCC vs LLVM/Clang —— 对比表)
      • [GCC vs LLVM/Clang ------ 对比简表](#GCC vs LLVM/Clang —— 对比简表)
    • [2. `compiler` 术语差异](#2. compiler 术语差异)
    • [3. 工程结构](#3. 工程结构)
    • [4. GCC 真实流水线](#4. GCC 真实流水线)
    • [5. LLVM / Clang 真实流水线](#5. LLVM / Clang 真实流水线)
      • [1️⃣ 预处理](#1️⃣ 预处理)
      • [2️⃣ 生成 LLVM IR(关键分歧点)](#2️⃣ 生成 LLVM IR(关键分歧点))
      • [3️⃣ IR 编译 & 优化(可选但真实)](#3️⃣ IR 编译 & 优化(可选但真实))
      • [4️⃣ IR 链接(可选,但常见于 LTO)](#4️⃣ IR 链接(可选,但常见于 LTO))
      • [5️⃣ LLVM IR → 汇编(后端)](#5️⃣ LLVM IR → 汇编(后端))
      • [6️⃣ 汇编](#6️⃣ 汇编)
      • [7️⃣ 链接](#7️⃣ 链接)
    • [6. GCC vs LLVM 流水线并排对照](#6. GCC vs LLVM 流水线并排对照)
    • [7. 一个"现实工程"的关键认知](#7. 一个“现实工程”的关键认知)
      • [为什么 **你平时只敲一行命令**?](#为什么 你平时只敲一行命令?)

1. GCC vs LLVM/Clang ------ 对比表

阶段 GCC 工具 GCC 生成文件 LLVM 工具 LLVM 生成文件 说明
预处理 cpp(gcc 驱动) *.i clang -E *.i 宏与头文件展开
前端解析 cc1 (AST,内部) clang (AST,内部) 语法 / 语义分析
IR 生成 cc1 (GIMPLE/RTL,内部) clang -emit-llvm *.ll / *.bc LLVM IR 可落盘
IR 汇编 无此阶段 --- llvm-as *.bc .ll → .bc(可选)
IR 链接 无此阶段 --- llvm-link combined.bc 多 IR 合并(可选)
IR 优化 cc1 (内部 IR) opt *.opt.ll / *.bc Pass 管线
后端代码生成 cc1 *.s llc *.s 目标相关汇编
汇编 as *.o llvm-mc / as *.o ELF relocatable
静态库打包 ar / gcc-ar lib*.a llvm-ar / llvm-lib lib*.a 归档目标文件
链接 ld(gcc 调用) app lld / ld app 生成可执行文件
启动文件参与 ld crt1.o crti.o crtn.o lld crt*.o 文件被链接,不是工具
运行库参与 ld libc.so libgcc.a lld libc.so compiler-rt 库文件

GCC vs LLVM/Clang ------ 对比简表

复制代码
GCC:
.c → .i → (GIMPLE/RTL) → .s → .o → app
      (黑箱)

LLVM:
.c → .i → .ll/.bc → opt → .s → .o → app
        (文件级接口)

2. compiler 术语差异

GCC 文档里的 "compiler"

在 GCC 语境中:

compiler = gcc 这个驱动程序 + 内部子程序

文档默认假设:
  • 用户调用的是 gcc
  • 所有阶段都是 gcc 帮你协调
  • 内部细节不是 API,而是"实现"

📌 cc1 / cc1plus 在文档里是"实现细节"


LLVM 文档里的 "compiler"

在 LLVM 语境中:

compiler = 一组可以自由组合的工具

例如:

  • clang 只是前端
  • opt 是优化器
  • llc 是后端
  • lld 是链接器

📌 每一个工具都是"一等公民"


根本差异总结

项目 GCC LLVM
compiler 是什么 一个"整体" 一组"模块"
是否强调内部阶段
是否鼓励拆开用 不鼓励 强烈鼓励

GCC vs LLVM/Clang 的真实流水线 + 实际命令 + 生成文件

3. 工程结构

text 复制代码
project/
├── add.h
├── add.c
└── main.c

add.h

c 复制代码
#ifndef ADD_H
#define ADD_H

int add(int a, int b);

#endif

add.c

c 复制代码
#include "add.h"

int add(int a, int b) {
    return a + b;
}

main.c

c 复制代码
#include <stdio.h>
#include "add.h"

int main(void) {
    printf("%d\n", add(2, 3));
    return 0;
}

4. GCC 真实流水线

前提 :x86_64 Linux / macOS

gcc 15.x 行为一致(只是内部 IR 不可见)


1️⃣ 预处理(cpp)

bash 复制代码
gcc -E add.c > add.i
gcc -E main.c > main.i
生成文件
复制代码
add.i
main.i

✔️ 宏展开

✔️ #include 被真正展开

❌ 还不是编译


2️⃣ 编译(前端 + 优化 + 后端)

bash 复制代码
gcc -S add.i -o add.s
gcc -S main.i -o main.s
内部发生了什么(但你看不到文件):
复制代码
C
 → AST
 → GENERIC
 → GIMPLE(SSA)
 → RTL
 → 汇编
生成文件
复制代码
add.s
main.s

📌 GCC 的 IR 全部是"内部态"


3️⃣ 汇编(as)

bash 复制代码
as add.s -o add.o
as main.s -o main.o

(实际是 gcc 调用 as

生成文件
复制代码
add.o
main.o

✔️ ELF relocatable object

✔️ 还不能运行


4️⃣ 链接(ld)

bash 复制代码
gcc main.o add.o -o app
链接时真实参与的东西(重点)
复制代码
工具:
  ld

输入文件:
  main.o
  add.o
  crt1.o crti.o crtn.o
  libc.so
  libgcc.a

输出:
  app

📌 crt*.o 不是工具,是目标文件

📌 libc.so 不是工具,是共享库


5️⃣ 最终产物

bash 复制代码
./app
# 输出: 5

5. LLVM / Clang 真实流水线

LLVM 的关键不同点
IR 是"可见的文件级产物"


1️⃣ 预处理

bash 复制代码
clang -E add.c > add.i
clang -E main.c > main.i

生成:

复制代码
add.i
main.i

(与 GCC 几乎一致)


2️⃣ 生成 LLVM IR(关键分歧点)

bash 复制代码
clang -emit-llvm -S add.i -o add.ll
clang -emit-llvm -S main.i -o main.ll
生成文件
复制代码
add.ll
main.ll

📌 这是 LLVM 的"核心资产"


3️⃣ IR 编译 & 优化(可选但真实)

bash 复制代码
opt -O2 add.ll -o add.opt.bc
opt -O2 main.ll -o main.opt.bc

生成:

复制代码
add.opt.bc
main.opt.bc

4️⃣ IR 链接(可选,但常见于 LTO)

bash 复制代码
llvm-link add.opt.bc main.opt.bc -o all.bc

生成:

复制代码
all.bc

📌 GCC 没有这一阶段


5️⃣ LLVM IR → 汇编(后端)

bash 复制代码
llc all.bc -o all.s

生成:

复制代码
all.s

6️⃣ 汇编

bash 复制代码
llvm-mc -filetype=obj all.s -o all.o

或直接:

bash 复制代码
clang -c all.s -o all.o

生成:

复制代码
all.o

7️⃣ 链接

bash 复制代码
clang all.o -o app
实际链接器
  • 默认:lld
  • 或系统 ld

参与文件:

复制代码
crt*.o
libc.so
compiler-rt

6. GCC vs LLVM 流水线并排对照

阶段 GCC LLVM
预处理 cpp → .i cpp → .i
中间表示 内部(不可见) .ll / .bc
IR 优化 cc1 内部 opt
IR 链接 llvm-link
后端 cc1 llc
汇编 as llvm-mc / as
链接 ld lld / ld

7. 一个"现实工程"的关键认知

为什么 你平时只敲一行命令

bash 复制代码
gcc main.c add.c -o app
clang main.c add.c -o app

因为:

gcc / clang 都是"driver"

它们只是帮你自动执行了:

复制代码
预处理 → 编译 → 汇编 → 链接

GCC 把 main.c + add.c 当成"输入",
LLVM 把它们当成"可拆解的数据流"。


  1. 本节内容已经全部介绍完毕,希望通过这篇文章,大家对 GCCLLVM/Clang 有了更深入的理解和认识。
  2. 感谢各位的阅读和支持,如果觉得这篇文章对你有帮助,请不要吝惜你的点赞和评论 ,这对我们非常重要。再次感谢大家的关注和支持点我关注❤️
相关推荐
切糕师学AI1 天前
ARM汇编器与GNU汇编器:详细介绍与核心区别
arm开发·gnu·汇编器
心态还需努力呀2 天前
【鸿蒙PC命令行适配】GNU Hello 库在鸿蒙 PC 上的交叉编译与移植部署实战
华为·鸿蒙·gnu·openharmony·开源鸿蒙
加强洁西卡2 天前
【RISC-V】riscv64-linux-gnu工具链都有哪些工具
linux·gnu·risc-v
盛邦安全5 天前
漏洞预警 | GNU InetUtils telnetd 远程认证绕过漏洞(CVE-2026-24061)
服务器·gnu
Gobysec8 天前
Goby 漏洞安全通告|GNU InetUtils Telnetd USER环境变量注入 权限绕过漏洞(CVE-2026-24061)
数据库·安全·gnu·漏洞分析·漏洞预警
钮钴禄·爱因斯晨10 天前
操作系统第一章:计算机系统概述
linux·windows·ubuntu·系统架构·centos·鸿蒙系统·gnu
I_belong_to_jesus13 天前
LLVM后端入门8:Subtarget支持
c++·llvm
番茄灭世神15 天前
基于VScode的C/C++环境搭建
vscode·cmake·gcc·c\c++·llvm·工具链搭建
切糕师学AI18 天前
GDB: GNU 调试器
服务器·gnu