clang、opt、llc、llvm-mc、llvm-objdump、lld 分别做什么

作者:

在

作者:lihao技术文章发布:LLVM 与异构编译器 · 第 06 期

沿着一个可运行的 C++ 例子,检查 Clang、opt、llc、llvm-mc、llvm-objdump 与 LLD 的输入输出,区分驱动、IR 变换、代码生成、汇编和链接。

先按输入、输出找工具

前五期已经分清构建阶段、文件格式和编译器分层。真正开始排查问题时,还有一道坎:安装目录里有这么多程序,究竟该运行哪一个?先看手里的输入是什么,再决定停在哪里,比背一串工具名更管用。

工具本例输入 → 输出要解决的问题
clang / clang++C/C++ → IR、汇编、目标文件或可执行程序驱动工具链;停止位置由选项决定
optLLVM IR → LLVM IR,或分析信息单独观察分析与变换
llcLLVM IR → 目标汇编或目标文件观察目标代码生成
llvm-mc目标汇编 → 原生目标文件(本例)单独检查汇编器这一段
llvm-objdump目标文件 → 反汇编等检查结果查看已编码的指令和文件信息
LLD目标文件、库等 → 链接结果解析符号、布局与重定位;本文使用ELF入口ld.lld

这不是六个每次都要独立启动的步骤。Clang 驱动通常调用集成的编译、汇编功能,并组织链接;它不会为了完成普通编译而依次启动 opt、llc 和 llvm-mc。下面刻意拆开,是为了得到清楚的观察边界。

让同一个函数穿过这些边界

实验环境:Ubuntu 24.04.4(WSL2,x86-64),Clang/LLVM 18.1.3,GNU binutils 2.42。

准备 twice.cpp:

extern "C" unsigned twice(unsigned x) { return x * 2u + 0u; }

再准备 main.cpp:

extern "C" unsigned twice(unsigned);
int main() { return twice(21u) == 42u ? 0 : 1; }

使用 unsigned,是为了让这里的整数回绕有明确定义。extern "C"便于识别符号名,并没有把这份源文件改成 C 语言。先记录工具版本:

clang++-18 --version
opt-18 --version
llc-18 --version
llvm-mc-18 --version
llvm-objdump-18 --version

下面以 LLD保存实际链接器路径。若已安装 Ubuntu 的 lld-18,可用下面的查找方式;否则把变量设为你已安装的 ld.lld绝对路径。本次用的是从 Ubuntu 官方 lld-18 软件包解压出的 18.1.3,不是系统原先就有的命令。

LLD="$(command -v ld.lld-18)"
test -n "$LLD" || { echo "请先配置 LLD 路径"; exit 1; }
"$LLD" --version

从源码生成 IR,再分别变换、生成汇编和汇编成目标文件:

clang++-18 -std=c++17 -O1 -S -emit-llvm twice.cpp -o twice.ll
opt-18 -passes=instcombine -S twice.ll -o checked.ll
llc-18 -mtriple=x86_64-pc-linux-gnu -filetype=asm checked.ll -o twice.s
llvm-mc-18 -triple=x86_64-pc-linux-gnu -filetype=obj twice.s -o twice.o
llvm-objdump-18 -d twice.o
readelf -h twice.o

本次 twice.o 是 ELF 可重定位文件;函数反汇编中可以看到 leal (%rdi,%rdi), %eax和返回指令。不同版本、目标和选项可能生成不同指令,不能要求所有机器都与这两行一致。

clang++-18 -c main.cpp -o main.o
clang++-18 "-fuse-ld=$LLD" main.o twice.o -o demo
./demo
printf 'exit=%s\n' "$?"
readelf -p .comment demo

本次程序退出码为 0,意味着入口函数的检查通过;.comment中也记录了 LLD 18.1.3。这里仍由 clang++ 组织链接,因为它知道怎样为当前平台补入启动文件、标准库和其他默认参数。直接调用 ld.lld 并非不允许,但需要自己提供这些条件。

LLD 不是“只把字节拼在一起”。符号引用需要找到定义,重定位需要结合最终布局处理;缺库、架构不兼容、ABI 不匹配也不是换一个链接器名称就能自动解决的。LTO 还可能让链接过程参与 IR 优化与代码生成,本文没有把这一条路径混入普通目标文件实验。

同一个选项,要结合它属于哪个工具理解

命令停在哪里
clang++ -E预处理文本
clang++ -S目标汇编
clang++ -S -emit-llvm文本 LLVM IR
clang++ -c目标文件;若启用LTO,仍须检查实际格式
opt -S把处理后的IR写成文本
llc -filetype=obj直接生成原生目标文件

尤其别把 opt -S和 clang++ -S当成同一件事:前者写文本 IR,后者通常写目标汇编。选项名相同,只说明命令行恰好复用了字母。

clang++-18 -std=c++17 -O1 -### twice.cpp main.cpp -o planned

-###只打印驱动准备执行的任务,不执行这些任务。本次检查了这个计划,但没有把它记成已经生成了 planned。若想验证产物,要真正运行构建并检查文件。

三种失败,各有明确的边界

有意构造的输入本次结果说明
把 twice.o 交给 opt -S非零退出ELF原生目标文件不是LLVM IR输入
把无效指令写入 bad.s,交给 llvm-mc非零退出汇编器不接受该目标指令
链接时只给 main.o,省略 twice.o未定义符号 twice;非零退出声明存在不代表链接时已有定义

这些失败应保留命令和诊断,不能剪成“工具坏了”。如果 Clang 已经报语法错误,就先修输入;如果只到链接才报未定义符号,就从链接输入、库顺序与符号定义查起。阶段边界能缩小范围,但不是在证据不足时给某一组件定责。

对生态兼容的实际帮助

当你接入另一种目标平台时,这张表能变成检查清单:前端能否生成所需 IR;目标后端能否接受它;生成的目标文件是否符合平台 ABI;链接器、运行库和加载环境能否配合。每一项都应有单独的输入、输出和失败例子。

本次只验证一个 Linux x86-64 小程序。程序能运行不等于完整 C++ 生态兼容,更不代表国产 CPU、GPU 或 NPU 已经接入。它提供的是可以逐层定位问题的办法。

把工具输出当证据,必须先知道它没有检查什么

llvm-objdump解码出指令,不等于证明这些字节在运行路径上一定会执行;符号或节中也可能混有数据,反汇编还受目标与特性解释影响。readelf显示对象结构,不执行程序。opt接受IR,不意味着目标后端接受其中全部操作。

llc输出原生目标文件可以省掉显式.s文件,但并未取消目标选择、编码与对象格式的责任。llvm-mc适合隔离汇编层问题,它也不会替你检查高级语言的类型和业务预期。工具选择的原则是把待检命题交给覆盖该命题的观察方式。

例如本例反汇编出现lea,可以确认当前目标产物采用这一编码形式;要进一步声称“它比shift快”,还需要目标微架构、上下文与测量。一个助记符本身没有跨硬件通用的性能排名。

因此建议在记录中同时写输入身份、工具版本、命令、输出与检查目的。只有“截图里出现了文件名”,不够证明命令消费的是正确版本的输入,也不够支持运行与性能结论。

同一套命令移到另一台机器,先检查哪些依赖

driver发现的GCC安装、标准库头文件、默认链接器与启动对象可能不同。即使clang++版本一致,sysroot、-target、-march/-mcpu、标准库和链接参数变化,也可能形成不同程序。记录版本号是必要条件,不是完整环境身份。

编译输出还应明确哪些参数实际作用于前端、后端或链接器。-Wl,一类选项通过driver传给链接器,-Xclang面向编译核心;不能因为同一条命令接收它们,就假定所有阶段看到同样的参数。

本例使用绝对LLD路径,是为了确定实际选中的链接器;它不保证该路径在别机存在。可复用交付应说明组件版本与发现方法,把本机绝对路径保留为原始日志,避免把路径写成知识本身。关于各工具的准确输入输出,可分别核对opt与llc命令参考。

2026-10-18内容修订:补工具证据能力及跨机器依赖,不增加设备兼容结论。本次为文献与语义审校,未新增实验;首次发布日期、原网址及历史运行版本保持。

来源、验证范围与阅读路线

本期实测采用18.1.3;下列版本化文档来自18.1系列的18.1.8文档站,命令输出以本文实测为准。持续更新的官方页面用于补充原理,不据此改写旧版运行结果。

普通分段链路完成,程序退出0;LLD18.1.3已确认。三项预期失败均非零。-###仅检查计划。没有LTO或异构设备性能测试。

上一篇 · 下一篇:LLVM IR 到底是什么?为什么需要中间表示 · 文章归档 · 知识体系

勘误:2026-10-07,初版。发现问题时请附工具版本、命令与关键输出;确认后在此记录修改。

lihao
Author: lihao

喜欢这篇文章?登录后即可点赞,或先注册账号。

评论

0 条评论

欢迎交流与勘误。登录后可评论,提交后公开;请勿发布隐私、广告或无关内容。

写下你的评论