如何创建带 -mllvm 选项的 llvm pass
-mllvm
是 LLVM 编译器的一个选项,它允许你传递参数给 LLVM 的底层代码生成器。这个选项通常用于调试或者优化 LLVM 的代码生成 。
添加头文件
选择在某个地方创建你的头文件,添加必要的c/c++库,并在命名空间中声明 -mllvm 启动时激活的函数
以 obfuscator/include/llvm/Transforms/Obfuscation/Substitution.h 为例 :
#ifndef _SUBSTITUTIONS_H_
#define _SUBSTITUTIONS_H_
// LLVM include
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/CryptoUtils.h"
// Namespace
using namespace llvm;
using namespace std;
namespace llvm {
Pass *createSubstitution ();
Pass *createSubstitution (bool flag);
}
#endif
创建 -mllvm 参数
打开 obfuscator/lib/Transforms/IPO/PassManagerBuilder.cpp ,添加你创建的头文件:
#include "llvm/Transforms/Obfuscation/Substitution.h"
定义一个命令行选项
static cl::opt<bool> Substitution("sub", cl::init(false),
cl::desc("Enable instruction substitutions"));
cl::opt<bool>
: 这是 LLVM 命令行库中的一个模板类,用于定义一个命令行选项。这里的<bool>
指定了这个选项的类型是布尔型,可以修改<>中的内容变成其他类型,例如<std::string>Substitution
: 这是变量的名称,也是命令行选项的名称"sub"
: 这是命令行选项的标志,用户在命令行中使用这个标志来设置这个选项,使用方式为:-mllvm -subcl::init(false)
: 这是一个初始化器,指定了这个选项的初始值是false
cl::desc("Enable instruction substitutions")
: 这是一个描述器,提供了这个选项的描述信息。
在 populateModulePassManager 函数中使用创建的命令行选项调用头文件的函数
MPM.add(createSubstitution(Substitution));
创建pass文件夹
在obfuscator/lib/Transforms/ 目录下创建一个文件夹,例如obfuscator/lib/Transforms/Obfuscation ,在目录中创建
Makefile 、LLVMBuild.txt、CMakeLists.txt
创建CMakeLists.txt:
add_llvm_library(LLVMObfuscation
......
Substitution.cpp
......
)
-
add_llvm_library
: 这是 LLVM 构建系统中的一个函数,用于添加一个新的库。这个函数会处理所有必要的构建目标和依赖关系,以确保库可以被正确地构建和链接 -
LLVMObfuscation
: 这是添加的库的名称 -
Substitution.cpp
: 这是实现pass的源文件
创建LLVMBuild.txt:
[component_0]
type = Library
name = Obfuscation
parent = Transforms
library_name = Obfuscation
-
[component_0]
: 这是一个组件的标识符。在一个LLVMBuild.txt
文件中,可以定义多个组件,每个组件都有一个唯一的标识符 -
type = Library
: 这指定了组件的类型。在这个例子中,组件的类型是Library
,表示这是一个库。 -
name = Obfuscation
: 这是组件的名称。在这个例子中,组件的名称是Obfuscation
。 -
parent = Transforms
: 这指定了组件的父组件。在这个例子中,父组件是Transforms
。这意味着这个库是Transforms
组件的一部分。 -
library_name = Obfuscation
: 这是库的名称。在这个例子中,库的名称也是Obfuscation
。
创建Makefile:
LEVEL = ../../..
LIBRARYNAME = LLVMObfuscation
#LOADABLE_MODULE = 1
BUILD_ARCHIVE = 1
include $(LEVEL)/Makefile.common
LEVEL = ../../..
: 用于指定项目的根目录相对于当前目录的位置LIBRARYNAME = LLVMObfuscation
: 用于指定要构建的库的名称BUILD_ARCHIVE = 1
: 设置了一个变量BUILD_ARCHIVE
,其值为1
。用于指定要构建的是一个静态库。include $(LEVEL)/Makefile.common
: 包含了一个公共的 Makefile 文件,该文件通常包含了一些通用的构建规则和设置。这里,它的路径是相对于LEVEL
变量指定的目录的。
创建pass
在文件夹中创建对应的源文件,以Substitution.cpp为例:
#include "llvm/Transforms/Obfuscation/Substitution.h"
......
namespace {
struct Substitution : public FunctionPass {
......
}
};
} // end of anonymous namespace
char Substitution::ID = 0;
static RegisterPass<Substitution> X("substitution", "operators substitution");
Pass *llvm::createSubstitution(bool flag) { return new Substitution(flag); }
......
bool Substitution::runOnFunction(Function &F){
......
}
......
-
struct Substitution : public FunctionPass
: 这是Substitution
结构体的定义,它继承自FunctionPass
,是一个函数级别的 pass。 -
char Substitution::ID = 0;
: 这行代码定义了Substitution
类的一个静态成员ID
,并将其初始化为0
。在 LLVM 中,每个 pass 类都需要有一个唯一的ID
成员,用于在 PassManager 中识别这个 pass。 -
static RegisterPass<Substitution> X
: 这行代码创建了一个RegisterPass<Substitution>
对象X
,并将其注册为一个 pass。"substitution"
是这个 pass 的命令行选项名,"operators substitution"
是这个 pass 的描述。
在对应的LLVMBuild.txt中添加pass
在父目录的LLVMBuild.txt添加pass:
[common]
subdirectories = ...... Obfuscation ......
在同目录的IPO文件夹的LLVMBuild.txt添加pass:
[component_0]
......
required_libraries = ...... Obfuscation ......
不透明谓词"是一个在程序执行到某处时,对程序员而言其值必然是已知的表达式。然而,由于某种原因,编译器或者说静态分析器无法推断出这个值,只能在运行时确定,可以作为控制流混淆时的条件生成器,用于构造一些必真或必假的条件,改造目标程序的控制流
OpaquePredicate 主要实现了使用不透明谓词来改造基本块的控制流,生成分支结构或循环
分支结构的不透明谓词混淆
分支结构的不透明谓词混淆主要是对一些代数上的永真式和永假式进行判断,并将需要执行的指令放入必定跳转到的分支中
RandMod
RandMod函数使用以下不透明谓词:
x % z = 1; y % z = 0; (x * y) % z = 0
x,y,z都是随机的整数
PrimeOr
PrimeOr函数使用以下不透明谓词:
p 1 ∗ ( x ) ! = p 2 ∗ ( y ) p1*(x) !=p2 *(y) p1∗(x)!=p2∗(y)
p1p2是两个不相等的素数,x,y是从程序流程中取得的两个数
timeop
timeop函数使用以下不透明谓词:
time()1 !=time() 2
time()是c/c++标准函数,time()1,time()2分别是两次调用time函数的返回值
循环结构的不透明谓词混淆
循环结构的不透明谓词混淆主要是对一些迭代的参数进行判断,当参数迭代到符合某项条件后,执行指定的指令,并跳出循环,迭代的过程对程序员而言是必然的
Threexplusone
Threexplusone函数参考了数学上的3x+1猜想,对于每一个正整数,如果它是奇数,则对它乘3再加1,如果它是偶数,则对它除以2,如此循环,最终都能够得到1。
Threexplusone先选择一个随机数作为x,对x进行3x+1迭代,当x小于某个随机数时,执行指定的指令,并停止迭代
Axplusb
Axplusb函数参考了3x+1猜想在自然数上的推广,对于每一个正整数x,如果它对某个随机数n求余不等于0,则对它乘A再加b,其中n<A<2n,b为某个整数,使得Ax+b对n求余等于0,如果它对n求余等于0,则对它除以n,如此迭代,最终会收敛于某个有理数的循环
Axplusb先选择两个随机数作为x,n,对x进行Ax+b迭代,当x小于某个随机数时,执行指定的指令,并停止迭代
#include "llvm/Transforms/passtest/OpaquePredicate.h"
static cl::opt<int>
ObfTimes("oploop",
cl::desc("Choose how many time the -sub pass loops on a function"),
cl::value_desc("number of times"), cl::init(0), cl::Optional);
namespace{
struct OpaquePredicate : public FunctionPass{
static char ID;
bool op;
Instruction* nextI;
Instruction* currentI;
std::vector<llvm::Instruction*> originalInstructions;
std::vector<llvm::Instruction*> opInstructions;
Instruction* tempTerm;
OpaquePredicate() : FunctionPass(ID) {}
OpaquePredicate(bool op) : FunctionPass(ID) {this->op = op; OpaquePredicate();}
void readfunction(Function &F);
void takeInput(Instruction& I);
void movecurrentI(llvm::IRBuilder<> builder);
void moveInstructions(llvm::IRBuilder<> builder);
void test(Instruction& I);
void test1(Instruction& I);
void test2(Instruction& I);
void RandMod(Instruction& I);
void Threexplusone(Instruction& I);
void Axplusb(Instruction& I);
void PrimeOr(Instruction& I);
void timeop(Instruction& I);
void clockop(Instruction& I);
bool isPrime(int num);
bool isArithmeticOperation(const Instruction& I);
bool runOnFunction(Function &F) override {
// Function *tmp = &F;
if(op){
readfunction(F);
// printinfo(F);
return true;
}
return false;
}
};
}
void OpaquePredicate::readfunction(Function &F){
// llvm::errs() << "Running subtest pass on Function:"<<F.getName()<<"\n";
std::vector<Instruction*> instructions;
for (auto &BB : F){
for (auto &I : BB){
if (isArithmeticOperation(I))
instructions.push_back(&I);
// if (isbr(I))
// {
// llvm::errs() << "br: " << I << "\n";
// instructions.push_back(&I);
// }
}
}
int time = ObfTimes;
while (time--)
{
for (auto *I : instructions){
// test2(*I);
Threexplusone(*I);
// Axplusb(*I);
// RandMod(*I);
// PrimeOr(*I);
// timeop(*I);
// clockop(*I);
}
}
}
void OpaquePredicate::takeInput(Instruction& I){
currentI = &I;
opInstructions.push_back(currentI);
nextI = I.getNextNode();
if(llvm::isa<llvm::StoreInst>(nextI)){
opInstructions.push_back(nextI);
nextI = nextI->getNextNode();
}
while (nextI) {
originalInstructions.push_back(nextI);
nextI = nextI->getNextNode();
}
}
void OpaquePredicate::movecurrentI(llvm::IRBuilder<> builder){
tempTerm = builder.CreateUnreachable();
for (llvm::Instruction* inst : opInstructions) {
inst->moveBefore(tempTerm);
}
tempTerm->eraseFromParent();
opInstructions.clear();
}
void OpaquePredicate::moveInstructions(llvm::IRBuilder<> builder){
tempTerm = builder.CreateUnreachable();
for (llvm::Instruction* inst : originalInstructions) {
inst->moveBefore(tempTerm);
}
tempTerm->eraseFromParent();
originalInstructions.clear();
}
void OpaquePredicate::test(Instruction& I){
llvm::Instruction* nextI = I.getNextNode();
if (nextI && nextI->getOpcode() == Instruction::Add){
llvm::LLVMContext& context = I.getContext();
llvm::IRBuilder<> builder(context);
std::vector<llvm::Instruction*> originalInstructions;
while (nextI) {
originalInstructions.push_back(nextI);
nextI = nextI->getNextNode();
}
builder.SetInsertPoint(&I);
llvm::Function* func = I.getFunction();
llvm::BasicBlock* testBlock = llvm::BasicBlock::Create(context, "testBlock", func);
builder.CreateBr(testBlock);
builder.SetInsertPoint(testBlock);
llvm::Instruction* tempTerm = builder.CreateUnreachable();
for (llvm::Instruction* inst : originalInstructions) {
inst->moveBefore(tempTerm);
}
tempTerm->eraseFromParent();
}
}
void OpaquePredicate::test1(Instruction& I){
llvm::Instruction* nextI = I.getNextNode();
if (nextI && nextI->getOpcode() == Instruction::Add){
llvm::LLVMContext& context = I.getContext();
llvm::IRBuilder<> builder(context);
std::vector<llvm::Instruction*> originalInstructions;
llvm::Instruction* addInstr = nextI; // 保存add指令
nextI = nextI->getNextNode(); // 更新nextI为add指令后面的指令
while (nextI) {
originalInstructions.push_back(nextI);
nextI = nextI->getNextNode();
}
builder.SetInsertPoint(&I);
uint64_t randNum = (llvm::cryptoutils->get_uint64_t() % 200);
ConstantInt *co = (ConstantInt *)ConstantInt::get(llvm::Type::getInt64Ty(I.getContext()), randNum);
llvm::Function* func = I.getFunction();
llvm::BasicBlock* icmpBlock = llvm::BasicBlock::Create(context, "icmpBlock", func);
llvm::BasicBlock* trueBlock = llvm::BasicBlock::Create(context, "trueBlock", func);
llvm::BasicBlock* falseBlock = llvm::BasicBlock::Create(context, "falseBlock", func);
builder.CreateBr(icmpBlock);
builder.SetInsertPoint(icmpBlock);
// 在icmpBlock中计算co*(co+1)
llvm::Value* mul = builder.CreateMul(co, builder.CreateAdd(co, ConstantInt::get(Type::getInt64Ty(context), 1)), "mul");
llvm::Value* mod = builder.CreateSRem(mul, ConstantInt::get(Type::getInt64Ty(context), 2), "mod");
// 创建icmp指令
llvm::Value* cond = builder.CreateICmpEQ(mod, ConstantInt::get(Type::getInt64Ty(context), 0), "cond");
// 根据cond的值跳转到trueBlock或falseBlock
builder.CreateCondBr(cond, trueBlock, falseBlock);
// 在falseBlock中插入I的下一个指令
builder.SetInsertPoint(falseBlock);
llvm::Instruction* tempTerm = builder.CreateUnreachable();
addInstr->moveBefore(tempTerm); // 移动add指令
builder.CreateBr(trueBlock);
tempTerm->eraseFromParent();
// 在trueBlock中插入其余的指令
builder.SetInsertPoint(trueBlock);
llvm::Instruction* tempTerm2 = builder.CreateUnreachable();
for (llvm::Instruction* inst : originalInstructions) {
inst->moveBefore(tempTerm2);
}
tempTerm2->eraseFromParent();
}
}
//x % z = 1
//y % z = 0
//(x * y) % z = 0
void OpaquePredicate::RandMod(Instruction& I){
takeInput(I);
llvm::LLVMContext& context = I.getContext();
llvm::IRBuilder<> builder(context);
builder.SetInsertPoint(currentI);
// llvm::Type* int64Type = llvm::Type::getInt64Ty(I.getContext()); // 获取64位整数类型
llvm::Type* int32Type = llvm::Type::getInt32Ty(I.getContext());
// 在栈上为整数分配内存
llvm::AllocaInst* num1Alloca = builder.CreateAlloca(int32Type);
llvm::AllocaInst* num2Alloca = builder.CreateAlloca(int32Type);
llvm::AllocaInst* randNumAlloca = builder.CreateAlloca(int32Type); // 新增:分配一个新的内存
// 生成一个1-10的随机数和两个0-300范围内的随机数
uint32_t randNum = (llvm::cryptoutils->get_uint32_t() % 10) + 1; // 新增:生成一个1-10的随机数
uint32_t randNum1;
uint32_t randNum2;
do {
randNum1 = llvm::cryptoutils->get_uint32_t() % 301; // 生成一个0-300范围内的随机数
} while (randNum1 % randNum != 1);
do {
randNum2 = llvm::cryptoutils->get_uint32_t() % 301; // 生成一个0-300范围内的随机数
} while (randNum2 % randNum != 0);
// 将随机数存储到分配的内存中
builder.CreateStore(ConstantInt::get(int32Type, randNum1), num1Alloca);
builder.CreateStore(ConstantInt::get(int32Type, randNum2), num2Alloca);
builder.CreateStore(ConstantInt::get(int32Type, randNum), randNumAlloca); // 新增:将随机数存储到分配的内存中
// 用llvm::Value*加载内存中的数
llvm::Value* num1Load = builder.CreateLoad(num1Alloca);
llvm::Value* num2Load = builder.CreateLoad(num2Alloca);
llvm::Value* randNumLoad = builder.CreateLoad(randNumAlloca); // 新增:加载内存中的随机数
llvm::Function* func = I.getFunction();
llvm::BasicBlock* icmpBlock = llvm::BasicBlock::Create(context, "icmpBlock", func);
llvm::BasicBlock* trueBlock = llvm::BasicBlock::Create(context, "trueBlock", func);
llvm::BasicBlock* falseBlock = llvm::BasicBlock::Create(context, "falseBlock", func);
builder.CreateBr(icmpBlock);
builder.SetInsertPoint(icmpBlock);
llvm::Value* mul = builder.CreateMul(num1Load, num2Load, "mul"); // 计算num1Load*num2Load
llvm::Value* mod = builder.CreateSRem(mul, randNumLoad, "mod"); // 修改:计算mul除以新数的余数
llvm::Value* cond = builder.CreateICmpEQ(mod, ConstantInt::get(int32Type, 1), "cond"); // 检查mod是否等于0
builder.CreateCondBr(cond, trueBlock, falseBlock);
builder.SetInsertPoint(falseBlock);
movecurrentI(builder);
if (!llvm::isa<llvm::BranchInst>(currentI))
{
builder.CreateBr(trueBlock);
}
builder.SetInsertPoint(trueBlock);
moveInstructions(builder);
}
void OpaquePredicate::Threexplusone(Instruction& I){
takeInput(I);
llvm::LLVMContext& context = I.getContext();
llvm::IRBuilder<> builder(context);
builder.SetInsertPoint(currentI);
llvm::Type* int32Type = llvm::Type::getInt32Ty(I.getContext());
llvm::AllocaInst* numAlloca = builder.CreateAlloca(int32Type);
uint32_t randNum = (llvm::cryptoutils->get_uint32_t() % 9000) + 1000;
builder.CreateStore(ConstantInt::get(int32Type, randNum), numAlloca);
llvm::Function* func = I.getFunction();
llvm::BasicBlock* loopicmpBlock = llvm::BasicBlock::Create(context, "loopicmpBlock", func);
llvm::BasicBlock* outloopBlock = llvm::BasicBlock::Create(context, "outloopBlock", func);
llvm::BasicBlock* mod2icmpBlock = llvm::BasicBlock::Create(context, "mod2icmpBlock", func);
llvm::BasicBlock* ThreexplusoneBlock = llvm::BasicBlock::Create(context, "ThreexplusoneBlock", func);
llvm::BasicBlock* xDividedBy2Block = llvm::BasicBlock::Create(context, "xDividedBy2Block", func);
llvm::BasicBlock* runicmpBlock = llvm::BasicBlock::Create(context, "runicmpBlock", func);
llvm::BasicBlock* runBlock = llvm::BasicBlock::Create(context, "runBlock", func);
llvm::Value* three = ConstantInt::get(int32Type, 3);
llvm::Value* two = ConstantInt::get(int32Type, 2);
llvm::Value* one = ConstantInt::get(int32Type, 1);
builder.CreateBr(loopicmpBlock);
builder.SetInsertPoint(loopicmpBlock);
llvm::Value* randNumLoad = builder.CreateLoad(numAlloca);
llvm::Value* cond = builder.CreateICmpSGT(randNumLoad, one);
builder.CreateCondBr(cond, mod2icmpBlock, outloopBlock);
builder.SetInsertPoint(mod2icmpBlock);
llvm::Value* mod = builder.CreateSRem(randNumLoad, two);
llvm::Value* condMod = builder.CreateICmpEQ(mod, one);
builder.CreateCondBr(condMod, ThreexplusoneBlock, xDividedBy2Block);
builder.SetInsertPoint(ThreexplusoneBlock);
llvm::Value* mul = builder.CreateMul(three, randNumLoad);
llvm::Value* add = builder.CreateAdd(mul, one);
builder.CreateStore(add, numAlloca);
builder.CreateBr(runicmpBlock);
builder.SetInsertPoint(xDividedBy2Block);
llvm::Value* div = builder.CreateSDiv(randNumLoad, two);
builder.CreateStore(div, numAlloca);
builder.CreateBr(runicmpBlock);
builder.SetInsertPoint(runicmpBlock);
uint32_t randNum2 = (llvm::cryptoutils->get_uint32_t() % 999) + 2;
llvm::Value* randNum2Value = ConstantInt::get(int32Type, randNum2);
llvm::Value* numAllocaLoad = builder.CreateLoad(numAlloca);
llvm::Value* cond2 = builder.CreateICmpSLT(numAllocaLoad, randNum2Value);
builder.CreateCondBr(cond2, runBlock, loopicmpBlock);
builder.SetInsertPoint(runBlock);
movecurrentI(builder);
if (!llvm::isa<llvm::BranchInst>(currentI))
{
builder.CreateBr(outloopBlock);
}
builder.SetInsertPoint(outloopBlock);
moveInstructions(builder);
}
void OpaquePredicate::Axplusb(Instruction& I){
takeInput(I);
llvm::LLVMContext& context = I.getContext();
llvm::IRBuilder<> builder(context);
builder.SetInsertPoint(currentI);
llvm::Type* int32Type = llvm::Type::getInt32Ty(I.getContext());
llvm::AllocaInst* numAlloca = builder.CreateAlloca(int32Type);
uint32_t randNum = (llvm::cryptoutils->get_uint32_t() % 9000) + 1000;
builder.CreateStore(ConstantInt::get(int32Type, randNum), numAlloca);
llvm::AllocaInst* n = builder.CreateAlloca(int32Type);
uint32_t randNum2 = (llvm::cryptoutils->get_uint32_t() % 8) + 2;
builder.CreateStore(ConstantInt::get(int32Type, randNum2), n);
llvm::AllocaInst* A = builder.CreateAlloca(int32Type);
builder.CreateStore(ConstantInt::get(int32Type, randNum2+1), A);
llvm::Value* Aload = builder.CreateLoad(A);
// std::vector<llvm::Instruction*> numInstructions;
// for(uint32_t i = randNum2-1; i > 0; --i){
// llvm::Value* num = ConstantInt::get(int32Type, i);
// numInstructions.push_back(llvm::dyn_cast<llvm::Instruction>(num));
// }
llvm::Function* func = I.getFunction();
llvm::BasicBlock* loopicmpBlock = llvm::BasicBlock::Create(context, "loopicmpBlock", func);
llvm::BasicBlock* outloopBlock = llvm::BasicBlock::Create(context, "outloopBlock", func);
std::vector<llvm::BasicBlock*> blocks;
for(uint32_t i = 1; i < randNum2; ++i) {
std::string blockName = "Block" + std::to_string(i);
llvm::BasicBlock* block = llvm::BasicBlock::Create(context, blockName, func);
blocks.push_back(block);
}
llvm::BasicBlock* modAicmpBlock = llvm::BasicBlock::Create(context, "modAicmpBlock", func);
llvm::BasicBlock* xDividedByABlock = llvm::BasicBlock::Create(context, "xDividedByABlock", func);
llvm::BasicBlock* runicmpBlock = llvm::BasicBlock::Create(context, "runicmpBlock", func);
llvm::BasicBlock* runBlock = llvm::BasicBlock::Create(context, "runBlock", func);
builder.CreateBr(loopicmpBlock);
builder.SetInsertPoint(loopicmpBlock);
llvm::Value* randNumLoad = builder.CreateLoad(numAlloca);
llvm::Value* cond = builder.CreateICmpSGT(randNumLoad, ConstantInt::get(int32Type, 1));
builder.CreateCondBr(cond, modAicmpBlock, outloopBlock);
builder.SetInsertPoint(modAicmpBlock);
llvm::Value* nLoad = builder.CreateLoad(n);
llvm::Value* mod = builder.CreateSRem(randNumLoad, nLoad);
llvm::SwitchInst* switchInst = builder.CreateSwitch(mod, xDividedByABlock, randNum2);
for (uint32_t i = 0; i < blocks.size(); ++i) {
switchInst->addCase(builder.getInt32(i+1), blocks[i]);
builder.SetInsertPoint(blocks[i]);
llvm::Value* num = ConstantInt::get(int32Type, i+1);
llvm::Value* B = builder.CreateSub(nLoad,num);
llvm::Value* mul = builder.CreateMul(Aload, B);
llvm::Value* add = builder.CreateAdd(mul, randNumLoad);
builder.CreateStore(add, numAlloca);
builder.CreateBr(runicmpBlock);
}
builder.SetInsertPoint(xDividedByABlock);
llvm::Value* div = builder.CreateSDiv(randNumLoad, Aload);
builder.CreateStore(div, numAlloca);
builder.CreateBr(runicmpBlock);
builder.SetInsertPoint(runicmpBlock);
uint32_t randNum3 = (llvm::cryptoutils->get_uint32_t() % 900) + 100;
llvm::Value* randNum3Value = ConstantInt::get(int32Type, randNum3);
llvm::Value* numAllocaLoad = builder.CreateLoad(numAlloca);
llvm::Value* cond2 = builder.CreateICmpSLT(numAllocaLoad, randNum3Value);
builder.CreateCondBr(cond2, runBlock, loopicmpBlock);
builder.SetInsertPoint(runBlock);
movecurrentI(builder);
if (!llvm::isa<llvm::BranchInst>(currentI))
{
builder.CreateBr(outloopBlock);
}
builder.SetInsertPoint(outloopBlock);
moveInstructions(builder);
}
void OpaquePredicate::PrimeOr(Instruction& I){
takeInput(I);
llvm::LLVMContext& context = I.getContext();
llvm::IRBuilder<> builder(context);
builder.SetInsertPoint(currentI);
llvm::Type* int64Type = llvm::Type::getInt64Ty(I.getContext());
llvm::AllocaInst* num1Alloca = builder.CreateAlloca(int64Type);
llvm::AllocaInst* num2Alloca = builder.CreateAlloca(int64Type);
uint64_t randNum1;
uint64_t randNum2;
do {
randNum1 = llvm::cryptoutils->get_uint64_t() % 10000;
} while (!isPrime(randNum1));
do {
randNum2 = llvm::cryptoutils->get_uint64_t() % 10000;
} while (!isPrime(randNum2)||randNum2==randNum1);
builder.CreateStore(ConstantInt::get(int64Type, randNum1), num1Alloca);
builder.CreateStore(ConstantInt::get(int64Type, randNum2), num2Alloca);
llvm::Function* func = I.getFunction();
llvm::BasicBlock* icmpBlock = llvm::BasicBlock::Create(context, "icmpBlock", func);
llvm::BasicBlock* falseBlock = llvm::BasicBlock::Create(context, "falseBlock", func);
llvm::BasicBlock* trueBlock = llvm::BasicBlock::Create(context, "trueBlock", func);
builder.CreateBr(icmpBlock);
builder.SetInsertPoint(icmpBlock);
llvm::Instruction* value = currentI;
do{
value = value->getPrevNode();
}while (llvm::isa<llvm::BranchInst>(value)|| llvm::isa<llvm::StoreInst>(value));
llvm::AllocaInst* numa = builder.CreateAlloca(int64Type);
llvm::AllocaInst* numb = builder.CreateAlloca(int64Type);
llvm::Value* a = builder.CreatePtrToInt(value, llvm::Type::getInt64Ty(context));
builder.CreateStore(a, numa);
llvm::Value* b = builder.CreateNot(a);
builder.CreateStore(b, numb);
llvm::Value* NumA = builder.CreateLoad(numa);
llvm::Value* NumB = builder.CreateLoad(numb);
// 加载randNum1和randNum2
llvm::Value* randNum1Val = builder.CreateLoad(num1Alloca);
llvm::Value* randNum2Val = builder.CreateLoad(num2Alloca);
// 计算randNum1*a和randNum2*b
llvm::Value* mul1 = builder.CreateMul(randNum1Val, NumA);
llvm::Value* mul2 = builder.CreateMul(randNum2Val, NumB);
// 比较两个结果是否相等
llvm::Value* cmp = builder.CreateICmpEQ(mul1, mul2);
// 根据比较结果跳转
builder.CreateCondBr(cmp, trueBlock, falseBlock);
builder.SetInsertPoint(falseBlock);
movecurrentI(builder);
if (!llvm::isa<llvm::BranchInst>(currentI))
{
builder.CreateBr(trueBlock);
}
builder.SetInsertPoint(trueBlock);
moveInstructions(builder);
}
void OpaquePredicate::timeop(Instruction& I){
Module* M = I.getModule();
// 定义函数类型:i64 (i64*)
std::vector<Type*> params;
params.push_back(Type::getInt64PtrTy(M->getContext()));
FunctionType* funcType = FunctionType::get(Type::getInt64Ty(M->getContext()), params, false);
// 在模块中插入或获取函数
Function* timeFunc = cast<Function>(M->getOrInsertFunction("time", funcType));
// 确保函数声明没有体
timeFunc->setDoesNotRecurse();
// 定义sleep函数类型:i32 (i32)
std::vector<Type*> sleepParams;
sleepParams.push_back(Type::getInt32Ty(M->getContext()));
FunctionType* sleepFuncType = FunctionType::get(Type::getInt32Ty(M->getContext()), sleepParams, false);
// 在模块中插入或获取sleep函数
Function* sleepFunc = cast<Function>(M->getOrInsertFunction("sleep", sleepFuncType));
// 确保函数声明没有体
sleepFunc->setDoesNotRecurse();
takeInput(I);
llvm::LLVMContext& context = I.getContext();
llvm::IRBuilder<> builder(context);
builder.SetInsertPoint(currentI);
llvm::Type* int64Type = llvm::Type::getInt64Ty(I.getContext());
// 创建一个空的i64指针参数
llvm::Value* arg = llvm::ConstantPointerNull::get(llvm::Type::getInt64PtrTy(M->getContext()));
// 创建函数调用
llvm::CallInst* callInst = builder.CreateCall(timeFunc, arg);
// 将返回的i64值转换为llvm::Value*
llvm::Value* timeValue = static_cast<llvm::Value*>(callInst);
// 创建一个i32类型的1作为参数
llvm::Value* sleepArg = llvm::ConstantInt::get(llvm::Type::getInt32Ty(M->getContext()), 1);
// 调用sleep函数
builder.CreateCall(sleepFunc, sleepArg);
llvm::Function* func = I.getFunction();
llvm::BasicBlock* icmpBlock = llvm::BasicBlock::Create(context, "icmpBlock", func);
llvm::BasicBlock* trueBlock = llvm::BasicBlock::Create(context, "trueBlock", func);
llvm::BasicBlock* falseBlock = llvm::BasicBlock::Create(context, "falseBlock", func);
builder.CreateBr(icmpBlock);
builder.SetInsertPoint(icmpBlock);
// 创建另一个函数调用
llvm::CallInst* callInst2 = builder.CreateCall(timeFunc, arg);
// 将返回的i64值转换为另一个llvm::Value*
llvm::Value* timeValue2 = static_cast<llvm::Value*>(callInst2);
// 比较两个值是否相等
llvm::Value* isEqual = builder.CreateICmpEQ(timeValue, timeValue2);
// 根据比较结果跳转到不同的基本块
builder.CreateCondBr(isEqual, trueBlock, falseBlock);
builder.SetInsertPoint(falseBlock);
movecurrentI(builder);
if (!llvm::isa<llvm::BranchInst>(currentI))
{
builder.CreateBr(trueBlock);
}
builder.SetInsertPoint(trueBlock);
moveInstructions(builder);
}
void OpaquePredicate::clockop(Instruction& I){
Module* M = I.getModule();
// 定义函数类型:
FunctionType* funcType = FunctionType::get(Type::getInt64Ty(M->getContext()), false);
// 在模块中插入或获取函数
Function* clockFunc = cast<Function>(M->getOrInsertFunction("clock", funcType));
// 确保函数声明没有体
clockFunc->setDoesNotRecurse();
takeInput(I);
llvm::LLVMContext& context = I.getContext();
llvm::IRBuilder<> builder(context);
builder.SetInsertPoint(currentI);
llvm::Type* int64Type = llvm::Type::getInt64Ty(I.getContext());
// 创建一个调用clock函数的指令
llvm::Value* callInst = builder.CreateCall(clockFunc, {});
// 创建一个新的alloca指令,用于存储clock函数的结果
llvm::AllocaInst* allocaInst = builder.CreateAlloca(int64Type);
// 创建一个新的store指令,将clock函数的结果存储在allocaInst指向的内存中
builder.CreateStore(callInst, allocaInst);
llvm::Function* func = I.getFunction();
llvm::BasicBlock* icmpBlock = llvm::BasicBlock::Create(context, "icmpBlock", func);
llvm::BasicBlock* trueBlock = llvm::BasicBlock::Create(context, "trueBlock", func);
llvm::BasicBlock* falseBlock = llvm::BasicBlock::Create(context, "falseBlock", func);
builder.CreateBr(icmpBlock);
builder.SetInsertPoint(icmpBlock);
// 创建一个新的load指令,从allocaInst指向的内存中加载值
llvm::Value* loadInst = builder.CreateLoad(allocaInst);
// 创建一个新的调用clock函数的指令
llvm::Value* callInst2 = builder.CreateCall(clockFunc, {});
// 创建一个新的alloca指令,用于存储clock函数的结果
llvm::AllocaInst* allocaInst2 = builder.CreateAlloca(int64Type);
// 创建一个新的store指令,将clock函数的结果存储在allocaInst2指向的内存中
builder.CreateStore(callInst2, allocaInst2);
// 创建一个新的load指令,从allocaInst2指向的内存中加载值
llvm::Value* loadInst2 = builder.CreateLoad(allocaInst2);
llvm::Value* MulInst = builder.CreateMul(loadInst2, loadInst);
llvm::Value* icmpInst = builder.CreateICmpEQ(MulInst, ConstantInt::get(int64Type, 0));
// 根据icmp指令的结果跳转到不同的基本块
builder.CreateCondBr(icmpInst, trueBlock, falseBlock);
builder.SetInsertPoint(falseBlock);
movecurrentI(builder);
if (!llvm::isa<llvm::BranchInst>(currentI))
{
builder.CreateBr(trueBlock);
}
builder.SetInsertPoint(trueBlock);
moveInstructions(builder);
}
bool OpaquePredicate::isArithmeticOperation(const Instruction& I){
if (I.getOpcode() == Instruction::Add || I.getOpcode() == Instruction::Sub || I.getOpcode() == Instruction::Mul || I.getOpcode() == Instruction::SDiv || I.getOpcode() == Instruction::UDiv || I.getOpcode() == Instruction::SRem || I.getOpcode() == Instruction::URem || I.getOpcode() == Instruction::Shl || I.getOpcode() == Instruction::LShr || I.getOpcode() == Instruction::AShr || I.getOpcode() == Instruction::And || I.getOpcode() == Instruction::Or || I.getOpcode() == Instruction::Xor){
return true;
}
return false;
}
bool OpaquePredicate::isPrime(int num) {
if (num <= 1) {
return false;
}
for (int i = 2; i <= sqrt(num); i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
Pass *llvm::OP(bool test){
return new OpaquePredicate(test);
}
char OpaquePredicate::ID = 0;
static RegisterPass<OpaquePredicate> X("OpaquePredicate", "OpaquePredicate Pass");
只说重点,没讲到的函数都不重要
addSquareSub
本质是利用差平方公式:
( a + b ) ( a − b ) = a 2 − b 2 (a+b)(a-b) = a^2 - b^2 (a+b)(a−b)=a2−b2
将a+b转化成
( a 2 − b 2 ) / a − b (a^2-b^2)/a-b (a2−b2)/a−b
代码如下:
// Create (b*b - c*c) / (b - c)
if (bo->getOpcode() == Instruction::Add) {
if(bo->getOperand(0) != bo->getOperand(1)){
// Create b*b
BinaryOperator *bb = BinaryOperator::CreateMul(bo->getOperand(0), bo->getOperand(0), "", bo);
// Create c*c
BinaryOperator *cc = BinaryOperator::CreateMul(bo->getOperand(1), bo->getOperand(1), "", bo);
// Create b*b - c*c
BinaryOperator *numerator = BinaryOperator::CreateSub(bb, cc, "", bo);
// Create b - c
BinaryOperator *denominator = BinaryOperator::CreateSub(bo->getOperand(0), bo->getOperand(1), "", bo);
// Create (b*b - c*c) / (b - c)
op = BinaryOperator::CreateSDiv(numerator, denominator, "", bo);
bo->replaceAllUsesWith(op);
subSquareadd和addSquareSub大致相似,不再赘述
addToLogic
本质是使用逻辑运算符表示加法
#原式
a = b+c
#混淆后
while c != 0:
carry = b & c
b = b ^ c
c = carry << 1
a = b
addToLogic的实现需要使用循环,在llvm IR中,实现循环必须使用基本块,所以代码较为复杂
代码:
llvm::LLVMContext& context = I.getContext();
llvm::IRBuilder<> builder(context);
std::vector<llvm::Instruction*> originalInstructions;
llvm::Instruction* nextI = I.getNextNode();
while (nextI) {
originalInstructions.push_back(nextI);
nextI = nextI->getNextNode();
}
// 获取 I 的操作数
llvm::Value* op1 = I.getOperand(0);
llvm::Value* op2 = I.getOperand(1);
// 设置插入点为指令 I
builder.SetInsertPoint(&I);
// 创建两个在栈上为一个32位整数分配内存的操作
llvm::AllocaInst* alloca1 = builder.CreateAlloca(builder.getInt32Ty(), 0, "alloca1");
llvm::AllocaInst* alloca2 = builder.CreateAlloca(builder.getInt32Ty(), 0, "alloca2");
alloca1->setAlignment(4);
alloca2->setAlignment(4);
// 将操作数存储到分配的内存中
builder.CreateStore(op1, alloca1);
builder.CreateStore(op2, alloca2);
llvm::Function* func = I.getFunction();
llvm::BasicBlock* icmpBlock = llvm::BasicBlock::Create(context, "icmpBlock", func);
llvm::BasicBlock* trueBlock = llvm::BasicBlock::Create(context, "trueBlock", func);
llvm::BasicBlock* falseBlock = llvm::BasicBlock::Create(context, "falseBlock", func);
builder.CreateBr(icmpBlock);
builder.SetInsertPoint(icmpBlock);
llvm::Value* load1 = builder.CreateLoad(alloca1, "load1");
llvm::Value* load2 = builder.CreateLoad(alloca2, "load2");
llvm::Value* icmp = builder.CreateICmpNE(load2, builder.getInt32(0), "icmp");
builder.CreateCondBr(icmp, trueBlock, falseBlock);
builder.SetInsertPoint(trueBlock);
llvm::Value* andOP = builder.CreateAnd(load1, load2, "andOP");
llvm::Value* xorOP = builder.CreateXor(load1, load2, "xorOP");
llvm::Value* shlOP = builder.CreateShl(andOP, 1, "shlOP");
builder.CreateStore(xorOP, alloca1);
builder.CreateStore(shlOP, alloca2);
builder.CreateBr(icmpBlock);
builder.SetInsertPoint(falseBlock);
llvm::Value* newload= builder.CreateLoad(alloca1, "newload");
I.replaceAllUsesWith(newload);
// builder.CreateBr(continueBlock);
// 添加一个临时的终止指令
llvm::Instruction* tempTerm = builder.CreateUnreachable();
// 将原先 I 后方的所有指令都移动到 falseBlock 的末尾
for (llvm::Instruction* inst : originalInstructions) {
inst->moveBefore(tempTerm);
}
-
originalInstructions用于记录需要替换的指令其后方的指令
-
函数的实际作用为使用三个基本块替换原先的指令,首先提取原指令的两个操作数,进行循环判定要跳转的基本块
-
icmpBlock:作用是判断变量是否满足循环条件决定是否跳出循环
-
trueBlock:执行循环内逻辑运算操作
-
falseBlock:跳出循环,执行后续的操作
andSubstitution
本质是使用德摩根定律,将AND运算转化为OR运算
即A AND B = NOT ((NOT A) OR (NOT B))
代码:
Value* A = I.getOperand(0);
Value* B = I.getOperand(1);
// Create NOT instructions
Value* notA = BinaryOperator::CreateNot(A, "notA", &I);
Value* notB = BinaryOperator::CreateNot(B, "notB", &I);
// Create OR instruction
Value* notA_or_notB = BinaryOperator::CreateOr(notA, notB, "notA_or_notB", &I);
// Create NOT instruction
Value* result = BinaryOperator::CreateNot(notA_or_notB, "result", &I);
// Replace the original AND instruction with the new NOT instruction
I.replaceAllUsesWith(result);
orSubstitution和xorSubstitution都使用了德摩根定律,不再赘述
ToRemove
ToRemove的作用是标记原先的指令,放入待删除列表
void subtest::ToRemove(llvm::Instruction& I){
if (std::find(toRemove.begin(), toRemove.end(), &I) == toRemove.end()) {
// llvm::errs() <<"TOremove\n\n"<< I << "\n\n";
toRemove.push_back(&I);
}
}
remove
remove的作用是将待删除列表中的指令删除
void subtest::remove(){
for (auto* I : toRemove) {
llvm::errs() <<"remove\n\n"<< *I << "\n\n";
I->eraseFromParent();
}
toRemove.clear();
}
总结
- addSquareSub和subSquareadd利用差平方公式进行混淆,操作较为简单,缺点是多次循环使用后会导致数值溢出
- addToLogic使用逻辑运算符表示加法,操作较为复杂,需要使用基本块进行跳转操作
- andSubstitution使用德摩根定律进行混淆
- 使用replaceAllUsesWith替换指令后,原指令并不会被删除,而是留在原IR中,可以选择将其删除
#include "llvm/Transforms/passtest/subtest.h"
static cl::opt<int>
ObfTimes("loop",
cl::desc("Choose how many time the -sub pass loops on a function"),
cl::value_desc("number of times"), cl::init(0), cl::Optional);
namespace{
struct subtest : public FunctionPass{
static char ID;
bool test;
std::vector<llvm::Instruction*> toRemove;
subtest() : FunctionPass(ID) {}
subtest(bool test) : FunctionPass(ID) {this->test = test; subtest();}
bool isArithmeticOperation(const llvm::Instruction& I);
bool isLogicalOperation(const llvm::Instruction& I);
void addIFInstruction(llvm::Instruction& I);
void DoaddToLogic(Function &F);
void addToLogic(llvm::Instruction& I);
void subTomuladd(llvm::Instruction& I);
void DoaddSquareSub(Function &F);
void addSquareSub(BinaryOperator *bo);
void DosubSquareadd(Function &F);
void subSquareadd(BinaryOperator *bo);
void ToRemove(llvm::Instruction& I);
void remove();
void addRand(llvm::Instruction& I);
void DoaddRand(Function &F);
void addNeg(llvm::Instruction& I);
void andSubstitution(llvm::Instruction& I);
void orSubstitution(llvm::Instruction& I);
void xorSubstitution(llvm::Instruction& I);
void readfunction(Function &F);
void printinfo(Function &F);
bool runOnFunction(Function &F) override {
// Function *tmp = &F;
if(test){
readfunction(F);
// printinfo(F);
return true;
}
return false;
}
};
}
// void subtest::printinfo(Function &F){
// int count = 0;
// int count1 = 0;
// llvm::errs() << "Running subtest pass on Function:"<<F.getName()<<"\n";
// // for (Function::iterator bb = tmp->begin(); bb != tmp->end(); ++bb)
// // {
// // llvm::errs() << "BasicBlock: " << bb->getName() << "\n";
// // count++;
// // }
// for (auto &BB : F){
// llvm::errs() << "BasicBlock: " << BB.getName() << "\n";
// // BB.print(llvm::errs());
// int count2 = 0;
// for (auto &I : BB){
// llvm::errs() << "Instruction: " << I << "\n";
// std::ostringstream addressStream;
// addressStream << std::hex << std::showbase << reinterpret_cast<void*>(&I);
// llvm::errs() << "Instruction address: " << addressStream.str() << "\n\n\n\n\n";
// count2++;
// }
// llvm::errs() << "Number of Instructions in the BasicBlock: " << count2 << "\n\n";
// count1+=count2;
// count++;
// }
// llvm::errs() << "Number of BasicBlocks: " << count << "\n";
// llvm::errs() << "Number of Instructions in the Function: " << count1 << "\n\n";
// }
void subtest::readfunction(Function &F){
int time = ObfTimes;
while(time--){
DoaddSquareSub(F);
// DoaddRand(F);
DosubSquareadd(F);
// DoaddToLogic(F);
}
DoaddToLogic(F);
// for (auto &BB : F) {
// for (auto &I : BB) {
// // andSubstitution(I);
// orSubstitution(I);
// }
// }
remove();
}
void subtest::ToRemove(llvm::Instruction& I){
if (std::find(toRemove.begin(), toRemove.end(), &I) == toRemove.end()) {
// llvm::errs() <<"TOremove\n\n"<< I << "\n\n";
toRemove.push_back(&I);
}
}
void subtest::remove(){
for (auto* I : toRemove) {
llvm::errs() <<"remove\n\n"<< *I << "\n\n";
I->eraseFromParent();
}
toRemove.clear();
}
bool subtest::isArithmeticOperation(const llvm::Instruction& I){
if(I.getOpcode() == Instruction::Add || I.getOpcode() == Instruction::Sub || I.getOpcode() == Instruction::Mul || I.getOpcode() == Instruction::SDiv /*|| I.getOpcode() == Instruction::UDiv || I.getOpcode() == Instruction::SRem || I.getOpcode() == Instruction::URem*/){
return true;
}
return false;
}
bool subtest::isLogicalOperation(const llvm::Instruction& I){
if(I.getOpcode() == Instruction::And || I.getOpcode() == Instruction::Or || I.getOpcode() == Instruction::Xor){
return true;
}
return false;
}
void subtest::addNeg(llvm::Instruction& I){
if(I.getOpcode() == Instruction::Add){
BinaryOperator *op = NULL;
op = BinaryOperator::CreateNeg(I.getOperand(1), "", &I);
op->print(llvm::errs());
op = BinaryOperator::Create(Instruction::Sub,I.getOperand(0), op,"", &I);
op->print(llvm::errs());
I.replaceAllUsesWith(op);
}
}
void subtest::addRand(llvm::Instruction& I) {
BinaryOperator *op = NULL;
if (I.getOpcode() == Instruction::Add) {
Type *ty = I.getType();
uint64_t randNum = (llvm::cryptoutils->get_uint64_t() % 2000)-1000;
ConstantInt *co = (ConstantInt *)ConstantInt::get(ty, randNum);
op =BinaryOperator::Create(Instruction::Add, I.getOperand(0), co, "", &I);
op =BinaryOperator::Create(Instruction::Add, op, I.getOperand(1), "", &I);
op = BinaryOperator::Create(Instruction::Sub, op, co, "", &I);
I.replaceAllUsesWith(op);
ToRemove(I);
}
}
void subtest::DoaddRand(Function &F) {
for (auto &BB : F) {
for (auto &I : BB) {
addRand(I);
}
}
}
void subtest::andSubstitution(llvm::Instruction& I) {
BinaryOperator *op = NULL;
if (I.getOpcode() == Instruction::And) {
Value* A = I.getOperand(0);
Value* B = I.getOperand(1);
// Create NOT instructions
Value* notA = BinaryOperator::CreateNot(A, "notA", &I);
Value* notB = BinaryOperator::CreateNot(B, "notB", &I);
// Create OR instruction
Value* notA_or_notB = BinaryOperator::CreateOr(notA, notB, "notA_or_notB", &I);
// Create NOT instruction
Value* result = BinaryOperator::CreateNot(notA_or_notB, "result", &I);
// Replace the original AND instruction with the new NOT instruction
I.replaceAllUsesWith(result);
ToRemove(I);
}
}
void subtest::orSubstitution(llvm::Instruction& I) {
BinaryOperator *op = NULL;
if (I.getOpcode() == Instruction::Or) {
Value* A = I.getOperand(0);
Value* B = I.getOperand(1);
// Create NOT instructions
Value* notA = BinaryOperator::CreateNot(A, "notA", &I);
Value* notB = BinaryOperator::CreateNot(B, "notB", &I);
// Create AND instructions
Value* notA_and_notB = BinaryOperator::CreateAnd(notA, notB, "notA_and_notB", &I);
// Create NOT instruction
Value* result = BinaryOperator::CreateNot(notA_and_notB, "result", &I);
// Replace the original OR instruction with the new NOT instruction
I.replaceAllUsesWith(result);
ToRemove(I);
}
}
void subtest::xorSubstitution(llvm::Instruction& I) {
BinaryOperator *op = NULL;
if (test)
{}
if (I.getOpcode() == Instruction::Xor) {
Value* A = I.getOperand(0);
Value* B = I.getOperand(1);
// Create NOT instructions
Value* notA = BinaryOperator::CreateNot(A, "notA", &I);
Value* notB = BinaryOperator::CreateNot(B, "notB", &I);
// Create AND instructions
Value* A_and_notB = BinaryOperator::CreateAnd(A, notB, "A_and_notB", &I);
Value* notA_and_B = BinaryOperator::CreateAnd(notA, B, "notA_and_B", &I);
// Create OR instruction
Value* result = BinaryOperator::CreateOr(A_and_notB, notA_and_B, "result", &I);
// Replace the original XOR instruction with the new OR instruction
I.replaceAllUsesWith(result);
ToRemove(I);
}
}
void subtest::addSquareSub(BinaryOperator *bo) {
BinaryOperator *op = NULL;
// Create (b*b - c*c) / (b - c)
if (bo->getOpcode() == Instruction::Add) {
if(bo->getOperand(0) != bo->getOperand(1)){
// Create b*b
BinaryOperator *bb = BinaryOperator::CreateMul(bo->getOperand(0), bo->getOperand(0), "", bo);
// Create c*c
BinaryOperator *cc = BinaryOperator::CreateMul(bo->getOperand(1), bo->getOperand(1), "", bo);
// Create b*b - c*c
BinaryOperator *numerator = BinaryOperator::CreateSub(bb, cc, "", bo);
// Create b - c
BinaryOperator *denominator = BinaryOperator::CreateSub(bo->getOperand(0), bo->getOperand(1), "", bo);
// Create (b*b - c*c) / (b - c)
op = BinaryOperator::CreateSDiv(numerator, denominator, "", bo);
bo->replaceAllUsesWith(op);
// bo->eraseFromParent();
}
ToRemove(*bo);
}
}
void subtest::DoaddSquareSub(Function &F){
for (auto &BB : F){
for (auto &I : BB){
if(isArithmeticOperation(I)){
addSquareSub(dyn_cast<BinaryOperator>(&I));
}
}
}
}
void subtest::subSquareadd(BinaryOperator *bo){
BinaryOperator *op = NULL;
// Create (b*b - c*c) / (b+c)
if (bo->getOpcode() == Instruction::Sub) {
if(bo->getOperand(0) != bo->getOperand(1)){
// Create b*b
BinaryOperator *bb = BinaryOperator::CreateMul(bo->getOperand(0), bo->getOperand(0), "", bo);
// Create c*c
BinaryOperator *cc = BinaryOperator::CreateMul(bo->getOperand(1), bo->getOperand(1), "", bo);
// Create b*b - c*c
BinaryOperator *numerator = BinaryOperator::CreateSub(bb, cc, "", bo);
// Create b + c
BinaryOperator *denominator = BinaryOperator::CreateAdd(bo->getOperand(0), bo->getOperand(1), "", bo);
// Create (b*b - c*c) / (b + c)
op = BinaryOperator::CreateSDiv(numerator, denominator, "", bo);
bo->replaceAllUsesWith(op);
// bo->eraseFromParent();
}
ToRemove(*bo);
}
}
void subtest::DosubSquareadd(Function &F){
for (auto &BB : F){
for (auto &I : BB){
if(isArithmeticOperation(I)){
subSquareadd(dyn_cast<BinaryOperator>(&I));
}
}
}
}
void subtest::addIFInstruction(llvm::Instruction& I){
llvm::LLVMContext& context = I.getContext();
llvm::IRBuilder<> builder(context);
std::vector<llvm::Instruction*> originalInstructions;
llvm::Instruction* nextI = I.getNextNode();
while (nextI) {
originalInstructions.push_back(nextI);
nextI = nextI->getNextNode();
}
// 设置插入点为指令 I 的下一条指令
builder.SetInsertPoint(I.getNextNode());
// 创建一个在栈上为一个32位整数分配内存的操作
llvm::AllocaInst* alloca = builder.CreateAlloca(builder.getInt32Ty(), 0, "alloca");
alloca->setAlignment(4);
// 创建一个有符号的比较
llvm::Value* zero = builder.getInt32(0);
llvm::Value* icmp = builder.CreateICmpSGT(&I, zero, "icmp");
// 创建三个基本块作为跳转的目标
llvm::Function* func = I.getFunction();
llvm::BasicBlock* trueBlock = llvm::BasicBlock::Create(context, "trueBlock", func);
llvm::BasicBlock* falseBlock = llvm::BasicBlock::Create(context, "falseBlock", func);
llvm::BasicBlock* continueBlock = llvm::BasicBlock::Create(context, "continueBlock", func);
// 创建一个条件跳转指令
builder.CreateCondBr(icmp, trueBlock, falseBlock);
// 在 trueBlock 中为之前分配内存的整数赋值1
builder.SetInsertPoint(trueBlock);
llvm::Value* one = builder.getInt32(1);
builder.CreateStore(one, alloca);
// 在 trueBlock 中添加一个跳转至 continueBlock 的无条件跳转指令
builder.CreateBr(continueBlock);
// 在 falseBlock 中添加一个跳转至 continueBlock 的无条件跳转指令
builder.SetInsertPoint(falseBlock);
builder.CreateBr(continueBlock);
// 将原先的 I 后方的指令放在 continueBlock 后面
llvm::Instruction* firstInContinueBlock = &*continueBlock->getFirstInsertionPt();
for (llvm::Instruction* inst : originalInstructions) {
inst->moveBefore(firstInContinueBlock);
}
}
void subtest::addToLogic(llvm::Instruction& I){
if (I.getOpcode() == Instruction::Add)
{
llvm::LLVMContext& context = I.getContext();
llvm::IRBuilder<> builder(context);
std::vector<llvm::Instruction*> originalInstructions;
llvm::Instruction* nextI = I.getNextNode();
while (nextI) {
originalInstructions.push_back(nextI);
nextI = nextI->getNextNode();
}
// 获取 I 的操作数
llvm::Value* op1 = I.getOperand(0);
llvm::Value* op2 = I.getOperand(1);
// 设置插入点为指令 I
builder.SetInsertPoint(&I);
// 创建两个在栈上为一个32位整数分配内存的操作
llvm::AllocaInst* alloca1 = builder.CreateAlloca(builder.getInt32Ty(), 0, "alloca1");
llvm::AllocaInst* alloca2 = builder.CreateAlloca(builder.getInt32Ty(), 0, "alloca2");
alloca1->setAlignment(4);
alloca2->setAlignment(4);
// 将操作数存储到分配的内存中
builder.CreateStore(op1, alloca1);
builder.CreateStore(op2, alloca2);
llvm::Function* func = I.getFunction();
llvm::BasicBlock* icmpBlock = llvm::BasicBlock::Create(context, "icmpBlock", func);
llvm::BasicBlock* trueBlock = llvm::BasicBlock::Create(context, "trueBlock", func);
llvm::BasicBlock* falseBlock = llvm::BasicBlock::Create(context, "falseBlock", func);
// llvm::BasicBlock* continueBlock = llvm::BasicBlock::Create(context, "continueBlock", func);
builder.CreateBr(icmpBlock);
builder.SetInsertPoint(icmpBlock);
llvm::Value* load1 = builder.CreateLoad(alloca1, "load1");
llvm::Value* load2 = builder.CreateLoad(alloca2, "load2");
llvm::Value* icmp = builder.CreateICmpNE(load2, builder.getInt32(0), "icmp");
builder.CreateCondBr(icmp, trueBlock, falseBlock);
builder.SetInsertPoint(trueBlock);
llvm::Value* andOP = builder.CreateAnd(load1, load2, "andOP");
llvm::Value* xorOP = builder.CreateXor(load1, load2, "xorOP");
llvm::Value* shlOP = builder.CreateShl(andOP, 1, "shlOP");
builder.CreateStore(xorOP, alloca1);
builder.CreateStore(shlOP, alloca2);
builder.CreateBr(icmpBlock);
builder.SetInsertPoint(falseBlock);
llvm::Value* newload= builder.CreateLoad(alloca1, "newload");
I.replaceAllUsesWith(newload);
// builder.CreateBr(continueBlock);
// 添加一个临时的终止指令
llvm::Instruction* tempTerm = builder.CreateUnreachable();
// 将原先 I 后方的所有指令都移动到 falseBlock 的末尾
for (llvm::Instruction* inst : originalInstructions) {
inst->moveBefore(tempTerm);
}
// 删除临时的终止指令
tempTerm->eraseFromParent();
ToRemove(I);
}
}
void subtest::DoaddToLogic(Function &F){
for (auto &BB : F){
for (auto &I : BB){
addToLogic(I);
}
}
}
void subtest::subTomuladd(llvm::Instruction& I){
if (I.getOpcode() == Instruction::Sub)
{
BinaryOperator *op = NULL;
llvm::Value* one = llvm::ConstantInt::get(I.getOperand(0)->getType(), -1);
op = BinaryOperator::CreateMul(I.getOperand(1),one, "", &I);
op = BinaryOperator::Create(Instruction::Add,I.getOperand(0), op,"", &I);
I.replaceAllUsesWith(op);
ToRemove(I);
}
}
char subtest::ID = 0;
static RegisterPass<subtest> X("subtest", "subtest Pass");
Pass *llvm::subtests(bool test){
return new subtest(test);
}