Home
avatar

230

OPT-Pass

LLVM Pass Framework 是 对 LLVM 中间表示(IR, Intermediate Representation)进行分析和转换的模块化结构。

  1. 安装LLVM
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -

sudo apt-add-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-19 main"
# 注意这里将 "llvm-toolchain-jammy-19" 改为 "llvm-toolchain-jammy-13"
sudo apt-add-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-13 main"

sudo apt-get update

sudo apt-get install -y llvm-19 llvm-19-dev llvm-19-tools clang-19
# 安装 LLVM 13 和 Clang 13
sudo apt-get install -y llvm-13 llvm-13-dev llvm-13-tools clang-13

从源构建LLVM (Ubuntu 24.04.2 LTS)(4小时)image-20250619234704468

git clone https://github.com/llvm/llvm-project.git
cd llvm-project
git checkout release/19.x
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD=host -DLLVM_ENABLE_PROJECTS=clang <llvm-project/root/dir>/llvm/
cmake --build .
  1. 构建llvm-tutor
cd ~/llvm-tutor/build
cmake -DLT_LLVM_INSTALL_DIR=/usr/lib/llvm-19 ~/llvm-tutor
make

image-20250619232233588

安装lit

pipx install lit

test

lit ~/llvm-tutor/build/test

image-20250619232157673

HelloWorld Pass

  • 清除cmake缓存
rm -rf build
mkdir build
cd build
cmake -DLT_LLVM_INSTALL_DIR=/usr/lib/llvm-19 ~/llvm-tutor/HelloWorld/
make 

image-20250620100725342

  • 准备测试文件(LLVM IR文件)
# Generate an LLVM test file
/usr/lib/llvm-19/bin/clang -O1 -S -emit-llvm ~/llvm-tutor/inputs/input_for_hello.c -o input_for_hello.ll
#-S 用于生成*.ll文件
  • opt运行
/usr/lib/llvm-19/bin/opt -load-pass-plugin ./libHelloWorld.so -passes=hello-world -disable-output input_for_hello.ll

image-20250620101145946

编译pass、生成IR、运行opt

Overview Pass

image-20250620103113350

OpcodeCounter

  • 类型:分析Pass
  • 作用:分析每个函数中使用了哪些 LLVM 指令(Opcode),打印统计摘要。

顶层构建包括所有Pass

rm -rf build
mkdir build
cd build
cmake -DLT_LLVM_INSTALL_DIR=/usr/lib/llvm-19 ..
make 
export LLVM_DIR=/usr/lib/llvm-19
# Generate an LLVM file to analyze
$LLVM_DIR/bin/clang -emit-llvm -c ~/llvm-tutor/inputs/input_for_cc.c -o input_for_cc.bc
# Run the pass through opt
$LLVM_DIR/bin/opt -load-pass-plugin ~/llvm-tutor/build/lib/libOpcodeCounter.so --passes="print<opcode-counter>" -disable-output input_for_cc.bc

image-20250620110732845

InjectFuncCall

  • 类型:代码插桩(转换Pass)
  • 作用:对每个函数插入一条 printf 调用,打印函数信息。
export LLVM_DIR=/usr/lib/llvm-19
# Generate an LLVM file to analyze
$LLVM_DIR/bin/clang -O0 -emit-llvm -c ~/llvm-tutor/inputs/input_for_hello.c -o input_for_hello.bc
# Run the pass through opt
$LLVM_DIR/bin/opt -load-pass-plugin ~/llvm-tutor/build/lib/libInjectFuncCall.so --passes="inject-func-call" input_for_hello.bc -o instrumented.bin

$LLVM_DIR/bin/lli instrumented.bin

image-20250620113444197

对比:

image-20250620114217869

StaticCallCounter

  • 类型:分析Pass

  • 作用:用于统计静态直接函数调用次数的分析 Pass,不考虑运行时行为或函数指针调用。

image-20250620130556384

export LLVM_DIR=/usr/lib/llvm-19
# Generate an LLVM file to analyze
$LLVM_DIR/bin/clang -emit-llvm -c ~/llvm-tutor/inputs/input_for_cc.c -o input_for_cc.bc
# Run the pass through opt
$LLVM_DIR/bin/opt -load-pass-plugin ~/llvm-tutor/build/lib/libStaticCallCounter.so -passes="print<static-cc>" -disable-output input_for_cc.bc

image-20250620131217757

通过static启动

~/llvm-tutor/build/bin/static input_for_cc.bc

DynamicCallCounter

  • 类型:分析Pass

  • 作用:统计定义在当前模块中的函数调用次数。

对于 DynamicCallCounter,我们必须运行插桩的二进制文件才能看到输出。

export LLVM_DIR=/usr/lib/llvm-19
# Generate an LLVM file to analyze
$LLVM_DIR/bin/clang -emit-llvm -c ~/llvm-tutor/inputs/input_for_cc.c -o input_for_cc.bc
# Instrument the input file
$LLVM_DIR/bin/opt -load-pass-plugin /home/zcm230/llvm-tutor/build/lib/libDynamicCallCounter.so -passes="dynamic-cc" input_for_cc.bc -o instrumented_bin

# Run the instrumented binary
$LLVM_DIR/bin/lli  ./instrumented_bin

image-20250620150347711

对比:

image-20250620150559889

Mixed Boolean Arithmetic Transformations

MBASub

ab==(a+b)+1a - b == (a + b反) + 1
export LLVM_DIR=/usr/lib/llvm-19
$LLVM_DIR/bin/clang -emit-llvm -S ~/llvm-tutor/inputs/input_for_mba_sub.c -o input_for_sub.ll
$LLVM_DIR/bin/opt -load-pass-plugin ~/llvm-tutor/build/lib/libMBASub.so -passes="mba-sub" -S input_for_sub.ll -o out.ll

input_for_sub.ll

image-20250620153532909

经pass优化后的out.ll:

image-20250620153623689

MBAAdd

a + b == (((a ^ b) + 2 * (a & b)) * 39 + 23) * 151 + 111
export LLVM_DIR=/usr/lib/llvm-19
$LLVM_DIR/bin/clang -O1 -emit-llvm -S ~/llvm-tutor/inputs/input_for_mba.c -o input_for_mba.ll
$LLVM_DIR/bin/opt -load-pass-plugin ~/llvm-tutor/build/lib/libMBAAdd.so -passes="mba-add" -S input_for_mba.ll -o out.ll
LLVM Optimization

喜欢这篇文章嘛,觉得文章不错的话,奖励奖励我!

支付宝打赏支付宝微信打赏 微信