Mold 3.0:链接器用 Rust 重写后发布首个大版本,目标取代 GNU ld

构建一个大型 C++ 项目时,编译阶段可以摊到几十个核上并行跑,唯独最后一步例外:所有目标文件汇到链接器里,由单个进程解析符号、处理重定位、排出最终的二进制。Firefox 的 debug 构建重新链接一次,GNU ld 要跑 92.865 秒,而这段时间里大多数 CPU 核心处于空闲状态。

10 月 5 日发布的 mold 3.0 把这个环节的耗时压到 0.89 秒,并且完成了一次彻底的换血:整个链接器从 C++ 重写为 Rust。这是 mold 的首个 Rust 大版本,2.42.1 成为 C++ 版本的绝唱。项目作者 Rui Ueyama 就是 LLVM lld 的原作者,他给 3.x 系列定下的目标写进了 release notes:让 Linux 发行版把系统默认链接器换成 mold。

mold:GitHub 17k stars 的开源链接器项目

一、为什么最快的链接器当不上默认链接器

Linux 世界提供 /usr/bin/ld 这个系统链接器的发行版,绝大多数装的仍然是 GNU ld。这件事已经持续了二十多年,期间快链接器换了三代:2008 年 Google 写了 gold,之后 Ueyama 在 LLVM 里写了 lld,2020 年他又写了 mold。每一代都比上一代快得多,但发行版的默认值始终没动过。

Ueyama 在 2.42.1 的发布公告里把责任揽了一半。他的原话是:自己花了大量精力把链接器做快,但在兼容性上投入不足,而兼容性恰恰是快链接器成为系统默认组件的前提。发行版要拿 mold 当 /usr/bin/ld,意味着内核、固件、引导程序这些特殊目标也得能链接,这类任务依赖 linker script 把节区钉死在指定地址上,是 GNU ld 覆盖了几十年、文档模糊但实现完备的领域。

差距能有多直观?ASPLOS 2027 论文给出的九个工作负载里,GNU ld 有 7 个配置直接链接失败——其中没有程序写得刁钻的因素,它们只是用到了只有 lld 和 mold 实现的命令行选项、按需解析的归档符号,或较新的 ELF 特性。对大型现代 C++ 项目来说,实际的兼容性基线早已是 lld 而非 GNU ld。这个数字同时也解释了发行版的保守:默认链接器换掉之后,任何构建失败都是发行版的 bug,没人愿意为几百毫秒的提速接下这种责任。

mold 3.x 的路线因此分成三步:补齐 linker script 缺失特性,让内核和固件可链接;做大规模兼容性测试;与发行版维护者合作推进默认替换。3.0 的 release notes 提到,团队用 Gentoo 的全部软件包做了构建验证,没有发现回归。

二、快从哪来:把每一个阶段都改成数据并行

mold 的速度不是靠某个单点优化。论文的消融实验(ablation study)结论是:没有任何一项优化占主导地位,加速来自所有阶段并行化的累积效应。

链接的标准流水线有五步:解析输入文件、符号解析、节区处理(垃圾回收、相同代码折叠、字符串合并)、布局计算、输出生成。lld 已经并行了其中几步,但符号解析仍是单线程的。这一步的架构难点在于,符号解析与归档成员的按需提取纠缠在一起:是否从静态库里拉出一个目标文件,取决于前面的符号解析结果,天然是顺序依赖。

mold 的做法是把解析和符号解析彻底解耦:先把所有输入文件(包括每个归档的每个成员)全部并行解析完,再做一轮独立的并行符号解析,用原子 CAS 操作处理竞争。之后的每个阶段——重定位扫描、垃圾回收、相同代码折叠、字符串合并、布局计算、输出写盘——全部套用同一结构:对同质元素数组的数据并行循环。阶段之间串行,阶段内部全并行。论文对比了 gold 的路线:gold 用任务并行加依赖令牌的工作队列,实际运行中大多数任务被依赖链串行化,多线程开与不开几乎没有差别,gold 因此默认关闭多线程。

并行的代价与收益都写在数据里。单线程跑 Firefox debug 链接,mold 花 12.2 秒,lld 只要 11.4 秒——mold 的并行架构有额外开销(全量急切解析、为并行度多做的几轮工作),单核下反而略慢。线程拉到 32,mold 加速 13.5 倍,0.9 秒收工;lld 在 16 线程就到顶,只有 2.6 倍。CPU 总时间上,mold 32 线程比单线程多烧 73% 的 CPU 换来 13.5 倍延迟下降;64 线程时 CPU 时间再涨 80% 而挂钟时间不动——瓶颈已经从计算转到内存:64 线程时 DRAM 随机读平均延迟从 570 个周期涨到 1070 个周期,加线程只是在加长排队。

端到端数据(Threadripper 7980X,debug 构建,论文 Table 4):

程序moldlldGNU ldmold 加速比
TensorFlow 2.21(9.9 GiB)3.23s52.16s链接失败16.1x
Chromium 145(40,945 个输入文件)1.89s13.24s链接失败7.0x
Firefox 1490.89s4.44s92.87s5.0x
LibreOffice 26.20.46s2.50s23.20s5.4x
Godot 4.60.51s1.20s26.64s2.4x

TensorFlow 那个 16.1x 里有一个工作负载特有的因素:它的链接用了带二十多个 glob 模式的 version script,lld 对 250 万个定义符号逐模式单线程匹配,这一项就吃掉 52 秒里的约 30 秒。排除这个因素,加速比约 7x。Chromium 的 7.0x 则是纯粹的规模效应:四万多个输入文件的解析占了 lld 13.2 秒里的 7 秒,而 mold 的解析全并行。

ARM64 上优势缩小但不消失。M1 Ultra(16 性能核)上 mold 对 lld 的加速比是 1.7–12.6x:核少而快,串行链接器沾光(lld 链 Firefox debug 用 3.26 秒,快过 Threadripper 上的 4.44 秒),mold 则因少核损失大于单核增益,同一任务从 0.89 秒变成 1.02 秒。

三、为什么用 Rust 重写,以及重写为什么可信

Ueyama 给出的理由里有时间维度:2020 年写 mold 时 Rust 还是个新语言,到 2026 年,Rust 已经是系统软件的务实选择——性能与 C++ 相当,同时提供内存安全保证。一个预期要服役几十年的工具,在生命周期的相对早期做这次重写,在他的成本账里是划算的。

对链接器这个特定工种,内存安全的收益有具体落点:链接器解析的是别人编译出来的目标文件,输入损坏是常态而非异常,处理过程是在映射内存上做大量指针运算。C++ 版的 mold 在输入损坏时会越界读内存然后段错误崩溃;Rust 版同样的访问会被边界检查拦下,程序在出错点 panic 并给出明确报错。3.0 release notes 把这一行为变化写成了正式承诺。

大规模重写的风险,公告原文没有回避:「AI 辅助编码的最新进展让大规模重写比以前可行得多,但它们并没有消除风险。」HN 上有人猜测这次重写用了 AI 工具,这个猜测与原文的表述是相容的,不过项目方没有公布具体的工具与流程,社区能验证的只有结果——3.0 与 2.42.1 接受完全相同的命令行选项,支持相同的目标架构,除列明的 bug 修复外产出相同的输出。团队在所有支持的目标架构上跑了测试套件,并对比了广泛真实工作负载下的链接器输出。

工程侧的迁移也是彻底的:构建系统从 CMake 换成 Cargo,要求 Rust 1.95 以上;依赖里去掉了 Intel oneTBB,继续静态链接 mimalloc;测试套件从 ctest 迁到 cargo test。对发行版打包者,这些变化都写在 release notes 的 Build Changes 一节里,MOLD_TARGETS 这样的 CMake 变量换成了 Cargo features。

四、成为 /usr/bin/ld 之前还差什么

3.0 是重写后的第一个版本,也是 drop-in 替换:从 2.42.1 升级不需要改任何构建配置。真正的考验在 3.x 后续版本——linker script 的完备程度决定内核和固件能不能链,兼容性测试的覆盖面决定发行版敢不敢换。

Ueyama 还留了一个态度转变:incremental linking(增量链接)。他从写 lld 时代就反对把增量链接当作方向,理由是链接本不该慢到需要增量——正确做法是把全量链接做到接近文件复制的速度。现在 mold 链接多 GB 二进制只要一两秒,他认为这个问题已基本解决,编辑-构建-测试循环的瓶颈转移到了工具链的其他环节(比如编译速度),但如果能找到不破坏 mold 简洁性的简单设计,增量链接仍然可以加。

与 mold 同期用 Rust 写的性能向链接器还有 wild,2026 年 8 月的基准里 mold 中位数比 wild 快 1.9 倍。GNU gold 已在 2025 年被标记废弃,Windows 侧的默认链接器也在 lld 的覆盖范围内。系统默认链接器的位置空了二十年,现在有一个速度、兼容性承诺、维护者履历三项齐备的候选者,外加一份经过同行评审的架构论文(arXiv 2608.23228)。发行版愿不愿意换,接下来几年会有答案。

上手路径

  • Clang / GCC 12.1+:编译时加 -fuse-ld=mold
  • 更老的 GCC:安装后用 -B/usr/local/libexec/mold 指定
  • 源码构建:cargo build --release(Rust 1.95+),./install-mold.sh 安装
  • 各架构预编译包挂在 GitHub Releases;mold 支持 x86-64、ARM 32/64、RISC-V 32/64、PowerPC 32/64、s390x、LoongArch、SPARC64、m68k、SH-4

来源: