- 寄存器
Dalvik 指令集完全基于寄存器,也就是说,没有栈。 所有寄存器都是 32 位,无类型的。也就是说,虽然编译器会为每个局部变量分配一个寄存器,但是理论上一个寄存器中可以存放一个int,之后存放一个String(的引用),之后再存放一个别的东西。 如果要处理 64 位的值,需要连续的两个寄存器,但是代码中仍然只写一个寄存器。这种情况下,你在代码中看到的vx实际上是指vx和vx + 1。 寄存器有两种命名方法。v命名法简单直接。假设一共分配了 10 个寄存器,那么我们可以用v0到v9来命名它们。
https://wx3.sinaimg.cn/large/0060lm7Tly1g1iq3sdfsjj30co03lmxk.jpg
除此之外,还可以用p命名法来命名参数所用的寄存器,参数会占用后面的几个寄存器。假如上面那个方法是共有两个参数的静态方法,那么,我们就可以使用p0和p1取代v8和v9。如果是实例方法,那么可以用p0 ~ p2取代v7 ~ v9,其中p0是this引用。
https://wx4.sinaimg.cn/large/0060lm7Tly1g1iq4dut9bj30bn03w74p.jpg
但在实际的代码中,一般不会声明所有寄存器的数量,而是直接声明局部变量所用的寄存器(后面会看到)。也就是说局部变量和参数的寄存器是分开声明的。我们无需关心vx是不是py,只需知道所有寄存器的数量是局部变量与参数数量的和。
数据类型Dalvik 拥有独特的数据类型表示方法,并且和 Java 类型一一对应: 其中对象类型由L<包名>/<类名>;(完全限定名称)表示,要注意末尾有个分号,比如String表示为Ljava/lang/String;。 数组类型是[加上元素类型,比如int[]表示为[I。左方括号的个数也就是数组的维数,比如int[][]表示为[[I。 类定义一个 smali 文件中存放一个类,文件开头保存类的各种信息。类的定义是这样的。 .class <权限修饰符> <非权限修饰符> <完全限定名称>.super <超类的完全限定名称>.source <源文件名>比如这是某个MainActivity: .class public Lnet/flygon/myapplication/MainActivity;.super Landroid/app/Activity;.source "MainActivity.java"我们可以看到该类是public的,完整名称是net.flygon.myapplication.MainActivity,继承了android.app.Activity,在源码中是MainActivity.java。如果类是abstract或者final的,会在public/private/protected后面表示。 类可以实现接口,如果类实现了接口,那么这三条语句下面会出现.implements <接口的完全限定名称>。比如通常用于回调的匿名类中会出现.implements Landroid/view/View$OnClickListener;。 类还可以拥有注解,同样,这三条语句下方出现这样的代码: .annotation <完全限定名称> 键 = 值 ....end annotation这些语句下面就是类拥有的字段和方法。 字段定义字段定义如下: .field <权限修饰符> <非权限修饰符> <名称>:<类型>其中非权限修饰符可以为final或者abstract。 比如我在MainActivity中定义一个按钮: .field private button1:Landroid/widget/Button;方法定义方法定义如下: .method <权限修饰符> <非权限修饰符> <名称>(<参数类型>)<返回值类型> ....end method要注意如果有多个参数,参数之间是紧密挨着的,没有逗号也没有空格。如果某个方法的参数是int, int, String,那么应该表示为IILjava/lang/String;。 .locals方法里面可以包含很多很多东西,可以说是反编译的重点。首先,方法开头处可能会含有局部变量个数声明和参数声明。.locals <个数>可以用于变量个数声明,比如声明了.locals 10之后,我们就可以直接使用v0到v9的寄存器。 .param另外,参数虽然也占用寄存器,但是声明是不在一起的。.param px,"<名称>"用于声明参数。不知道是不是必需的。 .prologue之后.prologue的下面是方法中的代码。代码是接下来要讲的东西。 .line代码之间可能会出现.line <行号>,用来标识 Java 代码中对应的行,不过这个是非强制性的,修改之后对应不上也无所谓。 .local还可能出现局部变量声明,.local vx, "<名称>":<类型>。这个也是非强制性的,只是为了让你清楚哪些是具名变量,哪些是临时变量。临时变量没有这种声明,照样正常工作。甚至你把它改成不匹配的类型(int改成Object),也可以正常运行。 数据定义https://wx3.sinaimg.cn/large/0060lm7Tly1g1iq69zoosj30ld0c7jsd.jpg
|