最近逆向了一个工程,其中有一个init() 方法 如下:
// Byte code:
// 0: ldc com/aa/notice/network/OkHttpManager
// 2: monitorenter
// 3: getstatic com/aa/notice/network/OkHttpManager.serverTask : Lcom/aa/notice/network/OkHttpManager;
// 6: ifnonnull -> 20
// 9: new com/aa/notice/network/OkHttpManager
// 12: dup
// 13: aload_0
// 14: invokespecial : (Landroid/content/Context;)V
// 17: putstatic com/aa/notice/network/OkHttpManager.serverTask : Lcom/aa/notice/network/OkHttpManager;
// 20: ldc com/aa/notice/network/OkHttpManager
// 22: monitorexit
// 23: return
// 24: astore_0
// 25: ldc com/aa/notice/network/OkHttpManager
// 27: monitorexit
// 28: aload_0
// 29: athrow
// Exception table:
// from to target type
// 3 20 24 finally }
遇到了一些指令,大致解释如下:
ldc: 该系列命令负责把数值常量或String常量从常量池推送至栈顶。 该命令后面需要给一个常量在常量池中位置(编号)的参数,哪些常量是放在常量池呢?比如:final static int id = 32768; final static float double = 6.5. 对于const系列命令和push系列命令操作范围之外的数值类型常量,都放在常量池中。所有不是通过new创建的String都是放在常量池中的。
0x12 ldc 将int, float或String型常量值从常量池中推送至栈顶
0x13 ldc_w 将int, float或String型常量值从常量池中推送至栈顶(宽索引)
0x14 ldc2_w 将long或double型常量值从常量池中推送至栈顶(宽索引)
monitorenter 和 monitorexit 是同步指令 相当于java中的synchronized。
getstatic、putstatic:遇到 new、 getstatic、 putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化, 则需要先触发其初始化, 生成这4条指令的最常见的 Java代码场景是:
(1)、使用 new关键字实例化对象的时候;
(2)、读取或设置一个类的静态字段的时候(即在字节码中,执行getstalic或putstatic指令时),被final修饰、已在编译期把结果放入常量池的静态字段除外;
(3)、调用一个类的静态方法的时候(即在字节码中执行invokestatic指令时)。
dup:其作用就是复制之前分配的空间的引用并压入栈顶。
invokespecial:只能调用三类方法:<init>方法;private方法;super.method()。因为这三类方法的调用对象在编译时就可以确定。
invokevirtual:是一种动态分派的调用指令:也就是引用的类型并不能决定方法属于哪个类型。
这里可以看到其中main方法主要做的
0 new jvm.study.Test [1]
3 dup
4 invokespecial jvm.study.Test() [16]
7 astore_1 [t]
8 return
这里有个dup指令。其作用就是复制之前分配的jvm.study.Test空间的引用并压入栈顶。那么这里为什么需要这样么做呢?因为invokespecial指令通过[16]这个常量池入口寻找到了jvm.study.Test()构造方法,构造方法虽然找到了。但是必须还得知道是谁的构造方法,所以要将之前分配的空间的应用压入栈顶让invokespecial命令应用才知道原来这个构造方法是刚才创建的那个引用的,调用完成之后将栈顶的值弹出。之后调用astore_1将此时的栈顶值弹出存入局部变量中去。
load系列A:该系列命令负责把本地变量送到栈顶。这里的本地变量不仅可以是数值类型,还可以是引用类型。
load系列B:该系列命令负责把数组的某项送到栈顶。该命令根据栈里内容来确定对数组的某项进行操作。
store系列A:该系列命令负责把栈顶的值存入本地变量。这里的本地变量不仅可以是数值类型,还可以是引用类型
store系列B:该系列命令负责把栈顶项的值存到数组。该命令根据栈里内容来确定对哪个数组的哪项进行操作。
网友评论