1. 下载和编译 LLVM
LLVM 下载地址 http://releases.llvm.org/download.html,
目前最新版是 6.0.0,下载完成之后,执行 tar 解压 llvm 包:
1 2 |
tar -xzvf llvm-6.0.0.src.tar.xz |
再下载 Clang 解压:
1 2 |
tar -xzvf cfe-6.0.0.src.tar.xz |
将 cfe-6.0.0.src 目录复制到 llvm-6.0.0.src/tools,重命名为 clang。通过 brew 安装 cmake:
1 2 |
brew install cmake |
然后在命令行下切换到 llvm-6.0.0.src 目录,新建 build 目录,切换到 build 目录执行 cmake 生成配置文件,命令如下:
1 2 3 4 |
mkdir build cd build cmake -G Xcode CMAKE_BUILD_TYPE="Debug" .. |
执行完成之后,可以看到 Xcode 的工程文件 LLVM.xcodeproj,打开工程文件,会提示是否自动创建 Schemes,如图所示:
点击 Manually Manage Schemes 手动创建,添加 ALL_BUILD,如图所示:
然后在 Xcode 上进行编译,编译过程比如慢,可能得二十分钟到半小时左右,全部编译完文件会在 11G 左右。
2. 编写 Pass 代码
我们编写第一个 Pass 的功能很简单,只是输出程序中的每个方法名,操作步骤如下:
(1) 在 lib/Transforms 目录下新建一个文件夹,文件夹名称为 FirstPass,在 FirstPass 目录下创建文件 FirstPass.cpp,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
//导入头文件 #include "llvm/ADT/Statistic.h" #include "llvm/IR/Function.h" #include "llvm/Pass.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; //指定所使用的 LLVM 命名空间 namespace { //定义 First 类继承自 FunctionPass struct First : public FunctionPass { static char ID; // Pass ID First() : FunctionPass(ID) {} //定义 runOnFunction 重载继承父类的抽象虚函数 bool runOnFunction(Function &F) override { //打印每个函数的名字 errs() << "First: "; errs().write_escaped(F.getName()) << '\n'; return false; } }; } char First::ID = 0; //初始化 Pass ID //最后注册 FirstPass, 指定命令行参数为 First static RegisterPass <First>X("First", "First Pass"); |
(2) 然后再在 lib/Transforms/FirstPass 下新建 CMakeLists.txt,编辑内容如下:
1 2 3 4 5 6 7 8 9 |
add_llvm_loadable_module( LLVMFirstPass FirstPass.cpp DEPENDS intrinsics_gen PLUGIN_TOOL opt ) |
(3) 在 lib/Transforms/CMakeLists.txt 添加 add_subdirectory(FirstPass)
(4) 重新编译整个工程,添加 LLVMFirstPass 到 Scheme,如图:
编译 LLVMFirstPass 成功之后,动态库保存在 build/Debug/lib/LLVMFirstPass.dylib。
3. 使用 opt 加载和调试 Pass
(1) 编写一段测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <stdio.h> int test() { printf("test\n"); return 0; } int main(){ int num = 1; printf("main %d\n", num); test(); return 0; } |
编译源文件,生成 Bitcode:
1 2 |
clang -emit-llvm -c test.c -o test.bc |
(2) 在 Xcode 中将 opt 添加到 scheme,编辑 scheme 的启动参数,-load 参数指向 LLVMFirstPass.dylib,-First 参数就是刚才在源代码里注册的参数,如图所示:
编译 opt 并运行起来,可以看到输出了程序的每个函数名称,并且前面还打印了 First 字符串,效果如下:
1 2 3 4 |
First: test First: main Program ended with exit code: 0 |
opt 编译成功保存在 build/Debug/bin/opt。也可以给 pass 的代码下断点,在 Xcode 上运行 opt 就可以调试 pass,效果如图:
转载请注明:exchen's blog » 开发和调试第一个 LLVM Pass