一.smali的基础语法
1.smali数据类型与Java语言的对照关系
B---byte
C---char
D---double
F---float
I---int
J---long
S---short
V---void
Z---boolean
[XXX---array Lxxx/yyy---object 数组
[I int数组
[Z 布尔值数组
2.smali的方法定义规则
方法的一般定义为 Func-Name (Para-Type1Para-Type2Para-Type3...)Return-Type
参数与参数之间没有任何的间隔
如:
Hello()V 表示:void hello() 调用时无需参数,同时无返回值。
Hello(III)Z
表示:Boolean hello(int,int,int)调用时需要传递三个int参数。返回值为boolean的值
Hello(Z[I[ILjava/lang/String;J)Ljava/lang/String;
表示: String hello(boolean,int[],int[],String,long)
调用时候需要传递(一个布尔值,一个int数组,一个string对象,一个long整形)
返回值是一个string值
3.smali语言中的一些关键字
.field private isFlag:z 定义变量
.method 函数
.end method 函数结束
.parameter 参数
.prologue 代码开始的位置
.line 123 此方法位于第123行
invoke-super 调用父函数
invoke-direct 调用函数
invoke-static 调用静态函数
const v0, 0x1 把0x1(1)赋值给v0(0x1-----0x代表十六进制,0x1代表1)
return-void 函数返回void(无返回值)
new-instance 创建实例
iput-object 对象赋值
iget-object 调用对象
4.smali的条件跳转
e/eq equals(等于)
ne not equals(不等于)
z zero (0)
g greater(大于)
l Less(小于)
lt less than(小于)
gt greater than(大于)
"if-eq vA, vB, :cond_**" 如果vA等于vB则跳转到:cond_**
"if-ne vA, vB, :cond_**" 如果vA不等于vB则跳转到:cond_**
"if-le vA, vB, :cond_**" 如果vA小于等于vB则跳转到:cond_**
"if-ge vA, vB, :cond_**" 如果vA大于等于vB则跳转到:cond_**
"if-lt vA, vB, :cond_**" 如果vA小于vB则跳转到:cond_**
"if-gt vA, vB, :cond_**" 如果vA大于vB则跳转到:cond_**
"if-eqz vA, :cond_**" 如果vA等于0则跳转到:cond_**
"if-nez vA, :cond_**" 如果vA不等于0则跳转到:cond_**
"if-lez vA, vB, :cond_**" 如果vA小于等于vB则跳转到:cond_**
"if-gez vA, vB, :cond_**" 如果vA大于等于vB则跳转到:cond_**
"if-ltz vA, :cond_**" 如果vA小于0则跳转到:cond_**
"if-gtz vA, :cond_**" 如果vA大于0则跳转到:cond_**
5.smali中类的表达
.class public Lcom/aaaaa;
.super Lcom/bbbbb;
.source "ccccc.java"
它是com.aaaaa这个package下的一个类(第1行)
继承自com.bbbbb这个类(第2行)
这是一个由ccccc.java编译得到的smali文件(第3行)
6.smali中内部类的声明
一般来说在Smali文件中是这个样子的:
# annotations .annotation system Ldalvik/annotation/MemberClasses;
value = {
Lcom/aaa$qqq;
Lcom/aaa$www;
}
.end annotation
这个声明是内部类的声明:aaa这个类它有两个成员内部类——qqq和www。
7.smali中的寄存器语法
在smali里的所有操作都必须经过寄存器来进行
本地寄存器:用v开头数字结尾的符号来表示,如v0,v1,v2…v15..,用于方法内数 值之间的传递;
参数(parameter)寄存器:用p开头数字结尾的符号来表示,如p0,p1,p2…,表示该方法依次接
收过来的参数值。
特别注意:p0不一定是函数中的第一个参数。在非static函数中,p0代指“this”,
p1表示函数的第一个参数,p2代表函数中的第二个参数…而在static函数中p0才对应第一个参数。
因为Java的static方法中没有this方法
例如:
const/4 v0, 0x1
iput-boolean v0, p0, Lcom/aaa;->IsRegistered:Z
我们来分析一下上面的两句smali代码,首先它使用了v0本地寄存器,并把值0x1 存到v0中,
然后第二句用iput-boolean这个指令把v0中的值存放到com.aaa.IsRegistered这个成员变量中。
即相当于:this.IsRegistered= true;
在非static函数中p0代表的是 “this”,在这里就是com.aaa实例)。
8.smali中类成员变量操作和表示
成员变量格式是:
.field public/private [static] [final] varName:<类型>。
对于不同的成员变量也有不同的指令。
获取的指令有:iget、sget、iget-boolean、sget-boolean、iget-object、sget- object等。
写入的指令有:iput、sput、iput-boolean、sput-boolean、iput-object、 sput-object等。
没有“-object”后缀的表示操作的成员变量对象是基本数据类型,带“-object” 表示操作的成员变量是对象类型,特别地,boolean类型则使用带“-boolean” 的指令操作。
sget-object v0, Lcom/aaa;->ID:Ljava/lang/String;
解释:获取内部类aaa中的string类型的ID的值保存给V0 V0=this.ID
sget-object用来获取变量值并保存到紧接着的参数的寄存器中,
它获取 ID这个String类型的成员变量并放到v0这个寄存器中。
注意:前面需要该变量所属的类的类型,后面需要加一个冒号和该成员变量的类型
中间是“->”表示所属关系。
iget-object v0, p0, ->view:Lcom/aaa/view;
解释:Lcom/aaa;(内部类不是stratic,所以p0是this)this.view=V0
可以看到iget-object指令比sget-object多了一个参数,就是该变量所在 类的实例,在这里就是p0即“this”。
9.smali语法中的代码函数的调用
invoke 调用
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 :调用实例的接口方法
invoke-static:用于调用static函数
const-string v0, "NDKLIB"
invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
调用static void System.loadLibrary(String)来加载NDK编译的so库用的方法,这里v0就是参数"NDKLIB"。
invoke-super:调用父类方法用的指令,一般用于调用onCreate、onDestroy 等方法。
invoke-direct:调用private函数
invoke-direct {p0}, Landroid/app/TabActivity;-><init>()V
这里init()就是定义在TabActivity中的一个private函数
invoke-virtual:用于调用protected或public函数。
sget-object v0, Lcom/dddd;->bbb:Lcom/ccc;
invoke-virtual {v0, v1}, Lcom/ccc;->Messages(Ljava/lang/Object;)V
v0是bbb:Lcom/ccc
v1是传递给Messages方法的Ljava/lang/Object参数。
invoke-xxxxx/range:当方法的参数多于5个时(含5个),不能直接使用以上 的指令,而是在后面加上“/range”,range表示范围,使用方法也有所不同:
invoke-direct/range {v0 .. v5}, Lcmb/pb/ui/PBContainerActivity;->h(ILjava/lang/CharSequence;Ljava/lang/String;Landroid/content/Intent;I)Z
需要传递v0到v5一共6个参数,这时候大括号内的参数采用省略形式,且需要连续
10.smali中对返回结果的操作
在Java代码中调用函数和返回函数结果可以用一条语句完成,而在Smali里则需要 分开来完成,在使用上述指令后,如果调用的函数返回非void,那么还需要用到 move-result(返回基本数据类型)和move-result-object(返回对象)指令:
const-string v0, "Eric" v0=Eric
invoke-static {v0}, Lcmb/pbi;->t(Ljava/lang/String;)Ljava/lang/String;
move-result-object v2 v2=pbi.t(Eric)
v2保存的就是调用t方法返回的String字符串。