如何为LLVM Pass传递运行时参数以指定待检测函数?
嘿,这个需求在LLVM Pass开发里太常见了!我给你拆解几个实际可行的方案,都是项目里验证过的靠谱路子:
方法1:通过命令行参数动态传递目标函数名
这是最直接、最符合“动态指定”需求的方案,LLVM原生支持给Pass绑定命令行参数:
- 第一步,在你的Pass类里,用LLVM的
cl::opt工具注册一个命令行选项,用来接收目标函数名:
#include "llvm/Support/CommandLine.h" static cl::opt<std::string> TargetFunction( "target-func", cl::desc("Specify the target function to analyze"), cl::value_desc("function name") );
- 第二步,在Pass的核心逻辑(比如
runOnModule或runOnFunction方法)里,直接读取这个参数并匹配模块中的函数:
bool runOnModule(Module &M) override { // 根据命令行传入的名字查找目标函数 Function *TargetFunc = M.getFunction(TargetFunction); if (!TargetFunc) { errs() << "Warning: Target function '" << TargetFunction << "' not found in module!\n"; return false; } // 这里写你的检测逻辑,比如遍历函数的基本块、指令 errs() << "Analyzing target function: " << TargetFunc->getName() << "\n"; // ...你的检测代码... return true; }
- 运行Pass时,直接在命令行指定参数即可:
opt -load ./YourPass.so -your-pass-name -target-func=my_target_function input.ll -o output.ll
方法2:通过IR元数据传递目标函数名
如果不想每次运行都敲命令行参数,也可以把目标函数名嵌入到IR文件的元数据中,让Pass自动读取:
- 首先,在生成的IR文件里添加模块级元数据(可以手动编辑,也可以通过前端编译时插入):
!llvm.module.flags = !{!0} !0 = !{i32 4, !"target-function", !"my_target_function"}
- 然后在Pass里读取这个元数据:
bool runOnModule(Module &M) override { MDNode *ModuleFlag = M.getModuleFlag("target-function"); if (!ModuleFlag) { errs() << "Error: No target function specified in module metadata!\n"; return false; } // 解析元数据中的函数名 StringRef TargetFuncName = cast<MDString>(ModuleFlag->getOperand(2))->getString(); Function *TargetFunc = M.getFunction(TargetFuncName); // 后续检测逻辑... return true; }
这种方式适合需要把目标函数和IR文件绑定的场景,不用每次运行都指定参数。
方法3:新Pass Manager的构造函数传参(LLVM 13+)
如果你用的是LLVM 13及以后的新Pass Manager(推荐现代LLVM项目使用),可以通过Pass的构造函数直接传递参数:
- 定义你的Pass类,在构造函数中接收目标函数名:
#include "llvm/Passes/PassPlugin.h" #include "llvm/Passes/PassManager.h" class TargetFuncAnalysisPass : public PassInfoMixin<TargetFuncAnalysisPass> { private: std::string TargetFuncName; public: explicit TargetFuncAnalysisPass(std::string Name) : TargetFuncName(std::move(Name)) {} PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) { Function *TargetFunc = M.getFunction(TargetFuncName); if (!TargetFunc) { errs() << "Warning: Target function '" << TargetFuncName << "' not found!\n"; return PreservedAnalyses::all(); } // 你的检测逻辑... return PreservedAnalyses::all(); } };
- 在注册Pass或编写工具时,通过命令行参数获取名字并传入Pass的构造函数:
int main(int argc, char **argv) { cl::opt<std::string> TargetFunc("target-func", cl::desc("Target function name")); cl::ParseCommandLineOptions(argc, argv); PassBuilder PB; ModulePassManager MPM; // 将命令行参数传入Pass构造函数 MPM.addPass(TargetFuncAnalysisPass(TargetFunc)); // 后续模块处理逻辑... return 0; }
几个注意点
- 一定要处理目标函数不存在的情况,避免Pass崩溃,比如上面例子中的错误提示。
- 如果是C++函数,IR中的名字会被修饰(比如
_ZN3Foo3barEv),你可以传入修饰后的名字,或者在Pass里用llvm::demangle工具把修饰名转成可读名字再匹配。 - 命令行参数的方式是最灵活的动态指定方案,也是实际开发中用得最多的。
内容的提问来源于stack exchange,提问作者mikasa
相关产品推荐
相关产品推荐

