1编写Pass
实施步骤如下所示。
# 1 进入LLVM源地址下的lib/Transform目录中,
cd LLVM源地址/lib/Transforms
# 2 创建文件夹OPWSC,进入此文件
mkdir OPWSC
cd OPWSC
# 3 创建文件mypass.cpp及CMakeLists.txt文件
touch mypass.cpp
touch CMakeLists.txt
# 4 在/xxxx/lib/Transforms下的MakeLists.txt文件中添加以下内容
add_subdirectory(OPWSC)
# 5 进入build目录(本人安装是build目录与LLVM源地址目录放置于同一目录中)
# 如果build目录为LLVM源地址的子目录,则使用 cmake ../
cmake ../LLVM源地址
make
其中,mypass.cpp中填写以下内容
//这是必须的,因为我们正在编写 Pass,操作函数,并进行打印
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
//这是必须的,因为上述文件中所用到的函数来自于llvm命名空间
using namespace llvm;
//使用匿名命名空间,保持对象的局部性,具有内链特性 。匿名命名空间内声明的内容仅对当前文件可见
namespace {
//定义结构体mypass,它是FunctionPass类的子类。
struct mypass : public FunctionPass {
//声明了 LLVM 用于标识传递的传递标识符。这允许LLVM避免使用过多的C++运行时信息
static char ID;
mypass() : FunctionPass(ID) {}
//此处重写了FunctionPass类中中虚函数runOnFunction(Function &F)
bool runOnFunction(Function &F) override {
//errs是LLVM中定义的C++输出流,用于打印所有的函数
errs() << "my pass: ";
errs().write_escaped(F.getName()) << '\n';
return false;
}
}; // 结构体定义结束
} // 匿名命名空间结束
//初始化pass的ID,LLVM使用ID来标识pass,但其取值不重要。
char mypass::ID = 0;
//注册mypass类,所有的Pass必须经过注册才能使用。给它一个命令行参数“my”及名字“wyf's own Pass”。
//如果pass遍历了控制流图却不对其进行更改,则第三个参数设置为true。
//如果pass为分析类,则第四个参数设置为true。
static RegisterPass<mypass> X("my", "wyf's own Pass",
false /* Only looks at CFG */,
false /* Analysis Pass */);
CMakeLists.txt中填写以下内容
# 基于mypass.cpp用于生成build/lib/LLVMOPWSC.so文件,LLvm是默认加的
add_library( OPWSC MODULE mypass.cpp)
# 使用c++11
target_compile_features(OPWSC PRIVATE cxx_range_for cxx_auto_type)
# 不使用C++ RTTI.
set_target_properties(OPWSC PROPERTIES
COMPILE_FLAGS "-fno-rtti"
)
具体目录结构如下所示
-
build目录
- lib
- LLVMOPWSC.so
- lib
-
LLVM源地址目录
- lib
- Transforms
- OPWSC
- CMakeLists.txt
- mypass.cpp - CMakeLists.txt
- OPWSC
- Transforms
- lib
-
ori.c
-
ori.bc
2使用opt查看
# 1 将文件ori编译为.bc文件
clang -O3 -emit-llvm ori.c -c -o ori.bc
# opt查看
opt -load build/lib/LLVMOPWSC.so -my ori.bc
从结果可以看出,此Pass的功能是打印出ori所有中所有函数名。
至此,第一个Pass已编写完毕。