精华内容
下载资源
问答
  • Dalvik

    千次阅读 2021-09-03 11:21:57
    Dalvik字节码: 1.了解dalvik寄存器 dalvik中的寄存器都是32位 2.寄存器之v命名法与p命名法 参数寄存器 P0-Pn 局部变量寄存器 V0-Vn 3.dex文件反汇编工具 smali.jar\ddx.jar 4.类型 smali==>Java V ...

    Dalvik字节码:

    1.了解dalvik寄存器

    dalvik中的寄存器都是32位

    2.寄存器之v命名法与p命名法

    参数寄存器 P0-Pn

    局部变量寄存器 V0-Vn

    3.dex文件反汇编工具

             smali.jar\ddx.jar

    4.类型

    smali==>Java

    V void

    Z boolean 

    B byte

          C    char

    S short

    I int

    J long

    F float

    D double

    L java类

    [ 数组

    5.字段

    Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;

    6.方法

    Lpackage/name/ObjectName;->MethodName (III) Z

    Dalvik指令:

            基础字节码-名称后缀/字节码后缀 目的寄存器  源寄存器

            名称后缀是wide,表示数据宽度为64位

            字节码后缀是from16,表示源寄存器为16位

    空操作指令

            nop

    数据操作指令

            move(-wide/-object/-result/-result-object/-result-wide/- exception)

            move(-wide/-object)/from16

            move(-object)/16

    返回指令(重点)

            return-void(表示方法的放回值为空)

            return(表示方法的反回值为32位非对象类型的值)

            return-wide(表示方法的反回值为64位非对象类型的值)

            return-object(表示方法的反回值为对象类型的值)

    数据定义指令(重点)

            const(-wide/-string/-class)

            const/4

            const(-wide)/16

            const(-wide)/32

            const(-wide)/high16

    实例操作指令

            check-cast(类型转换)

            instance-of(检查)  

            new-instance(新建) 

    数组操作指令

            array-length(获取数组长度)

            new-array(新建数组)

            filled-new-array(定义数组并初始化)

            filled-new-array/range(定义数组并初始化/指定取值范围)

            filled-array-data(数组元素取值与赋值)

    异常指令(throw)

    跳转指令(重点)

            goto 紧跟一个标签直接跳转到标签所在位置

            packed-switch(有规律)、sparse-switch(无规律)

            if-eq(等于)/if-ne(不等于)

            if-lt(小于)/if-le(小于等于)

            if-gt(大于)/if-ge(大于等于)

    比较指令(cmp)

            大于(1)/等于(0)/小于(-1)=>cmpg、cmp

            大于(-1)/等于(0)/小于(1)=>cmpl

    字段操作指令

            普通字段=>iget(读)/iput(写)

            静态字段=>sget(读)/sput(写)

    方法调用指令(重点)

            invoke-virtual(调用实例的虚方法) Java当中的普通方法

            invoke-super(调用实例的父类/基类方法) 

            invoke-direct(调用实例的直接方法) 调用java当中的构造方法

            invoke-static(调用实例的静态方法)

            invoke-interface(调用实例的接口方法)

    数据转换指令

            neg-数据类型=>求补

            not-数据类型=>求反

    数据类型1-to-数据类型2=>将数据类型1转换为数据类型2

    数据运算指令

            add/sub/mul/div/rem  加/减/乘/除/模

            and/or/xor  与/或/非

            sh1/shr/ushr 有符号左移/有符号右移/无符号右移

    smali文件:

      无论是普通类、抽象类、接口类或者内部类,在反编译出的代码中,它 们都以单独的smali 文件来存放。每个 smali 文件都由若干条语句组成, 所有的语句都遵循着一套语法规范。

    1.描述类的信息

    .class < 访问权限> [ 修饰关键字] < 类名>

    .super < 父类名>

    .source <源文件名>

     2. 静态字段

    # static fields

    .field < 访问权限> static [ 修饰关键字] < 字段名>:< 字段类型>

     3.实例字段

    # instance fields

    .field < 访问权限> [ 修饰关键字] < 字段名>:< 字段类型>

     4.直接方法

    # direct methods

    .method <访问权限> [ 修饰关键字] < 方法原型>

    <.locals> “.locals ”指定了使用的局部变量的个数
    [.param] “.param”指定了方法的参数

    [.prologue] “.prologue ”指定了代码的开始处

    [.line]          “.line ”指定了该处指令在源代码中的行号

    <代码体>

     .end method

     5. 虚方法的声明与直接方法相同,只是起始处的注释为“virtual  methods”。

     6.接口

     # interfaces

       .implements < 接口名>“.implements ”是接口关键字,后面的接口

       名是 DexClassDef 结构中 interfacesOff 字段指定的内容。

     7.注解

      # annotations

        .annotation [ 注解属性] < 注解类名>

    [ 注解字段 = 值]

      .end annotation

       注解的作用范围可以是类、方法或字段。如果注解的作用范围是类,   “.annotation ”指令会直接定义在 smali 文件中,如果是方法或字段,“.annotation ”指令则会包含在方法或字段定义中。

    展开全文
  • dalvik

    2015-06-11 21:19:00
    Dalvik VM 和 Java VM的区别 Dalvik VM基于寄存器,JVM基于栈。Dalvik VM基于?二地址\三地址?,而JVM基于?零地址?。 转载于:https://www.cnblogs.com/next-ten-years-2023/p/4570208.html...

    Dalvik VM 和 Java VM的区别

    1. Dalvik VM基于寄存器,JVM基于栈。Dalvik VM基于?二地址\三地址?,而JVM基于?零地址?。

    转载于:https://www.cnblogs.com/next-ten-years-2023/p/4570208.html

    展开全文
  • Dalvik opcodes

    2018-02-08 12:36:33
    Dalvik是Google公司自己设计用于Android平台的虚拟机。 Dalvik虚拟机是Google等厂商合作开发的Android移动设备平台的核心组成部分之一。 它可以支持已转换为** .dex格式**的Java应用程序的运行,.dex格式是专为...
  • Dalvik源码

    2017-06-16 10:36:25
    在SDKandroid中是不能看Dalvik的,想看还需要!有需要的可以下载
  • Dalvik虚拟机 PPT版

    千次下载 热门讨论 2013-10-23 01:26:13
    Android应用程序是运行在Dalvik虚拟机里面的,并且每一个应用程序对应有一个单独的Dalvik虚拟机实例。Android应用程序中的Dalvik虚拟机实例实际上是从Zygote进程的地址空间拷贝而来的,这样就可以加快Android应用...
  • dalvik.zip

    2019-06-27 11:07:27
    dalvik源码离线帮助文档,全套的,方便对照查询,有些小伙伴可能不会下载,这里就分享一下
  • Android Dalvik

    2011-03-07 09:45:46
    Android Dalvik 虚拟机,想了解Android Dalvik 的朋友看过来
  • 进入 Android Dalvik 虚拟机,android dalvik介绍 Dalvik 虚拟机的特点——掌握 Android 程序的运行原理 Android 系统的架构采用分层思想,这样的好处是拥有减少各层之间的依赖性、便于独 立分发、容易收敛问题和...
  • Dalvik虚拟机

    2020-12-10 11:15:22
    1.Dalvik虚拟机和java虚拟机的异同点 最显著曲边是他们分别具有不同的类文件格式以及指令集 a. Dalvik虚拟机执行的是dex(Dalvik Executable)格式的类文件,一个dex文件可包含若干个类,dex将各个类中重复的字符串...

    1.Dalvik虚拟机和java虚拟机的异同点

    最显著曲边是他们分别具有不同的类文件格式以及指令集

    a. Dalvik虚拟机执行的是dex(Dalvik Executable)格式的类文件,一个dex文件可包含若干个类,dex将各个类中重复的字符串和其他常数只保存一次,从而节省空间,适用于内存和处理器速度优先的手机系统;而Java虚拟机使用的是.class格式类文件,一个class文件只包含一个类;
    b. Dalvik虚拟机使用的指令是基于寄存器;Java虚拟机使用的指令集是基于堆栈的;各有优劣

    2.Dalvik虚拟机自身优化措施

    a. 将多个类文件合成到一个dex文件中,节省空间
    b. 使用只读内存映射方式加载dex文件,以便可以多进程共享dex文件,节省程序加载时间;
    c. 提前调整好字节序和字对齐方式,使得它们更适合本机机器,一遍提高指令执行速度;
    d. 尽量提前执行字节码校验,提高程序的加载速度;
    e. 需要重写字节码的优化要提前进行

    3.内存管理(重点)

    Dalvik虚拟机的内存大体上可以分为Java Object Heap、Bitmap Memory和Native Heap三种。

    Java Object Heap是用来分配Java对象的,也就是我们在代码new出来的对象都是位于Java Object Heap上的。Dalvik虚拟机在启动的时候,可以通过-Xms和-Xmx选项来指定Java Object Heap的最小值和最大值。为了避免Dalvik虚拟机在运行的过程中对Java Object Heap的大小进行调整而影响性能,我们可以通过-Xms和-Xmx选项来将它的最小值和最大值设置为相等。
    Java Object Heap的最小和最大默认值为2M和16M,但是手机在出厂时,厂商会根据手机的配置情况来对其进行调整,例如,G1、Droid、Nexus One和Xoom的Java Object Heap的最大值分别为16M、24M、32M 和48M。我们可以通过ActivityManager类的成员函数getMemoryClass来获得Dalvik虚拟机的Java Object Heap的最大值。
    ActivityManager类的成员函数getMemoryClass的实现如下所示:

    public class ActivityManager {  
        ......  
    
        /** 
         * Return the approximate per-application memory class of the current 
         * device.  This gives you an idea of how hard a memory limit you should 
         * impose on your application to let the overall system work best.  The 
         * returned value is in megabytes; the baseline Android memory class is 
         * 16 (which happens to be the Java heap limit of those devices); some 
         * device with more memory may return 24 or even higher numbers. 
         */  
        public int getMemoryClass() {  
            return staticGetMemoryClass();  
        }  
    
        /** @hide */  
        static public int staticGetMemoryClass() {  
    // Really brain dead right now -- just take this from the configured  
    // vm heap size, and assume it is in megabytes and thus ends with "m".  
    String vmHeapSize = SystemProperties.get("dalvik.vm.heapsize", "16m");  
    return Integer.parseInt(vmHeapSize.substring(0, vmHeapSize.length()-1));  
        }  
    
        ......  
    }
    
    

    这个函数定义在文件frameworks/base/core/java/android/app/ActivityManager.java中。
    Dalvik虚拟机在启动的时候,就是通过读取系统属性dalvik.vm.heapsize的值来获得Java Object Heap的最大值的,而ActivityManager类的成员函数getMemoryClass最终也通过读取这个系统属性的值来获得Java Object Heap的最大值。

    这个Java Object Heap的最大值也就是我们平时所说的Android应用程序进程能够使用的最大内存。这里必须要注意的是,Android应用程序进程能够使用的最大内存指的是能够用来分配Java Object的堆。

    Bitmap Memory也称为External Memory,它是用来处理图像的。在HoneyComb之前,Bitmap Memory是在Native Heap中分配的,但是这部分内存同样计入Java Object Heap中,也就是说,Bitmap占用的内存和Java Object占用的内存加起来不能超过Java Object Heap的最大值。这就是为什么我们在调用BitmapFactory相关的接口来处理大图像时,会抛出一个OutOfMemoryError异常的原因:

    java.lang.OutOfMemoryError: bitmap size exceeds VM budget
    
    

    在HoneyComb以及更高的版本中,Bitmap Memory就直接是在Java Object Heap中分配了,这样就可以直接接受GC的管理。

    Native Heap就是在Native Code中使用malloc等分配出来的内存,这部分内存是不受Java Object Heap的大小限制的,也就是它可以自由使用,当然它是会受到系统的限制。但是有一点需要注意的是,不要因为Native Heap可以自由使用就滥用,因为滥用Native Heap会导致系统可用内存急剧减少,从而引发系统采取激进的措施来Kill掉某些进程,用来补充可用内存,这样会影响系统体验。

    此外,在HoneyComb以及更高的版本中,我们可以在AndroidManifest.xml的application标签中增加一个值等于“true”的android:largeHeap属性来通知Dalvik虚拟机应用程序需要使用较大的Java Object Heap。事实上,在内存受限的手机上,即使我们将一个应用程序的android:largeHeap属性设置为“true”,也是不能增加它可用的Java Object Heap的大小的,而即便是可以通过这个属性来增大Java Object Heap的大小,一般情况也不应该使用该属性。为了提高系统的整体体验,我们需要做的是致力于降低应用程序的内存需求,而不是增加增加应用程序的Java Object Heap的大小,毕竟系统总共可用的内存是固定的,一个应用程序用得多了,就意味意其它应用程序用得少了。

    3.垃圾收集(GC)

    Dalvik虚拟机可以自动回收那些不再使用了的Java Object,也就是那些不再被引用了的Java Object。垃圾自动收集机制将开发者从内存问题中解放出来,极大地提高了开发效率,以及提高了程序的可维护性。

    我们知道,在C或者C++中,开发者需要手动地管理在堆中分配的内存,但是这往往导致很多问题。例如,内存分配之后忘记释放,造成内存泄漏。又如,非法访问那些已经释放了的内存,引发程序崩溃。如果没有一个好的C或者C++应用程序开发框架,一般的开发者根本无法驾驭内存问题,因为程序大了之后,很容易造成失控。最要命的是,内存被破坏的时候,并不一定就是程序崩溃的时候,它就是一颗不定时炸弹,说不准什么时候会被引爆,因此,查找原因是非常困难的。

    从这里我们也可以推断出,Android为什么会选择Java而不是C/C++来作为应用程序开发语言,就是为了能够让开发远离内存问题,而将精力集中在业务上,开发出更多更好的APP来,从而迎头赶超iOS。当然,Android系统内存也存在大量的C/C++代码,这只要考虑性能问题,毕竟C/C++程序的运行性能整体上还是优于运行在虚拟机之上的Java程序的。不过,为了避免出现内存问题,在Android系统内部的C++代码,大量地使用了智能指针来自动管理对象的生命周期。选择Java来作为Android应用程序的开发语言,可以说是技术与商业之间一个折衷,事实证明,这种折衷是成功的。

    回到正题,在GingerBread之前,Dalvik虚拟使用的垃圾收集机制有以下特点:

    a. Stop-the-world,也就是垃圾收集线程在执行的时候,其它的线程都停止;
    Full heap collection,也就是一次收集完全部的垃圾;
    一次垃圾收集造成的程序中止时间通常都大于100ms。

    b. 在GingerBread以及更高的版本中,Dalvik虚拟使用的垃圾收集机制得到了改进,如下所示:
    Cocurrent,也就是大多数情况下,垃圾收集线程与其它线程是并发执行的;
    Partial collection,也就是一次可能只收集一部分垃圾;
    一次垃圾收集造成的程序中止时间通常都小于5ms。

    Dalvik虚拟机执行完成一次垃圾收集之后,我们通常可以看到类似以下的日志输出:

    D/dalvikvm(9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms
    
    

    在这一行日志中,GC_CONCURRENT表示GC原因,2049K表示总共回收的内存,3571K/9991K表示Java Object Heap统计,即在9991K的Java Object Heap中,有3571K是正在使用的,4703K/5261K表示External Memory统计,即在5261K的External Memory中,有4703K是正在使用的,2ms+2ms表示垃圾收集造成的程序中止时间

    4.即时编译(JIT)

    前面提到,JIT是相对AOT而言的,即JIT是在程序运行的过程中进行编译的,而AOT是在程序运行前进行编译的。在程序运行的过程中进行编译既有好处,也有坏处。好处在于可以利用程序的运行时信息来对编译出来的代码进行优化,而坏处在于占用程序的运行时间,也就是说不能花太多时间在代码编译和优化之上。
    为了解决时间问题,JIT可能只会选择那些热点代码进行编译或者优化。根据2-8原则,一个程序80%的时间可能都是在重复执行20%的代码。因此,JIT就可以选择这20%经常执行的代码来进行编译和优化。
    为了充分地利用好运行时信息来优化代码,JIT采用一种激进的方法。JIT在编译代码的时候,会对程序的运行情况进行假设,并且按照这种假设来对代码进行优化。随着程序的代码,如果前面的假设一直保持成立,那么JIT就什么也不用做,因此就可以提高程序的运行性能。一旦前面的假设不再成立了,那么JIT就需要对前面编译优化的代码进行调整,以便适应新的情况。这种调整成本可能是很昂贵的,但是只要假设不成立的情况很少或者几乎不会发生,那么获得的好处还是大于坏处的。由于JIT在编译和优化代码的时候,对程序的运行情况进行了假设,因此,它所采取的激进优化措施又称为赌博,即Gambling。

    Dalvik虚拟机从Android 2.2版本开始,才支持JIT,而且是可选的。在编译Dalvik虚拟机的时候,可以通过WITH_JIT宏来将JIT也编译进去,而在启动Dalvik虚拟机的时候,可以通过-Xint:jit选项来开启JIT功能。

    5.Java本地调用(JNI)

    无论如何,虚拟机最终都是运行在目标机器之上的,也就是说,它需要将自己的指令翻译成目标机器指令来执行,并且有些功能,需要通过调用目标机器运行的操作系统接口来完成。这样就需要有一个机制,使得函数调用可以从Java层穿越到Native层,也就是C/C++层。这种机制就称为Java本地调用,即JNI。当然,我们在执行Native代码的时候,有时候也是需要调用到Java函数的,这同样是可以通过JNI机制来实现。也就是说,JNI机制既支持在Java函数中调用C/C++函数,也支持在C/C++函数中调用Java函数。

    事实上,Dalvik虚拟机提供的Java运行时库,大部分都是通过调用目标机器操作系统接口来实现的,也就是通过调用Linux系统接口来实现的。例如,当我们调用android.os.Process类的成员函数start来创建一个进程的时候,最终会调用到linux系统提供的fork系统调用来创建一个进程。

    同时,为了方便开发者使用C/C++语言来开发应用程序,Android官方提供了NDK。通过NDK,我们就可以使用JNI机制来在Java函数中调用到C/C++函数。不过Android官方是不提倡使用NDK来开发应用程序的,这从它对NDK的支持远远不如SDK的支持就可以看得出来。

    6. 进程和线程管理

    别是考虑到多核的情况,因此,就完全没有必要在虚拟机中提供一个进程和线程库。

    Dalvik虚拟机运行在Linux操作系统之上。

    关于Android应用程序进程,它有两个很大的特点,下面我们就简要介绍一下。

    第一个特点是每一个Android应用程序进程都有一个Dalvik虚拟机实例。这样做的好处是Android应用程序进程之间不会相互影响,也就是说,一个Android应用程序进程的意外中止,不会影响到其它的Android应用程序进程的正常运行。

    第二个特点是每一个Android应用程序进程都是由一种称为Zygote的进程fork出来的。Zygote进程是由init进程启动起来的,也就是在系统启动的时候启动的。Zygote进程在启动的时候,会创建一个虚拟机实例,并且在这个虚拟机实例将所有的Java核心库都加载起来。每当Zygote进程需要创建一个Android应用程序进程的时候,它就通过复制自身来实现,也就是通过fork系统调用来实现。这些被fork出来的Android应用程序进程,一方面是复制了Zygote进程中的虚拟机实例,另一方面是与Zygote进程共享了同一套Java核心库。这样不仅Android应用程序进程的创建过程很快,而且由于所有的Android应用程序进程都共享同一套Java核心库而节省了内存空间。

    展开全文
  • 下一节,介绍Dalvik指令集Android Dalvik虚拟机之Dalvik指令集-Smali汇编解析 Dalvik虚拟机为自己专门设计了一套指令集,并且制定了自己的指令格式与调用规范。我们将Dalvik指令集组成的代码称为Dalvik汇编代码,将...

    下一节,介绍Dalvik指令集Android Dalvik虚拟机之Dalvik指令集-Smali汇编解析

    Dalvik虚拟机为自己专门设计了一套指令集,并且制定了自己的指令格式与调用规范。我们将Dalvik指令集组成的代码称为Dalvik汇编代码,将这种代码表示的语言称为Dalvik汇编语言(Dalvik汇编语言并不是正式的语言,只是描述Dalvik指令集代码的一种称呼)。

    1. Dalvik指令格式

    一段Dalvik汇编代码由一系列Dalvik指令组成,指令语法由指令的位描述与指令格式标识来决定。位描述约定如下:

    • 每16位的字采用空格分隔开来。

    • 每个字母表示4位,每个字母按顺序从高字节开始,排列到低字节。每4位之间可能使有竖线“|”来表示不同的内容。

    • 顺序采用A~Z的单个大写字母作为一个4位的操作码,op表示一个8位的操作码。

    • “Ø”来表示这字段所有位为0值。

    以指令格式“A|G|op  BBBB  F|E|D|C”为例:

    指令中间有两个空格,每个分开的部分大小为16位,所以这条指令由三个16位的字组成。第一个16位是“A|G|op”,高8位由A与G组成,低字节由操作码op组成。第二个16位由BBBB组成,它表示一个16位的偏移值。第三个16位分别由F,E,D,C共四个4位组成,在这里它们表示寄存器参数。

    单独使用位标识还无法确定一条指令,必须通过指令格式标识来指定指令的格式编码。它的约定如下:

    • 指令格式标识大多由三个字符组成,前两个是数字,最后一个是字母。

    • 第一个数字是表示指令有多少个16位的字组成。

    • 第二个数字是表示指令最多使用寄存器的个数。特殊标记“r”标识使用一定范围内的寄存器。

    • 第三个字母为类型码,表示指令用到的额外数据的类型。取值见下表。

    还有一种特殊的情况是末尾可能会多出另一个字母,如果是字母 s 表示指令采用静态链接,如果是字母 i 表示指令应该被内联处理。指令格式标识的类型码如下:

    助记符                                位大小                                       说明
    b88位有符号立即数
    c16,32常量池索引
    f16接口常量(仅对静态链接格式有效)
    h16有符号立即数(32位或64位数的高值位,低值位为0)
    i32立即数,有符号整数或32位浮点数
    m16方法常量(仅对静态链接格式有效)
    n44位的立即数
    s16短整型立即数
    t8,16,32跳转,分支
    x0无额外数据

    以指令格式标识 22x 为例:

    第一个数字2表示指令有两个16位字组成,第二个数字2表示指令使用到2个寄存器,第三个字母x表示没有使用到额外的数据。

    另外,Dalvik指令对语法做了一些说明,它约定如下:

    • 每条指令从操作码开始,后面紧跟参数,参数个数不定,每个参数之间采用逗号分开。

    • 每条指令的参数从指令第一部分开始,op位于低8位,高8位可以是一个8位的参数,也可以是两个4位的参数,还可以为空,如果指令超过16位,则后面部分依次作为参数。

    • 如果参数采用“vX”的方式表示,表明它是一个寄存器,如v0,v1等。这里采用v而不用r是为了避免与基于该 虚拟机架构本身的寄存器命名产生冲突,如ARM架构寄存器命名采用r开头。

    • 如果参数采用“#+X”的方法表示,表明它是一个常量数字。

    • 如果参数采用“+X”的方式表示,表明它是一个相对指令的地址偏移。

    • 如果参数采有“kind@X”的方式表示,表明它是一个常量池索引值。其中kind表示常量池类型,它可以是“string”(字符串常量池索引),“type”(类型常量池索引),“field”(字段常量池索引)或者“meth”(方法常量池索引)。

    以指令 “op vAA, string@BBBB” 为例:指令用到了1个寄存器参数 vAA,并且还附加了一个字符串常量池索引 string@BBBB,其实这条指令格式代表着 const-string 指令。

    2. DEX文件反汇编工具

    目前DEX可执行文件主流的反汇编工具有:BakSmali与Dedexer。两者的反汇编效果都不错,在语法上也有着很多的相似处。下面通过代码对比两者的语法差异,测试代码采用上一节的Hello.java,首先使用dx工具生成Hello.dex文件,然后在命令提示符下输入以下命令使用baksmali.jar反汇编 Hello.dex:

    $ java -jar baksmali.jar -o baksmaliout Hello.dex

    命令成功执行会在baksmaliout目录下生成Hello.smali文件,使用文本编辑器打开它:

    # virtual methods
    .method public foo(II)I
        .registers 5
        .parameter
        .parameter
        .prologue
        .line 3
        add-int v0, p1, p2
        sub-int v1, p1, p2
        mul-int/2addr v0, v1
        return v0
    .end method

    执行以下命令使用ddx.jar(Dedexer的jar文件)反汇编Hello.dex:

    $ java -jar ddx.jar -d ddxout Hello.dex

    命令成功执行后,会在ddxout目录下生成Hello.ddx文件,使用文本编辑器打开它,foo()函数代码如下:

    .method public foo(II)I
    .limit registers 5
    ; this: v2 (LHello;)
    ; parameter[0] : v3 (I)
    ; parameter[1] : v4 (I)
    .line 3
        add-int v0, v3, v4
        sub-int v1, v3, v4
        mul-int/2addr  v0,v1
        return v0
    .end method

    两种反汇编代码大体的结构组织是一样的,在方法名,字段类型与代码指令序列上它们保持一致,具体的差异表现在一些语法细节上。对比之下,可以发现如下不同点:

    • 前者使用.registers指令指定函数用到的寄存器数目,后者在.registers指令前加了limit前缀。

    • 前者使寄存器p0作为this引用,后者使用寄存器v2作为this引用。

    • 前者使用一条.parameter指令指定函数一个参数,后者则使用parameter数组指定参数寄存器。

    • 前者使用.prologue指令指定函数代码起始处,后者却没有。

    • 两者寄存器表示法不同,前者使用p命名法,后者使用v命名法。

    BakSmali提供反汇编功能的同时,还支持使用Smali工具打包反汇编代码重新生成dex文件,这个功能被广泛应用于apk文件的修改,补丁,破解等场合,因而更加受到开发人员的青睐。本系列blog默认都将采用Smali语法格式。

    3. 了解Dalvik寄存器

    Dalvik虚拟机基于寄存器架构,在代码中大量地使用到了寄存器。Dalvik虚拟机是作用于特定架构的CPU上运行的,在设计之初采用了ARM架构,ARM架构的CPU本身集成了多个寄存器,Dalvik将部分寄存器映射到了ARM寄存器上,还有一部分则通过调用栈进行模拟。注意:Dalvik中用到的寄存器都是32位的,支持任何类型,64位类型用2个相邻寄存器表示。(这节具体的内容还是看书吧!非虫的书)

    4. 两种不同的寄存器表示方法——v命名法与p命名法

    前面曾多次提到v命名法与p命名法,它们是Dalvik字节码中两种不同的寄存器表示方法。下面我们来看看,它们在表现上有一些什么样的区别。

    假设一个函数使用到M个寄存器,并且该函数有N个参数,根据Dalvik虚拟机参数传递方式中的规定:参数使用最后的N个寄存器,局部变量使用从v0开始的前(M-N)个寄存器。如前面的小节中,foo()函数使用到了5个寄存器,2个显式的整形参数,其中foo()函数是Hello类的非静态方法,函数被调用时会传入一个隐式的Hello对象引用,因此,实际传入的参数数量是3个。根据传参规则,局部变量将使用前2个寄存器,参数会使用后3个寄存器。

    v命名法采用以小写字母“v”开头的方式表示函数中用到的局部变量与参数,所有的寄存器命名从v0开始,依次递增。对于foo()函数,v命名法会用到v0,v1,v2,v3,v4等五个寄存器,v0与v1用来表示函数的局部变量寄存器,v2表示被传入的Hello对象的引用,v3与v4分别表示两个传入的整形参数。

    p命令法对函数的局部变量寄存器命名没有影响,它的命名规则是:函数中引入的参数命名从p0开始,依次递增。对于foo()函数,p命名法会用到v0,v1,p0,p1,p2等五个寄存器,v0与v1同样用来表示函数的局部变量寄存器,p0表示被传入的Hello对象的引用,p1与p2分别表示两个传入的整形参数。

    对于有M个寄存器及N个参数的函数foo()来说,v命名法与p命名法的表现形式如下表所示。通过观察可以发现,使用p命名法表示的Dalvik汇编代码,通过寄存器的前缀更容易判断寄存器到底是局部变量寄存器还是参数寄存器,在Dalvik汇编代码较长,使用寄存器较多的情况下,这种优势将更加明显。表:v命名法与p命名法:

    v命名法                                           p命名法                                   寄存器含义
    v0v0第一个局部变量寄存器
    v1v1第二个局部变量寄存器
    ......中间的局部变量寄存器依次递增
    vM-Np0第一个参数寄存器
    ......中间的参数寄存器分别依次递增
    vM-1pN-1第N个参数寄存器

    5. Dalvik字节码的类型,方法与字段表示方法

    Dalvik字节码有着一套自己的类型,方法与字段表示方法,这些方法与Dalvik虚拟机指令集一起组成了一条条的Dalvik汇编代码。

    5.1. 类型

    Dalvik字节码只有两种类型,基本类型与引用类型。Dalvik使用这两种类型来表示Java语言的全部类型,除了对象与数组属于引用对象外,其他的Java类型都是基本类型。BakSmali严格遵守了DEX文件格式中的类型描述符定义。类型描述符对照如下表:

    语法                                     含义
    Vvoid,只用于返回值类型
    Zboolean
    Bbyte
    Sshort
    Cchar
    Iint
    Jlong
    Ffloat
    Ddouble
    LJava类类型
    [数组类型

    每个Dalvik寄存器都是32位大小,对于小于或等于32位长度的类型来说,一个寄存器就可以存放该类型的值。而像J,D等64位的类型,它们的值是使用相邻两个寄存器来存储的,如 v0 与 v1,v3 与 v4等。

    L类型可以表示Java类型中的任何类。这些类在Java代码中以 package.name.ObjectName方式引用,到了Dalvik汇编代码中,它们以Lpackage/name/ObjectName; 形式表示,注意最后有个分号,L表示后面跟着一个Java类,package/name/表示对象所在的包,ObjectName表示对象的名称,最后的分号表示对象名结束。例如:Ljava/lang/String;相当于java.lang.String。

    [类型可以表示所有基本类型的数组。[后面紧跟基本类型描述符,如 [I 表示一个整型一维数组,相当于Java中的int[]。多个[在一起时可用来表示多维数组,如 [[I 表示int[][],[[[I表示 int[][][]。注意多维数组的维数最大为255个。L与[ 可以同时使用用来表示对象数组。如 [Ljava/lang/String;就表示Java中的字符串数组。

    5.2. 方法 

    方法的表现形式比类名要复杂一些,Dalvik使用方法名,类型参数与返回值来详细描述一个方法。这样做一方面有助于Dalvik虚拟机在运行时从方法表中快速地找到正确的方法,另一方面,Dalvik虚拟机也可以使用它们来做一些静态分析,比如Dalvik字节码的验证与优化。方法格式如下:

    Lpackage/name/ObjectName;->Methodname(III)Z

    在这个例子中,Lpackage/name/ObjectName;应该理解为 个类型,MethodName为具体的方法名,(III)Z是方法的签名部分,其中括号 内的III为方法的参数(在此为三个整型参数),Z表示方法的返回类型(boolean类型)。

    下面是一个更为复杂的例子:

    method(I[[IILjava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;

    按照上面的知识,将其转换成Java形式的代码应该为:

    String method(int, int[][], int, String, Object[])

    BakSmali生成的方法代码 .method指令开始,以 .end method指令结束,根据方法类型的不同,在方法指令开始前可能会用“”号加以注释。如“# virtual methods”表示这是一个虚方法,“#direct methods”表示这是一个直接方法。

    5.3. 字段

    字段与方法很相似,只是字段没有方法签名域中的参数与返回值,取而代之的是字段的类型。同样,Dalvik虚拟机定位字段与字节码静态分析时会用到它。字段的格式如下:

    Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;

    字段由类型(Lpackage/name/ObjectName;),字段名(FieldName)与字段类型(Ljava/lang/String;)组成。其中字段名与字段类型中间用冒号“”隔开。

    BakSmali生成的字段代码以 .field指令开头,根据字段类型的不同,在字段指令的开始可能会用“#”号加以注释,如:“# instance fields”表示这是一个实例字段,“#static fields”表示这是一个静态字段。

    原文:https://my.oschina.net/fhd/blog/365337

    展开全文
  • Dalvik 虚拟机

    2019-09-25 20:05:57
    Dalvik 虚拟机介绍 Dalvik 虚拟机执行程序 JIT 转载于:https://www.cnblogs.com/hanhandaren/p/11095990.html
  • Dalvik虚拟机操作码pdf

    2018-07-08 01:10:50
    Dalvik虚拟机操作码pdf Dalvik虚拟机操作码pdf Dalvik虚拟机操作码pdf
  • 《Android Dalvik虚拟机结构及机制剖析:第1卷 Dalvik虚拟机结构剖析》是一本以情景方式对Android的源代码进行深入分析的书,内容广泛,主要从Dalvik虚拟机整体结构、获取和编译Dalvik虚拟机的源码、源码分析辅助...
  • debugging_dalvik

    2014-07-02 12:05:06
    Debugging Dalvik programs with IDA
  • dalvik linux-x86.zip

    2020-10-29 09:23:20
    linux-x86下的android虚拟机dalvik。可以在linux下运行android的dex。./dalvik/dalvik -cp g.dex:gg.dex GoogleDevlik
  • Android Dalvik虚拟机

    2019-03-26 18:03:57
    Android Dalvik虚拟机Dalvik虚拟机的特点--掌握Android 程序的运行原理Dalvik 虚拟机概述Dalvik 虚拟机与Java 虚拟机的区别Java 虚拟机运行的是Java 字节码, Dalvik 虚拟机运行的是Dalvik 字节码。Dalvik可执行文件...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 62,522
精华内容 25,008
关键字:

dalvik