依稀记得在NJU谭添老师的课上讲过一些
编译器
在了解IR(中间代码)之前,首先要了解一个编译器是如何运作的,也就是编译原理,在这里并不会过多赘述。
- 词法分析:正则表达式找出单词并判断拼写,打上token进入下一环节
- 语法分析:同过上下文无关算法来判断是否符合语法,转化为AST进入下一环节
- 语义分析:通过属性语法来判断是否有问题,包括作用域,类型检查等等,生成修饰过的AST
- 优化:生成IR,并进行各种优化
- 目标代码生成:通过IR生成目标代码
静态分析通常是在IR上进行的,所以也称IR为静态分析的基石
3AC(3-Address Code)
三地址码是一种常见的中间代码形式,而Soot就是一种三地址码。
格式:在一个语句右侧只有一个操作符。
常见的形式如下所示:
1 2 3 4 5 6
| x = y bop z x = uop z x = y goto L if x goto L if x rop y goto L
|
在产生三地址码的过程中,不可避免的要产生中间变量以满足其要求:
1 2 3 4 5
| a = b + c - d * e ----------------- t1 = d * e t2 = c - t1 a = b + t2
|
Jimple语法与API
- invokespecial:用来调用构造函数,父类方法和私有方法(constructor、superclass method、private method)。
- invokevirtual:用来调用实例方法、基于类进行分派(instance method、virtual dispatch)
- invokeinterface:用来调用接口中的方法
- invokestatic:用来调用静态方法
实际上在学习了编译原理之后,对于整个程序大致流程会产生什么样的中间代码已经基本清楚了,但对于不同的编程语言产生的一些接口还需要进一步的实践了解
Jimple示例
Jimple是一种典型的三地址码。下面给出一些简单的Java代码和对应的Jimple代码作为示例:
do-while 循环
1 2 3 4 5 6 7 8 9
| 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) } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public static void main(java.lang.String[]) { java.lang.String[] r0; int[] r1; int $i0,i1;
r0 := @parameter0: java.lang.String[]; r1 = newarray (int)[10]; i1 = 0; label1: i1 = i1 + 1; $i0 = r1[i1]; if $i0 < 10 goto label1;
return; }
|
方法调用
1 2 3 4 5 6 7 8 9 10 11 12
| public class MethodCall3AC{
String foo(String para1,String para2){ return para1 + " " + para2; } public static void main(String[] args){ MehtodCall3AC mc = new MehtodCall3AC(); String result = mc.foo("hello","world"); } }
|
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
| java.lang.String foo(java.lang.String,java.lang.String) { MethodCall3AC r0; java.lang.String r1, r2, $r7; java.lang.StringBuilder $r3,$r4,$r5,$r6;
r0 := @this: MethodCall3AC; r1 := @parameterr0: java.lang.String; r2 := @parameterr1: java.lang.String; $r3 = new java.lang.StringBulider; specialinvoke $r3.<java.lang.StringBulider: void<init>()>(); $r4 = virtualinvoke $r3.<java.lang.StringBulider: java.lang.StringBulider append(java.lang.String)>(r1); $r5 = virtualinvoke $r4.<java.lang.StringBulider: java.lang.StringBulider append(java.lang.String)>(" "); $r6 = virtualinvoke $r5.<java.lang.StringBulider: java.lang.StringBulider append(java.lang.String)>(r2); $r7 = virtualinvoke $r6.<java.lang.StringBulider: java.lang.String toString()>();
return $r7; }
public static void main(java.lang.String[]) { java.lang.String[] r0; MethodCall3AC $r1;
r0:= @parameter0: java.lang.String[]; $r1= new MethodCall3AC; specialinvoke $r1.<MethodCall3AC: void<init>()>(); virtualinvoke $r1.<MethodCall3AC: java.lang.String foo(java.lang.Stirng,java.lang.String)>("hello","world"); return; }
|
类
1 2 3 4 5 6 7 8
| package a.b.c; public class Class3AC{
public static final double pi = 3.14; public static void main(String[] args){ } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public class a.b.c.Class3AC extends java.lang.Object { public static final double pi;
public void <init>() { a.b.c.Class3AC r0; r0 := @this: a.b.c.Class3AC; specialinvoke r0.<java.lang.Object: void <init>()>(); return; } public static void main(java.lang.String[]) { java.lang.String[] r0; r0:= @parameter0: java.lang.String[]; return; } public static void <clinit>() { <a.b.c.Class3AC: double pi> = 3.14; return; } }
|