基于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.cpp

  ADDITIONAL_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/IPO

  DEPENDS
  intrinsics_gen
  omp_gen

  COMPONENT_NAME
  IPO

  LINK_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作测试更快

参考:
https://github.com/0x3f97/oll...
https://neyoufan.github.io/20...

你可能感兴趣的:(llvmiosclang)