基于LLVM 中间表示(IR)分析实例
2017-07-28 23:11
429 查看
LLVM是很优秀的编译器,其支持多源语言,多后台,而且同程序整体和整个生命周期的分析、转换和优化。
LLVM 中间表示(Intermediaterepresentation,简称IR)作为LLVM的中间语言,对LLVM各种特性的支持有非常重要的作用。
有很多时候我们需要对LLVMIR进行分析,LLVM官方有文档:http://llvm.org/docs/WritingAnLLVMPass.html,其介绍了一个基本的步骤,和对其中一些常用的Pass的介绍,其中的实例很简单,只是简单地打印出函数的名字。
因此为了加深对Pass的学习,下面将分析两个实例:
1、写一个Pass打印出Module、Function、BasicBlock、变量的值或者一些一些属性。
1)所有的步骤都参见官方文档,在/llvm/lib/Transforms目录下面新建一个文件夹(以BasicBlockName为例),到该目录下面新建两个文件一个就是需要用到的BasicBlockName.cpp文件,另外一个就是Makefile。还需要将新建的文件夹的名字加到/llvm/lib/Transforms目录下面的Makefile里面PARALLEL_DIRS的后面添加该文件名。这样即可编辑cpp文件。
2)在cpp文件中添加如下代码:
1#include "llvm/Pass.h"
2#include "llvm/IR/Function.h"
3#include "llvm/IR/Module.h"
4#include "llvm/IR/BasicBlock.h"
5#include "llvm/IR/Instruction.h"
6#include "llvm/IR/Instructions.h"
7#include "llvm/Support/raw_ostream.h"
8
9 usingnamespace llvm;
10
11namespace
12{
13 struct BasicBlockName : publicModulePass
14 {
15 static char ID;
16 BasicBlockName():ModulePass(ID){}
17 virtual boolrunOnModule(Module &M)
18 {
19 for(Module::iterator Mit=M.begin(),Mite=M.end();Mit!=Mite;Mit++)
20 {
21 errs()<<"Function:"<<Mit->getName()<<"\n";
22 for(llvm::Function::iterator Fit =Mit->begin(),Fite = Mit->end();Fit!=Fite;Fit++)
23 {
24 llvm::BasicBlock* bb =Fit;
25 errs()<<"----BasicBlock:"<<bb->getName()<<"\n";
26 if(bb->size()>1)
27 {
28 for(BasicBlock::iteratorBit=bb->begin(),Bite=bb->end();Bit!=Bite;Bit++)
29 {
30 errs()<<"--------"<<Bit->getOperand(0)->getName()<<"| "
31 <<Bit->getOperand(0)->getValueName()<<" |"
32 <<Bit->getOperand(0)->getValueID()<<" |"
33 <<Bit->getOperand(0)->getNumUses()<<" ** end\n";
34 }
35 }
36 }
37 }
38 returnfalse;
39 }
40 };
41}
42
43 charBasicBlockName::ID = 0;
44 staticRegisterPass Y("BasicBlock","BBName",false,false);
3)对代码中进行解释:
第13行处定义了一个继承自ModulePass的BaiscBlockName结构体,17行是具体实现该函数功能,19、22、28分别针对不同的层次使用一个for循环遍历IR中的对象,代码中getName、getValue等函数得到需要的值然后打印出来即可。
4)需要到编译llvm的build文件夹下面make一下,就会在Release+Asserts/lib下面生成BasicBlockName.so文件,然后按照官方文档使用,opt-load ***/BasicBlockName.so-BasicBlock test.bc > /dev/null 这样即可打印出对应的名字。
2、删除IR中一条未被使用的指令。
1)所有的步骤和上述一致,源代码如下所示:
1 #include "llvm/Pass.h"
2 #include "llvm/IR/Function.h"
3 #include "llvm/IR/Module.h"
4 #include "llvm/IR/BasicBlock.h"
5 #include "llvm/IR/Instruction.h"
6 #include "llvm/IR/Instructions.h"
7 #include"llvm/Support/raw_ostream.h"
8 #include"llvm/Transforms/Utils/Local.h"
9
10 using namespace llvm;
11
12 namespace
13 {
14 structDeleteInstruction : public BasicBlockPass
15 {
16 static char ID;
17 DeleteInstruction():BasicBlockPass(ID){}
18
19 virtual boolrunOnBasicBlock(BasicBlock &BB)
20 {
21 errs()<<"do nothing"<<"\n";
22 bool change = false;
23 intsign = 0;
24 intcount = 0;
25 errs()<<"Initilized erasecount:"<<count<<"\n";
26 for(BasicBlock::iterator DI = BB.begin();DI!=BB.end();)
27 {
28 Instruction *Inst = DI++;
29 if(isInstructionTriviallyDead(Inst))
30 {
31 Inst->eraseFromParent();
32 change = true;
33 }
34 sign++;
35 count++;
36 }
37 errs()<<"Before erasecount:"<<count<<"\n";
38 count = 0;
39 for(BasicBlock::iterator DI =BB.begin();DI!=BB.end();)
40 {
41 DI++;
42 count++;
43 }
44 errs()<<"After erasecount:"<<count<<"\n";
45 return change;
46 return false;
47 }
48 };
49 }
50
51 charDeleteInstruction::ID = 0;
52 staticRegisterPass X("DeleteInstruction","DI",false,false);
2)代码解释:
因为对Instruction进行操作,所以只需要继承BasicBlockPass即可,29行对指令是否会被用到进行判断,判断函数来自第8行的头文件里面,31行删除就会删除未被使用的指令,由于目前还不知道怎么将修改后的保存到磁盘,所有在39新加了一个循环对删除后的指令进行计数,前后不一致则表示删除成功。
3)运行结果:
do nothing
Initilized erase count:0
Before erase count:11
After erase count:10
需要注意的是源程序中需要有变量未被初始化和使用,这里才会出现不同。
LLVM 中间表示(Intermediaterepresentation,简称IR)作为LLVM的中间语言,对LLVM各种特性的支持有非常重要的作用。
有很多时候我们需要对LLVMIR进行分析,LLVM官方有文档:http://llvm.org/docs/WritingAnLLVMPass.html,其介绍了一个基本的步骤,和对其中一些常用的Pass的介绍,其中的实例很简单,只是简单地打印出函数的名字。
因此为了加深对Pass的学习,下面将分析两个实例:
1、写一个Pass打印出Module、Function、BasicBlock、变量的值或者一些一些属性。
1)所有的步骤都参见官方文档,在/llvm/lib/Transforms目录下面新建一个文件夹(以BasicBlockName为例),到该目录下面新建两个文件一个就是需要用到的BasicBlockName.cpp文件,另外一个就是Makefile。还需要将新建的文件夹的名字加到/llvm/lib/Transforms目录下面的Makefile里面PARALLEL_DIRS的后面添加该文件名。这样即可编辑cpp文件。
2)在cpp文件中添加如下代码:
1#include "llvm/Pass.h"
2#include "llvm/IR/Function.h"
3#include "llvm/IR/Module.h"
4#include "llvm/IR/BasicBlock.h"
5#include "llvm/IR/Instruction.h"
6#include "llvm/IR/Instructions.h"
7#include "llvm/Support/raw_ostream.h"
8
9 usingnamespace llvm;
10
11namespace
12{
13 struct BasicBlockName : publicModulePass
14 {
15 static char ID;
16 BasicBlockName():ModulePass(ID){}
17 virtual boolrunOnModule(Module &M)
18 {
19 for(Module::iterator Mit=M.begin(),Mite=M.end();Mit!=Mite;Mit++)
20 {
21 errs()<<"Function:"<<Mit->getName()<<"\n";
22 for(llvm::Function::iterator Fit =Mit->begin(),Fite = Mit->end();Fit!=Fite;Fit++)
23 {
24 llvm::BasicBlock* bb =Fit;
25 errs()<<"----BasicBlock:"<<bb->getName()<<"\n";
26 if(bb->size()>1)
27 {
28 for(BasicBlock::iteratorBit=bb->begin(),Bite=bb->end();Bit!=Bite;Bit++)
29 {
30 errs()<<"--------"<<Bit->getOperand(0)->getName()<<"| "
31 <<Bit->getOperand(0)->getValueName()<<" |"
32 <<Bit->getOperand(0)->getValueID()<<" |"
33 <<Bit->getOperand(0)->getNumUses()<<" ** end\n";
34 }
35 }
36 }
37 }
38 returnfalse;
39 }
40 };
41}
42
43 charBasicBlockName::ID = 0;
44 staticRegisterPass Y("BasicBlock","BBName",false,false);
3)对代码中进行解释:
第13行处定义了一个继承自ModulePass的BaiscBlockName结构体,17行是具体实现该函数功能,19、22、28分别针对不同的层次使用一个for循环遍历IR中的对象,代码中getName、getValue等函数得到需要的值然后打印出来即可。
4)需要到编译llvm的build文件夹下面make一下,就会在Release+Asserts/lib下面生成BasicBlockName.so文件,然后按照官方文档使用,opt-load ***/BasicBlockName.so-BasicBlock test.bc > /dev/null 这样即可打印出对应的名字。
2、删除IR中一条未被使用的指令。
1)所有的步骤和上述一致,源代码如下所示:
1 #include "llvm/Pass.h"
2 #include "llvm/IR/Function.h"
3 #include "llvm/IR/Module.h"
4 #include "llvm/IR/BasicBlock.h"
5 #include "llvm/IR/Instruction.h"
6 #include "llvm/IR/Instructions.h"
7 #include"llvm/Support/raw_ostream.h"
8 #include"llvm/Transforms/Utils/Local.h"
9
10 using namespace llvm;
11
12 namespace
13 {
14 structDeleteInstruction : public BasicBlockPass
15 {
16 static char ID;
17 DeleteInstruction():BasicBlockPass(ID){}
18
19 virtual boolrunOnBasicBlock(BasicBlock &BB)
20 {
21 errs()<<"do nothing"<<"\n";
22 bool change = false;
23 intsign = 0;
24 intcount = 0;
25 errs()<<"Initilized erasecount:"<<count<<"\n";
26 for(BasicBlock::iterator DI = BB.begin();DI!=BB.end();)
27 {
28 Instruction *Inst = DI++;
29 if(isInstructionTriviallyDead(Inst))
30 {
31 Inst->eraseFromParent();
32 change = true;
33 }
34 sign++;
35 count++;
36 }
37 errs()<<"Before erasecount:"<<count<<"\n";
38 count = 0;
39 for(BasicBlock::iterator DI =BB.begin();DI!=BB.end();)
40 {
41 DI++;
42 count++;
43 }
44 errs()<<"After erasecount:"<<count<<"\n";
45 return change;
46 return false;
47 }
48 };
49 }
50
51 charDeleteInstruction::ID = 0;
52 staticRegisterPass X("DeleteInstruction","DI",false,false);
2)代码解释:
因为对Instruction进行操作,所以只需要继承BasicBlockPass即可,29行对指令是否会被用到进行判断,判断函数来自第8行的头文件里面,31行删除就会删除未被使用的指令,由于目前还不知道怎么将修改后的保存到磁盘,所有在39新加了一个循环对删除后的指令进行计数,前后不一致则表示删除成功。
3)运行结果:
do nothing
Initilized erase count:0
Before erase count:11
After erase count:10
需要注意的是源程序中需要有变量未被初始化和使用,这里才会出现不同。
相关文章推荐
- 基于LLVM IR的几款程序分析工…
- 基于大数据分析的异常检测方法及其思路实例
- 基于KLT算法的MATLAB人脸识别实例分析
- [置顶] 基于稀疏表示的多目标跟踪基本流程(文献分析)
- 基于jQuery的select下拉框选择触发事件实例分析
- 递归调用实例分析2.在函数中间的递归与在函数尾部的递归
- Javascript基于AJAX回调函数传递参数实例分析
- Javascript基于AJAX回调函数传递参数实例分析
- 基于mini6410的linux按键驱动实例分析
- php基于闭包实现函数的自调用(递归)实例分析
- 基于大数据分析的异常检测方法及其思路实例
- IPC analysis on android with a demo (基于IPC实例分析android IPC机制)
- php基于闭包实现函数的自调用(递归)实例分析
- DynaForm入门教程3-基于单工步拉延分析的4个实例
- Hive数据分析——Spark是一种基于rdd(弹性数据集)的内存分布式并行处理框架,比于Hadoop将大量的中间结果写入HDFS,Spark避免了中间结果的持久化
- WEB中基于XMLHTTP的简单实例分析
- 基于结构;基于对象;面向对象;基于接口四种C++编程思想的实例分析
- 基于PHP实现的事件机制实例分析
- (LLVM)中间语言(IR)基本语法简介