如何在LLVM中定义可在链接脚本中访问的链接器符号
实现方案
方案1:模块内联汇编(全版本兼容,实现最简单)
直接通过llvm::Module提供的appendModuleInlineAsm方法注入你需要的汇编符号定义即可,效果和手动写汇编文件完全一致:
#include "llvm/IR/Module.h" bool YourPass::runOnModule(Module &M) { // 直接注入汇编符号定义,和手写sym.s的逻辑完全相同 M.appendModuleInlineAsm(R"( .global asdf asdf = 0x1234 )"); return true; }
编译后生成的目标文件符号和你示例中的sym.o完全一致,符号asdf为ABS类型,值为0x1234,不占用任何段空间。
方案2:原生IR API实现(LLVM 13+支持)
如果你希望用纯LLVM IR API实现,不需要依赖汇编语法,可以按以下逻辑创建全局绝对符号:
#include "llvm/IR/Module.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Type.h" #include "llvm/ADT/APInt.h" bool YourPass::runOnModule(Module &M) { auto &Ctx = M.getContext(); // 创建全局变量实例,不需要初始值 auto *AbsSym = new llvm::GlobalVariable( M, llvm::Type::getInt8Ty(Ctx), true, // 标记为常量 llvm::GlobalValue::ExternalLinkage, nullptr, // 初始值设空,不分配数据段空间 "asdf" // 符号名 ); // 关键:设置为绝对符号,值固定为0x1234 AbsSym->setAbsoluteSymbolRange(llvm::APInt(64, 0x1234), llvm::APInt(64, 0x1234)); AbsSym->setSize(0); // 标记符号大小为0 return true; }
对应正确的IR写法如下,你之前的尝试错误是因为给全局变量指定了初始值,导致LLVM将其识别为普通数据变量:
target triple = "x86_64-pc-linux-gnu" @asdf = external global i8, !absolute_symbol !0 !0 = !{i64 0x1234, i64 0x1234}
注意事项
- 方案1兼容所有LLVM版本,实现更简单,不容易出错,优先推荐使用
- 方案2需要LLVM 13及以上版本才支持
setAbsoluteSymbolRange接口
内容的提问来源于stack exchange,提问作者PPenguin
相关产品推荐
相关产品推荐

