如何在LLVM Pass中通过头文件链接外部函数并使用getOrInsertFunction
实现LLVM插桩调用display()的方案
1. 先修正头文件与实现分离
原foo.h直接包含函数实现,会导致链接冲突,建议拆分:
foo.h(仅声明):
#ifndef __FOO_H__ #define __FOO_H__ #include <stdio.h> void display(); #endif
foo.c(实现):
#include "foo.h" void display(){ printf("Hello"); }
2. 编写instrumentation.cpp(LLVM Pass代码)
以下代码实现在main函数开头插入display()调用的插桩逻辑:
#include "llvm/Pass.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Module.h" #include "llvm/Support/raw_ostream.h" #include "foo.h" // 引入函数声明以确保签名一致 using namespace llvm; namespace { struct InstrumentDisplayPass : public ModulePass { static char ID; InstrumentDisplayPass() : ModulePass(ID) {} bool runOnModule(Module &M) override { // 定义display函数的类型:无参数、无返回值 FunctionType *displayFuncType = FunctionType::get( Type::getVoidTy(M.getContext()), false ); // 获取或插入display函数到当前模块 Function *displayFunc = M.getOrInsertFunction("display", displayFuncType).getCallee(); // 定位main函数 Function *mainFunc = M.getFunction("main"); if (!mainFunc) { errs() << "未找到main函数!\n"; return false; } // 在main函数的入口基本块插入display调用 IRBuilder<> builder(&*mainFunc->getEntryBlock().getFirstInsertionPt()); builder.CreateCall(displayFunc); return true; } }; } // 匿名命名空间 char InstrumentDisplayPass::ID = 0; static RegisterPass<InstrumentDisplayPass> X( "instrument-display", "在main函数插入display()调用", false, false );
3. 编译与运行步骤
步骤1:生成LLVM中间码
# 编译foo.c为LLVM IR clang -S -emit-llvm foo.c -o foo.ll # 编译simple.c为LLVM IR clang -S -emit-llvm simple.c -o simple.ll
步骤2:编译LLVM Pass为共享库
clang++ -fPIC -shared instrumentation.cpp -o libInstrumentDisplay.so `llvm-config --cxxflags --ldflags --system-libs --libs core passes`
步骤3:应用插桩Pass到simple.ll
opt -load ./libInstrumentDisplay.so -instrument-display < simple.ll > instrumented.ll
步骤4:链接生成可执行文件并运行
clang instrumented.ll foo.ll -o simple_instrumented ./simple_instrumented # 输出:Hello World
内容的提问来源于stack exchange,提问作者Satanu Maity
相关产品推荐
相关产品推荐

