如何从零写一个链接器:claudes-c-compiler内置链接器的符号解析与重定位完全指南

发布时间:2026/10/2 21:06:03
如何从零写一个链接器:claudes-c-compiler内置链接器的符号解析与重定位完全指南 如何从零写一个链接器claudes-c-compiler内置链接器的符号解析与重定位完全指南【免费下载链接】claudes-c-compilerClaude Opus 4.6 wrote a dependency-free C compiler in Rust, with backends targeting x86 (64- and 32-bit), ARM, and RISC-V, capable of compiling a booting Linux kernel.项目地址: https://gitcode.com/gh_mirrors/cl/claudes-c-compilerclaudes-c-compilerCCC是一个用 Rust 从零编写的、零依赖的 C 编译器它不仅内置了编译器前端、优化器、汇编器还自带一个完整的链接器——能把.o目标文件和.a静态库直接拼成可运行的 ELF 可执行文件无需系统ld。本文带你拆解这个内置链接器最核心的两块逻辑符号解析与重定位帮你建立从零实现链接器的完整认知。 链接器到底在做什么链接器的工作可以概括为一句话把多个半成品目标文件组装成一个成品可执行文件。每个.o文件里都有代码和数据但其中的函数调用、全局变量引用都只是占位符重定位项地址尚未确定。链接器要完成三步步骤通俗解释对应模块① 加载输入解析.o、.a、.so文件input.rs② 符号解析搞清楚每个名字是谁定义的、从哪个库来linker_common/③ 重定位把占位符填上最终地址写出 ELFemit_exec.rs完整的流水线设计输入加载 → 符号解析 → 节合并 → PLT/GOT → 地址布局 → 重定位应用在 x86/linker/README.md 中有详细图示是入门的最佳路线图。四个架构x86-64、ARM、RISC-V、i686共享同一套 ELF64 链接逻辑被抽取到 linker_common/每个后端只需实现自己架构相关的部分重定位类型、PLT/GOT、ELF 头。这是从零写链接器时非常值得学习的架构设计。 第一步解析目标文件链接一切之前先要把磁盘上的字节流变成内存结构。parse_object.rs 中的parse_elf64_object完成这件事校验 ELF 魔数、ELFCLASS64、小端字节序、ET_REL可重定位对象解析节头表从.shstrtab还原节名读取每个节的原始字节解析.symtab符号表每个符号 24 字节解析所有SHT_RELA重定位表按目标节分组解析结果存进Elf64Object结构体节列表、符号表、节数据、重定位表一个对象文件就变成了一张待办清单。为了复用symbols.rs 定义了GlobalSymbolOpstrait让四个后端用各自的GlobalSymbol结构字段略有差异统一接入同一套解析/合并代码——这是泛型 trait处理多架构差异的经典手法。 符号解析谁定义了这个名字这是链接器的心脏。dynamic.rs 中的register_symbols_elf64遍历每个对象文件的符号表把符号登记到全局符号表globals一个HashMap符号名, GlobalSymbol规则清晰明了已定义的全局符号→ 写入全局表全局定义会覆盖弱定义静态定义还能覆盖动态来自.so的定义COMMON 符号C 语言文件级未初始化变量的产物→ 记录但允许被真实定义替换未定义符号→ 只插入占位条目表示我还需要它优先级总结为静态已定义 动态已定义 弱定义 未定义。这套规则正是理解ld行为的关键。静态库的选择性加载--start-group 算法.a静态库不能整个塞进可执行文件——那会拖入几百个你根本用不到的对象。archive.rs 实现了传统 Unix 链接语义循环直到不再有变化 对每个尚未拉入的库成员 如果它定义了当前未定义符号中的任意一个 拉入该成员登记它的符号这个迭代到不动点的循环能自动处理成员之间的传递依赖A 需要 BB 又需要 C。link.rs 中更进一步把所有库放在一个组里反复扫描等效于 GNU ld 的--start-group/--end-group解决了库之间的循环依赖问题。动态库兜底去系统 .so 里找人用户显式-l的库都加载完后还剩未定义符号dynamic.rs 的resolve_dynamic_symbols_elf64会到标准系统库libc.so.6、libm.so.6、libgcc_s.so.1里匹配命中的符号标记为is_dynamic并把 SONAME 记入DT_NEEDED列表。有个精妙细节链接器自己会提供一批符号_edata、_end、_GLOBAL_OFFSET_TABLE_、__bss_start等清单维护在 symbols.rs在检查未定义之前先排除否则会误报错误。 节合并把碎片拼成整块符号都找齐后各对象文件的.text、.data、.bss等碎片要拼成输出文件的大节。merge.rs 的merge_sections_elf64做三件事按名字归并.text.foo、.text.bar→ 统一进.text计算偏移每个输入节在输出节中的起始位置遵守对齐要求排序布局只读 → 可执行 → 读写 → BSS 的经典顺序至此每个符号都能算出最终虚拟地址——接下来就是重定位登场。 重定位填上最终地址重定位项的通用形式是四个数offset补丁位置、sym涉及哪个符号、type怎么算、addend附加常数。以 x86-64 为例最常见的几种计算式S符号值、A加数、P补丁位置、GGOT 项地址重定位类型计算式用途R_X86_64_64S A64 位绝对地址R_X86_64_PC32S A - P32 位 PC 相对call指令的位移R_X86_64_GOTPCRELG A - P经 GOT 间接寻址R_X86_64_GOTPCRELX可松弛为直接lea本地符号的优化机会链接器遍历所有输入节的所有重定位逐项计算并写入输出缓冲区对应偏移——这就是 emit_exec.rs 中重定位应用阶段。值得注意的两个优化GOT→LEA 松弛本地定义符号不必绕 GOT把mov symGOTPCREL(%rip), %reg改写成lea sym(%rip), %reg省一次内存间接访问死节消除--gc-sections时gc_sections.rs 从入口点做可达性分析不可达的节直接丢弃 PLT 与 GOT如何调用动态库函数调用printf这类运行时才在共享库里解析的函数不能直接写地址——链接器于是生成两个跳板GOT全局偏移表存放符号地址的数组PLT过程链接表每个外部函数一个 16 字节存根先跳到 GOT 项初始时 GOT 项指回 PLT 存根内部的解析器第一次调用时动态链接器ld.so解析出真实地址并打补丁——这就是延迟绑定。PLT/GOT 的构建逻辑在 plt_got.rs它扫描所有重定位PLT32遇到动态函数就分配 PLT 项若代码取的是动态数据对象地址如stderr还会生成COPY 重定位在.bss里复制一份。️ 推荐阅读路径想动手学习建议按这个顺序读源码x86/linker/README.md — 完整流水线设计文档含内存布局图linker_common/README.md — 共享模块的文件清单与设计决策linker_common/parse_object.rs → dynamic.rs → merge.rs — 解析、符号解析、合并三件套x86/linker/emit_exec.rs — 输出与重定位应用的重头戏x86/linker/emit_shared.rs — 进阶.so共享库输出RELRO、R_X86_64_RELATIVE构建后运行./target/release/ccc --version看到Backend: standalone即确认正在使用内置链接器。✅ 小结从零写一个链接器核心就是三张表 一次回填解析.o得到符号表和重定位表用优先级规则构建全局符号表靠迭代算法按需拉取静态库合并节、分配地址后按类型计算式逐项填充占位符动态符号留给运行时用 PLT/GOT 搭好跳板claudes-c-compiler 的内置链接器证明了这套逻辑完全可以在一个纯 Rust、零依赖的项目里实现——它甚至撑起了 Linux 内核级项目的链接需求。跟着 src/backend/linker_common/ 的源码走一遍你就拥有了理解任何现代链接器ld、lld、mold的底层视角。【免费下载链接】claudes-c-compilerClaude Opus 4.6 wrote a dependency-free C compiler in Rust, with backends targeting x86 (64- and 32-bit), ARM, and RISC-V, capable of compiling a booting Linux kernel.项目地址: https://gitcode.com/gh_mirrors/cl/claudes-c-compiler创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询