ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

mold 如何用 --zero-to-bss 把全零自定义段转换为 BSS 减小输出文件?

mold 如何用 --zero-to-bss 把全零自定义段转换为 BSS 减小输出文件? mold 如何用 --zero-to-bss 把全零自定义段转换为 BSS 减小输出文件【免费下载链接】moldmold: A Modern Linker 项目地址: https://gitcode.com/GitHub_Trending/mo/mold如果你在 C/C 代码里用__attribute__((section(.sectname)))定义了自定义段来存放未初始化的全局变量会发现一个尴尬的事实GCC 和 Clang 不会把这些段自动标记为 BSS。哪怕段内容全是零字节它们也会被编译器输出为普通的SHT_PROGBITS数据段实打实地占用输出文件的空间。mold 提供--zero-to-bss选项来解决这个问题链接时扫描输入数据段把内容全为零的段转换为 BSSSHT_NOBITS而 BSS 段在文件映像中不占任何空间输出文件随之变小且运行时语义不变。先看问题自定义全零段默认不会被识别为 BSSmold 文档给出了一个典型例子摘自 docs/mold.md__attribute__((section(.sectname))) int vec[256];默认情况下这会生成一个名为.sectname的SHT_PROGBITS段内容是 1024 字节全零。加上--zero-to-bss后mold 会把它识别为空数据并转换为SHT_NOBITS段减小输出文件体积。原因是编译器的行为限制只有当段名是.bss或类似惯例名称时GCC 和 Clang 才会给输出段设置SHT_NOBITS标志。像__attribute__((section(.sectname)))这种非标准段名定义的段即使只包含未初始化变量也始终被输出为非 BSS 段。这一行为在源码 src/passes.cc 的注释中有同样说明。执行步骤用 --zero-to-bss 重新链接并对比仓库自带的测试 test/zero-to-bss.sh 展示了一条完整的验证路径。下面按同样的方式操作脚本在 FreeBSD 上会自动跳过1. 准备一个含全零自定义段的对象文件。测试用例同时定义了全零段和常量段便于对比哪些段被转换、哪些不受影响#include stdio.h __attribute__((section(.zero))) char zero[256]; __attribute__((section(.const))) const char konst[256]; int main() { printf(Hello world\n); }2. 先不加选项链接记录基线$CC -B. -o $t/exe1 $t/a.o readelf -WS $t/exe1 | grep -E .zero\sPROGBITS readelf -WS $t/exe1 | grep -E .const\sPROGBITS $QEMU $t/exe1 | grep Hello-B.让编译器把本地目录的mold当作链接器使用$CC、$t、$QEMU都是测试脚本变量测试框架 test/common.inc 中的环境实际操作时替换为你本机的 C 编译器、临时目录以及跨架构运行时的 QEMU 二进制本机同架构运行则直接执行二进制即可。预期结果.zero和.const两个段都以PROGBITS类型出现在输出中——这正是没有--zero-to-bss时的默认行为。3. 加上--zero-to-bss重新链接并验证$CC -B. -o $t/exe2 $t/a.o -Wl,--zero-to-bss readelf -WS $t/exe2 | grep -E .zero\sNOBITS readelf -WS $t/exe2 | grep -E .const\sPROGBITS $QEMU $t/exe2 | grep Hello判断标准来自测试脚本本身的断言readelf -WS中.zero段的类型变为NOBITS——转换成功.const段仍是PROGBITS——常量段不在转换范围内内容未被动过两次链接生成的可执行文件运行后都能输出Hello——转换不改变运行时语义。选项的适用条件与边界docs/mold.md 对该选项的完整描述是Convert all-zero data sections into BSS. When this option is enabled,moldscans input data sections that are not of typeSHT_NOBITSand checks whether their contents consist solely of zero bytes. Such sections are then converted into BSS (SHT_NOBITS) sections. This reduces the size of the output file, since BSS sections occupy no space in the file image.结合 src/passes.cc 中convert_zero_to_bss的实现一个段被转换必须同时满足以下条件段类型是SHT_PROGBITS且带SHF_ALLOC和SHF_WRITE标志即可分配、可写的数据段不带SHF_EXECINSTR标志代码段不参与转换段内没有任何重定位项isec-get_rels(ctx).empty()段内容非空且每一个字节都是零。此外转换只作用于可达reachable的输入文件中的存活段。这些条件解释了上面验证结果中.const段为何保持PROGBITS不变它不含任何非零数据的同时也不满足转换前提mold 只对符合条件的全零可写数据段做替换。在现有构建中启用由于 mold 是 GNU 链接器的 drop-in replacement启用方式就是在链接命令中追加该选项。测试用例使用的写法是经由编译器透传cc -B. -o output program.o -Wl,--zero-to-bss直接调用 mold 时则写成mold -o output program.o --zero-to-bss。选项在命令行中的登记位置见 src/cmdline.cc其帮助文本为 Convert all-zero data sections into BSS。验证小结检查项命令期望结果来自测试脚本的断言默认链接readelf -WS exe \| grep -E .zero\sPROGBITS全零自定义段为PROGBITS启用选项后readelf -WS exe \| grep -E .zero\sNOBITS该段变为NOBITS常量段不受影响readelf -WS exe \| grep -E .const\sPROGBITS仍为PROGBITS运行时语义不变运行二进制两次输出相同测试中断言含Hello这个选项只做一件事把符合条件的全零数据段改为SHT_NOBITS并清空段内容isec-contents nullptr文件体积收益来自 BSS 不写入文件映像。如果你的输出文件里全零空间主要来自标准.bss编译器本来就会按 BSS 输出--zero-to-bss的收益集中在自定义段名__attribute__((section(...)))定义的全零段上。【免费下载链接】moldmold: A Modern Linker 项目地址: https://gitcode.com/GitHub_Trending/mo/mold创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表