笔记参考
视频链接
1.编译器和静态分析器
1.1编译器
编译器将源代码(Source code) 转换为机器代码(Machine Code)。
1.词法分析器(Scanner),结合正则表达式,通过词法分析(Lexical Analysis)将 source code 翻译为 token。保证单词的正确性,字母的拼写和有意义。
2.语法分析器(Parser),结合上下文无关文法(Context-Free Grammar),通过语法分析(Syntax Analysis),将 token 解析为抽象语法树(Abstract Syntax Tree)。保证句子的语法正确,主谓宾定状补。其中,上下文不敏感准确性弱于敏感,但是已经足够,保证速度。
3.语义分析器(Type Checker),结合属性语法(Attribute Grammar),通过语义分析(Semantic Analysis),将 AST 解析为 decorated AST。在语义合不合理的层面进行分析。
4.转换器(Translator),将 decorated AST 翻译为三地址码这样的中间表示形式IR(Intermediate Representation),并基于 IR 做静态分析(例如代码优化、查漏洞工作)。
5.代码生成器(Code Generator),将 IR 转换为机器代码
不可以跳步,因为静态分析要做的是non-trivial的事情(代码优化),前面先做trivial的事情,静态分析要在IR上进行下一步分析。
2.抽象语法树(AST) vs. 中间表示(IR)
2.1差别
- 抽象语法树:高层,贴近语法结构;依赖于编程语言;适合做快速的类型检查;看不出来控制流信息,但是人比较方便读懂。
- 中间表示:底层,贴近机器码;具有语言无关性;简洁而统一;包含控制流信息;通常作为静态分析的基础。程序语言的中间表达形式,去除了如注释等无关程序运行的部分,通用。
2.2 IR: Three-Address Code (3AC)
2.2.1定义
三地址码(3AC)是指每一条指令最多包含三个地址(Address)的代码,其右侧结构最多只能有一个操作符,同时这里的地址也不是内存中的地址,而是下面三种形式中的一种:
- 变量:如a,b
- 常量:如3
- 编译器自动生成的临时变量:如t1
,
t2
范例如下:
- 将 t2 = a + b + 3转换成三地址码(3AC):
- t1 = a + b
- t2 = t1 + 3
2.2.2三地址码常见形式
x = y bop z, bop:二元运算符或者逻辑操作(+ - * /)
x = uop y, uop:一元运算符(取负,取反,转换)
goto L, L:程序位置标记
if x rop y goto L, rop:关系运算符 (<, >, ==, >=, <=等)
goto L: 无条件跳转
if x goto L,if … goto L: 条件跳转
2.2.3 3AC in Real Static Analyzer: Soot
Soot 是一个用于分析和优化 Java 字节码的框架,它提供了一系列强大的功能和工具,广泛应用于研究和工业界的程序分析、优化和安全性检查。Jimple 是 Soot 框架中提供的一种中间表示,专门设计用于简化和提高 Java 字节码的分析和优化效率,主要特点是将复杂的字节码指令简化为三地址码形式。
DoWhileLoop3AC.java:
package nju.sa.examples;
public class DoWhileLoop3AC {
public static void main(String[] args) {
int[] arr = new int[10];
int i = 0;
do {
i = i + 1;
} while (arr[i] < 10);
}
}
使用soot框架转化代码:
javac DoWhileLoop3AC.java
java -cp soot.jar soot.Main -cp . -pp -f jimple DoWhileLoop3AC
DoWhileLoop3AC.jimple:
public static void main(java.lang.String[])
{
int[] r0;
int $i0, i1;
java.lang.String[] r1;
r1 := @parameter0: java.lang.String[];
r0 = newarray (int)[10];
i1 = 0;
label1:
i1 = i1 + 1;
$i0 = r0[i1];
if $i0 < 10 goto label1;
return;
}
java IR(Jimple)基本知识
invokespecial:call constructor, call superclass methods, call private methods
invokevirtual: instance methods call (virtual dispatch)
invokeinterface: cannot optimization, checking interface implementation
invokestation:call static methods
Java 7: invokedynamic -> Java static typing, dynamic language runs on JVM
method signature: class name, return type, method name(parameter1 type, parameter2 type)
3.Static Single Assignment (SSA)
3.1定义
静态单赋值(SSA)也是一种经典的IR,普通三地址码与静态单赋值形式最主要的区别就是SSA给每个变量都赋值一次,不会出现变量的重复赋值,每个变量都有一个定义。
3.1.1Φ函数
由于SSA的性质,为了保证每个变量拥有唯一定义且不会产生歧义,故引入了Φ函数(称为phi-function),在控制流交汇结点使用Φ函数进行聚合,比如Φ(x0,x1)会根据流的路径来选择是x2=x0或者x2=x1。
3.2优缺点
优点:
- 控制流信息间接地集成到了独特变量名中,传递一些简单的分析信息,加快流不敏感分析的速度;
- 定义与使用是显式的,能更精确地找到其定义的地方,此外一些优化算法在SSA上表现更好。
缺点:
- 如果程序分叉太多,则引入了太多的变量和Φ函数;
- 转换到机器码的过程会产生许多性能的问题。
4.Basic Blocks (BB)
基本块(Basic Blocks),就是满足以下性质的,最大长度的连续三地址码单元:
- 只可以把块的第一个指令作为入口,不能从其他地方进入。
- 只可以把块的最后一条指令作为出口,不能从其他地方出去。
4.1构建思路
INPUT: 三地址指令序列 P
OUTPUT: P 的基本块列表
Method:
(1) 确定 P 的入口 (leaders)P 的第一个指令是一个leader
任何一个有条件或无条件跳转的目标指令,是一个leader
任何一个有条件或无条件跳转的下一条指令,是一个leader
(2) 建立P的基本块每个leader到下一个leader之间就是一个BB
5.Control Flow Graphs (CFG)
5.1介绍
- 三地址码最终是在控制流图(CFG) 上进行分析,通常要构建控制流图进行控制流分析。
- CFG作为静态分析的基础架构。
- CFG中的节点既可以是单个的3AC,也可以是Basic Blocks(BB)。
5.2添加边
- 如果两个BB前后相连且无跳转,则加边
- 如果从A无条件跳转B,则A到B加边
- 如果从A有条件跳转到B,则加边
此外,将跳转的目标从指令代号改成基本块的名字。在CFG中若 A -> B,则我们说 A 是 B 的前驱(predecessor),B 是 A 的后继(successor)。
除了构建好的基本块,通常还会额外添加两个结点入口(Entry)和出口(Exit)便于初始化,最终控制流图就构建完毕。