新闻详情

新闻详情

首页 / 资讯中心 / 详情

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

发布时间:2026/10/2 21:06:06来源:尧图网络
如何从零写一个链接器: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),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

公路落石检测实战:VOC转YOLO、小目标优化与边缘部署 2026/10/2 21:58:49

公路落石检测实战:VOC转YOLO、小目标优化与边缘部署

简介:本资源是一个面向计算机视觉初学者与目标检测实践者的公路落石检测专用数据集,聚焦于真实场景下的小目标识别任务,适用于YOLO系列模型训练、VOC格式迁移学习及标注工具实操练习。数据包共1019个文件,主体为282张JPEG图像、28…

阅读更多 →
基于Docker Swarm的Elasticsearch生产级集群部署与运维实践 2026/10/2 21:58:47

基于Docker Swarm的Elasticsearch生产级集群部署与运维实践

先把结论说在前头:这套方案不是我搭着玩的,是真的跑过一年线上环境的。三个 Elasticsearch 数据节点、三个 master 节点,全部跑在 Docker Swarm 之上,每天承载数亿条日志写入和搜索请求,期间还经历过两次机房节点故障、…

阅读更多 →
Keychain、无遥测与Socket隔离:Coucou的8个安全实践清单 2026/10/2 21:58:39

Keychain、无遥测与Socket隔离:Coucou的8个安全实践清单

Keychain、无遥测与Socket隔离:Coucou的8个安全实践清单 【免费下载链接】coucou A tiny friend that lives in your notch (macOS) or at the top of your screen (Windows, Linux) and keeps an eye on your coding agents: Claude Code, Gemini CLI, Antigravity…

阅读更多 →
频率域图像处理核心:傅里叶变换、频域滤波与同态滤波全解析 2026/10/2 21:58:12

频率域图像处理核心:傅里叶变换、频域滤波与同态滤波全解析

数字图像处理这门课,理论上讲,前几章再零碎,大家照着例题还是能把作业写出来的。但到了第四章频率域图像处理,大多数人的反应会突然慢下来:坐标系成了 u、v,图像变成了复数矩阵,之前积累的线性代…

阅读更多 →
YOLOv8垃圾分割检测系统:端到端实例分割实战指南 2026/10/2 21:58:12

YOLOv8垃圾分割检测系统:端到端实例分割实战指南

简介:YOLOv8垃圾分割检测系统是一套面向人工智能初学者与计算机视觉实践者的轻量级垃圾分类解决方案,聚焦图像识别与实例分割任务,适用于智能环卫、环保监测及课程设计等场景。资源包共41个文件,含15张JPG/PNG格式的样本图像、3个…

阅读更多 →
PowerShell禁止运行npm.ps1?一条命令解决Node.js脚本执行策略报错 2026/10/2 21:58:12

PowerShell禁止运行npm.ps1?一条命令解决Node.js脚本执行策略报错

在PowerShell里输入 npm -v ,回车,终端弹出一段红字:“npm : 无法加载文件 D:\nodejs\npm.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 about_Execution_Policies。”这句话我见过太多次了。毫不夸张地说&…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉