標籤:des android style blog http io ar os 使用
轉載請標明出處:http://blog.csdn.net/goldenfish1919/article/details/40821415
以下內容來自:http://bbs.pediy.com/showthread.php?t=151769
dalvik位元組碼有兩種類型,原始類型和參考型別。對象和數組是參考型別,其它都是原始類型。
V void,只能用於返回值類型
Z boolean
B byte
S short
C char
I int
J long(64位)
F float
D double(64位)
對象以Lpackage/name/ObjectName;的形式表示。
前面的L表示這是一個物件類型,package/name/是該對象所在的包,ObjectName是對象的名字,“;”表示對象名稱的結束。
相當於java中的package.name.ObjectName。例如:Ljava/lang/String;相當於java.lang.String
數組的表示形式
[I——表示一個整型一維數組,相當於java中的int[]。
對於多維陣列,只要增加[就行了。[[I相當於int[][],[[[I相當於int[][][]。注意每一維的最多255個。
對象數組的表示:[Ljava/lang/String;表示一個String對象數組。
方法
表示形式:Lpackage/name/ObjectName;->MethodName(III)Z
Lpackage/name/ObjectName;表示類型,MethodName是方法名。III為參數(在此是3個整型參數),Z是傳回型別(bool型)。
方法的參數是一個接一個的,中間沒有隔開。
一個更複雜的例子:
method(I[[IILjava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
在java中則為:
String method(int, int[][], int, String, Object[])
欄位
表示形式:
Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;
即包名,欄位名和各欄位類型。
寄存器
在dalvik位元組碼中,寄存器都是32位的,能夠支援任何類型。64位類型(Long和Double型)用2個寄存器表示。
有兩種方式指定一個方法中有多少寄存器是可用的。.registers指令指定了方法中寄存器的總數。.locals指令表明了方法中非參寄存器的數量。
方法的傳參
當一個方法被調用的時候,方法的參數被置於最後N個寄存器中。如果一個方法有2個參數,5個寄存器(v0-v4),那麼參數將置於最後2個寄存器——v3和v4。
非靜態方法中的第一個參數總是調用該方法的對象。
例如,非靜態方法LMyObject;->callMe(II)V有2個整型參數,另外還有一個隱含的LMyObject;參數,所以總共有3個參數。
假如在該方法中指定了5個寄存器(v0-v4),以.registers方式指定5個或以.locals方式指定2個(即2個local寄存器+3個參數寄存器)。
當該方法被調用的時候,調用該方法的對象(即this引用)存放在v2中,第一個整型參數存放在v3中,第二個整型參數存放在v4中。
對於靜態方法除了沒有隱含的this參數外其它都一樣。
寄存器的命名方式
有兩種方式——V命名方式和P命名方式。P命名方式中的第一個寄存器就是方法中的第一個參數寄存器。
在下表中我們用這兩種命名方式來表示上一個例子中有5個寄存器和3個參數的方法。
v0 第一個local register
v1 第二個local register
v2 p0 第一個parameter register
v3 p1 第二個parameter register
v4 p2 第三個parameter register
你可以用任何一種方式來引用參數寄存器——他們沒有任何差別。
注意:baksmali預設對參數寄存器使用P命名方式。如果想使用V命名方式,可以使用-pl—no-parameter-registers選項。
使用P命名方式是為了防止以後如果要在方法中增加寄存器,需要對參數寄存器重新進行編號的缺點。
Long/Double值
Long和double類型是64位的,需要2個寄存器(切記切記)。
例如,對於非靜態方法LMyObject;->MyMethod(IJZ)V,參數分別是LMyObject;,int,long,bool。故該方法需要5個寄存器來儲存參數。
p0 this
p1 I
p2,p3 J
p4 Z
補充:
# static fields 定義靜態變數的標記
# instance fields 定義執行個體變數的標記
# direct methods 定義靜態方法的標記
# virtual methods 定義非靜態方法的標記
建構函式的傳回型別為V,名字為<init>。
if-eq p1, v0, :cond_8 表示如果p1和v0相等,則執行cond_8的流程:
:cond_8
invoke-direct {p0}, Lcom/paul/test/a;->d()V
調用com.paul.test.a的d()方法
if-ne p1, v0, :cond_b 表示不相等則執行cond_b的流程:
:cond_b
const/4 v0, 0x0
invoke-virtual {p0, v0}, Lcom/paul/test/a;->setPressed(Z)V
invoke-super {p0, p1, p2}, Landroid/view/View;->onKeyUp(ILandroid/view/KeyEvent;)Z
move-result v0
大概意思就是調用com.paul.test.a的setPressed方法,然後再調用父類View的onKeyUp方法,最後 return v0
舉兩個例子:
sget-object v5, Lcom/google/youngandroid/runtime;->Lit227:Lgnu/mapping/SimpleSymbol;
擷取com.google.youngandroid.runtime中的Lit227欄位存入v5寄存器,相當於
gnu.mapping.SimpleSymbol localVariable = com.google.youngandroid.runtime.Lit227;
sput-object v0, Lcom/google/youngandroid/runtime;->Lit78:Lkawa/lang/SyntaxTemplate;
Likewise, this is setting the value of a static field. i.e.
設定com.google.youngandroid.runtime.Lit78的值為v0寄存器中的kawa.lang.SyntaxTemplate類型變數的值。相當於com.google.youngandroid.runtime.Lit78 = kawa.lang.SyntaxTemplate localVariable;
剩下的比較簡單你應該能明白了。
下面我們來看一個簡單的例子:
public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);TextView textview1 = (TextView) this.findViewById(R.id.text);textview1.setText(R.string.hello_world);}}產生的smali:
.class public Lcom/example/hello/MainActivity;.super Landroid/app/Activity;.source "MainActivity.java"# direct methods.method public constructor <init>()V .locals 0 .prologue .line 14 invoke-direct {p0}, Landroid/app/Activity;-><init>()V return-void.end method# virtual methods.method protected onCreate(Landroid/os/Bundle;)V .locals 2 .parameter "savedInstanceState" .prologue .line 18 invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V .line 19 const/high16 v1, 0x7f03 invoke-virtual {p0, v1}, Lcom/example/hello/MainActivity;->setContentView(I)V .line 20 const/high16 v1, 0x7f0a invoke-virtual {p0, v1}, Lcom/example/hello/MainActivity;->findViewById(I)Landroid/view/View; move-result-object v0 check-cast v0, Landroid/widget/TextView; .line 21 .local v0, textview1:Landroid/widget/TextView; const v1, 0x7f070002 invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(I)V .line 22 return-void.end method
我們重點來看下onCreate()這個的方法。
.method protected onCreate(Landroid/os/Bundle;)V
.locals 2
.parameter "savedInstanceState"
.prologue
.line 18
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V // 這是調用super也就是Activity.onCreate(Bundle) p0:this,p1:Bundle
.line 19
const/high16 v1, 0x7f03 //把0x7f03這個常量賦值給v1 ,0x7f03就是R.layout.activity_main
invoke-virtual {p0, v1}, Lcom/example/hello/MainActivity;->setContentView(I)V // 調用MainActivity.setContentView(v1),p0:this,v1就是R.layout.activity_main
.line 20
const/high16 v1, 0x7f0a // 把0x7f0a 這個常量賦值給v1 ,0x7f0a 就是R.id.text
invoke-virtual {p0, v1}, Lcom/example/hello/MainActivity;->findViewById(I)Landroid/view/View; // 調用View = MainActivity.findViewById(v1),p0:this,v1:R.id.text
move-result-object v0 // 把上一個指令的輸出結果move到v0,就是給textview1賦值
check-cast v0, Landroid/widget/TextView;// 把v0強轉成TextView
.line 21
.local v0, textview1:Landroid/widget/TextView;
const v1, 0x7f070002 // 把int常量0x7f070002放到v1中,就是讀出來R.string.hello_world
invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(I)V //調用TextView.setText(v1) TextView是v0,參數是v1
.line 22
return-void
.end method
還是挺簡單的一個例子。跟class位元組碼非常向。我們看一下同樣的代碼在class中和smali中有啥不一樣的。
public void multiply(int a, int b){int result = a * b;System.out.println(result);}smali表示:
# virtual methods
.method public multiply(II)V
.locals 2
.parameter "a"
.parameter "b"
.prologue
.line 26
mul-int v0, p1, p2 // p1和p2相乘,結果放到v0中
.line 27
.local v0, result:I
sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; // 擷取System.out的引用,放到v1中
invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(I)V // 調用PrintStream.println(v0)
.line 28
return-void
.end method
class表示:
public void multiply(int, int);
Code:
Stack=2, Locals=4, Args_size=3
0: iload_1 // 本地變數1壓棧
1: iload_2 // 本地變數2壓棧
2: imul // 棧中取上面的2個做乘法
3: istore_3 // 結果出棧,放到本地變數3中
4: getstatic#5; //Field java/lang/System.out:Ljava/io/PrintStream; // System.out壓棧
7: iload_3 // 本地變數3壓棧
8: invokevirtual#6; //Method java/io/PrintStream.println:(I)V // 調用PrintStream.println
11: return
LineNumberTable:
line 6: 0
line 7: 4
line 8: 11
上面可以很清晰的看出來,實現同樣的功能,基於寄存器要比基於棧的指令數要少。int result = a * b;在smali中就一條指令,而在class中要4條指令。
關於smali所有指令的格式和含義可以參考:http://pallergabor.uw.hu/androidblog/dalvik_opcodes.html
Android-smali文法學習