二进制里找不到的绝对路径:GCC 把字符串拆成了 16 字节碎片
来源:stoppels.ch — 2026-11-12
📋 概述
很多发行版在打包后扫描二进制里的构建路径,用来判断包是否可重定位。但用 GCC 12 及以上编译 x86-64 时,字符串常量根本不以原样出现:GCC 会把 /home/linuxbrew/.linuxbrew 拆成两段重叠的 16 字节常量塞进 xmm 寄存器,于是 strings 里只剩拼出来的怪路径 /home/linuxbrew/xbrew/.linuxbrew。作者解释了这套分片与去重优化的触发条件与代价,并认为应该给个关掉的开关。
🔑 核心要点
- std::string、strcpy、memcpy 拷贝的常量会被拆成重叠的 16 字节片段,只当指针传递的字符串(如 fopen)保持完整
- 结果 grep -acF 与 strings 都匹配不到原路径,只剩 xbrew 这种拼接出来的假目录
- Conda 式 _placehold 填充到 256 字节后,因 lcm(10,16)=80 只需存 5 个去重常量,strings 只剩 176 字节
- Clang 不拆字符串却生成几乎相同的两条重叠 32 字节装载,说明性能收益可以忽略
- 代价是空间反而更大:53 字节路径占 64 字节,只有共享长前缀时才划算
- 作者已向 gcc-patches 提交补丁,要求提供关闭这项优化的开关
💡 金句
跑一下 strings 是理解一个不透明二进制最省事的办法,这份便利比省下的几个字节更值钱。
← 返回 Lobsters 首页
👍 0
👎 0