Dalvik指令集
Dalvik是Google公司自己设计的用于Android平台的虚拟机。Dalvik虚拟机是Google等厂商合作开发的Android移动设备平台的核心组成部分之一。它可以支持已转换为 .dex(即Dalvik Executable)格式的Java应用程序的运行,.dex格式是专为Dalvik设计的一种压缩格式,适合内存和处理器速度有限的系统。Dalvik 经过优化,允许在有限的内存中同时运行多个虚拟机的实例,并且每一个Dalvik 应用作为一个独立的Linux 进程执行。独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭。一段Dalvik汇编代码由一系列Dalvik指令组成,指令语法由指令的位描述与指令格式标识来决定。
Dalvik虚拟机是基于寄存器架构的,数据的访问通过寄存器单间直接传递。对java的每个线程都有一个pc计数器和一个java栈。Pc计数器类似arm cpu中的PC寄存器和x86 cpu中的IP寄存器,不同的是,PC计数器只对当前方法有效。
语 法 | 含 义 |
---|---|
V | void,只用于返回值类型 |
Z | boolean |
B | byte |
S | short |
C | char |
I | int |
J | long |
F | float |
D | double |
L | Java类类型 |
[ | 数组类型 |
1、空操作指令
助记符为nop,值为00,通常用来做对齐代码,无实际操作。
2、数据操作指令 move
3、返回指令 return
“return-void”表示函数从一个void方法返回。
“return vAA表示函数返回一个32位非对象类型的值,回值寄存器为8位的寄存器vAA
“return-wide vAA表示函数返回一个64位非对象类型的值。返回值为8位的寄存器对vAA
“return object vAA”表示函数返回一个对象类型的值。返回值为8位的寄存器vAA
4、数据定义指令 const
用来定义程序中用到的常量、字符串、类等数据。
“const/high16 vAA,#+B000”将数值右边零扩展为32位后赋给寄存器vAA。
“const-wide/16 vAA,#+BBBB”将数值符号扩展为64位后赋给寄存器对vAA.
“const-wide/32 vAA,#+BBBBBBBB”将数值符号扩展为64位后赋给寄存器对vAA
“const-wide vAA,#+BBBBBBBBBBBBBBBB”将数值赋给寄存器对vAA
“const–wide/high16 vAA,#+BB00000000将数值右边零扩展为64位后赋给寄存器对vAA
“cost-string vAA, string@BBBBBBBB”通过字符串索引构造一个字符串并赋给寄存器vAA
“const-string-/jumbo vAA, string@BBBBBBBB”通过字符串索引(较大)构造一个字符串并赋给寄存器vAA。
“const-class- vAA,type@BBBB”通过类型索引获取一个类引用并赋给寄存器vAA
“const-class-/jumbo vAAAA,type@BBBBBBBB”通过给定的类型索引获取一个类引用并赋给寄存器 VAAAA.这条指令占用两个字节,值为 OxOOff( Android 4.4.0中新增的指)
5、实例操作指令
类型转换,检查,新建。
“check-cast vAA,type@BBBB”将vAA寄存器中的对象引用转换成指定的类型,如果失败会抛出 ClassCastException异常。如果类型B指定的是基本类型,对于非基本类型的A来说,运行时始终会失败。
”instance-of vA,vB,type@CCCC”判断vB寄存器中的对象引用是否可以转换成指定的类型,如果可以vA寄存器赋值为1,否则vA寄存器赋值为0。
“new-instance VAA,type@BBBB”构造一个指定类型对象的新实例,并将对象引用赋值给vAA寄存器,类型符tpe指定的类型不能是数组类.
“check-cast/jumbo VAAAA, type@BBBBBBBB”指令功能与“ check-cast vAA,type@BBBB”相同,只是寄存器值与指令的索引取值范围更大( Android4.0中新增的指令)
“ instance-of/jumbo VAAAA, VBBBB,type@ CCCCCCCC”指令功能与“ instance-of vA ,vB ,type @cCCC”相同,只是寄存器值与指令的索引取值范围更大( Android40中新增的指令)。
“new-instance/jumbo VAAA/,type@ BBBBBBBB”指令功能与“new- instance VAA,type@BBBB”相同,只是寄存器值与指令的索引取值范围更大( Android4.0中新增的指令)
6、锁指令 monitor (多用在多线程程序中对同一对象的操作)
“monitor-enter vAA”为指定的对象获得锁。
“monitor -exit vAA” 释放指定的对象的锁。
7、数组操作指令
包括数组长度,新建数组,数组赋值,数组元素取值与赋值等操作。
“array length vA,vB”获取给定vB寄存器中数组的长度并将值赋给vA寄存器,数组长度指的是数组的条目个数。
“new- array vA,vB,type@CCCC”构造指定类型( (type@CCCC)与大小(vB)的数组并将值赋给vA寄存器.
“ filled-new array{ vC,vD,vE,vF},type@BBBB构造指定类型( type@BBBB))与大小(vA)的数组填充数组内容。vA寄存器是隐含使用的,除了指定数组的大小外还指定了参数的个数,vC~vG是使用到的参数寄存器序列。
“filled-new-array/range{vCCCC..vNNNN),type@BBBB指令功能与“ filled-new array{vC,vD,vE, vfF,vG},type@BBBB”相同,只是参数寄存器使用range字节码后指定了取值范围,vC是第一个参数寄存器,N=A+C-1。
“filled-array-data vAA,+ BBBBBBBB”用指定的数据来填充数组,vAA寄存器为数组引用,引用必须为基础类型的数组,在指令后面会紧跟一个数据表。
“new- -array/jumbo vAAAA, VBBBB,type@CCCCCCCC指令功能与“new- array vA,vB,type @CCCC相同,只是寄存器值与指令的索引取值范围更大( Android4.0中新增的指令)
“filled new-array/jumb{vCCCC..vNNNN),type@BBBBBBBB指令功能与 filled-new-array/range fvCCCC.nn), type@BBBE”相同,只是索引取值范围更大( Android4.0中新增的指令)。
“ arrayop vAA,vBB,vCC对vBB寄存器指定的数组元素进入取值与赋值。vCC寄存器指定数组元素索引,vAA寄存器用来存放读取的或需要设置的数组元素的值。读取元素使用aget类指令,元素赋值使用aput类指令,根据数组中存储的类型指令后面会紧跟不同的指令后,指令列表有aget aget-wide, aget-object, aget-boolean, aget-byte, aget-char aget-short, aput, aput-wide, aput-object, aput-boolean, aput-byte,aput-char,aput-short.
8、异常指令 抛出异常
“throw vAA”抛出vAA寄存器中指定类型的异常。
9、跳转指令 当前地址跳转到指定的偏移量。
1) 无条件跳转(goto)
“goto +AA”无条件跳转到指定偏移处,偏移量AA不能为0.
“goto/16 +AAAA”无条件跳转到指定偏移处,偏移量AAAA不能为0.
“goto/32 +AAAAAAAA”无条件跳转到指定偏移处.
2) 分支跳转(switch)
“ packed- switch vAA +BBBBBBBB”分支跳转指令。vAA寄存器为 switch分支中需要判断的值, BBBBBBBB脂向一个 packed-switch- payload格式的偏移表,表中的值是有规律递增的。
“ sparse- switch VAA,+ BBBBBBBB”分支跳转指令。vAA寄存器为 switch分支中需要判断的值, BBBBBBBB指向一个 sparse-switch- payload格式的偏移表,表中的值是无规律的偏移量。
3)条件跳转 (if)
“if-eq”如果vA等于vB则跳转。Java语法表示为“if(vA==vB)
“if-ne”如果v不等于vB则跳转 Java语法表示为“if(vA!=vB)
“if-lt”如果vA小于vB则跳转 Java语法表示为“if(vA<VB)”
“if-ge”如果vA大于等于vB则跳转 Java语法表示为“if(vA>=vB)
“if-gt”如果vA大于vB则跳转。 Java语法表示为“if(vA>VB)”
“if-le”如果vA小于等于vB则跳转。Java法表示为“if(vA<=vB)
“if -testz vAA,+BBBB”条件跳转指令。拿AA寄存器与0比较,如果比较结果满足或值为0时就跳转到BBBB指定的偏移处。偏移量BBBB不能为0。
if- test类型的指令有以下几条:
“ if-eqz如果vAA为0则跳转。Java语法表示为“if(!vAA)”
“if-nez”如果vAA不为0则跳转。Java语法表示为“if(vAA)”
“if-ltz”如果vAA小于0则跳转。Java语表示为“if(vAA<0)”
“if-gez”如果vAA大于等于0则跳转。Java语法表示为“if(vAA>=0)
“if-gtz如果vAA大于0则跳转。Java语法表示为“if(vAA>0)
“if-lez”如果vAA小于等于0则跳转。Java语法表示为“if(vAA<=0)
10、比较指令 对两个寄存器的值进行比较
格式:compkind vAA,vBB,vCC
注:vBB和vCC是两个需要比较的寄存器,并把比较的结果放到vAA寄存器中
“cmpl-float”比较两个单精度浮点数。如果vBB寄存器大于vCC寄存器,则结果为-1,相等则结果为0,小于的话结果为1.
“cmpg-float”比较两个单精度浮点数。如果vBB寄存器大于vCC寄存器,则结果为1,相等则结果为0,小于的话结果为-1。
“cmpl-double”比较两个双精度浮点数。如vBB寄存器对大于vCC寄存器对,则结果为-1,相等则结果为0,小于的话结果为-1。
“cmpg-double””比较两个双精度浮点数。如果vBB寄存器对大于vCC寄存器对,则结果为1,相等则结果为0,小于的话结果为-1。
“cmp-long”比较两个长整型数。如果vBB寄存器大于vCC寄存器,则结果为1,相等则结果为0,小于的话结果为1。
11、字段操作指令 用来对对象实例的字段进入读写操作
1)普通字段指令前缀为i,静态字段的指令前缀为是s。例:iget 、iput
2)根据访问字段类型不同,字段操作指令后面会紧跟字段类型的后缀。例i get-byte读取实例字段的值的类型为字节类型、iput-short 设置实例字段的值类型为短整型。
3)普通字段指令:iget、iget-wide、iget-object、iget-boolean、iget-byte、iget-char、iget-short、iput、iput-wide、iput-object、iput-boolean、iput-byte、iput-char、iput-short。
4)静态字段操作指令:sget、sget-wide、sget-object、sget-boolean、sget-byte、sget-char、sget-short、sput、sput-wide、sput-object、sput-boolean、sput-byte、sput-char、sput-short。
12、方法调用指令 负责调用类实例 invoke
格式:“nvokek-ind{vC,vD,vE,vF,vG},meth@BBBB”、“invokekind/rangce{vCCCC..vNNNN},meth@B BBB”两类,两类指令在作用上并无不同,只是后者在设置参数寄存器时使用了range来指定寄存器的范围。
13、数据转换指令 将一种类型的数值转换成另一种类型。
格式:unop,vA,vB vB寄存器或vB寄存器对存放需要转换的数据,转换后的结果保存在vA寄存器或vA寄存器中。
“neg-int”对整型数求补。
“not-int”对整形数求反。
“neg-long”对长整型数求补。
“not-long”对长整型数求反。
“neg-float”对单精度浮点数求补。
“neg-double”对双精度浮点型数求补。
“int-to-long”将整型换为长整型。
“int-to-float”将数转换为单精度浮点型 。
“int.-to-double”将整型数转换为双精度浮点型 。
“long-to-int”将长整型数转换为整型。
“long-to-float”长型数转换为单精度浮点型。
“long-to- double”将长型数转换为双精度浮点型。
“float-to-int”将单精度点型数转换为整型。
“float-o-long”将单精度浮点型数转换为长整型。
“float-to-double将单精度浮点型数转换为双精度浮点型。
“double-to-int”将双精度浮点型数转换为整型。
“double-to-long”将双精度浮点型数转换为长型。
“double.-to-float”将双精度浮点型数转换为单精度浮点型 。
“int-to-byte”将整型转换为字节型。
“int-to-char”将整形转换为字符串。
“int-to-short”将整型转换为短整型。
14、数据运算指令
包括算数运算指令和逻辑运算指令
数据运算指令有如下四类
1)binop vAA,vBB,vCC"将vBB寄存器与vCC寄存器进行运算,结果保存到AA寄存器。
2)binop/2 addr vA,vB”将vA寄存器与vB寄存器进行运算,结果保存到vA寄存器 。
3)binp/lit6 vA,vB,#+CCCC”将vB寄存器与常量CCCC进行运算,结果保存到vA寄存器。
4)binp/lit VAA, VBB,#+CC"将vBB寄存器与常量CC进行运算,结果保存到vAA寄存器。
后面3类指令比第1类指令分别多出了2addr、lit6、lit8等指令后缀。
四类指令中基础字节码相同的指令执行的运算操作是类似的。第1类指令中,根据数据的类型不同会在基础字码后面加上数据类型后缀,如-int或-long分别表示操作的数据类型为整型与长整型。
第一类指令可归类如下
“add-type”vBB寄存器与vCC寄存器值进行加法运算(vBB+vCC)。
“sub-type”vBB寄存器与vCC寄存器值进行减法运算(vBB-vCC)。
“mul-type”vBB寄存器与vCC寄存器值进行乘法运算( vBB x vCC) 。
“div-type”vBB寄存器与vCC寄存器值进行除法运算(vBB/vCC)。
“rem-type"BB寄存器与vCC寄存器值进行模运算(vBB%vCC)。
“and-type"vBB寄存器与vCC寄存器值进行与运算( vBB AND vCC)。
“ or-type"BB寄存器与vCC寄存器值进行或运算( VBB OR VCC)。
“xor-type"vBB寄存器与CC寄存器值进行异或运算( VBB XOR VCC)。
“shi-type"vBB寄存器值(有符号数)左移vCC位(vBB<<vCC)。
“shr-type"wB寄存器值(有符号数)右移vCC位(vBB>>CC)。
“ ushr-type"wBB寄存器值(无符号数)右移vCC位(vBB>>vCC)。
其中基础字节码后面的-type可以是-int、-long,-float,-double。