int $0x80

LogFunctionNames 모듈 개발 - 뼈대 작성과 컴파일타임에서의 함수 이름 로깅 본문

컴퓨터공부/엘엘비엠

LogFunctionNames 모듈 개발 - 뼈대 작성과 컴파일타임에서의 함수 이름 로깅

cd80 cd80 2016.07.15 22:58
크리에이티브 커먼즈 라이선스
Creative Commons License

이 강의글의 컨셉은 LLVM을 깊게 이해한 개발이 아닌 일단 쓰는 법을 익혀보자 이기 때문에 아주 자세한 내용은 다루지 않습니다


ModulePass는 모듈을 변조하거나 최적화할때 사용하고, FunctionPass는 함수, BasicBlockPass는 각 basic block별로 적용합니다

그 중에서 우리는 각 함수의 맨 첫부분에 함수의 이름을 로깅하는 코드를 작성할 것이기 때문에 FunctoinPass를 사용합니다. 해당 개발은 다음 글에서 진행합니다


아래에서 나오는 UtilizedLLVM은 http://clang.llvm.org/get_started.html 을 그대로 따라한 LLVM 3.9.0 버젼입니다. LLVM이 업데이트되어 저 링크를 보고 따라했는데 3.9.0 이상버젼이 나온다면 이전 글에서 3.6.2를 받았을 때와 마찬가지로 branch를 지정해서 받으시면 됩니다


우선 lib/Transforms/ 로 이동합니다

Hello는 dummy module로, LLVM 모듈 개발시 참고할 만 하나 이것보다는 좀더 쉬운 예제로 시작하겠습니다


우선 우리 코드들이 들어갈 Utility 디렉토리를 생성하고 CMakeLists.txt와 LLVMBuild.txt를 수정합니다



Utility 디렉토리에서도 CMakeLists.txt를 작성해야합니다

LLVM Obfuscator 의 CMakeLists.txt를 참고하겠습니다

https://github.com/obfuscator-llvm/obfuscator/blob/llvm-3.6.1/lib/Transforms/Obfuscation/CMakeLists.txt

LLVM Pass들은 모두 LLVM 프리픽스를 가진 라이브러리 파일로 빌드됩니다

우리 모듈은 LLVMUtility로 정했고 처음 개발해볼 모듈인, 함수가 호출될때 해당 함수의 이름을 로깅하는 모듈의 파일명을 LogFunctionNames.cpp 로 정했습니다


다음으로 LLVMBuild.txt를 작성합니다

마찬가지로 LLVM Obfuscator에서 LLVMBuild.txt를 가져와서 Obfuscation을 Utility로 변경합니다

https://github.com/obfuscator-llvm/obfuscator/blob/llvm-3.6.1/lib/Transforms/Obfuscation/LLVMBuild.txt


이제 LogFunctionNames.cpp를 작성하면 됩니다

이번에도 뼈대를 LLVM Obfuscator에서 가져오겠습니다

https://github.com/obfuscator-llvm/obfuscator/blob/llvm-3.6.1/lib/Transforms/Obfuscation/BogusControlFlow.cpp

이 파일을 받아 LogFunctionNames.cpp로 파일명을 변경하고 주석과 include, 플래그를 모두 지웁니다


최종적으로 이런 형태가 되면 됩니다

이제 몇가지 수정을 하겠습니다

BogusControlFlow를 LogFunctionNames로 바꾸고

createBogus 를 createLogger로

static RegisterPass<BogusControlFlow> X("boguscf", "inserting bogus control flow"); 를 static RegisterPass<LogFunctionNames> X("logger", "inserting logging routine for functions"); 로 바꿉니다



수정할것이 약간 많아 설명을 건너뛰고 마지막으로 어떤 형태가 돼야 하는지 보여드리겠습니다

#include "llvm/Pass.h"

#include "llvm/IR/Module.h"

#include "llvm/IR/Function.h"

#include "llvm/IR/BasicBlock.h"

#include "llvm/IR/Instructions.h"

#include "llvm/IR/InstrTypes.h"

#include "llvm/IR/Constants.h"

#include "llvm/IR/Type.h"

#include "llvm/ADT/Statistic.h"

#include "llvm/IR/GlobalValue.h"

#include "llvm/IR/LLVMContext.h"

#include "llvm/Transforms/Utils/Cloning.h"

#include "llvm/Transforms/Utils/BasicBlockUtils.h"

#include "llvm/CodeGen/ISDOpcodes.h"

#include "llvm/Support/raw_ostream.h"

#include "llvm/Support/Debug.h"

#include "llvm/Support/CommandLine.h"

#include "llvm/Transforms/IPO.h"

#include <list>


#include "llvm/Transforms/Utility/LogFunctionNames.h"

using namespace llvm;

namespace {

struct LogFunctionNames : public FunctionPass {

static char ID; // Pass identification

bool flag;

LogFunctionNames() : FunctionPass(ID) {}

LogFunctionNames(bool flag) : FunctionPass(ID) {this->flag = flag; LogFunctionNames();}


virtual bool runOnFunction(Function &F){

errs() << "Current function name: [" << F.getName() << "]\n";

return false;

}

};

}


char LogFunctionNames::ID = 0;

static RegisterPass<LogFunctionNames> X("logger", "inserting logging routine for functions");


Pass *llvm::createLogger() {

return new LogFunctionNames();

}


Pass *llvm::createLogger(bool flag) {

return new LogFunctionNames(flag);

}

이렇게 되면 뼈대는 우선 작성을 완료했습니다



여기서 include한 파일중 하나인 "llvm/Transforms/Utility/LogFunctionNames.h"을 작성합니다

llvm 소스 베이스를 기준으로 include/llvm/Transforms/Utility/LogFunctionNames.h 입니다. lib 아닙니다

//===- LogFunctionNames.h - LogFunctionNames Utility pass-------------------------===//

//

//                     The LLVM Compiler Infrastructure

//

// This file is distributed under the University of Illinois Open Source

// License. See LICENSE.TXT for details.

//

//===--------------------------------------------------------------------------------===//

//

// This file contains includes and defines for the LogFunctionNames pass

//

//===--------------------------------------------------------------------------------===//


#ifndef _LOGFUNCTIONNAMES_H_

#define _LOGFUNCTIONNAMES_H_



// LLVM include

#include "llvm/Pass.h"

#include "llvm/IR/Module.h"

#include "llvm/IR/Function.h"

#include "llvm/IR/BasicBlock.h"

#include "llvm/IR/Instructions.h"

#include "llvm/IR/InstrTypes.h"

#include "llvm/IR/Constants.h"

#include "llvm/IR/Type.h"

#include "llvm/ADT/Statistic.h"

#include "llvm/IR/GlobalValue.h"

#include "llvm/IR/LLVMContext.h"

#include "llvm/Transforms/Utils/Cloning.h"

#include "llvm/Transforms/Utils/BasicBlockUtils.h"

#include "llvm/CodeGen/ISDOpcodes.h"

#include "llvm/Support/raw_ostream.h"

#include "llvm/Support/Debug.h"

#include "llvm/Support/CommandLine.h"

#include "llvm/Transforms/IPO.h"

#include <list>


using namespace std;

using namespace llvm;


// Namespace

namespace llvm {

Pass *createLogger ();

Pass *createLogger (bool flag);

}

#endif 


여기까지만 해도 빌드는 되지만 아직 createLogger()를 PassManager에 등록하지 않았습니다


LLVMObfuscator에서는 populateModulePassManager에서 모든 Pass들을 등록했지만 우리는 용도에 맞게 populateFunctionPassManager에서 createLogger를 FunctionPassManager에 추가하겠습니다

lib/Transforms/IPO/PassManagerBuilder.cpp 를 수정합니다

우선 #include "llvm/Transforms/Utility/LogFunctionNames.h" 을 인클루드 하고


void PassManagerBuilder::populateFunctionPassManager(

    legacy::FunctionPassManager &FPM) {

  addExtensionsToPM(EP_EarlyAsPossible, FPM);

  FPM.add(createLogger());

  // Add LibraryInfo if we have some.

  if (LibraryInfo)

    FPM.add(new TargetLibraryInfoWrapperPass(*LibraryInfo));

  ...생략...

}

위와같이 추가해줍니다


이상태에서 빌드하면 이전 글에서 언급했던 오류중에 하나인

/root/UtilizedLLVM/lib/Transforms/IPO/PassManagerBuilder.cpp:214: undefined reference to `llvm::createLogger()'

이런 에러가 발생합니다

해결 하는 방법은 이전 글에 있으니 기억이 안나신다면 다시 보고 오셔서 해결해보시길 바랍니다

지금부터는 이 오류를 해결한 상태에서 진행하기 때문에 꼭 지금 해결하셔야 합니다






http://clang.llvm.org/get_started.html

빌드법은 위 링크 7번 참고하세요


빌드는 꽤 오래걸립니다. 그래도 앞으로는 우리 모듈이 수정되면 우리 모듈만 새로 빌드해서 링크하기 때문에 처음에만 조금 기다리면 됩니다

소스코드는 어떤걸 사용해도 무방하나 제가 자주 테스트용으로 사용하는 코드는 아래와 같습니다. 스샷에서 사용한 코드와 같은 코드입니다

int add(int x, int y){

return x+y;

}

int main(){

printf("5+3=%d\n", add(5,3));

}




문제 하나.

undefined reference to ~~에러

이전 글 참고해주세요


문제 둘.

make 시 ld가 segmentation fault로 죽음

저는 링킹중 메모리 용량이 부족해 이런 문제가 발생했습니다

아래 링크를 참고해 swap file을 설정하시면 됩니다

https://www.digitalocean.com/community/tutorials/how-to-add-swap-on-ubuntu-14-04




첫 유틸리티 모듈은 글의 초반부에서 얘기했던 것 처럼, 프로그램의 각 함수마다 맨 처음에 함수의 이름을 출력하는 기능을 할것이기 때문에 이번 글에서는 함수의 이름을 동적으로 어떻게 가져오는지를 알아보고, 모듈 개발시 자잘한 부분인 구조적 뼈대를 갖추는 법에 대해 이전 글에 이어서 자세히 설명했습니다

다음 글에서는 puts함수를 타겟 모듈에 동적으로 삽입하는 법에 대해 다루겠습니다



LLVM API를 이용해 개발하다 보면 어느 개발에서나 그렇 듯 레퍼런스를 많이 읽어봐야 합니다

다음 글에서 다룰 함수를 동적 삽입하는 경우에도 아주 간단한 함수 하나로 끝낼 수 있지만 레퍼런스를 잘 보지 않아 300줄가량의 코드를 작성했던 적이 있습니다

오늘 코드에서는 Function 클래스의 getName 메소드만을 사용했는데, 

http://llvm.org/docs/doxygen/html/classllvm_1_1Function.html

위의 function 클래스의 레퍼런스를 보면 getName 메소드가 존재하지 않습니다

ctrl+f를 누르고 검색해보면 Value 클래스에 정의되어있는 것을 알 수 있고, 레퍼런스 맨 위의 inheritance diagram을 보면 Function이 Value를 최상위클래스로써 상속받는 다는 것을 알 수 있습니다

Value 클래스는 앞으로도 항상 보게 될 클래스이므로 이번 글에서 다룬 Function 클래스와 함께 레퍼런스를 훑어보시길 추천드립니다

신고
3 Comments
댓글쓰기 폼