llvm pass 初探
字数 1236 2025-08-22 12:23:18
LLVM Pass 开发指南
一、LLVM 基础概念
LLVM 最初是 "Low Level Virtual Machine" 的缩写,但现在已发展为一个编译器基础架构(infrastructure)。它不是一个完整的编译器,而是将编译器所需功能以模块化形式实现并包装成库。
现代编译器通常分为三个部分:
- 前端(Frontend):将高级语言代码转换为中间表示(IR)
- 优化层(Optimization):对IR进行分析和优化
- 后端(Backend):将优化后的IR转换为目标机器代码
LLVM 采用这种分层设计,使其能够灵活适应不同编程语言和目标平台。
二、环境配置
1. 源码获取
从 GitHub 下载 LLVM 源码(示例使用 LLVM 18.1.8)
2. 依赖安装
sudo apt-get install g++
sudo apt-get install make
sudo apt-get install cmake
sudo apt install ninja-build
3. 编译LLVM
cd llvm-project
sudo cmake -S llvm -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang"
cd build
ninja -j8
4. CLion配置
- 导入LLVM源码到CLion
- 找到
llvm/CMakeLists.txt并打开 - 在Settings → CMake中添加Release配置
- 设置CMake选项:
-G Ninja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang" -DBUILD_SHARED_LIBS=ON
三、LLVM Pass开发
1. 新版Pass管理器特点
- 使用基于概念的多态性而非显式接口
- 所有Pass继承自
PassInfoMixin<PassT>模板类 - Pass必须实现
run()方法,返回PreservedAnalyses
2. 创建Pass头文件
在llvm/include/llvm/Transforms/Utils/下创建Encode.h:
#ifndef LLVM_TRANSFORMS_UTILS_ENCODE_H
#define LLVM_TRANSFORMS_UTILS_ENCODE_H
#include "llvm/IR/PassManager.h"
namespace llvm {
class EncodePass : public PassInfoMixin<EncodePass> {
public:
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
} // namespace llvm
#endif // LLVM_TRANSFORMS_UTILS_ENCODE_H
3. 实现Pass
在llvm/lib/Transforms/Utils/下创建Encode.cpp:
#include "llvm/Transforms/Utils/Encode.h"
using namespace llvm;
PreservedAnalyses EncodePass::run(Function &F, FunctionAnalysisManager &AM) {
errs() << F.getName() << "\n";
return PreservedAnalyses::all();
}
4. 修改构建配置
- 在
llvm/lib/Transforms/Utils/CMakeLists.txt中添加Encode.cpp - 在
llvm/lib/Passes/PassRegistry.def中添加:FUNCTION_PASS("encode", EncodePass()) - 在
llvm/lib/Passes/PassBuilder.cpp中添加头文件引用:#include "llvm/Transforms/Utils/Encode.h"
5. 编译Pass
在CLion中重新加载CMake项目,然后在cmake-build-release目录下执行:
ninja -j2 opt
注意:如果遇到循环依赖问题,检查lib/support/BLAKE3/CMakeLists.txt中是否意外添加了Encode.cpp相关内容。
四、使用Pass
1. 准备测试代码
创建hello_clang.c:
#include <stdio.h>
void test_hello1() {
printf("test_hello1\n");
return;
}
void test_hello2() {
printf("test_hello2\n");
return;
}
int main(int argc, char const *argv[]) {
printf("hello clang\n");
return 0;
}
2. 生成LLVM IR
clang -O3 -emit-llvm hello_clang.c -S -o hello_clang.ll
重要:必须使用-O3优化选项,否则生成的IR可能无法被Pass正确处理。
3. 运行Pass
有两种方式运行Pass:
-
直接使用opt工具:
opt -passes=encode hello_clang.ll -
构建.so文件(旧版方式)
五、应用场景
LLVM Pass在以下领域有广泛应用:
- 代码混淆(如OLLVM的控制流平坦化、虚假控制流)
- IR信息提取
- 静态分析
- 代码优化
相比自行开发脚本或插件,基于LLVM框架的项目更容易实现,因为它提供了丰富的API和基础设施。