对于我的源代码,我有以下IR:
; ModuleID = '<stdin>'
@.str = private unnamed_addr constant [9 x i8] c"SOME_ENV_VAR\00", align 1
@.str1 = private unnamed_addr constant [26 x i8] c"Need to set $ENV_Variable.\0A\00", align 1
; Function Attrs: nounwind
define void @foo(i8* %bar) #0 {
entry:
%bar.addr = alloca i8*, align 4
%baz = alloca i8*, align 4
store i8* %bar, i8** %bar.addr, align 4
%call = call i8* @getenv(i8* getelementptr inbounds ([9 x i8]* @.str, i32 0, i32 0)) #2
store i8* %call, i8** %baz, align 4
%0 = load i8** %baz, align 4
%cmp = icmp eq i8* %0, null
br i1 %cmp, label %if.then, label %if.else
if.then: ; preds = %entry
%call1 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([26 x i8]* @.str1, i32 0, i32 0))
br label %if.end
if.else: ; preds = %entry
%1 = load i8** %bar.addr, align 4
%2 = load i8** %baz, align 4
%call2 = call i8* @strcpy(i8* %1, i8* %2) #2
br label %if.end
if.end: ; preds = %if.else, %if.then
ret void
}
; Function Attrs: nounwind
declare i8* @getenv(i8*) #0
declare i32 @printf(i8*, ...) #1
; Function Attrs: nounwind
declare i8* @strcpy(i8*, i8*) #0
我打算写一个 pass ,它在编译时(使用 LLVM )生成bitcode,其中strcpy(dest,src)的调用被替换为strncpy(dest ,SRC,n)中。
到目前为止,我编写了以下代码:
#include <stdlib.h>
#include <stdio.h>
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/IR/IRBuilder.h"
using namespace llvm;
namespace
{
Module* makeLLVMModule() {
Module* mod = new Module(llvm::StringRef("CustomPass"),getGlobalContext());
Constant* c = mod->getOrInsertFunction(llvm::StringRef("foo"),Type::getInt32Ty(getGlobalContext()),NULL);
Function* foo = cast<Function>(c);
Function::arg_iterator args =foo->arg_begin();
Value* bar = args++;
BasicBlock* Entry = BasicBlock::Create(getGlobalContext(),llvm::Twine("Entry"), foo);
BasicBlock* False = BasicBlock::Create(getGlobalContext(),llvm::Twine("False"), foo);
BasicBlock* True = BasicBlock::Create(getGlobalContext(),llvm::Twine("True"), foo);
char* pPath;
pPath = getenv("SOME_ENV_VAR");
IRBuilder<> builder(Entry);
Value* envVarDoesntExist = builder.CreateICmpEQ(llvm::StringRef(pPath),Constant::getNullValue(Value),llvm::Twine("temp"));
//---1
builder.CreateCondBr(envVarDoesntExist, False, True);
builder.SetInsertPoint(True);
builder.CreateCall3(strncpy,bar,llvm::StringRef(pPath),45,llvm::Twine("temp"));
//---2
builder.SetInsertPoint(False);
builder.CreateCall(printf,llvm::StringRef("Need to set $ENV_Variable.\n"),llvm::Twine("temp"));
//---1
return mod;
}
}
char funcP::ID = 0;
static RegisterPass<funcP> X("funcp", "funcP", false, false);
Constant::getNullValue(Value)
用于获取NULL值吗?答案 0 :(得分:0)
我打算写一个pass,它在编译时(使用LLVM)生成bitcode,其中对strcpy(dest,src)的调用被替换为strncpy(dest,src,n)。
然后你需要做的是找到调用指令并进行更改。没有必要重新创建整个流程,它已经在您的源代码中了。
您需要做的就是create a function pass,iterate over all the instructions in the function和if the instruction是call instruction,被叫方的名字是strcpy
然后创建一个新的通话对新函数的指令,然后用新指令replace旧指令。
在您的代码中,编译器中的值(例如45
和所有StringRef
)和您正在处理的代码中的值之间似乎存在一些基本的误解(其中一个的实例) llvm::Value
)的子类型。具体来说,您不能只使用45
作为您正在处理的代码中的函数的参数 - 您必须从该数字create a constant int,然后您可以使用该常量。
最后一点注意事项 - 您可以从StringRef
implicitly construct const char*
StringRef
,您无需在整个地方明确调用{{1}}的构造函数。 Same with Twine