dalvik字节码问答

本文深入探讨了Dalvik字节码,包括其定义、格式、常量池、类和对象操作指令、函数调用、异常处理以及字节码的程序结构。详细介绍了常量池与常量解析表的作用,以及如何通过invoke指令、field操作指令和switch指令进行函数调用、字段访问和条件跳转。此外,还阐述了Dalvik的quick指令优化和try-catch数据结构的工作原理。
摘要由CSDN通过智能技术生成

参考资料

https://source.android.com/devices/tech/dalvik/dalvik-bytecode.html

https://source.android.com/devices/tech/dalvik/instruction-formats.html

http://www.milk.com/kodebase/dalvik-docs-mirror/docs/dalvik-bytecode.html



什么是Dalvik字节码?

dalvik 的虚拟机指令代码。dalvik字节码之于dalvik VM,就像可执行程序的机器码之于CPU一样。

dalvik 字节码是一种基于寄存器的虚拟机指令系统。它的含义是,每一个可执行函数都有一个Frame,Frame的大小是固定,包括固定数目大小的虚拟寄存器。
dalvik VM 会为这个函数的参数、本地变量、临时变量都分配一个虚拟寄存器。所有的运算都是在寄存器之间完成的。
当然,我说的,变量与寄存器不是一对一的关系,而是多对一的关系。因为变量的生命周期并不完全一样,有些变量之间生命周期不重合,就会出现共用一个寄存器的情况。

在下面的描述中,我们用v0, v1, ... vN 表示寄存器,一共有N+1寄存器。

除了常用的寄存器外,还有两个隐含的寄存器:result和exception。当函数返回时,返回值被写入到result寄存器,而抛出异常时,异常对象会被放入exception寄存器。
在dalvik的实现中,这两个寄存器都是放在Thread对象中的。一个Thread对象代表一个java线程,一个java线程同时只需要一个result和exception寄存器。

dalvik字节码指令分成几大部分:
  • const 指令:负责将常量值放入到虚拟寄存器中;
  • mov指令:在虚拟寄存器之间拷贝数据;
  • 比较指令:比较两个寄存器的值,有部分指令是直接与0比较的;
  • 分支指令:包括if系列指令如if-eq, if-ge等等,以及switch指令,goto指令。switch指令作为一个单独指令存在的;
  • invoke指令:函数调用指令,分成invoke-direct, invoke-static, invoke-native, invoke-virtual和invoke-interface几大系列;
  • field操作指令:包括put/get,针对静态域和非静态域;
  • class相关的指令:比如new-instance, instance-of,checkcast等等
  • 异常处理指令:包括throw, move-exception这样的指令;
  • 算术、位移等指令:不多说了;
  • 其他指令

字节码的格式

dalvik字节码是以一个字(两字节)为单位,必须是一个字的整数倍。所以,你看到dexdump出的字节指令,其长度都必须x2才能得到其字节长度。

不同指令的字节码长度不一样,相同操作类型的指令长度是一样的,根据指令操作类型,就可以确定指令的长度。比如 mov v1, v2,指令长度是1字。

字节码在dex文件中存储时,都是小端的。因此,第一个字节必须是操作类型(操作符),是一个0~255范围内的一个数字,根据操作符,我们可以确定后续有多少个字以及表示什么意思。


每个操作符都有一个格式(format),根据格式,我们可以知道该指令的长度,参数有哪些、每个参数的长度、参数是如何存储的,这些重要的信息。不同的指令可以有相同的格式,因此,dalvik将他们分类,并给每个格式以不同的描述。每种格式被称为Format ID。

下表详细说明了dalvik字节码的格式(来自https://source.android.com/devices/tech/dalvik/instruction-formats.html)。这个表分为4列。其中前3列分别是Format, ID, Syntax。

Format列

"op" 表示操作符,8位1字节无符号整数。大写字母"A","B","C"等表示4位数;" Ø" 表示空,占4位,必须为0;
每个部分用'|'分割,表示一个逻辑上独立的部分。
排列最小单位是字(两字节),中间不分割。例如B|A|op,这个长度是1个字(两字节),但是包括3部分,op操作符和 A, B两个参数; 而AA|opBBBB 包含两个字(4字节),其中"AA|op"是第一个字,而"BBBB"则是在第二字。

因为在实际存储时,是以小端方式,而在描述时,则以大端方式。阅读时要注意。比如 ØØ|op , 在实际存储时,“op”在第0字节,而“ØØ”在第1字节。在如
AA|opBBBB 则是 op在第0字节,AA在第1字节,BBBB 占用第2,3字节。

ID列

ID由3部分组成: <长度><寄存器个数><类型描述>。 例如 "10x"  "1"表示指令长度为1, "0"表示用到0个寄存器,"x"表示类型描述; “ 21t“ 表示指令长度为2,用到1个寄存器,并需要跳转("t"表示分支跳转)。
最后类型描述部分各个字符表示的意思如下表:
Mnemonic Bit Sizes Meaning
b 8 有符号1字节立即数
c 16, 32 常量池索引
f 16 interface相关的常量
h 16 16位有符号立即数,表示32/64位中的最高16位
i 32 32位有符号立即数,或者32位的浮点数
l 64 64位有符号立即数,或者双精度浮点数
m 16 method的常量索引值
n 4 4位有符号立即数
s 16 16位有符号立即数
t 8, 16, 32 分支目标偏移值
x 0 无更多附加数

Syntax列

字节码可以反汇编,形成类似汇编代码的助记符形式,方便人类阅读。一般形式是 op Arg1[, Arg2, [,Arg3 ...]] 这种形式。
你在Format列看到的字符会反映到Syntax列。例如,如果在Foramt列看到了"AA",那么在Syntax列看到的“AA”所指的是同一个概念。

在Syntax,会给它加不同前缀,形成不同的格式,代表不同含义:
  • "vX": 前缀"v"表示这是一个虚拟寄存器,"X"对应Foramt列中的参数,"X"的值就是虚拟寄存器的索引;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值