如何检查LLVM变量中存储的数据?——针对汇编转LLVM IR提升器的技术问询
如何验证LLVM IR中加载变量的值?
问题描述
我正在构建一个将汇编代码转换为LLVM IR的提升器,现在需要找到可行的方法来检查LLVM变量中存储的数据。举个例子,我写了一段代码创建了一个dummy函数,里面只包含一个基本块:先为变量SRC分配内存,把立即数31存进去,再从内存加载到名为loaded的变量。我想确认%loaded变量的值确实是31,请问有什么办法可以做到?
示例C++代码
int main() { llvm::LLVMContext context; llvm::Type* type = llvm::Type::getVoidTy(context); Module* modu = new Module("test", context); modu->getOrInsertFunction("dummy",type); Function* dummy = modu->getFunction("dummy"); BasicBlock* block = BasicBlock::Create(context, "entry", dummy); IRBuilder<> builder(block); llvm::Value* SRC = builder.CreateAlloca(Type::getInt32Ty(context), nullptr); llvm::Value* s = builder.CreateStore(llvm::ConstantInt::get(context, llvm::APInt(/*nbits*/32, 31, true)), SRC, /*isVolatile=*/false); llvm::Value* loaded = builder.CreateLoad(SRC, "loaded"); builder.CreateRetVoid(); PassManager <llvm::Module>PM; llvm::AnalysisManager <llvm::Module>AM; verifyFunction(*(modu->getFunction("dummy")), &llvm::errs()); verifyModule(*modu, &llvm::errs()); PassBuilder PB; PB.registerModuleAnalyses(AM); PM.addPass(PrintModulePass()); PM.run(*modu, AM); }
生成的LLVM IR输出
; ModuleID = 'test' source_filename = "test" define void @dummy() { entry: %0 = alloca i32, align 4 store i32 31, i32* %0, align 4 %loaded = load i32, i32* %0, align 4 ret void }
解决方案
很高兴帮你解决这个问题!针对你想验证%loaded变量值的需求,有几种实用的方法,根据你的场景选择即可:
方法一:编写LLVM静态分析Pass(编译期验证)
如果不需要运行程序,只想在编译期通过分析IR来验证值,编写一个自定义的分析Pass是最适合的。这个Pass可以遍历IR指令,追踪Load操作的来源,确认存储的值是否符合预期。
下面是一个简单的Pass示例,它会找到Load指令并检查对应的Store值:
#include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" #include "llvm/Passes/PassPlugin.h" #include "llvm/Passes/PassManager.h" #include "llvm/Analysis/LoopAnalysisManager.h" #include "llvm/Analysis/CGSCCPassManager.h" using namespace llvm; struct ValueCheckerPass : public PassInfoMixin<ValueCheckerPass> { PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM) { for (BasicBlock &BB : F) { for (Instruction &I : BB) { // 找到所有Load指令 if (LoadInst *LI = dyn_cast<LoadInst>(&I)) { Value *ptrOperand = LI->getPointerOperand(); // 遍历这个指针的所有使用者,查找对应的Store指令 for (User *user : ptrOperand->users()) { if (StoreInst *SI = dyn_cast<StoreInst>(user)) { if (SI->getPointerOperand() == ptrOperand) { Value *storedVal = SI->getValueOperand(); // 如果存储的是常量整数,直接读取值 if (ConstantInt *constVal = dyn_cast<ConstantInt>(storedVal)) { errs() << "找到Load指令: " << *LI << "\n"; errs() << "对应的存储值为: " << constVal->getSExtValue() << "\n"; // 这里添加验证逻辑,判断是否等于31 if (constVal->getSExtValue() == 31) { errs() << "✅ 验证通过:%loaded的值确实是31\n"; } } } } } } } } return PreservedAnalyses::all(); } static bool isRequired() { return true; } }; // 注册Pass,方便opt工具调用 extern "C" LLVM_ATTRIBUTE_WEAK PassPluginLibraryInfo llvmGetPassPluginInfo() { return { LLVM_PLUGIN_API_VERSION, "ValueCheckerPass", "v0.1", [](PassBuilder &PB) { PB.registerPipelineParsingCallback( [](StringRef Name, FunctionPassManager &FPM, ArrayRef<PassBuilder::PipelineElement>) { if (Name == "value-checker") { FPM.addPass(ValueCheckerPass()); return true; } return false; } ); } }; }
使用方式:
- 把这个Pass编译成动态库(比如
libValueCheckerPass.so)。 - 用你的代码生成LLVM IR的.bc文件。
- 用opt工具运行Pass:
opt -load-plugin libValueCheckerPass.so -passes="value-checker" test.bc -disable-output,就能看到验证结果。
方法二:通过LLVM解释器(lli)运行并打印值
如果可以运行生成的IR,这是最直接的验证方式。你只需要修改代码,添加打印loaded变量的指令,然后用lli运行IR即可。
修改你的代码,在builder.CreateRetVoid();之前添加:
// 添加打印指令 builder.CreatePrint(loaded);
重新生成IR后,用lli test.ll运行,终端会输出31,直观确认值的正确性。
方法三:使用LLDB调试(适合复杂场景)
如果你的场景更复杂,需要调试整个流程,可以给变量添加调试信息,然后用LLDB加载生成的可执行文件,设置断点查看变量值。不过这种方法需要生成可执行文件,步骤稍多,但适合深入调试。
内容的提问来源于stack exchange,提问作者hany erfan
相关产品推荐
相关产品推荐

