llvm pass 初探
字数 1236 2025-08-22 12:23:18

LLVM Pass 开发指南

一、LLVM 基础概念

LLVM 最初是 "Low Level Virtual Machine" 的缩写,但现在已发展为一个编译器基础架构(infrastructure)。它不是一个完整的编译器,而是将编译器所需功能以模块化形式实现并包装成库。

现代编译器通常分为三个部分:

  1. 前端(Frontend):将高级语言代码转换为中间表示(IR)
  2. 优化层(Optimization):对IR进行分析和优化
  3. 后端(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配置

  1. 导入LLVM源码到CLion
  2. 找到llvm/CMakeLists.txt并打开
  3. 在Settings → CMake中添加Release配置
  4. 设置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. 修改构建配置

  1. llvm/lib/Transforms/Utils/CMakeLists.txt中添加Encode.cpp
  2. llvm/lib/Passes/PassRegistry.def中添加:
    FUNCTION_PASS("encode", EncodePass())
    
  3. 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:

  1. 直接使用opt工具:

    opt -passes=encode hello_clang.ll
    
  2. 构建.so文件(旧版方式)

五、应用场景

LLVM Pass在以下领域有广泛应用:

  • 代码混淆(如OLLVM的控制流平坦化、虚假控制流)
  • IR信息提取
  • 静态分析
  • 代码优化

相比自行开发脚本或插件,基于LLVM框架的项目更容易实现,因为它提供了丰富的API和基础设施。

LLVM Pass 开发指南 一、LLVM 基础概念 LLVM 最初是 "Low Level Virtual Machine" 的缩写,但现在已发展为一个编译器基础架构(infrastructure)。它不是一个完整的编译器,而是将编译器所需功能以模块化形式实现并包装成库。 现代编译器通常分为三个部分: 前端(Frontend) :将高级语言代码转换为中间表示(IR) 优化层(Optimization) :对IR进行分析和优化 后端(Backend) :将优化后的IR转换为目标机器代码 LLVM 采用这种分层设计,使其能够灵活适应不同编程语言和目标平台。 二、环境配置 1. 源码获取 从 GitHub 下载 LLVM 源码(示例使用 LLVM 18.1.8) 2. 依赖安装 3. 编译LLVM 4. CLion配置 导入LLVM源码到CLion 找到 llvm/CMakeLists.txt 并打开 在Settings → CMake中添加Release配置 设置CMake选项: 三、LLVM Pass开发 1. 新版Pass管理器特点 使用基于概念的多态性而非显式接口 所有Pass继承自 PassInfoMixin<PassT> 模板类 Pass必须实现 run() 方法,返回 PreservedAnalyses 2. 创建Pass头文件 在 llvm/include/llvm/Transforms/Utils/ 下创建 Encode.h : 3. 实现Pass 在 llvm/lib/Transforms/Utils/ 下创建 Encode.cpp : 4. 修改构建配置 在 llvm/lib/Transforms/Utils/CMakeLists.txt 中添加 Encode.cpp 在 llvm/lib/Passes/PassRegistry.def 中添加: 在 llvm/lib/Passes/PassBuilder.cpp 中添加头文件引用: 5. 编译Pass 在CLion中重新加载CMake项目,然后在 cmake-build-release 目录下执行: 注意 :如果遇到循环依赖问题,检查 lib/support/BLAKE3/CMakeLists.txt 中是否意外添加了Encode.cpp相关内容。 四、使用Pass 1. 准备测试代码 创建 hello_clang.c : 2. 生成LLVM IR 重要 :必须使用 -O3 优化选项,否则生成的IR可能无法被Pass正确处理。 3. 运行Pass 有两种方式运行Pass: 直接使用opt工具 : 构建.so文件 (旧版方式) 五、应用场景 LLVM Pass在以下领域有广泛应用: 代码混淆(如OLLVM的控制流平坦化、虚假控制流) IR信息提取 静态分析 代码优化 相比自行开发脚本或插件,基于LLVM框架的项目更容易实现,因为它提供了丰富的API和基础设施。