前言
继llvm安装之后,进行自定义pass实现并运行。
需要注意的是,在网上有不少文章以及官方文档,如果读者可以成功实践,那最好不过了;不然仅以此文作为参考。
环境为Ubuntu20.04。
一、环境
编写pass实践在这里是基于源码编译的方式。相关文件如下所示:
root@ca0e100b0df4:/usr/local# ls
bin etc games include lib llvm llvm-project-main man sbin share src
root@ca0e100b0df4:/usr/local/llvm-project-main# ls
CONTRIBUTING.md bolt clang-tools-extra cross-project-tests libclc libunwind llvm openmp runtimes
README.md build cmake flang libcxx lld llvm-libgcc polly third-party
SECURITY.md clang compiler-rt libc libcxxabi lldb mlir pstl utils
...llvm 为源代码文件目录,build 为编译中间目录...
二、编写MyPass并运行
这里请参考官方文档中对每一步的说明。
1、准备三个文件:
CMakeLists.txt、MyPass.cpp 和 MyPass.exports,这三个文件可以对 llvm/lib/Transforms/Hello中文件内容稍作修改获得,具体如下;
1,CMakeLists.txt中内容如下:
# If we don't need RTTI or EH, there's no reason to export anything
# from the hello plugin.
if( NOT LLVM_REQUIRES_RTTI )
if( NOT LLVM_REQUIRES_EH )
set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/MyPass.exports)
endif()
endif()
if(WIN32 OR CYGWIN)
set(LLVM_LINK_COMPONENTS Core Support)
endif()
add_llvm_library( LLVMMyPass MODULE BUILDTREE_ONLY
MyPass.cpp
DEPENDS
intrinsics_gen
PLUGIN_TOOL
opt
)
2,MyPass.cpp中内容如下:
#include "llvm/IR/Function.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define DEBUG_TYPE "mypass"
namespace {
struct MyPass : public FunctionPass {
static char ID; // Pass identification, replacement for typeid
MyPass() : FunctionPass(ID) {}
bool runOnFunction(Function &F) override {
errs() << "MyPass: ";
errs().write_escaped(F.getName()) << '\n';
return false;
}
}; // end of struct Hello
} // end of anonymous namespace
char MyPass::ID = 0; //LLVM uses ID’s address to identify a pass, so initialization value is not important.
static RegisterPass<MyPass> X("mypass", "Hello World Pass"); //这里的 mypass 为pass名。
3,MyPass.exports为空。
2、将文件放入相应的目录下
新建文件夹 MyPass,将第一步中的三个文件放入其中。然后将该文件夹放入到 llvm/lib/Transforms/ 下(自己电脑上全路径为:/usr/local/llvm-project-main/llvm/lib/Transforms/)。
在 Transforms/CMakeLists.txt 中添加新的一行: add_subdirectory(MyPass),此 CMakeLists.txt 中内容如下:
add_subdirectory(Utils)
add_subdirectory(Instrumentation)
add_subdirectory(AggressiveInstCombine)
add_subdirectory(InstCombine)
add_subdirectory(Scalar)
add_subdirectory(IPO)
add_subdirectory(Vectorize)
add_subdirectory(Hello)
add_subdirectory(ObjCARC)
add_subdirectory(Coroutines)
add_subdirectory(CFGuard)
add_subdirectory(MyPass)
3、执行
第一步:通过 make 将 MyPass.cpp 编译为 LLVMMyPass .so 文件。
root@ca0e100b0df4:/# cd /usr/local/llvm-project-main/build/
root@ca0e100b0df4:/usr/local/llvm-project-main/build# make
...因为之前已经编译过了,此次 make 时间大概几十秒就可以,仅编译新的 MyPass 文件夹...
root@ca0e100b0df4:/usr/local/llvm-project-main/build# cd lib
root@ca0e100b0df4:/usr/local/llvm-project-main/build/lib# ls -l | grep MyPass
-rwxr-xr-x 1 root root 18904 May 19 22:39 LLVMMyPass.so
第二步:建立一个测试文件为 test.c,它位于 /home/dataVolume/tmp 目录下:
#include<stdio.h>
void haha(){
printf("haha\n");
}
int heihei(int a){
return a;
}
int main(){
haha();
int tmp=heihei(4);
return 0;
}
然后生成 test.c 相应的IR文件 test.ll:
root@ca0e100b0df4:/home/dataVolume/tmp# clang -emit-llvm -S test.c test.ll
第三步,采用 opt 工具来执行 MyPass,注意参数 -enable-new-pm=0 :
root@ca0e100b0df4:/home/dataVolume/tmp# opt -load /usr/local/llvm-project-main/build/lib/LLVMMyPass.so -mypass test.ll
WARNING: You're attempting to print out a bitcode file.
This is inadvisable as it may cause display problems. If
you REALLY want to taste LLVM bitcode first-hand, you
can force output with the `-f' option.
opt: unknown pass name 'mypass'
root@ca0e100b0df4:/home/dataVolume/tmp# opt -load /usr/local/llvm-project-main/build/lib/LLVMMyPass.so -mypass test.ll -enable-new-pm=0
WARNING: You're attempting to print out a bitcode file.
This is inadvisable as it may cause display problems. If
you REALLY want to taste LLVM bitcode first-hand, you
can force output with the `-f' option.
MyPass: haha
MyPass: heihei
MyPass: main
root@ca0e100b0df4:/home/dataVolume/tmp# opt -load /usr/local/llvm-project-main/build/lib/LLVMMyPass.so -mypass test.ll -enable-new-pm=0 >/dev/null
MyPass: haha
MyPass: heihei
MyPass: main
总结
相关资料:
参数 -enable-new-pm=0 表示:采用 legacy pass 管理器,禁用 new pass 管理器。
Out-of-tree:可以不需要再llvm源代码树下构建pass
llvm-pass-skeleton:更加方便的构建pass