静态分析:Intermediate Representation

Intermediate Representation

类似编译器会把 source code 转化成中间语言,静态程序分析器也需要一种表示形式,使得这种表示形式利于静态分析的进行。
IR有多种,并没有统一的标准。这里记录的是比较广泛的一种IR。

1. 编译器和静态分析器

编译器:source code 转换为机器码。

整体框架:
编译流程

  • 首先在 Scanner 利用 Regular Expression 进行词法分析
    • 比如图中 Youxxx 部分,由于有特殊符号,所以无法通过词法分析
  • 词法分析通过后会生成一堆token,然后转交给Parser。
    • parser 利用 Context-Free Grammar 进行语法分析
    • 图中 Like your hair I 虽然每个单词都正确,但是不满足语法要求
    • 这一步会生成AST
  • 语义分析
    • 图中 Apples eat you 虽然语法正确,但是语义却不对
    • 对于编译器来说,这一步实际是进行一些类型检查。比如把 float 赋值给 int 等。之后生成 Decorated AST。
  • 转换器转化为IR
    • 一般是变成三地址码IR
    • 静态分析,如代码优化,空指针分析,都是在IR阶段进行的。
  • 生成机器码。

为什么使用上下文不敏感(Context-Free)
对于编程语言来说,上下文不敏感已经足够。上下文敏感分析主要用来分析自然语言,用来分析编程语言有些“杀鸡用牛刀”。

2. AST vs. IR

在这里插入图片描述
可以看到:
AST vs IR
可以看到:

AST

  • 是更高层次的抽象,更接近语法结构
  • 通常依赖于编程语言
  • 适用于快速的类型分析
  • 缺少控制流信息
    • 图中很难看出这是一个循环

3AC IR

  • 通常是更底层的,更接近机器语言
  • 通常不依赖于编程语言
    • 可以将不同语言翻译成同一种表示格式
  • 很统一和简洁
    • do-while, assign 都没有了
  • 包含循环信息
  • 通常作为静态分析的基础

因为这些特性,所以三地址码形式的 IR 是有利于静态分析器的

3. IR: Three-Address Code(3AC)

实际上三地址码IR没有一个标准或形式化的定义

在等号右段最多只有一个操作符。

比如

t2 = a + b + 3

a + b + 3 有三个操作符,如果使用三地址码,则会转换为:

t1 = a + b
t2 = t1 + c

这里的三地址,与平时理解的地址并不相同,更多的是概念上的一种说法。
其中的 Address 是指的下面三种形式

  • Name :a,b
  • Constant : 3
  • Complier-generated temporary : t1, t2

每一种指令都会有对应的三地址码,下面是一些例子:
在这里插入图片描述

4. 3AC在静态分析中的实际应用:Soot

soot 使用的 soot IR 是 带有类型的三地址码。因为一些类型信息对于静态分析是非常有帮助的。
for-loop
在这里插入图片描述
main 函数传进来一个数组,这里的 r0 表示的就是这个数组,做一下声明。

r0 := @parameter0: java.lang.String []

是一种标志,r0 的值是传进来的标记值,标记的类型是 java.lang.String []

i1 相当于原来的 x 。这里源代码的 i 被优化掉了。

do-while
在这里插入图片描述
$i0 : 变量前带有 $ 表示该变量生成的一个临时变量。

method-call
在这里插入图片描述
因为 foo 是一个 instance 方法, this 指向了当前类的对象,将 this 给了 r0.
$r3 是根据 java 语法特性生成的。
生成 r3 之后,就需要调用相应的构造函数。

specialinvlove $r3.<java.lang.StringBuilder: java.lang.StringBuilder: void<init>()>();

前面的标识是JVM中的规范

JVM 中有几种规范:

  • invokespecial: call constructor, call supper class methods, call private methods
  • invokevirutal: instance methods call (virtual dispatch)
  • invokeinterface: cannot optimization, checking interfae implementation
  • invokestatic: call static methods
  • java 7: invokedynamic -> Java static typing, dynamic laguage runs on JVM

尖括号中的内容被称作 method signature,先是类名,然后是返回类型,方法名,方法参数类型

method signature: class name: return type, method name, (parameter1 type, parameter2 type, …)

此处调用默认构造函数,默认构造函数没有函数名,默认都为init。

之后以此类推,r4 是 r3调用 append 方法, 返回一个 StringBuilder ,传入参数是 String 类型, 真正传入的参数是 r1,等等。

main 函数也类似。
在这里插入图片描述
class
在这里插入图片描述

5. Static Single Assignment(SSA)

  • 所有 SSA 变量的 assignments 都会有不同的名字
    • 给每个定义一个新的名字
    • 新名字每次使用下标会递增
    • 每个变量都只有一次定义
      在这里插入图片描述

如果出现分支的情况,如下左图
在这里插入图片描述
左边做分支为 x0, 右分支为 x1, 那么合并后的 x 到底是 x0 还是 x1? 当出现这种情况时,SSA会生成一个 ϕ \phi ϕ方程,先定义一个临时变量 x2, 之后再继续。
在这里插入图片描述

6. Control Flow Analysis

控制流分析通常指的是建立控制流图,即 Control Flow Graph(CFG)

6.1 Basic Blocks(BB)

BB 是 CFG 的节点。
BB 是满足下列条件最长连续的 3AC 指令。

  • 只允许在第一个指令的地方进入
    在这里插入图片描述
    如图,可以从 a = q 处进入这个 block。 而如果从 b = x + a 进入,则是不允许的。
  • 出口为最后一个指令

如何构建 BB
在这里插入图片描述

  • 决定每个 BB 的 leader (入口)
    • 第一条指令是 leader
    • 任何无条件跳转和条件跳转的目标指令是 leader (保证唯一入口)
    • 任何紧跟着无条件跳转和条件跳转的指令是 leader (保证唯一出口)
  • 构建 BBs
    • 一个 BB 包含 leader 和所有下面的指令,直到遇到下一个 leader

比如下面这个例子:
在这里插入图片描述
按照第一个规则,第一条语句是 leader ,得到 (1)
按照第二个规则,跳转语句的目标是 leader,得到 (3), (7), (12)
按照第三个规则,上一句是跳转语句的指令是 leader, 得到 (5), (11),(12)
最终可以再根据 BBs 的构建规则,可以得到每个 BB 包含哪些语句。

6.2 Control Flow Graphs(CFG)

  • CFG 的 节点(node) 是 BB
  • 建立一条从 block A 到 block B 的边, 当且仅当
    • 有条件或无条件的从 A 的结尾跳转到 B 的开头。
    • B 在原来的顺序中紧跟着 A,并且 A 并不是以无条件跳转结尾
  • 通常把 指令的label 替换为 block
    在这里插入图片描述

最后加边,并添加入点和出点:
在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值