0

对于我的源代码,我有以下 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)生成位码,其中对 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 值吗?
4

1 回答 1

0

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

那么你需要做的就是找到调用指令并进行更改。无需重新创建整个流程,它已经在您的源代码中。

您需要做的就是创建一个函数传递遍历函数中的所有指令如果指令调用指令并且被调用者的名称是strcpy然后为您的新函数创建一个新的调用指令,然后替换旧指令与新指令。

此外,在编译器中的值(例如45和所有StringRefs)和您正在处理的代码中的值(的子类型之一的实例)之间,您的代码似乎也存在一些基本的误解llvm::Value。具体来说,您不能只45在正在处理的代码中将其用作函数的参数——您必须从该数字创建一个常量 int,然后才能使用该常量。

最后一点 - 您可以从 a隐式构造a ,您不需要在所有地方显式调用 's 构造函数。与 相同StringRefconst char*StringRefTwine

于 2013-12-02T07:55:02.763 回答