给llvm添加自定义Pass

背景

  • 最近在看ollvm这个东西的源码,于是乎想搞个自定义Pass玩玩看,按照网上的教程一顿倒腾发现一个坑点,那就是你编写的Pass只能通过opt这个工具来运行
  • 我想要的效果是,我的Pass集成进去之后,当我调用clang进行编译的时候,能够自动的调用我的Pass,不要让我再调用opt工具

爬坑过程

  • 环境准备

    1. 参照ollvm源码的目录结构,在lib/Transforms/ 目录下建立我的目录,我这里叫FreakishfoxVMP
    2. 拷贝lib/Transforms/Obfuscator/CMakeLists.txt 到lib/Transforms/FreakishfoxVMP
    3. 拷贝lib/Transforms/Obfuscator/LLVMBuild.txt 到lib/Transforms/FreakishfoxVMP
    4. 拷贝lib/Transforms/Obfuscator/Makefile 到lib/Transforms/FreakishfoxVMP
    5. 创建自己的Pass的主文件,我这里是FreakishfoxVMP.cpp, FreakishfoxVMP.h
    6. 修改CMakeLists.txt LLVMBuild.txt Makefile这几个文件中对应的项,主要是修改相关的字符串,文件名等
  • 一通操作之后,跑到最外层 make -j8

  • 几分钟之后编译完毕(我前面已经编译过一遍,花了大概一小时,后面的二次编译就比较快了),走起

  • 来到编译目录bin,执行 ./clang test.c -o test

  • 果然,坑了,完全没有反应啊

  • 于是简单思考一下,应该是哪里缺少配置或者缺少调用这个Pass的地方,因为对整个llvm的运作体系还不清楚,因此以葫芦画瓢,在ollvm源码根目录下直接搜索调用ollvm的Flattening这个Pass的调用

  •  38 char Flattening::ID = 0;
     39 static RegisterPass X("flattening", "Call graph flattening");
     40 Pass *llvm::createFlattening(bool flag) { return new Flattening(flag); }
    
    1. 这个是标准的Passz注册过程,38 39这两行是必须的,我肯定是加了
    2. 40行虽然我加了,但是我是没有主动调用过,于是想是不是createFlattening这个函数被ollvm的作者加到哪里去了,所以直接根目录 grep -r createFlattening ./
    3. 发现 IPO/PassManagerBuilder.cpp: MPM.add(createFlattening(Flattening));有调用,直接打开,看代码
    4.  
     422 void PassManagerBuilder::populateModulePassManager(
     423     legacy::PassManagerBase &MPM) {
     424   if (!PGOSampleUse.empty()) {
     425     MPM.add(createPruneEHPass());
     426     MPM.add(createSampleProfileLoaderPass(PGOSampleUse));
     427   }
     428
     429   // Allow forcing function attributes as a debugging and tuning aid.
     430   MPM.add(createForceFunctionAttrsLegacyPass());
     431
     432   MPM.add(createSplitBasicBlock(Split));
     433   MPM.add(createBogus(BogusControlFlow));
     434   MPM.add(createFlattening(Flattening));  //看到这里有调用
     435   MPM.add(createFreakishfoxVMP(FFVmp));   //直接在后面追加我自己的
    
    1. 其中的函数声明include什么的自己搞一下就好,然后继续make -j8
  • 又报错了,链接的时候提示找不到createFreakishfoxVMP这个符号,原因很明显,编译不报错,链接报错,那就是缺少依赖项,由于是PassManagerBuilder链接错误了,因此可以推测出来是我加了调用自定义Pass,但是没有给PassManagerBuilder模块添加自定义模块的库依赖导致的,因此继续寻找定义依赖的地方

    1. 继续依葫芦画瓢,查找ollvm对Obfusator这个模块的配置,grep -r Obfusation ./
    2. 为什么是Obfusation? Obfuscator这个模块的Makefile中定义的模块名称,没什么好奇怪的
    3. grep之后结果有意外收获
    4. 第一处:lib/Transforms/IPO/LLVMBuild.txt:required_libraries = Analysis BitWriter Core InstCombine IRReader Linker Object ProfileData Scalar Support TransformUtils Vectorize Instrumentation Obfuscation
    5. 第二处:lib/Transforms/LLVMBuild.txt:subdirectories = Coroutines IPO InstCombine Instrumentation Scalar Utils Vectorize ObjCARC Obfuscation
    6. 不犹豫,直接都在最后添加 FreakishfoxVMP, 再次make -j8
    7. 编译过了,过了...
  • 于是回到bin目录,./clang test.c -o test.c,OK,在我的自定义Pass的runOnFunction中打印的语句在console中输出了,也就是有效果了

总结

  • 添加自定义Pass一共有几步?
    1. 在lib/Transforms/目录下创建自己的Pass目录
    2. 从lib/Transforms/Obfuscator目录下拷贝CMakeLists.txt Makefile LLVMBuild.txt到自己的目录
    3. 修改CMakeLists.txt Makefile LLVMBuild.txt中对应的内容
    4. PassManagerBuilder::populateModulePassManager中添加对应调用
    5. 添加PassManagerBuilder对你的新增模块的link依赖,lib/Transforms/IPO/LLVMBuild.txt:required_libraries
    6. 把新目录添加到llvm的编译列表中去,lib/Transforms/LLVMBuild.txt:subdirectories
    7. 直接make -j8
  • 本着授人以渔的精神,这个小文章主要展示问题解决过程中的思考过程,最后的总结部分主要给那些已经被折麽的不行的同学直接操作用,^_^

你可能感兴趣的:(llvm,Android)