Smali语法

概述

  • Android代码一般是用 java 编写的,执行 java 程序一般需要用到 java 虚拟机,在 Android 平台上也不例外,但是出于性能上的考虑,并没有使用标准的 JVM,而是使用专门的Android虚拟机(5.0以下为Dalvik,5.0以上为ART)。Android 虚拟机的可执行文件并不是普通的 class 文件,而是再重新整合打包后生成的 dex 文件。dex 文件反编译之后就是 Smali 代码,所以说,Smali 语言是 Android 虚拟机的反汇编语言。
  • Dalvik VM是基于寄存器的,而JVM是基于栈的;Dalvik VM 比 JVM 速度更快,占用空间更少。

语法

数据类型

Smail Java 备注
v void
Z boolean
Z boolean
B byte
S short
C char
I int
J long
F float
D double
Lpackage/name; 对象类型 L表示这是一个对象类型,package表示该对象所在的包,;表示对象名称的结束
[ 数组类型 [I表示一个int型数据,[Ljava/lang/String 表示一个String的对象数组
+ 代码示例
- I表示 int 类型.
- [[I: 表示 int[][] 数组.
- I: 表示 int 类型.
- Ljava/lang/String;: 表示 String 类型.
- [Ljava/lang/Object;: 表示对象数组 (Object[]).
- Ljava/lang/String;: 表示返回值是 String.

method(I[[IILjava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
# 对应 java 
String method(int,int[][],int,String,Object[])

寄存器命名规则

  • p0, p1, …:方法参数寄存器.
  • v0, v1, …:局部变量寄存器.
  • 在非 static 方法中, p0 表示 this 对象, p1, p2, … 是方法的实际参数.
  • 在 static 方法中, p0 是第一个参数, this 不存在.
寄存器 介绍 备注
参数寄存器(p0, p1, ...) ①. 用于存储方法参数.
②. 在非 static 方法中, p0 表示 this 对象, p1, p2, ... 是方法的实际参数.
③. 在 static 方法中, p0 是第一个参数,this 不存在.
①. 参数寄存器(p0、p1、…)由虚拟机根据方法签名自动分配,不计入 .locals 的 N.
本地寄存器(v0, v1, ...) ①. 用于存储方法内部的局部变量.
①. .locals N: 声明本地寄存器数,参数寄存器的方法参数自动分配,不计入 N.
②. .registers M:声明参数寄存器和本地寄存器总数,等于参数寄存器数 + 本地寄存器数
+ 非 static 方法
1. p0  this,即当前类的实例<br>
2. p1 是传入的 String 参数(未使用),对应函数签名里的 String 参数.<br>
3. v0 是本地寄存器, 用于存储 "Hello" 字符串

.method public showMessage(Ljava/lang/String;)V
    .locals 1
    const-string v0, "Hello"
    invoke-virtual {p0, v0}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;)Landroid/widget/Toast;
    return-void
.end method
+ static 方法

1. p0, p1 是两个 int 参数.<br>
2. v0 是本地寄存器用于存储结果.<br>
3. add-int 是加法指令

.method public static add(II)I
    .locals 1
    add-int v0, p0, p1
    return v0
.end method
# 对应的 java 
public static int add(int a, int b) {
    return a + b;
}

字节码指令

  • 取值指令有:iget、sget、iget-boolean、sget-boolean、iget-object、sget-object 等.
  • 赋值指令有:iput、sput、iput-boolean、sput-boolean、iput-object、sput-object 等.

方法表示

- 方法使用 .method 表示开始,使用 .end method 表示结束.
- Ljava/lang/String$xxx; 表示 xxx 是 String 类的内部类.
方法 含义 备注
direct method ①. 指的是 private 方法,static 方法,构造函数,类初始块
②. 调用方式为 invoke-direct.
①. 不能被子类重写.
②. 通常用于类内部逻辑,不涉及多态.
virtual method ①.指的是public, protected, package-private 的实例方法
②.调用方式为 invoke-virtual.
①.可以被子类重写(支持多态).
②.支持动态绑定(运行时根据对象类型决定调用哪个方法).

参考链接

1.Smali语法