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...