LLVM15加载自定义pass的方法
最近学习LLVM,尝试编写LLVM Pass,发现网上的许多博客文章加载自定义Pass的方式仍然停留在旧版方法,LLVM13开始对PassManager进行了变更,在LLVM13-14版本可以采用临时方案-flegacy-pass-manager解决,但是到了LLVM15+,旧版的LegacyPassManager只能用opt加载,所以最好是学习使用新版的PassManager。
1. 编写自定义Pass(LLVM15+opt适配旧版PassManager)
参考LLVM官方Developing LLVM passes out of source
(1)创建目录结构,当前目录llvmPass下:
1 | . |
(2)llvmPass/CMakeLists:
先添加环境变量$LLVM_HOME 指向LLVM15下的LLVM-llvmorg-15.0.6/llvm/build,编写pass时需要用到该目录下的库文件等。
1 | if(NOT DEFINED ENV{LLVM_HOME}) |
(3)llvmPass/FuncName/CMakeList.txt:
1 | SET(CMAKE_CXX_FLAGS "-Wall -fno-rtti") |
(4)llvmPass/FuncEncrypt.cpp:
简单实现自定义Pass的功能:将程序函数名修改为encryptedXXX
1 |
|
cmake构建后,生成libFuncEncryptPass.so,查看下注册结果:
1 | opt -load ./llvmPass/build/FuncName/libFuncEncryptPass.so -help | grep Encrypt |
编写一个test.c文件,随便定义几个函数:
1 | func1(){ |
采用llvm15方案加载自定义pass:
clang:
1 | clang -fpass-plugin=./llvmPass/build/FuncName/libFuncEncryptPass.so test.c error: unable to load plugin './llvmPass/build/FuncName/libFuncEncryptPass.so': 'Plugin entry point not found in './llvmPass/build/FuncName/libFuncEncryptPass.so'. Is this a legacy plugin?' |
opt:
先编成IR:
1 | clang -emit-llvm test.c -S -o test.ll |
1 | opt -load-pass-plugin ./llvmPass/build/FuncName/libFuncEncryptPass.so -S -passes=FuncEncrypt test.ll -o test1.ll |
可以看到两者都提示没有找到plugin entry point
如开头所说,这是因为LLVM13开始采用了新的PassManager,对于opt可以增加-enable-new-pm=0解决:
1 | opt -load ./llvmPass/build/FuncName/libFuncEncryptPass.so -S --FuncEncrypt -enable-new-pm=0 test.ll -o test1.ll |
可以看到test.c中两个函数名都被成功修改。
2. NewPassManager方案(LLVM13+)
可能存在的问题
(1)执行clang 或 opt 后 提示 undefined symbol: _ZTIN4llvm12FunctionPassE:
Undefined Symbol: _ZTIN4llvm12FunctionPassE There is an inconsistency between LLVM main build system and the cmake support for building out-of-source. The LLVM binaries are built without runtime type info “-fno-rtti”. Therefore, the out-of-source passes have to be built the same way otherwise opt will complain that symbol “_ZTIN4llvm12FunctionPassE” is undefined.
To solve this problem, LLVM must be compile with RTTI enabled. Add “-DLLVM_REQUIRES_RTTI=1” to cmake, or add “REQUIRES_RTTI=1” to make.
意思是编译LLVM时没有开启RTTI 所以自定义pass也应该以相同方式构建,在CMakeLists中加一行:SET(CMAKE_CXX_FLAGS “-Wall -fno-rtti”)
参考链接
https://releases.llvm.org/15.0.0/docs/WritingAnLLVMPass.html#introduction-what-is-a-pass