詳解Android逆向之Smali語法
資料型別
Dalvik位元組碼只有兩種格式:基本型別和引用型別。物件和陣列屬於引用型別
語法 | 含義 |
---|---|
V | void,只用於返回值型別 |
Z | boolean |
B | byte |
S | short |
C | char |
I | int |
J | long |
F | flot |
D | double |
L | Java類 型別 |
[ | 陣列型別 |
Ljava/lang/String; 相當於java.lang.String
[I 相當於一維int陣列,int[]
[[I 相當於int[][]
方法
它使用方法名,引數型別和返回值來描述一個方法
package/name/ObjectName;->methodName(III)Z
package/name/ObjectName:一個類
methodName:方法名
III:引數型別
Z:返回值
(III)Z:方法簽名
BakSmali生成的方法程式碼以.method指令開始,以.end method指令結束,根據方法的型別不同,可以會在方法前加#表示方法型別
# vitual methods:虛方法,如:
# virtual methods
.method public get(Ljava/lang/String;)Lcn/woblog/markdowndiary/domain/Note;
.locals 2
.param p1, "noteId" # Ljava/lang/String;
.prologue
.line 50
iget-object v0, p0, Lcn/woblog/markdowndiary/repository/LocalNoteRepository;->orm:Lcom/litesuits/orm/LiteOrm;
const-class v1, Lcn/woblog/markdowndiary/domain/Note;
invoke-virtual {v0, p1, v1}, Lcom/litesuits/orm/LiteOrm;->queryById(Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;
move-result-object v0
check-cast v0, Lcn/woblog/markdowndiary/domain/Note;
return-object v0
.end method
# direct methods:直接方法,如:
# direct methods
.method public constructor <init>(Landroid/content/Context;)V
.locals 2
.param p1, "context" # Landroid/content/Context;
.prologue
.line 22
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
.line 23
iput-object p1, p0, Lcn/woblog/markdowndiary/repository/LocalNoteRepository;->context:Landroid/content/Context;
.line 24
const-string v0, "note.db"
invoke-static {p1, v0}, Lcom/litesuits/orm/LiteOrm;->newSingleInstance(Landroid/content/Context;Ljava/lang/String;)Lcom/litesuits/orm/LiteOrm;
move-result-object v0
iput-object v0, p0, Lcn/woblog/markdowndiary/repository/LocalNoteRepository;->orm:Lcom/litesuits/orm/LiteOrm;
.line 25
iget-object v0, p0, Lcn/woblog/markdowndiary/repository/LocalNoteRepository;->orm:Lcom/litesuits/orm/LiteOrm;
const/4 v1, 0x1
invoke-virtual {v0, v1}, Lcom/litesuits/orm/LiteOrm;->setDebugged(Z)V
.line 26
return-void
.end method
有些方法沒有這樣的註釋
.method public save(Lcn/woblog/markdowndiary/domain/Note;)V
.locals 1
.param p1, "note" # Lcn/woblog/markdowndiary/domain/Note;
.prologue
.line 37
iget-object v0, p0, Lcn/woblog/markdowndiary/repository/LocalNoteRepository;->orm:Lcom/litesuits/orm/LiteOrm;
invoke-virtual {v0, p1}, Lcom/litesuits/orm/LiteOrm;->save(Ljava/lang/Object;)J
.line 38
return-void
.end method
靜態方法:
.method public static formatTime(J)Ljava/lang/String;
.locals 4
.param p0, "date" # J
.prologue
.line 11
new-instance v0, Ljava/text/SimpleDateFormat;
const-string v1, "yyyy\u5e74MM\u6708dd\u65e5 EEEE"
sget-object v2, Ljava/util/Locale;->CHINESE:Ljava/util/Locale;
invoke-direct {v0, v1, v2}, Ljava/text/SimpleDateFormat;-><init>(Ljava/lang/String;Ljava/util/Locale;)V
.line 13
.local v0, "simpleDateFormat":Ljava/text/SimpleDateFormat;
invoke-static {p0, p1}, Ljava/lang/Long;->valueOf(J)Ljava/lang/Long;
move-result-object v1
invoke-virtual {v0, v1}, Ljava/text/SimpleDateFormat;->format(Ljava/lang/Object;)Ljava/lang/String;
move-result-object v1
return-object v1
.end method
欄位
與方法表示很相似,只是欄位沒有方法簽名和返回值,取而代之的是欄位型別
Lpackage/name/ObjectName;->FiedlName:Ljava/lang/String;
其中欄位名與欄位型別用冒號“:”分割
# static fields
.field private static instance:Lcn/woblog/markdowndiary/repository/LocalNoteRepository;
# instance fields
.field private final context:Landroid/content/Context;
其中:
# static fields:靜態欄位
# instance fields:例項欄位
Dalvik指令集
他在呼叫格式上模仿了C語言的呼叫約定,官方地址,指令語法與助詞有如下特點:
- 採用採用從目標(destination)到源(source)的方法
- 根據位元組碼的大小與型別不同,一些位元組碼添加了名稱字尾已消除歧義
2.1 32位常規型別的位元組碼未新增任何字尾
2.2 64位常規型別的位元組碼新增 -wide字尾
3.3 特殊型別的位元組碼根據具體型別新增字尾,-boolean,-byte,-char,-short,-int,-long,-float,-double,-object,-string,-class,-void之一 - 根據位元組碼的佈局和選項不同,一些位元組碼添加了位元組字尾消除歧義,字尾與位元組碼直接用/分割
- 在指令集的描述中,寬度值中每個字母表示寬度為4位
如:
move-wide/from16 vAA, vBBBB
move-wide/from16 v18, v0
move:基礎位元組碼(base opcode),標示是基本操作
wide:標示指令操作的資料寬度為64位寬度
from16:位元組碼字尾(opcode suffix),標示源(vBBBB)為一個16的暫存器引用變數
vAA:目的暫存器,v0~v255
vBBBB:源暫存器,v0~v65535
指令
nop
空操作,被用來做對齊程式碼
資料定義
用來定義程式中用到的常量,字串,類等資料
const/4 vA, #+B :將陣列擴充套件為32位後賦給暫存器vA
const/16 vAA, #+BBBB
const vAA, #+BBBBBBBB:將陣列賦值給暫存器vAA
const-wide/16 vAA, #+BBBBB :將數值擴充套件為64位後賦給暫存器vAA
const-string vAA, [email protected]:將字串索引構造一個字串並賦給vAA
const-class vAA, [email protected]:通過型別索引獲取一個類的引用並賦給暫存器vAA
private void testConst() {
int a = 1;
int b = 7;
int c = 254;
int d = 2345;
int d1 = 65538;
long e = 12435465657677L;
float f = 123235409234.09097945F;
double g = 111343333454999999999.912384375;
}
//-8到7用4,大於255小於等於65535用16
const/4 v0, 0x1
.line 25
.local v0, "a":I
const/4 v1, 0x7
.line 26
.local v1, "b":I
const/16 v2, 0xfe
.line 27
.local v2, "c":I
const/16 v3, 0x929
.line 28
.local v3, "d":I
const v4, 0x10002 //65538,大於65535用const v4
//long用const-wide
.line 30
.local v4, "d1":I
const-wide v6, 0xb4f5b835d4dL
.line 31
.local v6, "e":J
const v5, 0x51e58b39
.line 32
.local v5, "f":F
const-wide v8, 0x441824cbef6b9491L # 1.11343333455E20
資料操作指令
move destination, source
根據位元組碼大小和型別不同,後面迴天津不同的字尾
move vA, vB:vB暫存器值賦值給vA暫存器,都為4位
move-object vA,vB
move-result vAA:將上一個invoke型別的指令操作的單字非物件結果負責vAA暫存器
move-result-object vAA:將上一個invoke型別指令操作的物件賦值給vAA
move-exception vAA:儲存一個執行時發生的異常vAA暫存器,必須是異常發生時的異常處理的第一條指令
private void testMove() {
int a = 100;
long b = 100000000000000000L;
int c = a;
long d = b;
Log.d(TAG,c+"");
Log.d(TAG,d+"");
int e = getIntResult();
Log.d(TAG,e+"");
try {
int f = e/c;
} catch (ArithmeticException e1) {
e1.printStackTrace();
}catch (Exception e1) {
e1.printStackTrace();
}finally {
}
}
//move-result-object
invoke-direct {v7}, Ljava/lang/StringBuilder;-><init>()V
invoke-virtual {v7, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
move-result-object v7
const-string v8, ""
invoke-virtual {v7, v8}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v7
//move-result
invoke-direct {p0}, Lcom/woblog/testsmali/MainActivity;->getIntResult()I
move-result v6
//move exception
.line 35
:try_start_0
div-int v8, v6, v1
:try_end_0
.catch Ljava/lang/ArithmeticException; {:try_start_0 .. :try_end_0} :catch_0
.catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_1
.catchall {:try_start_0 .. :try_end_0} :catchall_0
.line 43
:goto_0
return-void
.line 36
:catch_0
move-exception v7
.line 37
.local v7, "e1":Ljava/lang/ArithmeticException;
:try_start_1
invoke-virtual {v7}, Ljava/lang/ArithmeticException;->printStackTrace()V
:try_end_1
.catchall {:try_start_1 .. :try_end_1} :catchall_0
goto :goto_0
.line 40
.end local v7 # "e1":Ljava/lang/ArithmeticException;
:catchall_0
move-exception v8
throw v8
.line 38
:catch_1
move-exception v7
.line 39
.local v7, "e1":Ljava/lang/Exception;
:try_start_2
invoke-virtual {v7}, Ljava/lang/Exception;->printStackTrace()V
:try_end_2
.catchall {:try_start_2 .. :try_end_2} :catchall_0
goto :goto_0
返回指令
return-void :返回一個void
return vAA:返回一個32位非物件型別的值,返回暫存器為8位
return-wide vAA:返回一個64位非物件型別的值,返回暫存器為8位
return-object vAA:返回一個物件型別
private String returnObject() {
return new String("");
}
private float returnFloat() {
return 12333334.00234345F;
}
private double returnDouble() {
return 3425465767.9345865;
}
private long returnLong() {
return 12445657999999L;
}
private int returnInt() {
return 1024;
}
private void returnVoid() {
int a = 3;
}
.method private returnDouble()D
.locals 2
.prologue
.line 40
const-wide v0, 0x41e9858eb4fde822L # 3.4254657679345865E9
return-wide v0
.end method
.method private returnFloat()F
.locals 1
.prologue
.line 36
const v0, 0x4b3c3116 # 1.2333334E7f
return v0
.end method
.method private returnInt()I
.locals 1
.prologue
.line 48
const/16 v0, 0x400
return v0
.end method
.method private returnLong()J
.locals 2
.prologue
.line 44
const-wide v0, 0xb51bb062a7fL
return-wide v0
.end method
.method private returnObject()Ljava/lang/String;
.locals 2
.prologue
.line 32
new-instance v0, Ljava/lang/String;
const-string v1, ""
invoke-direct {v0, v1}, Ljava/lang/String;-><init>(Ljava/lang/String;)V
return-object v0
.end method
.method private returnVoid()V
.locals 1
.prologue
.line 52
const/4 v0, 0x3
.line 53
.local v0, "a":I
return-void
.end method
鎖指令
鎖指令多用在多執行緒程式中對同一物件的操作
monitor-enter vAA 為指定的物件獲取鎖
monitor-exit vAA 釋放指定的物件的鎖
private void callSynchronizeClassMethod() {
synchronized (MainActivity.class) {
Log.d("TAG","synchronized class");
}
}
private void callSynchronizeMethod() {
synchronized (this) {
Log.d("TAG","synchronized this");
}
}
private synchronized void callLockMethod() {
Log.d("TAG","synchronized method");
}
.method private declared-synchronized callLockMethod()V
.locals 2
.prologue
.line 43
monitor-enter p0
:try_start_0
const-string v0, "TAG"
const-string v1, "synchronized method"
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
:try_end_0
.catchall {:try_start_0 .. :try_end_0} :catchall_0
.line 44
monitor-exit p0
return-void
.line 43
:catchall_0
move-exception v0
monitor-exit p0
throw v0
.end method
.method private callSynchronizeClassMethod()V
.locals 3
.prologue
.line 31
const-class v1, Lcom/woblog/testsmali/MainActivity;
monitor-enter v1
.line 32
:try_start_0
const-string v0, "TAG"
const-string v2, "synchronized class"
invoke-static {v0, v2}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 33
monitor-exit v1
.line 34
return-void
.line 33
:catchall_0
move-exception v0
monitor-exit v1
:try_end_0
.catchall {:try_start_0 .. :try_end_0} :catchall_0
throw v0
.end method
.method private callSynchronizeMethod()V
.locals 2
.prologue
.line 37
monitor-enter p0
.line 38
:try_start_0
const-string v0, "TAG"
const-string v1, "synchronized this"
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 39
monitor-exit p0
.line 40
return-void
.line 39
:catchall_0
move-exception v0
monitor-exit p0
:try_end_0
.catchall {:try_start_0 .. :try_end_0} :catchall_0
throw v0
.end method
例項操作
包括型別轉換,檢查和建立新例項
check-cast vAA, [email protected]:將vAA中的物件轉為指定型別,如果失敗會丟擲ClassCastException異常,如果型別B是基本型別,對於分基本型別的A來說執行始終是失敗的
instance-of vA, vB, [email protected]:判斷vB暫存器的物件是否可以轉為指定型別,如果可以vA為1,否則為0
new-instance vAA, [email protected]:構造一個指定型別的物件,並賦值給vAA暫存器,不能是陣列型別
CharSequence cs = new String();
Object o = cs;
String s = (String) cs;
//例項檢測
if (s instanceof CharSequence) {
Log.d("TAG", "ok");
} else {
Log.d("TAG","no");
}
//建立例項
StringBuilder sb = new StringBuilder();
sb.append("Ok");
String s1 = new String("new string");
String s2 = "string";
new-instance v1, Ljava/lang/String;
invoke-direct {v1}, Ljava/lang/String;-><init>()V
.line 33
.local v1, "cs":Ljava/lang/CharSequence;
move-object v7, v1
.local v7, "o":Ljava/lang/CharSequence;
move-object v8, v1
.line 35
check-cast v8, Ljava/lang/String;
.line 38
.local v8, "s":Ljava/lang/String;
instance-of v12, v8, Ljava/lang/CharSequence;
if-eqz v12, :cond_0
.line 39
const-string v12, "TAG"
const-string v13, "ok"
invoke-static {v12, v13}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 46
:goto_0
new-instance v11, Ljava/lang/StringBuilder;
invoke-direct {v11}, Ljava/lang/StringBuilder;-><init>()V
.line 47
.local v11, "sb":Ljava/lang/StringBuilder;
const-string v12, "Ok"
invoke-virtual {v11, v12}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
.line 49
new-instance v9, Ljava/lang/String;
const-string v12, "new string"
invoke-direct {v9, v12}, Ljava/lang/String;-><init>(Ljava/lang/String;)V
.line 50
.local v9, "s1":Ljava/lang/String;
const-string v10, "string"
.line 51
.local v10, "s2":Ljava/lang/String;
return-void
.line 41
.end local v9 # "s1":Ljava/lang/String;
.end local v10 # "s2":Ljava/lang/String;
.end local v11 # "sb":Ljava/lang/StringBuilder;
:cond_0
const-string v12, "TAG"
const-string v13, "no"
invoke-static {v12, v13}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
goto :goto_0
陣列操作
包括獲取陣列長度,新建陣列,陣列賦值,陣列元素取值與賦值等
array-length vA, vB:獲取vB暫存器中陣列的長度並賦值給vA暫存器
new-array vA, vB, [email protected]:構造指定型別([email protected])與大小(vB)的陣列,並賦值給vA暫存器
filled-new-array {vC,vD,vE,vF,vG}, [email protected]:構造指定型別([email protected])與大小vA的陣列並填充陣列內容,除了指定陣列的大小還指定了引數個數
filled-new-array/range {vCCCC .. vNNNN}, [email protected]:與上一條類似,只是引數使用取值範圍,vC是第一個引數暫存器,N=A+C-1
fill-array-data vAA, +BBBBBBBB:vAA為暫存器陣列引用,後面跟一個數據表
arrayop vAA, vBB, vCC:對vBB暫存器指定的陣列元素進入取值或賦值。vCC指定陣列元素索引,vAA暫存器用來存放讀取的或需要設定的值。讀取元素使用age類指令,賦值使用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
private void testArray() {
int[] ints = new int[2];
int[] ints1 = null;
int[] ints2 = {1,2,3};
Integer[] integers = new Integer[]{1,2,4};
int[] strings = {1,2,3,4,5,6,5,6,6,6,6,6,6,7,7,8,8,8,8,8,1,1,1,3,3,5,6,54,5,6,56,567,67,6,34,45,45,6,56,57,45,45,5,56,56,7,34,543,543,6,56,56,45,4,54,5,45,56};
//陣列長度
int length = ints.length;
int length1 = ints2.length;
int length2 = strings.length;
//獲取陣列元素
int string = strings[30];
int string1 = ints2[1];
//賦值
strings[30] = length;
ints2[1] = length2;
}
.method private testArray()V
.locals 15
.prologue
const/16 v14, 0x1e
const/4 v10, 0x3
const/4 v13, 0x2
const/4 v12, 0x1
.line 27
new-array v1, v13, [I
.line 28
.local v1, "ints":[I
const/4 v2, 0x0
.line 29
.local v2, "ints1":[I
new-array v3, v10, [I
fill-array-data v3, :array_0
.line 31
.local v3, "ints2":[I
new-array v0, v10, [Ljava/lang/Integer;
const/4 v10, 0x0
invoke-static {v12}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object v11
aput-object v11, v0, v10
invoke-static {v13}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object v10
aput-object v10, v0, v12
const/4 v10, 0x4
invoke-static {v10}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer;
move-result-object v10
aput-object v10, v0, v13
.line 33
.local v0, "integers":[Ljava/lang/Integer;
const/16 v10, 0x3a
new-array v9, v10, [I
fill-array-data v9, :array_1
.line 36
.local v9, "strings":[I
array-length v4, v1
.line 37
.local v4, "length":I
array-length v5, v3
.line 38
.local v5, "length1":I
array-length v6, v9
.line 41
.local v6, "length2":I
aget v7, v9, v14
.line 42
.local v7, "string":I
aget v8, v3, v12
.line 45
.local v8, "string1":I
aput v4, v9, v14
.line 46
aput v6, v3, v12
.line 47
return-void
.line 29
:array_0
.array-data 4
0x1
0x2
0x3
.end array-data
.line 33
:array_1
.array-data 4
0x1
0x2
0x3
0x4
0x5
0x6
0x5
0x6
0x6
0x6
0x6
0x6
0x6
0x7
0x7
0x8
0x8
0x8
0x8
0x8
0x1
0x1
0x1
0x3
0x3
0x5
0x6
0x36
0x5
0x6
0x38
0x237
0x43
0x6
0x22
0x2d
0x2d
0x6
0x38
0x39
0x2d
0x2d
0x5
0x38
0x38
0x7
0x22
0x21f
0x21f
0x6
0x38
0x38
0x2d
0x4
0x36
0x5
0x2d
0x38
.end array-data
.end method
異常指令
throw vAA:丟擲vAA暫存器中指定型別的異常
private void throw2() {
try {
throw new Exception("test throw runtime exception");
} catch (Exception e) {
e.printStackTrace();
}
}
private void throw1() {
throw new RuntimeException("test throw runtime exception");
}
.method private throw1()V
.locals 2
.prologue
.line 38
new-instance v0, Ljava/lang/RuntimeException;
const-string v1, "test throw runtime exception"
invoke-direct {v0, v1}, Ljava/lang/RuntimeException;-><init>(Ljava/lang/String;)V
throw v0
.end method
.method private throw2()V
.locals 3
.prologue
.line 31
:try_start_0
new-instance v1, Ljava/lang/Exception;
const-string v2, "test throw runtime exception"
invoke-direct {v1, v2}, Ljava/lang/Exception;-><init>(Ljava/lang/String;)V
throw v1
:try_end_0
.catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0
.line 32
:catch_0
move-exception v0
.line 33
.local v0, "e":Ljava/lang/Exception;
invoke-virtual {v0}, Ljava/lang/Exception;->printStackTrace()V
.line 35
return-void
.end method
跳轉指令
用於從當前地址跳轉到指定的偏移處,提供了三種指令:無條件(goto),分支跳轉(switch),條件跳轉(if)
goto +AA:無條件跳轉到指定偏移處,AA不能為0
goto/16 +AAAA
goto/32 +AAAAAAAA
packed-switch vAA, +BBBBBBBB:分支跳轉,vAA暫存器為switch分支需要判斷的值
if-test vA, vB, +CCCC 條件跳轉指令,比較vA暫存器與vB暫存器的值,如果比較結果滿足就跳轉到CCCC指定的偏移處,不能為0,有以下幾條:
if-eq:if(vA==vB)
if-ne:vA!=vB
if-lt:vA
private void testIfz() {
int a = 3;
if (a == 0) {
} else {
}
if (a != 0) {
} else {
}
if (a < 0) {
} else {
}
if (a > 0) {
} else {
}
if (a <= 0) {
} else {
}
if (a >= 0) {
} else {
}
if (a < 5) {
Log.d("TAG", "<5");
} else if (a > 5) {
Log.d("TAG", ">5");
} else {
Log.d("TAG", "=5");
}
}
private void testIf() {
int a = 2;
int b = 3;
if (a == b) {
} else {
}
if (a != b) {
} else {
}
if (a < b) {
} else {
}
if (a > b) {
} else {
}
if (a <= b) {
} else {
}
if (a >= b) {
} else {
}
}
.method private testIf()V
.locals 2
.prologue
.line 69
const/4 v0, 0x2
.line 70
.local v0, "a":I
const/4 v1, 0x3
.line 71
.local v1, "b":I
if-ne v0, v1, :cond_0
.line 76
:cond_0
if-eq v0, v1, :cond_1
.line 81
:cond_1
if-ge v0, v1, :cond_2
.line 86
:cond_2
if-le v0, v1, :cond_3
.line 91
:cond_3
if-gt v0, v1, :cond_4
.line 96
:cond_4
if-lt v0, v1, :cond_5
.line 102
:cond_5
return-void
.end method
.method private testIfz()V
.locals 3
.prologue
const/4 v1, 0x5
.line 27
const/4 v0, 0x3
.line 28
.local v0, "a":I
if-nez v0, :cond_0
.line 33
:cond_0
if-eqz v0, :cond_1
.line 38
:cond_1
if-gez v0, :cond_2
.line 43
:cond_2
if-lez v0, :cond_3
.line 48
:cond_3
if-gtz v0, :cond_4
.line 53
:cond_4
if-ltz v0, :cond_5
.line 59
:cond_5
if-ge v0, v1, :cond_6
.line 60
const-string v1, "TAG"
const-string v2, "<5"
invoke-static {v1, v2}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 66
:goto_0
return-void
.line 61
:cond_6
if-le v0, v1, :cond_7
.line 62
const-string v1, "TAG"
const-string v2, ">5"
invoke-static {v1, v2}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
goto :goto_0
.line 64
:cond_7
const-string v1, "TAG"
const-string v2, "=5"
invoke-static {v1, v2}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
goto :goto_0
.end method
比較指令
用於對兩個暫存器的值比較
cmpkind vAA, vBB, vCC:vBB和vCC為要比較的值,結果放到vAA中
cmpl-float:單精度,vBB大於vCC,vAA=-1,等於vAA=0,小於vAA=1
cmpg-float:單精度,vBB大於vCC,vAA=1,等於vAA=0,小於vAA=-1
cmpl-double:雙精度
cmpg-double:雙精度
cmp-long:長整形
private void testCmpLong() {
long a = 13;
long b = 12;
if (a < b) {
Log.d("TAG", "<");
} else if (a > b) {
Log.d("TAG", ">");
} else {
Log.d("TAG", "=");
}
}
private void testCmpDouble() {
double a = 13.4;
double b = 11.4;
if (a < b) {
Log.d("TAG", "<");
} else if (a > b) {
Log.d("TAG", ">");
} else {
Log.d("TAG", "=");
}
}
private void testCmpFloat() {
float a = 13.4F;
float b = 10.4F;
if (a < b) {
Log.d("TAG", "<");
} else if (a > b) {
Log.d("TAG", ">");
} else {
Log.d("TAG", "=");
}
}
.method private testCmpDouble()V
.locals 6