lld 默认拒绝链接未加 -fpic 的目标文件,因其严格校验共享库构建中所有 .o 文件必须为位置无关代码,而 gnu ld 会隐式修复重定位;正确做法是在每个编译阶段(如 clang -fpic -c)启用 pic,而非仅链接时指定。

LLD 默认拒绝链接未加 -fPIC 的目标文件,这不是 bug,是设计行为
当你用 lld 链接共享库(.so)时遇到类似 error: relocation R_X86_64_32 against symbol ... can not be used when making a shared object 的报错,根本原因不是 LLD “不支持”,而是它比 GNU ld 更严格地执行了位置无关代码(PIC)规则。GNU ld 会悄悄帮你重写某些重定位,而 LLD 直接报错——这是为了提前暴露潜在的 ABI/加载问题。
为什么 clang + lld 组合下容易触发这个错误
Clang 默认对可执行文件生成位置相关代码(non-PIC),只有显式指定 -fPIC 或 -shared 才会启用 PIC 模式;而 LLD 在链接 -shared 时不做妥协,直接校验所有输入目标文件是否满足 PIC 要求。
- 你用了
clang -shared -o libfoo.so foo.o bar.o,但foo.o是用clang -c foo.c(没加-fPIC)编译出来的 → 报错 - 你混用了 GCC 编译的目标(比如
gcc -c -fPIC)和 Clang 编译的目标(clang -c不带-fPIC)→ LLD 会卡在非 PIC 的那个 .o 上 - 你启用了 LTO(
-flto),但没统一加-fPIC→ LTO bitcode 合并后仍需最终生成 PIC 代码,漏掉就会失败
正确做法:所有参与共享库构建的 .o 必须带 -fPIC
不是只在链接时加 -fPIC,而是在每个 .c → .o 编译阶段就加:
clang -fPIC -c foo.c -o foo.o clang -fPIC -c bar.c -o bar.o clang -shared -o libfoo.so foo.o bar.o
如果你用 CMake,确保设置:
set(CMAKE_POSITION_INDEPENDENT_CODE ON) # 或针对特定 target: set_property(TARGET mylib PROPERTY POSITION_INDEPENDENT_CODE ON)
注意:CMAKE_POSITION_INDEPENDENT_CODE ON 会让所有 add_library 默认加 -fPIC,但 add_executable 不受影响——这点和 GNU 工具链一致,无需额外处理。
常见误操作与绕过陷阱
- 试图用
-Wl,-z,notext或-Wl,--no-as-needed绕过 → 无效,LLD 不吃这套,且会破坏共享库安全性 - 把
-fPIC只加在链接命令里(如clang -shared -fPIC ...)→ 错,-fPIC是编译选项,对.o生效,对链接器无效 - 在 Windows 上用
lld-link构建 DLL 时类比处理 → 不适用,Windows DLL 不强制要求 PIC,对应的是/DLL和导入库逻辑,别套用 Unix 的-fPIC思维 - 用
lld --allow-shlib-undefined以为能放宽 → 它只控制未定义符号检查,不触碰重定位合法性校验
真正关键的一点常被忽略:即使你只链接一个 .o 文件,只要目标是 -shared,那个 .o 就必须是 -fPIC 编译的。LLD 不做隐式转换,也不做“尽力而为”兼容——它要的是确定性、可复现、符合 ELF 共享库规范的行为。











