当前位置:   article > 正文

LLVM_pass应用3 获取对应操作符上下文即CFG和DFG_获取java代码的cfg、dfg

获取java代码的cfg、dfg


本文介绍通过llvm的pass分析源码对应IR指令集中的操作符的上下文流程
这样就方便我们通过遍历得到整个代码的cfg和dfg, 对于NLP转图处理有很大的帮助

1. 跳转指令br的cfg和dfg

在这里插入图片描述

2 . 加法add和比较cmp指令的cfg和dfg

在这里插入图片描述

3. 框架依然按照应用1中的使用,见下面链接

基础知识和框架请看

4. FirstPass.cpp主代码

代码主干

遍历函数
	遍历basicblock
		遍历statement
			找到目标操作符
				打印目标操作符所在行代码
				打印目标操作符数据流上级
				打印目标操作符数据流下级
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
#include <llvm/IR/BasicBlock.h>
#include <llvm/IR/Function.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/IR/User.h>
#include <llvm/IR/Instructions.h>
#include <llvm/Pass.h>
#include <fstream>
#include <llvm/Analysis/CFG.h>
#include <stdio.h>
#include <map>
#include "list"

using namespace llvm;

namespace {

    //定义 First 类继承自 FunctionPass
    struct First : public FunctionPass {
        static char ID; // Pass ID
        std::string str;
        First() : FunctionPass(ID) {}
        std::list<Instruction *>::iterator itor_former;  //定义迭代器
        int num_function = 0; // 用来记录多少个函数



        bool runOnFunction(Function &F) override {  //这里是一个函数一个函数的往里面传的数据
            errs() << F.getName() << "\n"; //显示函数名称
            errs() << "num_function=" << num_function <<"\n"; //num_function=0
            num_function++;

            // 打印call func的句子
            for (User *U : F.users()) {
                if (Instruction *Inst = dyn_cast<Instruction>(U)) {
                    errs() << "F is used in instruction:";
                    errs() << *Inst << "\n";
                }
            }  
            // raw_string_ostream rso(str);
            // StringRef name("Graph.dot"); //生成图
            // std::ofstream output_CFG_file(
            //     "output.txt"); //定义输出文件
            // output_CFG_file << "hello world:"; // 向文件内输出
            // output_CFG_file.close();

            
            //遍历函数中的basicblock
            for (Function::iterator BB = F.begin(); BB != F.end(); ++BB) {
                errs() << "块的长度 size:BB->size() "<< BB->size() <<"\n";//显示basicblock的名字和大小

                //在BB中遍历statement
                for(BasicBlock::iterator i = BB->begin(); i!=BB->end(); i++){
                    // 打印块内statement所有数据
                    // errs() << "每一行的数据和地址" << &*i ; //打印ir块里面的所有行,和地址
                    // errs() << "  *i:" << *i ; //打印ir块里面的所有行,和地址
                    // errs() << "  操作符i->getOpcodeName(): " << i->getOpcodeName()  << "\n"; //打印ir块里面的所有行,和地址

                    //dyn_cast<>操作符是一个“检查转换”操作。它检查操作数是否属于指定的类型
                    //判断本行中是否包含操作符add,打印这行数据
                    Instruction *inst = dyn_cast<Instruction>(i); 
                    if(inst->getOpcode() == Instruction :: Add || inst->getOpcode() == Instruction::Br || inst->getOpcode() == Instruction::ICmp){ 
                        for(User *U :inst ->users())
                        {
                            // 打印add行
                            // errs() <<"dyn_cast<Instruction>(U)"<<*dyn_cast<Instruction>(U) << "\n";
                            if(Instruction *Inst = dyn_cast<Instruction>(U))
                            {
                                //%13 = add nsw i32 %12, 2add
                                errs()<<"\n操作符定位到 of add/icmp used in : "<<*inst << "  " << inst->getOpcodeName() <<"\n";
                                
                                errs()<<"操作符下一级 : "<<*Inst << "\n"; 
                            }
                        }

                        // 输出其所使用的所有operands(操作数)就是加数被加数 
                        // %16 = add nsw i32 %15, 1  
                        // %15 = load i32, i32* %7, align 4和i32 1
                        for(Use &U :inst ->operands())
                        {
                            Value *v =U.get();
                            errs()<<"input of add originate from : " <<*v<<"\n";
                        }      
                    }
                }
                // for (BasicBlock *SuccBB : successors(curBB)) {
                //     errs() << "&*(SuccBB->begin()):" << &*(SuccBB->begin()) << "\n";  
                // }
            }
            return false;
        }
    };
}
 
char First::ID = 0;  //初始化 Pass ID
 
//最后注册 FirstPass, 指定命令行参数为 First
static RegisterPass <First>X("First", "First Pass");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97

5. 测试代码跟前两应用一样

#include <stdio.h>

int fun1(){
    printf("%s\n", "hello");
    return 25;
}
int fun2(){
    printf("%s\n", "fun2");
    return 23;
}
int main(int argc, char const *argv[]){
    int b=0;
    int i = 0;
    for (i = 0; i < 23; ++i){
        b+=2;
    }
    printf("%d\n", b);
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

转化为ir文件或者bc文件应用1中有涉及

  • hello.bc .c文件的字节码文件, 生成命令是clang -c -emit-llvm hello.c -o hello.bc
  • hello.ll .c文件的IR文件,指令集,生成命令clang -O0 -S -emit-llvm input.c -o input.ll

实验结果

zjq@DESKTOP-O28RVV3:test2_$ cat run.sh
cd build/ && make && cd ..
opt -load build/libFirstPass.so -First hello.ll
zjq@DESKTOP-O28RVV3:test2_$ source run.sh
[100%] Built target FirstPass
WARNING: You're attempting to print out a bitcode file.
This is inadvisable as it may cause display problems. If
you REALLY want to taste LLVM bitcode first-hand, you
can force output with the `-f' option.

fun1
num_function=0
块的长度 size:BB->size() 2
fun2
num_function=1
F is used in instruction:  %18 = call i32 @fun2()
块的长度 size:BB->size() 2
main
num_function=2
块的长度 size:BB->size() 12
input of add originate from :
; <label>:8:                                      ; preds = %14, %2
  %9 = load i32, i32* %7, align 4
  %10 = icmp slt i32 %9, 23
  br i1 %10, label %11, label %17

块的长度 size:BB->size() 3

操作符定位到 of add/icmp used in :   %10 = icmp slt i32 %9, 23  icmp
操作符下一级 :   br i1 %10, label %11, label %17
input of add originate from :   %9 = load i32, i32* %7, align 4
input of add originate from : i32 23
input of add originate from :   %10 = icmp slt i32 %9, 23
input of add originate from :
; <label>:17:                                     ; preds = %8
  %18 = call i32 @fun2()
  %19 = load i32, i32* %6, align 4
  %20 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.3, i32 0, i32 0), i32 %19)
  ret i32 0

input of add originate from :
; <label>:11:                                     ; preds = %8
  %12 = load i32, i32* %6, align 4
  %13 = add nsw i32 %12, 2
  store i32 %13, i32* %6, align 4
  br label %14

块的长度 size:BB->size() 4

操作符定位到 of add/icmp used in :   %13 = add nsw i32 %12, 2  add
操作符下一级 :   store i32 %13, i32* %6, align 4
input of add originate from :   %12 = load i32, i32* %6, align 4
input of add originate from : i32 2
input of add originate from :
; <label>:14:                                     ; preds = %11
  %15 = load i32, i32* %7, align 4
  %16 = add nsw i32 %15, 1
  store i32 %16, i32* %7, align 4
  br label %8

块的长度 size:BB->size() 4

操作符定位到 of add/icmp used in :   %16 = add nsw i32 %15, 1  add
操作符下一级 :   store i32 %16, i32* %7, align 4
input of add originate from :   %15 = load i32, i32* %7, align 4
input of add originate from : i32 1
input of add originate from :
; <label>:8:                                      ; preds = %14, %2
  %9 = load i32, i32* %7, align 4
  %10 = icmp slt i32 %9, 23
  br i1 %10, label %11, label %17

块的长度 size:BB->size() 4
zjq@DESKTOP-O28RVV3:test2_$
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

总结:

通过代码中定位操作符,然后得到对应操作符的上下文关系, cfg和dfg非常方便
具体细节代码中有注释
具体流程请跳转到1\2两节

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/331238
推荐阅读
相关标签
  

闽ICP备14008679号