天天看點

Dalvik指令集

特點

  • 參數采用從目标到源的方式
  • 根據位元組碼的大小與類型不同,一些位元組碼添加了名稱字尾以消除歧義
    • 32位正常類型的位元組碼未添加任何字尾
    • 64位正常類型的位元組碼添加-wide字尾
    • 特殊類型的位元組碼根據具體類型添加字尾。可以是-boolean、-byte、-char、-short、-int、-long、-float、-double、-object、-string、-class、-void之一。
  • 根據位元組碼的布局與選項不同,一些位元組碼添加了位元組碼字尾以消除歧義。這些字尾通過在位元組碼主名稱後添加斜杠“/”來分隔。
  • 在指令集的描述中,寬度值中每個字母表示寬度為4位。

例如:move-wide/from16 vAA, VBBBB

move 基礎位元組碼。辨別為基本操作。

wide 名稱字尾。辨別指令操作資料寬度(64位)

from16 位元組碼字尾。辨別源為16位寄存器引用變量

vAA 目的寄存器。取值v0-v255

vBBBB 源寄存器。取值v0-v65535

Dalvik指令集中大多數指令用到了寄存器作為目的操作數或源操作數,其中A/B/C/D/E/F/G/H代表一個4位數值,可表示0-15的數值或v0-v15的寄存器,而AA/BB/CC/DD/EE/FF/GG/HH代表8位的數值,可表示0-255的數值或v0-v255的寄存器,AAAA/BBBB/CCCC/DDDD/EEEE/FFFF/GGGG/HHHH代表8位的數值,可表示0-65535的數值或v0-v65535的寄存器。

空指令 nop

資料操作指令 move

# 原型
move destination, source
move destination

# 将寄存器vB指派給vA,源和目的寄存器為4位
move vA, vB 

# 将vBBBB指派給vAA,源為16位,目的為8位
move/from16 vAA, vBBBB

# 為4位的寄存器對指派。源和目标寄存器為4位
move-wide vA, vB 

move-wide/from16 vAA, vBBBB # 實作與move-wide相同
move-wide/ vAAAA, vBBBB # 實作與move-wide相同

# 為對象指派
move-object vA, vB # 源和目标為4位
move-object/from16 vAA, vBBBB # 源8位,目的16位
move-object/ vAAAA, vBBBB # 源和目标16位

move-result vAA # 将上一個invoke類型指令操作的單字非對象結果指派給vAA寄存器
move-result-wide vAA # 将上一個invoke類型指令操作的雙字非對象結果指派給vAA寄存器
move-result-object vAA # 将上一個invoke類型指令操作的對象結果指派給vAA寄存器

move-exception vAA # 儲存一個運作時發生的異常到vAA寄存器。必須是異常發生時的指令,否則無效
           

傳回指令 return

# 原型
return 

return-void # void傳回
return vAA # 傳回32位非對象類型的值,傳回值寄存器為8位
return-wide vAA # 傳回64位非對象類型的值,傳回值寄存器為8位
return-object vAA # 傳回對象類型的值,傳回值寄存器為8位
           

資料定義指令 const

# 原型
const

const/ vA, #+B                                # 将數值符号擴充為32位後指派給vA
const/ vAA, #+BBBB                           # 将數值符号擴充為32位後指派給vAA
const vAA, #+BBBBBBBB                          # 将數值指派給vAA
const/high16 vAA, #+BBBB0000                   # 将數值右邊零擴充為32位後指派給vAA
const-wide/ vAA, #+BBBB                      # 将數值擴充為64位後指派給vAA
const-wide/ vAA, #+BBBBBBBB                  # 将數值擴充為64位後指派給vAA
const-wide vAA, #+BBBBBBBBBBBBBBBB             # 将數值指派給vAA
const-wide/high16 vAA, #+BBBBBBBB00000000      # 将數值右邊零擴充為64位後指派給vAA
const-string vAA, string@BBBB                  # 通過字元串索引構造一個字元串并指派給vAA
const-string/jumbo vAA, string@BBBBBBBB        # 通過字元串索引(較大)建構字元串并指派給vAA
const-class vAA, [email protected]                     # 通過類型索引擷取一個類的引用并指派給vAA
const-class/jumbo vAAAA, [email protected]         # 通過類型索引擷取一個類的引用并指派給vAAAA,這條指令占用2個位元組,值為0x00ff
           

鎖指令

monitor-enter vAA # 為指定的對象擷取鎖
monitor-exit vAA  # 為指定的對象釋放鎖
           

執行個體操作指令

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 # 建構一個指定對象。類型不能為數組類

check-cast/jumbo vAAAA, type@BBBBBBBB # 寄存器值與索引取值範圍更大
instance-of/jumbo vAAAA, vBBBB, type@CCCCCCCC # 寄存器值與索引取值範圍更大
new-instance/jumbo # 寄存器值與索引取值範圍更大
           

數組操作

array-length vA, vB # 擷取vB數組的長度到vA
new-array vA, vB, type@CCCC # 根據類型和長度vB執行個體化數組到vA
filled-new-array {vC, vD, vE, vF, vG}, type@BBBB # 構造指定類型(type@BBBB)與大小(vA)的數組并填充内容。vA寄存器是隐含的,除了指定數組大小還指定了參數個數,vC~vG是使用到的參數寄存器序列。
filled-new-array/range {vCCCC .. vDDDD}, type@BBBB # 與“filled-new-array {vC, vD, vE, vF, vG}, type@BBBB”相同,隻是參數寄存器使用range位元組碼字尾指定了取值範圍,vC是第一個參數寄存器,N = A + C - 
fill-array-data vAA, +BBBBBBBB # 用指定資料填充數組

new-array/jumbo vAAAA, vBBBB, type@CCCCCCCC # 與“new-array vA, vB, type@CCCC”相同,寄存器與索引取值範圍更大
filled-new-array/jumbo {vCCCC .. vNNNN}, type@BBBBBBBB # 與“filled-new-array {vCC .. vNN}, type@BBBB”相同,寄存器與索引值取值範圍更大

arrayop vAA, vBB, vCC # 對數組vBB進行取值或者指派操作,vCC指定數組索引,vAA用來存放讀取的或需要設定的數組元素值。
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
           

異常指令 throw

跳轉指令

# 1. goto 無條件跳轉到指定偏移處
goto +AA # AA不能為0
goto/ +AAAA # AAAA不能為0
goto/ +AAAAAAAA

# 2. switch跳轉
packed-switch vAA, +BBBBBBBB # vAA要判斷的值,BBBBBBBB指向一個packed-switch-payload格式的偏移表,表中的值規律遞增 
sparse-switch vAA, +BBBBBBBB # vAA要判斷的值,BBBBBBBB指向一個sparse-switch-payload格式的偏移表,表中的值是無規律的偏移量

# 3. if跳轉
# 3.1 if-test vA, vB, +CCCC # 比較vA與vB,滿足則跳轉到CCCC處,CCCC不能為0
if-eq # if(vA == vB)
if-ne # if(vA != vB)
if-lt # if(vA < vB)
if-ge # if(vA >= vB)
if-gt # if(vA > vB)
if-le # if(vA <= vB)
# 3.2 if-testz vAA, +BBBB
if-eq # if(!AA)
if-ne # if(vAA)
if-lt # if(vAA<0)
if-ge # if(vAA>=0)
if-gt # if(vAA>0)
if-le # if(vAA<=0)
           

比較指令

# 原型
cmpkind vAA, vBB, vCC # 比較vBB與vCC,結果放到vAA

cmpl-float # 比較float,如果vBB>vCC結果為-1,如果vBB==vCC結果為0,如果vBB<vCC結果為1
cmpg-float # 比較float, 如果vBB>vCC結果為1,如果vBB==vCC結果為0,如果vBB<vCC結果為-1
cmpl-double # 比較double, vBB>vCC則-1,vBB==vCC則0,vBB<vCC則1
cmpg-double # 比較double,vBB>vCC則1,vBB==vCC則0,vBB<vCC則-1
cmpl-lang # 比較lang
           

字段操作指令

# 1. 普通字段
iinstanceop vA, vB, [email protected]
# 2. 靜态字段
sstaticop vAA, [email protected]

# 普通字段字首為i,比如讀取用iget,寫入用iput
# 靜态字段字首為s,比如讀取用sget,寫入用sput
# 根據通路字段類型不同,指令後緊跟類型字尾,比如iget-byte
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
           

方法調用指令 invoke

# 原型
invoke-kind {vC,vD,vE,vF,vG}, [email protected]
invoke-kind/range {vCCCC .. vNNNN}, [email protected]

# 調用虛方法
invoke-virtual
invoke-virtual/range

# 調用父類方法
invoke-super
invoke-super/range

# 調用直接方法
invoke-direct
invoke-direct/range

# 調用靜态方法
invoke-static
invoke-static/range

# 調用執行個體的接口方法
invoke-interface
invoke-interface/range

# 方法調用傳回值需要調用move-result* 指令來擷取,比如
invoke-static {}, Landroid/os/Parcel;->obtain()Landroid/os/Parcel;
move-result-object v0
           

資料轉換指令

# 原型
unop vA, vB # 轉為vB,結果存在vA中

neg-int # 整數求補
not-int # 整數求反
neg-long # 長整型求補
not-long # 長整型求反
neg-float # 單精度浮點求補
not-float # 單精度浮點求反

int-to-long
int-to-float
int-to-double
long-to-int
long-to-double
float-to-int
float-to-long
float-to-double
double-to-int
double-to-long
double-to-float
int-to-byte
int-to-char
int-to-short
           

資料運算指令

# 原型
binop vAA, vBB, vCC # 将vBB與vCC進行運算,結果儲存到vAA
binop/addr vA, vB  # 将vA與vB進行計算,結果儲存到vA
binop/lit16 vA, vB, #+CCCC # 将vB與常量CCCC進行計算,儲存到vA
binop/lit8 vAA, vBB, #+CC # 将vBB與CC進行計算,儲存到vAA

add-type # vBB+vCC
sub-type # vBB-vCC
mul-type # vBB*vCC
div-type # vBB/vCC
rem-type # vBB%vCC
and-type # vBB and vCC
or-type  # vBB or vCC
xor-type # vBB xor vCC
shl-type # vBB << vCC
shr-type # vBB >> vCC
ushr-type # vBB >> vCC

# -type可以為-int、-long、-float、-double