3.3.2 空指令
指令助记符 描述
nop 代码对齐,无实际操作
3.3.3 数据操作指令
指令助记符 描述
move vA, vB 将 vA 寄存器的内容赋值给 vB,非对象类型
move/from16 vAA, vBBBB --
move/
16 vAAAA, vBBBB --
move-wide vA, vB wide 后缀的指令会操作
64 位数据宽度,需使用两
个寄存器组成寄存器对。如 move-wide v0, v2 会将
v2、v3 寄存器对内容赋值给 v0、v1 寄存器对。
move-wide/from16 vAA, vBBBB --
move-wide/
16 vAAAA, vBBBB --
move-
object vA, vB 将 vA 寄存器的内容赋值给 vB,对象类型
move-
object/from16 vAA, vBBBB --
move-
object/
16 vAAAA, vBBBB --
move-result vAA 必须紧跟着调用指令 invoke 后面,把调用方法的
返回值赋值给寄存器 vAA,操作非对象类型。
move-result-wide vAA --
move-result-
object vAA 操作对象类型。
move-
exception vAA 必须作为异常捕捉的处理块的第一条指令,把捕捉
到的异常类型对象赋值给 vAA 寄存器。
3.3.4 返回指令
指令助记符 描述
return-void 返回空类型指令。
return vAA 返回
32 位寄存器 VAA 内容,非对象类型数据。
return-wide vAA 返回
64 位内容数据,非对象类型数据。
return-
object vAA 返回对象类型数据。
3.3.5 数据定义指令
指令助记符 描述
const/
4 vA, #+B 将
4 位宽度的立即数带符号扩展到
32 位,赋值给
vA 寄存器。
const/
16 vAA, #+BBBB 将
16 位宽度的立即数带符号扩展到
32 位, 赋值给
vA 寄存器。
const vAA, #+BBBBBBBB 将
32 位宽度的立即数赋值给 vA 寄存器。
const/high16 vAA, #+BBBB0000 将
16 位宽度的立即数右边零扩展到
32 位, 赋值给
vAA 寄存器。
const-wide/
16 vAA, #+BBBB 将
16 位宽度的立即数带符号扩展到
64 位,赋给
vAA 寄存器对。
const-wide/
32 vAA, #+BBBBBBBB 将
32 位宽度的立即数带符号扩展到
64 位,赋给
vAA 寄存器对。
const-wide vAA,
#+BBBBBBBBBBBBBBBB
将
64 位宽度的立即数赋给 vAA 寄存器对。
const-wide/high16 vAA,
#+BBBB000000000000
将
16 位宽度的立即数右边零扩展到
64 位, 赋值给
vAA 寄存器。
const-
string vAA,
string@BBBB 将字符串常量的引用赋值给 vAA 寄存器。
const-
string/jumbo vAA,
string@BBBBBBBB
jumbo 后缀表示指令的寄存器的索引范围更大。
const-
class vAA,
type@BBBB 将一个类的引用赋值给 vAA 寄存器。
3.3.6 锁指令
指令助记符 描述
monitor-enter vAA 获取 vAA 寄存器引用的对象的同步锁。
monitor-exit vAA 释放 vAA 寄存器引用的对象的同步锁。
3.3.7 实例操作指令
指令助记符 描述
check-cast vAA,
type@BBBB 把寄存器引用的对象转为指定的类型,如果不行则
会抛出一个 ClassCastException 异常。
instance-
of vA, vB,
type@CCCC 判断 vB 寄存器的引用对象是否可以转化为指定类
型,是则给 vA 寄存器赋
1,否则赋
0。
new-instance vAA,
type@BBBB 构造一个指定类型的实例,并把引用赋给寄存器。
3.3.8 数组操作指令
指令助记符 描述
array-length vA, vB 获取 vB 引用的数组长度赋值给 vA
new-
array vA, vB,
type@CCCC 构造一个指定类型和大小的数组,并把引用赋值
filled-
new-
array {vC, vD, vE,
vF, vG},
type@BBBB
构建一个指定类型的数组,数组大小由寄存器列表
{vC,…,vG}的 长度指定,元素由寄存器列表赋值,
初始化后, 使用指令 move-result-
object 获取构
建的数组的引用。
filled-
new-
array/range
{vCCCC .. vNNNN},
type@BBBB
寄存器列表使用连续的寄存器 vCCCC 到 vNNNN。
fill-
array-data vAA,
+BBBBBBBB (
with supplemental
data
as specified below
in
"fill-array-data-payload
Format")
使用指定的数据表来填充 vAA 指定的数组。
3.3.9 异常指令
指令助记符 描述
throw vAA 抛出一个指定类型的异常。
3.3.10 跳转指令
指令助记符 描述
goto +AA 无条件跳转到指定的指令。偏移量为
8 位宽度,且
不能为零。
goto/
16 +AAAA 偏移量为
16 位宽度,且不能为零。
goto/
32 +AAAAAAAA --
packed-switch vAA, +BBBBBBBB 根据+BBBBBBBB 给定的跳转偏移列表匹配 vAA 寄
存器值,跳转到指定指令。偏移表中的匹配值是有
规律递增的。
sparse-switch vAA, +BBBBBBBB 偏移表中的匹配值是无规律且可以被指定的。
if-test vA, vB, +CCCC
|-
if-eq
|-
if-ne
|-
if-lt
|-
if-ge
|-
if-gt
|-
if-le
条件跳转指令, 比较指定两个寄存器vA 和vB 的值,
满足条件后跳转到指定的指令。
条件:等于(eq)、不等于(ne)、小于(lt),大于
(gt),小于等于(le)、大于等于(ge)。
if-testz vAA, +BBBB
|-
if-eqz
|-
if-nez
|-
if-ltz
|-
if-gez
|-
if-gtz
|-
if-lez
条件跳转指令, 比较指定寄存器vAA 的值与
0 大小,
满足条件跳转到指定指令。
3.3.11 比较指令
cmpkind vAA, vBB, vCC
|- cmpl-
float (lt bias)
比较浮点数和长整型数的大小。 如果 vBB 寄存器大
于 vCC 寄存器,则结果为-
1,相等结果则为
0,小
|- cmpg-
float (gt bias)
|- cmpl-double (lt bias)
|- cmpg-double (gt bias)
|- cmp-long
于结果则为
1。结果赋给 vAA 寄存器。
3.3.12 字段操作指令
arrayop vAA, vBB, vCC
|- aget
|- aget-
type
|- aput
|- aput-
type
字段操作指令用来对象实例的成员变量进行读与
写操作的。分为数组字段、普通字段和静态字段。
vAA 寄存器存放读的结果或写的数据。
vBB 寄存器是数组的引用。
vCC 寄存器是数组读写元素的索引。
type 类型后缀包括 wide、object、boolean、
byte、
char、short 类型。
iinstanceop vA, vB, field@CCCC
|- iget
|- iget-
type
|- iput
|- iput-
type
普通字段操作指令。
sstaticop vAA, field@BBBB
|- sget
|- sget-
type
|- sput
|- sput-
type
静态字段操作指令。
3.3.13 方法调用指令
invoke-kind {vC, vD, vE, vF,
vG}, meth@BBBB
|- invoke-
virtual
|- invoke-super
|- invoke-direct
|- invoke-static
|- invoke-interface
调用指定的方法,{vC,…,vG}为传入方法的参数列
表。具体使用哪种调用方式,视方法的对象类型和
方法本身类型而定。
invoke-
virtual 调用实例的虚方法,通常成员对
象实例的方法都以该指令调用。
invoke-super 调用实例的父类方法。
invoke-direct 调用直接方法,通常私有方法都以
该指令调用。
invoke-static 调用静态方法。
invoke-interface 调用接口的方法。
invoke-kind/range {vCCCC ..
vNNNN}, meth@BBBB
|- invoke-
virtual/range
|- invoke-super/range
|- invoke-direct/range
|- invoke-static/range
|- invoke-interface/range
参数列表使用{vCCCC .. vNNNN}连续的寄存器列
表。
3.3.14 数据转换
unop vA, vB
|- neg-
type
|- not-
type
|-
type-to-type
|-
int-
to-byte
|-
int-
to-
char
|-
int-
to-short
数据类型转换指令,
type 类型后缀包括 int、 long、
float、double。
3.3.15 数据运算
binop vAA, vBB, vCC
|- add-
type
|- sub-
type
|- mul-
type
|- div-
type
|- rem-
type
|-
and-type1
|-
or-type1
|- xor-type1
|- shl-type1
|- shr-type1
|- ushr-type1
对寄存器 vBB 和寄存器 vCC 做算术运算,并把结果
赋值给 vAA。
type 类型后缀包括 int、long、float、double,。
type1 类型后缀只包括
int、long。
add:加法 sub:减法 add:乘法 div: 除法
rem:取模(%)
and:与
or:或 xor:异或
shl:有符号数左移 shr:有符号数右移
ushr:无符号数右移
binop/
2addr vA, vB 寄存器 vA 和寄存器 vB 做算术运算,结果赋值给寄
存器 vA。
binop/lit16 vA, vB, #+CCCC 寄存器 vB 与常量 CCCC 做算术运算, 结果赋值给 vA。
binop/lit8 vAA, vBB, #+CC 寄存器 vB 与常量 CC 做算术运算, 结果赋值给 vAA。
在以上指令中,在部分指令助记符后添加了 jumbo 后缀,这是在 Android
4.0 开始的扩
展指令,增加了寄存器和常量的取值范围。需要引起注意的是,以上指令表中形如 VA 表示
寄存器范围为 v0-v15,形如 VAA 表示寄存器范围为 v0-v255,这一点在理解指令时容易被忽
略而导致修改 smali 代码时编译出错。比如方法调用指令 invoke 未添加/range 时传入方法的
参数列表的寄存器需要在 v0-v15 范围内, 如果不在范围内需要将不合格寄存器赋值给合格
寄存器,然后再调用方法