前言
通常基于Java语言开发程序都是通过调用javac编译器将源代码编译成.class文件,这种文件能够被JVM识别,加载并执行的文件格式(除了常见的java源代码生成的class文件,其他的Scalar、Python和Groovy等语言都可以生成class文件,每个类和接口都单独占据一个class文件)。不过class文件内存占用量大,不适合移动端,采用堆栈的加载模式,文件IO操作多,class只包含一个类,不断的查找新类需要不断做IO操作。
Android的Dalvik和ART都是基于Dex格式的虚拟机实现,它们内部采用了寄存器模式访问数据,比普通的JVM基于栈实现更加高效。Dex格式文件不只能通过Java语言生成,C/C++也可以生成dex文件,通过dx命令生成dex文件。dex文件能够记录整个工程的所有类文件的信息,包括所有的文件,这样查询类的时候就不用多次IO,一次把所有类都加入到内存中。.dex里面记录的是Dalvik实现的虚拟机指令,如果使用baksmali工具就能够把.dex文件中的机器指令反编译成smali代码,也就是说smali代码其实是Dalvik的汇编语言。
基本语法
Smali的语法规则相对于Intel等硬件编译语言要简单的多,懂得Java语法的人很容易就能够将二者的实现一一对应,这里先介绍数据类型的表示,再说明方法调用指令,最后了解一下数据存储和返回指令。
类型定义
类型 | Java类型 | 说明 |
---|---|---|
v | void | 只能用于返回值类型 |
Z | boolean | |
B | byte | |
S | short | |
C | char | |
I | int | |
J | long | 2个寄存器 |
F | float | |
D | double | 2个寄存器 |
在Dalvik虚拟机中寄存器的位数是32位,而long和Double类型都有64为,单独的寄存器无法装下这两种数据类型,需要使用2个寄存器装载
上面定义的都是基础数据类型,现在看一下对象类型,对象类型包含普通对象和数组两大类:
类型名称 | 类型 | 说明 |
---|---|---|
对象类型 | Lpackage/name/ObjectName; | L:表示这是一个对象类型 package/name:该对象所在的包 ;:表示对象名称结束 |
数组 | [primaryType | [I:表示整形的一维int数组,相当于java的int[];对于多维的数组多加[就可以了 |
对象数组 | [Lpackage/name/ObjectName; | [Ljava/lang/String; 表示一个String的对象数组 |
方法调用
Smali中的方法被表示成“对象->方法描述符”形式,其中方法描述符就是“方法名(传入参数描述符)返回参数描述符”,传入和返回参数的描述符参考上面的类型定义,其中传入参数是连接在一起中间没有任何分隔符。
Lpackage/name/ObjectName;->methodName(III)Z
Lpackage/name/ObjectName;:表示类型
methodName:表示方法名
III:表示参数为3