背景
- 最近在看ollvm这个东西的源码,于是乎想搞个自定义Pass玩玩看,按照网上的教程一顿倒腾发现一个坑点,那就是你编写的Pass只能通过opt这个工具来运行
- 我想要的效果是,我的Pass集成进去之后,当我调用clang进行编译的时候,能够自动的调用我的Pass,不要让我再调用opt工具
爬坑过程
环境准备
- 参照ollvm源码的目录结构,在lib/Transforms/ 目录下建立我的目录,我这里叫FreakishfoxVMP
- 拷贝lib/Transforms/Obfuscator/CMakeLists.txt 到lib/Transforms/FreakishfoxVMP
- 拷贝lib/Transforms/Obfuscator/LLVMBuild.txt 到lib/Transforms/FreakishfoxVMP
- 拷贝lib/Transforms/Obfuscator/Makefile 到lib/Transforms/FreakishfoxVMP
- 创建自己的Pass的主文件,我这里是FreakishfoxVMP.cpp, FreakishfoxVMP.h
- 修改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<Flattening> X("flattening", "Call graph flattening"); 40 Pass *llvm::createFlattening(bool flag) { return new Flattening(flag); }
- 这个是标准的Passz注册过程,38 39这两行是必须的,我肯定是加了
- 40行虽然我加了,但是我是没有主动调用过,于是想是不是createFlattening这个函数被ollvm的作者加到哪里去了,所以直接根目录 grep -r createFlattening ./
- 发现 IPO/PassManagerBuilder.cpp: MPM.add(createFlattening(Flattening));有调用,直接打开,看代码
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)); //直接在后面追加我自己的
- 其中的函数声明include什么的自己搞一下就好,然后继续make -j8
又报错了,链接的时候提示找不到createFreakishfoxVMP这个符号,原因很明显,编译不报错,链接报错,那就是缺少依赖项,由于是PassManagerBuilder链接错误了,因此可以推测出来是我加了调用自定义Pass,但是没有给PassManagerBuilder模块添加自定义模块的库依赖导致的,因此继续寻找定义依赖的地方
- 继续依葫芦画瓢,查找ollvm对Obfusator这个模块的配置,grep -r Obfusation ./
- 为什么是Obfusation? Obfuscator这个模块的Makefile中定义的模块名称,没什么好奇怪的
- grep之后结果有意外收获
- 第一处:lib/Transforms/IPO/LLVMBuild.txt:required_libraries = Analysis BitWriter Core InstCombine IRReader Linker Object ProfileData Scalar Support TransformUtils Vectorize Instrumentation Obfuscation
- 第二处:lib/Transforms/LLVMBuild.txt:subdirectories = Coroutines IPO InstCombine Instrumentation Scalar Utils Vectorize ObjCARC Obfuscation
- 不犹豫,直接都在最后添加 FreakishfoxVMP, 再次make -j8
- 编译过了,过了…
于是回到bin目录,./clang test.c -o test.c,OK,在我的自定义Pass的runOnFunction中打印的语句在console中输出了,也就是有效果了
总结
- 添加自定义Pass一共有几步?
- 在lib/Transforms/目录下创建自己的Pass目录
- 从lib/Transforms/Obfuscator目录下拷贝CMakeLists.txt Makefile LLVMBuild.txt到自己的目录
- 修改CMakeLists.txt Makefile LLVMBuild.txt中对应的内容
- PassManagerBuilder::populateModulePassManager中添加对应调用
- 添加PassManagerBuilder对你的新增模块的link依赖,lib/Transforms/IPO/LLVMBuild.txt:required_libraries
- 把新目录添加到llvm的编译列表中去,lib/Transforms/LLVMBuild.txt:subdirectories
- 直接make -j8
- 本着授人以渔的精神,这个小文章主要展示问题解决过程中的思考过程,最后的总结部分主要给那些已经被折么的不行的同学直接操作用,^_^