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

(LLVM を使用して) コンパイルすると、strcpy(dest,src) への呼び出しが strncpy(dest,src,n) に置き換えられるビットコードを生成するパスを作成するつもりです。

次に、呼び出し命令を見つけて変更する必要があります。フロー全体を再作成する必要はありません。既にソース コードに含まれています。

関数 passを作成し、 function内のすべての命令を反復処理し、命令call 命令であり、呼び出し先の名前が である場合はstrcpy、新しい関数への新しい call 命令を作成し、古い命令を置き換えるだけです。新しい命令で。

45また、コンパイラの値 (およびすべてのなどStringRef) と処理中のコードの値 (のサブタイプのいずれかのインスタンス) の間で、コードに根本的な誤解があるようllvm::Valueです。具体的には、45処理しているコード内の関数へのパラメーターとして使用するだけではありません。その数値から定数 int を作成する必要があり、その定数を使用できます。

最後の注意 - aから aを暗黙的に構築できます。 のコンストラクターを明示的に呼び出す必要はありません。と同じStringRefconst char*StringRefTwine

于 2013-12-02T07:55:02.763 に答える