mold 报“can not be used; recompile with -fPIC”的 textrel 错误怎么排查?
mold 报“can not be used; recompile with -fPIC”的 textrel 错误怎么排查【免费下载链接】moldmold: A Modern Linker 项目地址: https://gitcode.com/GitHub_Trending/mo/mold用 mold 链接时遇到... relocation ... against symbolxxx can not be used; recompile with -fPIC通常意味着输出文件里出现了无法在链接期解析、又无法提升为 PLT/规范重定位的重定位mold 在默认策略下会直接报错误。mold 默认对“在只读 section 中创建动态重定位”这一情况报错等价于-z text 行为这是 docs/mold.md 中明确说明的moldby default reports an error if dynamic relocations are created in read-only sections.排查的核心是从错误信息里定位到具体的输入文件、section 和符号确认该目标文件编译时是否带了-fPIC/-fPIE再决定是重新编译还是改用 mold 提供的放宽选项。错误信息怎么读先定位 section 和符号这条错误有两个来源信息格式略有差别但都给出足够定位的三要素输入文件、section、符号普通重定位扫描路径src/input-sections.cc输入文件:section: 重定位类型 relocation at offset 0x偏移 against symbol 符号 can not be used; recompile with -fPIC动态重定位分类路径src/output-chunks.ccsection: relocation at offset 0x偏移 against symbol 符号 can not be used; recompile with -fPIC拿到文件、section 名和符号名后回到构建系统里检查这个源文件的编译选项问题文件基本可以确定是没有以-fPIC/-fPIE编译、却在 PIE 可执行文件或共享库链接中产生了绝对重定位的那个对象文件。两类典型触发场景与对应处理mold 的重定位处理依据一张决策表src/input-sections.cc按“输出类型共享库 / PIE / 位置依赖可执行文件× 符号类型绝对 / 本地 / 导入的数据 / 导入的代码”决定是报错、放行、走 PLT 还是提升为规范重定位。对照这张表实际最常见的两类情况是1. 链接可执行文件PIE时对象文件含对本地符号的绝对重定位典型代码形态汇编里直接写了movabs main, %rax这类对本地符号的绝对引用对应文件没有用-fPIC/-fPIE编译。仓库测试 test/arch-x86_64-warn-textrel.sh 就是这个场景的完整复现方式# 第 1 步制造一个含绝对重定位的对象未加 -fPIC cat EOF | cc -c -o a.o -x assembler - .globl fn fn: movabs main, %rax ret EOF # 第 2 步编译 main这里带 -fPIC cat EOF | cc -c -o b.o -fPIC -xc - void fn(); int main() { fn(); } EOF # 第 3 步用 mold 以 PIE 方式链接-B. 让编译器驱动使用当前目录下的 mold 二进制作为链接器 cc -B. -o exe a.o b.o -pie第 3 步会触发上面的错误。两条修复路径任选其一按错误信息提示把a.o对应的源文件加上-fPIC或-fPIE重新编译再链接如果这个程序本来就打算做位置依赖可执行文件改用 docs/mold.md 中记录的--no-pie--no-pic-executable链接。位置依赖可执行文件这一列在决策表中允许把导入数据/代码的重定位提升为规范重定位CANONICAL链接可以正常完成。test/textrel.sh 展示了同型输入.text里放了int (*fn)(const char *s) puts;这类指向导入函数puts的全局函数指针两个对象都用-fno-PIE编译用mold ... -no-pie链接成功后运行程序并grep Hello world确认输出Hello world 为测试中的示例输出。2. 链接共享库-shared时出现绝对重定位共享库这一行在决策表里更严格对绝对符号或导入的数据符号的 PC 相对重定位会直接报错只有导入的函数符号可以走 PLT。这种情况没有“换链接模式”的绕法正确做法就是把对应源文件用-fPIC重新编译后再链接——这正是错误信息本身给出的指示。想先放宽为警告或允许 textrel 时如果暂时改不动编译选项mold 提供了两个层面的放宽开关注意它们的效果不同--warn-textrel可执行文件与--warn-shared-textrel共享库把错误降级为警告输出文件仍然生成但会带上DT_TEXTREL标记表示动态加载器需要在运行期修补只读页。这两个选项的含义见 mold 的内置帮助src/cmdline.cc“Warn if the output file / .so needs text relocations”。test/arch-x86_64-warn-textrel.sh 中用同样的a.o/b.o加-Wl,-warn-textrel链接日志中出现两行警告文档示例输出...: relocation against symbol main in read-only section creating a DT_TEXTREL in an output file第二行来自 src/passes.cc 的Warn。--warn-shared-textrel的效果见 test/arch-x86_64-warn-shared-textrel.sh示例输出相同。-z notext/-z textoff按 docs/mold.md 的说明mold默认对只读 section 中的动态重定位报错给了-z notext或-z textoff后mold 会不报错地创建这些动态重定位-z text则恢复默认报错行为。这两个开关都只改变链接期行为不会消除 textrel 本身产物带DT_TEXTREL后加载与执行时仍需要动态加载器支持对只读页的修补。排查阶段建议先用它们确认根因最终修复仍以重新编译为目标。验证修复重新编译后重跑链接命令不再出现can not be used; recompile with -fPIC即表示该重定位已被正确解析或提升运行产物确认行为正常test/textrel.sh 的验证方式就是运行链接出的程序并检查输出内容若走的是警告/放宽路径按上面的示例日志核对是否出现creating a DT_TEXTREL in an output file以确认产物确实带上了 textrel后续仍要回到编译选项上去除它。容易混淆的另一种 “recompile with -fPIC” 消息链接可执行文件时还可能看到形如cannot create a copy relocation for 符号; recompile with -fPIE or -fPIC的报错它来自 copy relocation 的处理路径src/output-chunks.cc触发条件与上文不同符号在某个非 DSO 输入文件中未定义即该文件未按 PIC 方式编译、符号是 protected 可见性或链接时使用了-z nocopyreloc。看到这条消息时检查对象同样是“引用该符号的对象文件是否用了-fPIE/-fPIC编译”但修复手段是重新编译该对象文件而不是调整-z text相关的 textrel 开关。【免费下载链接】moldmold: A Modern Linker 项目地址: https://gitcode.com/GitHub_Trending/mo/mold创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考