最近研究了一下用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 文件, 也就是中间代码文件.
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:
- Define your statistic like this: s/ProgrammersManual.html#the-statistic-class-stats-option
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.
- Whenever you make a transformation, bump the counter:
That’s all you have to do. To get ‘opt‘ to print out the statistics gathered, use the ‘-stats‘ option:
参考:
http://llvm.org/docs/ProgrammersManual.html#the-statistic-class-stats-option