Android smali 语法三

来源:互联网 发布:startos软件源 编辑:程序博客网 时间:2024/04/30 07:42

在上篇博文的动手实践中,我们将.java文件转化成.smali文件后,发现java中的数据类型、域名、方法名在.smali文件中发生了改变。事实上,当.java文件被javac、dx工具转换成Dalvik VM可执行文件.dex后,数据类型、域名、方法名就已经发生了变化。.smali文件和.dex文件中数据类型、域名、方法名是相同的,所以我们看一下.dex文件中数据类型、域名、方法名就行了。

一、数据类型

.dex文件中存储的是Dalvik VM运行的字节码,字节码有两种主要的数据类型:基本数据类型(primitive types)和引用类型。引用类型由数组和对象组成,其它的全是基本数据类型。
基本类型由一个字母表示,事实上这些缩写的字母在.dex文件中以string形式存储。他们在 dex-format.html document文件(dalvik/docs/dex-foramt.html in the AOSP repository)中进行了定义
基本数据类型

Dalvik/smali Java V void-can only be used for return types Z boolean B byte C char I int J long(64bits) F float D double(b4bits)


对象的命名格式为:Lpackage/name/ObjectName; ——– L 表示它是对象, package/name/ 是对象所在的包,ObjectName 表示对象。该命名格式等价Java中 package.name.ObjectName。例如 Ljava/lang/String;等价于java.lang.String
数组的命名格式为:[I ——- 它表示一个int类型的一维数组,如果表示多维数组,者加[字符,例如:[[i=int [][] , [[[i=int[][][].
对象数组: [Ljava/lang/String;

二、方法

方法的定义是比较冗长的,通常包括方法名、参数类型、和返回类型。这些信息确保Dalvik VM能够正确的找到方法运行和对字节码进行进行静态分析。方法的格式:
Lpackage/name/ObjectName;->MethodName(III)Z
其中MethodName 是方法名,(III) 是方法的签名,Z是返回类型
例子:method(I[[IILjava/lang/String;[Ljava/lang/Object;)Ljava/lang/string等价于String method(int,int[][],int,String,Object)

三、域

域名的定义也是冗长的,通常包括作用域、域名、域的类型
域的格式:
Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;


四、科普:smali方法中的寄存器

为了给下篇的java方法中代码转化成 .smali文件方法中的指令做铺垫 ,我们在这里科普一下Dalvik 字节码中的寄存器

在davilk字节码中,寄存器总是32位的并且可以存储任何类型的值。2 个寄存器用来存储64位的类型(Long and Double)

1.在方法中定义寄存器的数量

在方法中有两种方式定义方法中可以使用的寄存器数量。.registers 指令定义了方法中可以使用的寄存器的总数量。可以选择性的使用.locals ,该指令定义了方法中非参数寄存器的数量。寄存器的总数量应当包括方法参数所使用的寄存器的数量

2.方法参数传递给方法的方式

当方法被调用时,传递给方法的参数被保存在最后的n个寄存器中。如果一个方法有2个参数和5个寄存器(v0-v4),那么参数将被放在最后两个寄存器中(v3和v4中)。
对于一个非静态方法来说,传递给它的第一个参数总是方法被调用的对象本身 。例如,假设你写了一个非静态的方法LMyObject;->callMe(II)V。这个方法有2个integer类型的参数,但是在这两个integer类型参数之前它也有一个隐含的参数LMyObject;,所以该方法总 共有3个参数。再例如,假设在方法中(v0-v5)定义了5个寄存器—由.register 5指令或者.locals 2指令( 2 local register + 3 parameter register)定义。当该方法被调用时,该对象(the this reference )会被放在v2寄存器中,第1个integer参数会被放在v3中,第2个integer参数会被放在v4中。
静态方法不会有隐含的this参数,其它的参数存放方法与非静态的方法参数存放方法一样。

3.寄存器的命名

寄存器命名有两种方案:v字命名法和p字命名法。

v字命名 p字命名 说明 v0 the first local register v1 the sencond local register v2l p0 the first paramter register v3 p1 the second parameter register v4 p2 the third parameter register

4.介绍参数寄存器(parameter)的原因

由于方法参数是保存在最后n个寄存器的,如果用 v 字命名法,修改smail 文件的寄存器总个数后,每个保存参数的寄存器序号仍旧需要修改。而使用 p 字命名法,则不需要保存参数的寄存器序号,比较方便。因此推荐使用P字命名法。
baksmail默认使用 p 命名法,如果想要使用v 命名法,加 -p/-no-parameter-register寄存器

5.Long/Double 值

Long/Double基本类型是64bit值,因此需要两个寄存器存放 它们的值。
假设你有一个非静态方法LMyObject;->MyMethod(IIJ)V,方法MyMethod,该方法需要5个寄存器来保存参数,如下

p0 this p1 I p2,p3 J p4 Z

本文参考自:
[1] https://github.com/JesusFreke/smali/wiki/TypesMethodsAndFields
[2]https://github.com/JesusFreke/smali/wiki/Registers

1 0