[置顶] 第3章Android Dalvik虚拟机 第二节



第3章 第二节Dalvik虚拟机汇编

1、 环境配置Ubuntu 15.10 IP:192.168.153.130
2、 介绍Dalvik虚拟机汇编


1、 Dalvik汇编指令
1) 指令格式
每16个字符用空格分开例子:
A|B|C|D  E|F|G
2) 每4位字符表示一个字母例子:
A|   (注意:A代表4位字符)
3) 顺序从A~Z的单个字母作为4个操作符,注意:如op表示为8位操作码例子:
A|B|C|D  E|F|op
4) 如出现“ø”表示这个字段所有为0 
5) 偏移值表示例子:
A|B|C|D BBBB


2、 指令的确认
1) 指令格式标示大多以3个字符组成,前面2个位位数字,后1个位为字母
2) 第1个数字是表示指令有多少个16位的字组成
3) 第2个数字是表示指令最多使用寄存器个数。
(注意:“r”表示标示取一定范围内的寄存器)
4) 第3个字母为类型码,表示指令用到的而外的指令
5) 其他特殊情况,如果字母为“s”表示静态连接,“i”指令表示内联处理
例子: 24x
2表示16位字组成,4表示最多4个寄存器个数,x表示无额外数据。


3、 其他一些说明
1) 参数采用“vX”方式表示,它是个寄存器如v0、v1等。
2) 参数采用“#+X”方式表示,它表示一个常量
3) 参数采用“+X”方式表示,它表示一个指令偏移量
4) 参数采用“strom@X”方式表示,它表示一个常量池索引池。
可以是“string”字符串常量的索引池
可以是“type”类型常量的索引池
可以是“field”字段常量的索引池
可以是“meth”方法常量的索引池
例子:A|B|op VBB strom@BBBB
A和B表示各自的4个操作符,op vBB 表示一个寄存器并且附加一个strom@BBBB常量池索引池。其实这指令代表着const-string指令。
要查指令详细信息可以到安卓源码中的Dalvik/docs/instruction-formats.html

[置顶] 第3章Android Dalvik虚拟机 第二节_第1张图片


 


4、 使用baksmali 工具进行DEX文件反汇编
java -jar baksmali-2.0.3.jar -o baksmaliout Hello.dex
 
[置顶] 第3章Android Dalvik虚拟机 第二节_第2张图片


5、 使用ddx.jar工具反汇编Hello.dex
java -jar ddx1.5.jar -d ddout Hello.dex
 
[置顶] 第3章Android Dalvik虚拟机 第二节_第3张图片

6、 两种汇编生成的文件结构一样,方法名和字段类型与代码指令列上它们保持是一致的。
不同点如下:
1) 前者用baksmali反汇编出来的寄存器“.registers” ,而后者ddx反汇编输出来的“.registers”指令前面加上了limit前缀。
2) 前者使用p0作为引用,而后者使用v2作为引用。
3) 前者使用“.parameter”是指定一个函数的参数,而后者“parameter”数组指定参数寄存器
4) 前者使用“.prologue”方法的开始,而后者则没有。
5) 前者使用p命名方法,后者使用v命名方法。


7、 查询andriod源码下的Dalvik 每个字节码的处理过程路径是:
root@strom-virtual-machine:~/android4.0.3/android-4.0.3_r1/dalvik/vm/mterp/c# 
cat OP_MOVE.cpp |more
HANDLE_OPCODE($opcode /*vA, vB*/)
    vdst = INST_A(inst);
    vsrc1 = INST_B(inst);

    ILOGV("|move%s v%d,v%d %s(v%d=0x%08x)",
        (INST_INST(inst) == OP_MOVE) ? "" : "-object", vdst, vsrc1,
        kSpacing, vdst, GET_REGISTER(vsrc1));
    SET_REGISTER(vdst, GET_REGISTER(vsrc1));
    FINISH(1);
OP_END


8、 查看INST_A和INST_B的声明文件如:
#define INST_A(_inst)       (((_inst) >> 8) & 0x0f)
#define INST_B(_inst)       ((_inst) >> 12)
Inst为一个16位指令,INST_A将_inst右移8位后与0x0f相与,也就是获取_inst高8位的低4位作为vdst的值。而_INST_B将_inst右移12位,就是获取_inst的最高4位作为vsrc1


9、 ILOGV用来输出调试信息
10、 SET_REGISTER用来设置寄存器的值,GET_REGISTER用来获取寄存器的值。
11、 其他寄存器大小类型为:GET_REGISTER_WIDE、GET_REGISTER_FLOAT声明如下:


# define GET_REGISTER(_idx)                 (fp[(_idx)])
# define SET_REGISTER(_idx, _val)           (fp[(_idx)] = (_val))


fp 为ARM栈寄存器,如在虚拟机运行某个函数时它会指向函数的局部变量区,说白了就是维护一份寄存器的列表。GET_REGISTER宏以”_idx“为索引返回一个寄存器值,而SET_REGISTER中的” _idx “为索引使用用来设置寄存器的值,(注意:一个是返回一个是设置)


12、开启寄存器的验证则使用#ifdef CHECK_REGISTER_INDICES,这个为真时会判断” _idx “是否小于寄存器的值,条件不成立说明超出了范围,虚拟机会抛出异常assert(!”bas reg”).


13、FINISH计算指令的长度,然后将pc的寄存器加上计算出来的偏移量,这样指令执行完成后,会执行下一条指令。


14、v和p的两种不同的寄存器写法一致但名称不值,p的寄存器更甚一筹因为比较好容易判断是局部变量寄存器还是参数寄存器,而且在较长的代码的情况下优势更加甚一筹。


15、Dalvik字节码的类型分为如下:


V void - can only be used for return types       # void只用于返回值类型
Z boolean # 布尔型
B byte # 字节型
S short # 短整型
C char # 字符类型
I int # 整型类型
J long (64 bits) # 长整型
F float # 单精度浮点数
D double (64 bits) # 双精度浮点型


16、Dalvik 方法例子:
Method (I[[IILjava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
对应的java形式代码为:
String method(int,int[][],int,String,Object[])


使用baksmali 工具反编译出来的代码为“.method“指令开始,以“.end method”指令结束。
已#virtual method 表示一个虚方法,而 # direct methods 表示一个直接方法。


17、Dalvi 字段例子:
Ljava/lang/System;->out:Ljava/io/PrintStream;


使用baksmali 工具反编译出来的代码为“.field”指令开头,如开头已“.instance field”表示一个实例字段,它是一个静态字段。

你可能感兴趣的:([置顶] 第3章Android Dalvik虚拟机 第二节)