zxlben

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Dalvik系列01 - 字节码格式

一般设计

  • 机器模型和调用约定是按照真实的物理机的体系结构和C风格的调用约定设计的:
    • 机器模型是基于寄存器的,在字节码创建完成后,栈桢就是固定的。每个栈桢包含了一组寄存器(由该栈桢的方法决定),栈桢也包含了一些附加数据用于方法的执行,比如程序计数器(PC)、包含该方法的dex文件等。
    • 对于基本类型(比如整型和浮点型),寄存器是32位的。64位的数据采用相邻的寄存器对表示,寄存器对没有对齐要求。
    • 对于对象引用类型,寄存器有足够的位宽来保存对象引用。
    • 从值的角度说,(Object)null==(int)0
    • 方法的N个调用参数按照顺序位于栈帧的最后N个寄存器,宽的参数占用2个寄存器。对于非静态成员方法,this是第一个参数。
  • 指令流的存储单元是16位的。有些指令中某些位是被忽略的,这些位必须为0。
  • 指令不会无条件的将操作数限制为特定类型。例如,没有指明类型的32位寄存器move指令,并不会限制于整型或者浮点型。
  • 有单独的,可枚举的,经过索引的常量池用于存储字符串,类型,字段和方法。
  • 字面量数据包括在指令中。
  • 实际上,一个方法需要超过16个寄存器并不常见,但是需要8个以上的寄存器是相当常见的。因此许多指令将寻址范围限制为前16个寄存器。在合理的情况下,指令可以将寻址范围扩大到前256个寄存器。除此之外,有些指令的寄存器寻址范围更大,包括一对 catch-all move指令,寻址范围可以达到v0-v65535。当有些指令需要的数据不在寻址范围内时,就需要将将数据从原有的寄存器放到比较低的寄存器中,当操作完成后,将结果在放回高寄存器中去。
  • 存在一些用于保持可变长度数据载荷的“伪指令”,这些数据被常规指令所引用(比如:fill-array-data)。在正常的指令执行过程中不会遇到这些指令。除此之外,有些指令必须位于偶数的字节码偏移(实际上由于字节码的存储单元是以2字节为单位的,所以实际上是四字节对齐)。为了满足这些指令的要求,dex生成工具必须插入一个nop指令作为一个"空格",否则这类指令将无法对齐。最后,虽然不是必须的,大多数工具会在函数的末尾插入这些指令,否则 it would likely be the case that additional instructions would be needed to branch around them.
  • 当被安装到一个正在运行的系统时,有些指令可能会被修改,改变它们的格式,被称作“安装时静态链接优化".这可以使得代码执行更快。
  • 人类语法与助记符
    • 先目标后源的指令参数顺序
    • 有些操作码(opcode)有一个用于消除歧义的后缀,指明了它操作的数据类型:

      • 32-bit的数据类型没有标记
      • 64-bit的数据类型有”-wide"标记
      • 类型相关的操作码(opcode)带有其类型的后缀或者一个缩写,包括:-boolean -byte -char -short -int -long -float -double -object -string -class -void.
    • 有些操作码有一个用于消除歧义的后缀,用于区分有相同语义,但是指令布局或者选项不同的指令。这些后缀和指令采用一个斜杠'/'进行分割。(用于消除人类模糊)
    • 例如指令"move-wide/from16 vAA, vBBBB"
      • move是基本的操作码(opcode),指明了基本操作(传送一个寄存器的值)
      • wide是一个名字后缀,指明指令操作一个宽(64bit)的数据
      • from16是操作码后缀,指明操作码有一个16位的寄存器作为源
      • vAA是目标寄存器(通过操作暗示;再次提及:目标参数在第一个),必须在v0-v255
      • vBBBB是源寄存器,需要在v0-v65535
    • 请参考<Dalvik系列02 - 指令格式>,获取各种指令格式的详细信息(在"Op & Format一列")
    • 参考dex文件格式文档获取字节码在整个文件中的位置

字节码汇总

  

 

参考链接:https://source.android.com/devices/tech/dalvik/dalvik-bytecode.html

posted on 2016-04-18 10:58  zxlben  阅读(321)  评论(0)    收藏  举报