【软件分析/静态分析】学习笔记02——中间表示Intermediate Representation

🔗 课程链接:李樾老师和谭天老师的:南京大学《软件分析》课程02(Intermediate Representation)_哔哩哔哩_bilibili

目录

第二章 Intermediate Representation

2.1 编译器与静态分析器的关系(Compilers & Static Analzers)

2.2 AST vs. IR

2.3 IR: 三地址码(Three-Address Code, 3AC)

2.4 真实静态分析器中的3AC:Soot

2.5 静态单赋值(Static Single Assignment, SSA)

2.6 控制流分析(Control Flow Analysis)⭐

2.6.1(Basic Blocks, BB)——建立节点

2.6.2 控制流图 (Control Flow Graph, CFG)——添加边

2.7 总结


第二章 Intermediate Representation

2.1 编译器与静态分析器的关系(Compilers & Static Analzers)

编译器的作用:
        将程序员写的Source Code转换成机器可以识别的Machine Code,并在转换中及时报错。

编译器的主体框架:

        

  1. 通过扫描器(Scanner)做词法分析(Lexical Analysis):根据正则表达式(Regular Expression)检查输入字符是否合法(例如如果是翻译一个英语句子,就是检查字符是否是英文的,单词是否正确/合法),如果通过了词法分析,每个单词就会生成Tokens,给下一步进行分析。
  2. 通过解析器(Parser)做语法分析(Syntax Analysis):通过语法规则(上下文无关文法,Context-Free Grammar)检查语法,通过就转换成抽象语法树AST
  3. 通过类型检查(Type Checker)做语义分析(Semantic Analysis):根据属性语法(Atrribute Grammar)检查语义(期望实现的是识别在英语中的例如Apple eats you,这样语法正确但是语义不对的句子,但是实际上实现的是,例如String的值除以int 这种类型不匹配的错误)如果通过,就生成Decorated AST
  4. 为了进行静态分析优化,要将Decorated AST转换为中间表示(IR),这里的IR一般为三地址码,再进行静态分析,最后通过代码生成器将优化后的代码生成机器码传给机器。

        实际上,静态分析就是做code优化的,静态分析器IR的基础上进行分析。

2.2 AST vs. IR

        

        如图所示

ASTIR
语法树形式的,hight-level,更接近程序源码通常是三地址码的形式,low-level,更接近机器编码
通常与语言有关通常与语言无关
\统一、简洁
缺少控制流信息包含控制流信息
适合做快速的类型检测通常被认为是静态分析的基础

        所以,以三地址码为主要形式的IR是更有利于做静态分析的。

2.3 IR: 三地址码(Three-Address Code, 3AC)

什么是3AC?

        三地址码就是最多有三个地址(address)的表达形式,并且由于这个性质,每个三地址码的右侧最多只能有一个运算符。这里的地址(Adress)可以是以下三种形式之一:

  • 变量名称: a, b 
  • 常量Constant: 3
  • 编译器生成的临时变量: t1, t2

例如:

        t2 = a + b + 3

转换为三地址码的形式就是:

        t1 = a + b

        t2 = t1 + 3

一些常见的3AC形式:

       

        如上图所示,3AC的操作符也包含很多种形式可以是很多种形式:

  • bop 代表的普通二进制运算或逻辑运算(+ - * /  ……)     
  • uop 代表的单运算符(取负数,非……)
  • 也可以没有运算符
  • goto L 无条件的跳转
  • if… goto L 有条件的跳转
  • rop 代表条件操作(>,<,==,……)

        当然这些知识简单的3AC形式,还有更复杂的,我们通过soot这个例子来学习,见2.4

2.4 真实静态分析器中的3AC:Soot

Soot是一个Java优化框架。它提供了四种中间表示法,用于分析和转换Java字节码。其中 Jimple是一种适合优化的类型化3地址中间表示法(typed 3-address code)。这一部分通过Jimple对3AC有更好的了解。

https://github.com/Sable/soot

Tutorials · soot-oss/soot Wiki · GitHub

1. For循环

        如下图所示将一个for循环的java代码转成3ac,这个例子比较简单,可以直接看懂,额外表注的还有关于传递参数时候的3AC表示。

2. Do-while 循环

        以下是do-while循环的3AC,理解起来也比较简单

3. 方法调用

        方法调用相对复杂一点,首先了解一些JVM的知识。

         JVM中主要的方法调用:

  • invokespecial:用于调用实例构造器<init>()方法、私有方法和父类中的方法
  • invokevirtual:调用非私有实例方法,比如 public 和 protected,大多数方法调用属于这一种,在调用的过程中会进行派生(vitual dispatch)
  • invokeinterface:调用接口方法,会检查实现这个接口的对象,但是调用的时候不能做一些优化
  • invokestatic:调用静态方法,
     
  • Java7: invokedynamic -> Java 是静态语言,动态解析出需要调用的方法,然后执行。

参考:5、JVM中的方法调用 - CarBlack - 博客园 (cnblogs.com)

        ② 方法签名(Method Signature)包含类名、 返回值类型、方法名 (参数1  类型,参数2  类型)

        例如:specialinvoke $r3.<java.lang.StringBuilder: void <init>()>(); 这个构造函数的尖括号里的就是一个方法签名,具体含义就是

  •         方法类型:java.lang.StringBuilder 构造函数
  •         方法名字:默认构造函数没有名字,统一叫<init>
  •         参数:没有参数 () 为空
  •         返回值:没有返回值,void

        再如下图中的3AC意思就是:调用$r3的append 方法,将 r1 加进字符串中

         再看3AC的代码可能就会理解一些了,以下的示例代码是在main函数中调用了foo方法,其中foo方法中有两个参数,返回拼接的字符串,先看foo函数的3AC代码

        main函数的3AC代码

 4. Class 类的3AC

         这里不太明白也没关系,反正再看地址码的时候别怕,仔细分析一定是可以看懂的。

2.5 静态单赋值(Static Single Assignment, SSA)

1. SSA的两个特点:

        ① 如下图,SSA里,会给每个变量不同的名字

        

        ② 但是如果是同一个变量在不同的分支呢?在这种情况下,SSA会在合并的时候,引入一个 \OΦ函数,如下图所示,在引入x2 等于这个 Φ 函数,后续使用x2。这个Φ(x0,x1)会根据流的路径来选择是x0 还是x1然后赋值给x2。

        

2. SSA的优点:

  • 程序流信息可以间接体现在不同的变量名上,通过不同的变量名,流的信息被间接地合并到唯一的变量名中
    •  可能有助于提供一些更简单的分析,例如,流不敏感分析通过SSA定义和使用对显式获得流敏感分析的部分精度。(因为流敏感度分析精度虽然高,但是太耗时了,而流不敏感分析就相当于上下文无关的分析,通过单一赋值制就可以获得很久之前就定义过的信息,知道是具体用了那边信息,就相当于获取到了上下文信息。)
  • Define-and-Use pairs(定义-使用对)明确
    • 在一些按需任务中启用更有效的数据事实存储和传播。
    • 一些优化任务在SSA上表现更好(例如,条件常数传播,全局值编号)。

3. SSA的缺点:

  • 如果程序有太多分叉,则会引入太多变量和Φ函数
  • 在最后还要转为机器码执行,在转换回去的时候由于过多的赋值操作产生性能方面的影响。

2.6 控制流分析(Control Flow Analysis)⭐

  • 在进行控制流分析的时候,通常采用建立控制流图(CFG)
  • CFG是静态分析的基础结构
  • CFG中的节点可以是单个的3AC,不过通常用Basic Blocks(BB),如下图所示

2.6.1(Basic Blocks, BB)——建立节点

1. BB的基本概念:        

        Basic Blocks(BB)是连续的满足以下性质的最大长度三地址指令的组成单元:
           -  这个Block的入口只有一个,就是第一个指令,不能从其他地方进来。
           -  这个Block的出口只有一个,就是最后一条指令,不能从其他地方出去。

         如下图所示,仅能从第一条指令出进去该Block,并且仅能从最后一条指令出去,中间的指令不允许进出,能满足这些性质的、连续的、最大的指令集合就是一个Basic Blocks。
        

2. 举个例子🌰

        如下图所示,怎么样来分代码块呢?
        

  • 首先,程序从(1)入口, (2) 没有其他入口和出口,但是(3) 有额外的入口,即从(11)跳转进入,所以(3) 不能和(1)(2)组合在一起,所以 (1)(2)可以组成一个Basic Block
    ——>得出结论如果一个指令是某个跳转的目标,则该指令只能作为一个BB的入口
  • 在看,(3)作为一个Block的入口,(4)没有入口,有个出口,可以加入,但是(5)不能加入,因为(4)已经有出口了,不能作为一个BB的中间指令,所以(3)(4)可以组成一个Basic Block
    ——>得出结论如果一个指令紧跟着一个跳转,则该指令只能作为一个BB的入口

        

3. 怎么建立BB

        通过上述例子的思考,就可以来尝试设计建立Basic Blocks的算法了,伪代码如下:

INPUT: 一个三地址指令序列 P
OUTPUT: P 的Basic Block列表
Method:
    (1) 确定 P 的入口 (leaders)
        · P 的第一句是一个入口
        · 任何一个跳转的目标指令,是一个入口
        · 任何一个跳转的下一条指令,是一个入口
    (2) 建立BBs for P
        · 每个入口到下一个入口之间就是一个BB

        练习:根据算法的设计思想,再看一下2中的例子,完成程序BBs的划分:

        

4. 将跳转到指令标签替换为跳转到基本块

         经过上述的划分,我们就把一个程序P 分割成了多个BBs,并且由于BB的定义导致跳转目标必定是某个BB的入口指令,所以可以将跳转目标的指令标签的形式,换成BB的编号。如下图所示,将原本的跳转到指令标签(7)替换为跳转到基本块 B4

        

2.6.2 控制流图 (Control Flow Graph, CFG)——添加边

1. 建立边

        在建立完CFG的节点之后,需要添加边(edge),基本规则如下:

  • A--->B 是跳转过去的,则AB 建立一个边,如第一组红色的AB
  • A--->有条件跳转,如第二组的蓝色的A跳转到第一组红B,且蓝A后还有指令蓝B
    • A--->建立一条边(if  goto)
    • A--->B(A紧接着的下一条指令 B) 也需要建立一条边(条件jump block 天然有两出口)
  • A->B 是第三组的绿A无条件跳转到第一组的红B,其中第三组的绿B按原指令紧挨着第三年组的绿A
    • A--->B 建立一条边 (goto)
    • A-×-> B  不建立绿A 向其代码紧挨着的下一条指令的边

        

        完成节点的划分、编号,最后一步就是再按照顺序以及根据上述示例的规则添加上边,将BB连接起来,最后通常,我们在加上Entry Exit,这样就得到了一个控制流图。

        我们还用2.6.1中的例子,为其添加上边,如下图所示。

        

 

2.7 总结

        这一章先讲了编译器与静态分析器的关系,侧重于了解静态分析处在什么位置,主要运用IR进行静态分析,介绍了AST与IR的不同。

         什么是三地址码,并通过soot更清楚的认识真实分析中的3AC。

        介绍CFG的建立步骤,以及Basic Blocks的划分方法,这些静态分析的基础。


🌻写在最后:

    笔者也是软件分析方向的学生, 这个是跟着课程总结和记录的学习笔记, 如果有错误的地方, 欢迎讨论\批评\指正.

   如果有更多关于软件分析领域的资料\论文\课程\建议, 欢迎留言, 一起学习进步~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值