LLVM Pass 初探

最近研究了一下用llvm對源代碼進行分析, 如在特定的指定中插入函數, 分析函數訪存次數等, 下面做一些記錄.


1. 首先要配置環境

先到 llvm 官網下載最新版llvm源碼. 我下載的是 3.5.0 版本. 解壓到用戶主目錄. 我的文件名是 llvm-3.5.0.src.

cd ~/llvm-3.5.0.src

./configure

./make

編譯的時間比較長, 耐心等待.


2.  將源文件編譯成bitcode文件

Getting Started with the LLVM System 一文最後的example提供了方法:

假設源文件名爲 hello.c編譯生成 .bc 文件, 也就是中間代碼文件.

% clang -O3 -emit-llvm  -c hello.c -o hello.bc


3. 編寫pass文件並編譯

這裏有一篇官方教程: Writing an LLVM Pass

在源碼目錄的lib/Transforms/下新建一個文件夾 my_pass.

在my_pass 目錄中編寫pass文件和Makefile, 

pass文件實際上是一個cpp文件, Writing an LLVM Pass中有一個示例:

#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

namespace {
  struct Hello : public FunctionPass {
    static char ID;
    Hello() : FunctionPass(ID) {}

    virtual bool runOnFunction(Function &F) {
      errs() << "Hello: ";
      errs().write_escaped(F.getName()) << '\n';
      return false;
    }
  };
}

char Hello::ID = 0;
static RegisterPass<Hello> X("hello", "Hello World Pass", false, false);

Makefile 文件:

# Makefile for hello pass

# Path to top level of LLVM hierarchy
LEVEL = ../../..

# Name of the library to build
LIBRARYNAME = Hello

# Make the shared library become a loadable module so the tools can
# dlopen/dlsym on the resulting library.
LOADABLE_MODULE = 1

# Include the makefile implementation stuff
include $(LEVEL)/Makefile.common

到了這一步之後, 官方教程出了點問題, 官方教程說直接在my_pass目錄執行make命令, 實際上這是錯的, 會出現這個問題. 正確的做法是:

(1) 先修改 llvm-3.5.0.src/lib/Transforms 目錄下的Makefile文件, 在變量PARALLEL_DIRS後加入你新建的目錄名 my_pass, 不加的話make的時候不會編譯你新建的目錄.

(2) 再回到源碼目錄 llvm-3.5.0.src/ 先執行make, 這個時候就會編譯你的my_pass目錄下的pass文件了. 並在 llvm-3.5.0.src/Release+Asserts/lib 目錄下會生成 一個對應的Hello.so文件, 這就是可以被opt命令加載的文件了.


4. run a pass with opt

進入到my_pass目錄, 執行

opt -load ../../../Release+Asserts/lib/Hello.so -hello < hello.bc > /dev/null


5. 記錄特定指令執行次數的方法

http://llvm.org/docs/ProgrammersManual.html#statistic

Often you may run your pass on some big program, and you’re interested to see how many times it makes a certain transformation. Although you can do this with hand inspection, or some ad-hoc method, this is a real pain and not very useful for big programs. Using the Statistic class makes it very easy to keep track of this information, and the calculated information is presented in a uniform manner with the rest of the passes being executed.

There are many examples of Statistic uses, but the basics of using it are as follows:

  1. Define your statistic like this: s/ProgrammersManual.html#the-statistic-class-stats-option
#define DEBUG_TYPE "mypassname"   // This goes before any #includes.

#include "llvm/ADT/Statistic.h"

STATISTIC(NumXForms, "The # of times I did stuff");

The STATISTIC macro defines a static variable, whose name is specified by the first argument. The pass name is taken from the DEBUG_TYPE macro, and the description is taken from the second argument. The variable defined (“NumXForms” in this case) acts like an unsigned integer.

  1. Whenever you make a transformation, bump the counter:
++NumXForms;   // I did stuff!

That’s all you have to do. To get ‘opt‘ to print out the statistics gathered, use the ‘-stats‘ option:

$ opt -stats -mypassname(這裏好像有問題, 加了mypassname參數會報錯, 去掉就好了) < program.bc > /dev/null
... statistics output ...


參考:

https://sites.google.com/site/arnamoyswebsite/Welcome/updates-news/llvmpasstoinsertexternalfunctioncalltothebitcode

Writing an LLVM Pass

http://llvm.org/docs/ProgrammersManual.html#the-statistic-class-stats-option

http://llvm.org/doxygen/classllvm_1_1Pass.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章