基于legacy pass manager的.a 格式pass编写

1.在github页面下载最新的llvm工程,现在最新的版本应该对应着是llvm13
cmake生成xcode工程

cd llvm-project cmake -S llvm -B build -G Xcode -DLLVM_ENABLE_PROJECTS="clang; libcxx; libcxxabi"

-S 指定llvm文件夹为源
编写一个SimplePass
2.cd 到 llvm-project/llvm/include/llvm/Transforms 创建Obfuscation文件夹,创建SimplePass头文件
cd llvm-project/llvm/include/llvm/Transforms mkdir Obfuscation cd Obfuscation touch SimplePass.h

将以下代码复制到SimplePass.h里
#include "llvm/IR/Function.h" #include "llvm/Pass.h" #include "llvm/Support/raw_ostream.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" // Namespace using namespace std; namespace llvm { Pass *createSimplePass(bool flag); }

3.cd 到 llvm-project/llvm/lib/Transforms 创建Obfuscation文件夹,创建SimplePass源文件、cmakelists.txt文件
cd llvm-project/llvm/lib/Transforms mkdir Obfuscation cd Obfuscation touch SimplePass.cpp touch CMakeLists.txt

复制以下内容到CMakeLists.txt
add_llvm_component_library(LLVMObfuscation SimplePass.cppADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms/Obfuscation/DEPENDS intrinsics_gen )

复制以下内容到SimplePass.cpp
#include "llvm/Transforms/Obfuscation/SimplePass.h"using namespace llvm; namespace { struct SimplePass : public FunctionPass { static char ID; // Pass identification, replacement for typeid bool flag; SimplePass() : FunctionPass(ID) { errs() << "FunctionPass\n"; } SimplePass(bool flag) : FunctionPass(ID) { this->flag = flag; errs() << "FunctionPass11\n"; SimplePass(); }virtual bool runOnFunction(Function &F) { errs() << "runOnFunction\n"; if(this->flag){ Function *tmp = &F; // 遍历函数中的所有基本块 for (Function::iterator bb = tmp->begin(); bb != tmp->end(); ++bb) { // 遍历基本块中的每条指令 for (BasicBlock::iterator inst = bb->begin(); inst != bb->end(); ++inst) { // 是否是add指令 if (inst->isBinaryOp()) { if (inst->getOpcode() == Instruction::Add) { ob_add(cast(inst)); } } } } return true; } return false; }// a+b === a-(-b) void ob_add(BinaryOperator *bo) { BinaryOperator *op = NULL; if (bo->getOpcode() == Instruction::Add) { // 生成 (-b) op = BinaryOperator::CreateNeg(bo->getOperand(1), "", bo); // 生成 a-(-b) //op = BinaryOperator::Create(Instruction::Sub, bo->getOperand(0), op, "", bo); op = BinaryOperator::Create(Instruction::Add, bo->getOperand(0), op, "", bo); op->setHasNoSignedWrap(bo->hasNoSignedWrap()); op->setHasNoUnsignedWrap(bo->hasNoUnsignedWrap()); }// 替换所有出现该指令的地方 bo->replaceAllUsesWith(op); } }; } char SimplePass::ID = 0; // 注册pass 命令行选项显示为simplepass static RegisterPass X("simplepa", "this is a Simple Pass"); Pass *llvm::createSimplePass(bool flag) { errs() << "createSimplePass\n"; return new SimplePass(flag); }

4.修改上级目录CMakeLists.txt,添加subdirectory
add_subdirectory(Obfuscation)

5.修改llvm-project/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp代码加入SimplePass
@1.初始化opt命令行参数,找和其他opt中间插进去,simple为在命令行参数名
#pragma mark - 添加的pass using namespace llvm namespace cusllvm { ....其他的opt省略 static cl::opt SimplePass("simple", cl::init(false), cl::desc("Enable simple pass")); }

@2.添加SimplePass,传入命令行参数SimplePass
#pragma mark - 添加 MPM.add(createSimplePass(cusllvm::SimplePass));

@3.修改llvm-project/llvm/lib/Transforms/IPO/CMakeLists.txt 加入链接SimplePass的文件夹名字
add_llvm_component_library(LLVMipo AlwaysInliner.cpp ...省略ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms ${LLVM_MAIN_INCLUDE_DIR}/llvm/Transforms/IPODEPENDS intrinsics_gen omp_genCOMPONENT_NAME IPOLINK_COMPONENTS ...省略 Scalar //加入Obfuscation Obfuscation )

6.build clang
@1.先生成工程,并非必要
cmake -S llvm -B build -G Xcode -DLLVM_ENABLE_PROJECTS="clang; libcxx; libcxxabi"

@2.重新编译clang工程
7.clang使用simplepass,注意这里一定要带上-flegacy-pass-manager参数,因为可能是在clang15以上默认是用的new-pass-manager,这里曾经卡了我很久,我说pass写好怎么不执行
pass执行格式 -mllvm -simple ,simple是opt注册名
./clang -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -mllvm -simple -flegacy-pass-manager test1.c -o after-test1

总结:1.clang15以后需要加-flegacy-pass-manager,老版本好像不要 2.pass执行格式-mllvm -opt注册名
3.每次改动一点点pass代码需要重新编译clang才行,是pass生成的.a文件链接进去的
思考:每次编译clang太耗时间了,就算一点点改动,也要编译10分钟,能不能编译好.a文件直接链接到clang文件里呢? (好像不可行,.o文件才是可链接状态)
解决方式1:生成dylib文件,用opt作测试更快
【基于legacy pass manager的.a 格式pass编写】参考:
https://github.com/0x3f97/oll...
https://neyoufan.github.io/20...

    推荐阅读