文章摘要
文章讨论了大型代码库中出现的巨大二进制文件问题,作者以亲身经历指出,在谷歌等公司中静态编译会导致超过25GiB的巨型二进制文件。这类似于"音障"问题,当代码规模超过x86_64架构的2GiB重定位限制时,就需要重新思考代码链接和构建方式。
文章总结
巨型二进制文件的挑战与解决方案
在攻读博士学位和提交学术论文期间,我遇到了一个特殊问题:为解决某些问题而构建的解决方案需要达到相当大的规模才能有效。审稿人常质疑这类问题是否存在,但实际上我在谷歌等企业环境中确实观察到过——只是无法引用这些案例。
巨型二进制文件现象
在超大型代码库中,一个独特问题是巨型二进制文件(ELF格式)。我曾见过包含调试符号超过25GiB的二进制文件。这种情况源于企业偏好静态构建服务以加速启动和简化部署——将全球最大代码库的所有代码静态包含,自然会产生庞大的二进制文件。
2GiB重定位屏障
就像音障一样,代码大小也存在临界点。对于x86_64架构,这个临界点是2GiB的"重定位屏障"。原因在于:
- CALL指令使用32位有符号相对偏移量
- 最大寻址范围是±2GiB(2³¹位)
- 当调用目标超过此范围时,会出现"重定位溢出"错误
解决方案:大型代码模型
最简单的解决方法是使用-mcmodel=large编译选项,它将:
1. 将相对调用改为64位绝对地址调用
2. 通过MOVABS和CALL两条指令实现跳转
但这种方法存在明显缺点: - 指令膨胀:单个调用从5字节增至12字节 - 寄存器压力:需要占用一个通用寄存器(如%rdx) - 在包含数百万调用点的二进制中,这些开销会显著累积
替代策略
虽然大型代码模型可行,但理想情况是尽可能保持小型代码模型。其他优化策略包括: - 重构代码布局 - 使用函数指针表 - 采用分段加载机制
(作者表示将在后续文章中深入探讨这些方案)
本文技术细节通过LLVM的lld链接器演示,因其错误信息更清晰。所有示例代码采用CC-BY-SA许可。
评论总结
以下是评论内容的总结:
标题修改建议
- 有评论认为HN的标题去敏感化算法需要调整,原标题更直接。
"The HN de-sensationalize algo for submission titles needs tweaking. Original title is simply 'Huge Binaries'."
- 有评论认为HN的标题去敏感化算法需要调整,原标题更直接。
对大二进制文件的担忧
- 25GiB的单个二进制文件被认为不合理,建议使用动态链接。
"25 GiB for a single binary sounds horrifying... at some point surely some dynamic linking is warranted" - 尽管静态编译简化部署,但超大二进制可能意味着代码结构问题。
"surely if your actual executable code doesn't even fit in 2GB it's time to ask if that's really one binary's worth of code"
- 25GiB的单个二进制文件被认为不合理,建议使用动态链接。
技术原因分析
- 模板实例化(如Eigen库)和调试符号可能导致二进制膨胀。
"Every math expression ends up as a new template instantiation." - 建议通过LTO(链接时优化)或分段编译消除死代码。
"You should be using LTO for release builds... --gc-sections does a good job of culling dead code"
- 模板实例化(如Eigen库)和调试符号可能导致二进制膨胀。
解决方案讨论
- 使用
-mcmodel=large或跳板(thunks)解决跳转限制,但可能影响性能。
"Makes sense, but... there is not a single JMP instruction"
"Though... it can be expensive to add trampolines, both in icache performance" - Facebook和Google通过代码布局优化(如BOLT)提升效率。
"Move all the hot BBs near each other... Facebook's solution: [BOLT]"
- 使用
实用性与折中
- 静态编译工具链在故障时更可靠,但需权衡体积问题。
"I keep on having the basic compile toolchain as statically compiled... It simply works better"
- 静态编译工具链在故障时更可靠,但需权衡体积问题。
总结观点:大二进制文件引发对代码结构、工具链优化的讨论,支持静态部署的便利性,但普遍认为需通过动态链接、LTO或布局优化平衡体积与性能。