需要有关撰写通行证的见解

时间:2013-12-01 07:04:32

标签: llvm llvm-clang llvm-ir

对于我的源代码,我有以下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);
  1. 从--- 1:如何将llvm :: StringRef转换为Value *?
  2. 从--- 2:如何将char *转换为Value *
  3. 可以Constant::getNullValue(Value)用于获取NULL值吗?

1 个答案:

答案 0 :(得分:0)

  

我打算写一个pass,它在编译时(使用LLVM)生成bitcode,其中对strcpy(dest,src)的调用被替换为strncpy(dest,src,n)。

然后你需要做的是找到调用指令并进行更改。没有必要重新创建整个流程,它已经在您的源代码中了。

您需要做的就是create a function passiterate over all the instructions in the functionif the instructioncall instruction,被叫方的名字是strcpy然后创建一个新的通话对新函数的指令,然后用新指令replace旧指令。

在您的代码中,编译器中的值(例如45和所有StringRef)和您正在处理的代码中的值之间似乎存在一些基本的误解(其中一个的实例) llvm::Value)的子类型。具体来说,您不能只使用45作为您正在处理的代码中的函数的参数 - 您必须从该数字create a constant int,然后您可以使用该常量。

最后一点注意事项 - 您可以从StringRef implicitly construct const char* StringRef,您无需在整个地方明确调用{{1}}的构造函数。 Same with Twine