LLVM Pass插入打印基本块名称时运行时错误求助
LLVM Pass插入打印Basic Block名称语句的错误修复
错误原因
报错信息Call parameter type does not match function signature!明确指出核心问题:
printBBname函数要求参数类型为i8*(对应C语言的const char*)- 原代码用
ConstantDataArray::getString生成的是[N x i8]类型的常量数组,直接传递给函数调用导致类型不兼容 - 额外问题:每次遍历Basic Block时重复创建
printBBname函数,会导致模块中出现多个同名函数定义
修复方案
- 参数类型适配:使用
IRBuilder::CreateGlobalStringPtr直接生成i8*类型的字符串指针,替代ConstantDataArray::getString - 避免重复定义函数:在遍历Basic Block前,先检查当前模块是否已存在
printBBname函数,仅在不存在时创建一次
修改后的完整Pass代码
#include "llvm/Pass.h" #include "llvm/IR/Function.h" #include "llvm/Support/raw_ostream.h" #include "llvm/IR/Module.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Value.h" #include "llvm/IR/Instruction.h" using namespace llvm; using namespace std; extern "C" void printBBname(const char *name) { printf("Basic Block: %s\n", name); } namespace { struct Hello : public FunctionPass { static char ID; Hello() : FunctionPass(ID) {} bool runOnFunction(Function &F) override { errs() << "Hello: "; errs().write_escaped(F.getName()) << '\n'; unsigned count = 0; LLVMContext& context = F.getContext(); Module *m = F.getParent(); assert(m != nullptr && "Module is null"); // 仅创建一次printBBname函数 Function *printFunc = m->getFunction("printBBname"); if (!printFunc) { Type *returnType = Type::getVoidTy(context); PointerType *argType = PointerType::get(Type::getInt8Ty(context), 0); FunctionType *FuncType = FunctionType::get(returnType, argType, false); printFunc = Function::Create(FuncType, Function::ExternalLinkage, "printBBname", m); assert(printFunc != nullptr && "Failed to create printBBname function"); } for(Function::iterator bb = F.begin(), e = F.end(); bb != e; ++bb){ bb->setName(F.getName() + "_" + to_string(count++)); errs() << "Basic Block name: " << bb->getName() << ", size: " << bb->size() << "\n"; IRBuilder<> Builder(context); // 创建i8*类型的字符串指针 Value *strPtr = Builder.CreateGlobalStringPtr(bb->getName()); Builder.SetInsertPoint(&*bb, bb->getFirstInsertionPt()); Builder.CreateCall(printFunc, strPtr); } return true; } }; } char Hello::ID = 0; static RegisterPass<Hello> X("hello", "Hello World Pass", false /* Only looks at CFG */, false /* Analysis Pass */);
测试验证
- 重新编译Pass:
cd ../skeleton/build cmake .. make
- 重新生成测试IR并运行Pass:
clang -emit-llvm -c hello.c -o hello.bc opt -load ../skeleton/build/libSkeletonPass.so --hello <hello.bc> out.bc
- 生成可执行文件并运行:
clang out.bc -o hello ./hello
运行后会输出每个Basic Block的名称,符合预期。
内容的提问来源于stack exchange,提问作者Yuta Nakamura
相关产品推荐
相关产品推荐

