relocation-model是llvm后端生成目标代码时对符号地址重定位方式的指令编码策略,它不决定链接方式或是否启用pic,而是指定全局符号寻址所依赖的地址假设,直接影响指令选择(如rip-relative、movabs等),选错将导致链接失败或运行时崩溃。

relocation-model 是什么,不是什么
relocation-model 控制 LLVM 后端生成的目标代码如何处理符号地址的重定位,它不决定链接方式(那是 linker-flavor 和链接脚本的事),也不控制是否启用 PIC(-fPIC 是编译器前端行为),而是告诉后端:「生成的指令中,对全局符号的寻址应基于哪种地址假设」。
这个选项最终影响的是指令编码——比如用 lea 还是 mov 加 lea,是否允许使用 rip-relative,能否用 32 位立即数加载 64 位地址等。选错会导致链接失败、运行时崩溃,或在裸机/内核场景下直接跳飞。
常见 relocation-model 值与适用场景
LLVM 支持的模型依赖目标平台,但通用值有:
-
static:默认用于os:none或内核目标(如x86_64-unknown-elf)。所有符号地址在链接时固定,不支持动态加载;生成的指令可含绝对地址(x86-64 上受限,需--mc-relax-all配合)。 -
pic:位置无关代码,适用于共享库(.so)或需要加载到任意地址的模块。要求所有全局访问走 GOT/PLT,指令多用rip-relative(x86-64)或gotpcrel(AArch64)。 -
dynamic-no-pic:仅用于可执行文件(ET_EXEC),允许绝对寻址但保留动态链接能力(如引用 libc 符号)。常见于传统 Linux 可执行文件,但现代发行版已基本弃用。 -
ropi/rwpi:ARM/AArch64 特有,分别表示只读/读写段位置无关,用于 TrustZone 或 bare-metal 场景;通常需配合--rosegment等链接器标志。
注意:relocation-model=pic 不等于「加了 -fPIC」——前者是后端代码生成策略,后者是前端是否插入 GOT 访问逻辑。两者必须匹配,否则会报 relocation truncated to fit 或 invalid operand for instruction。
怎么查当前 target 支持哪些 relocation-model
最可靠的方式是让 LLVM 自己列出来:
llc --version | head -1 llc -mtriple=aarch64-linux-gnu --print-targets 2>/dev/null | grep -A5 "Available options" # 或更直接: llc -mtriple=x86_64-pc-linux-gnu -relocation-model=help
如果输出类似 Invalid value 'help' for option 'relocation-model',说明该 triple 不支持 help 查询,此时应查对应 TargetInfo 子类源码(如 lib/Target/X86/X86TargetMachine.cpp 中 X86TargetMachine::getRelocationModel() 的默认分支)。
实际项目中,别靠猜:Rust 裸机 target JSON 里明确写 "relocation-model": "static",Clang 编译内核模块用 -mno-omit-leaf-frame-pointer -fno-pic -mgeneral-regs-only 配合 -relocation-model=static,都是为了规避 GOT 生成和间接跳转开销。
容易踩的坑:static vs pic 在 x86-64 下的隐式限制
x86-64 的 static 模式下,LLVM 默认仍倾向生成 rip-relative 地址计算(因更紧凑),但这在无运行时 loader 的环境(如 bootloader、kernel init)中可能失效——因为 rip 基址不可控。此时必须:
- 显式禁用:加
-mattr=+no-rip-relative(LLVM 15+)或--mc-relax-all强制展开为movabs+lea; - 确认
llc输出汇编里没有lea rax, [rip + xxx],而应是mov rax, offset sym(需链接器支持绝对重定位); - 若用
lld,确保链接脚本中SECTIONS显式指定ADDR,且未启用--pie——否则static模式会被覆盖为pic。
真正麻烦的不是选哪个值,而是整个 toolchain 链条(Clang → llc → lld → loader)对 relocation-model 的理解是否一致。一个环节没对齐,就会在最后一步报 R_X86_64_32S against <code>xxx: non-representable section on output 这种错误。











