Dalvik 可执行文件格式  

您所在的位置:网站首页 dbg是什么格式文件 Dalvik 可执行文件格式  

Dalvik 可执行文件格式  

2023-05-19 19:59| 来源: 网络整理| 查看: 265

本文档介绍了 .dex 文件的版式和内容,这类文件用于保存一系列类定义及其关联的辅助数据。

类型指南 名称 说明 byte 8 位有符号整数 ubyte 8 位无符号整数 short 16 位有符号整数,采用小端字节序 ushort 16 位无符号整数,采用小端字节序 int 32 位有符号整数,采用小端字节序 uint 32 位无符号整数,采用小端字节序 long 64 位有符号整数,采用小端字节序 ulong 64 位无符号整数,采用小端字节序 sleb128 有符号 LEB128,可变长度(见下文) uleb128 无符号 LEB128,可变长度(见下文) uleb128p1 无符号 LEB128 加 1,可变长度(见下文) LEB128

LEB128(“Little-Endian Base 128”)表示任意有符号或无符号整数的可变长度编码。该格式借鉴了 DWARF3 规范。在 .dex 文件中,LEB128 仅用于对 32 位数字进行编码。

每个 LEB128 编码值均由 1-5 个字节组成,共同表示一个 32 位的值。每个字节均已设置其最高有效位(序列中的最后一个字节除外,其最高有效位已清除)。每个字节的剩余 7 位均为载荷,即第一个字节中有 7 个最低有效位,第二个字节中也是 7 个,依此类推。对于有符号 LEB128 (sleb128),序列中最后一个字节的最高有效载荷位会进行符号扩展,以生成最终值。在无符号情况 (uleb128) 下,任何未明确表示的位都会被解译为 0。

双字节 LEB128 值的按位图 第一个字节第二个字节 1 bit6 bit5 bit4 bit3 bit2 bit1 bit0 0 bit13 bit12 bit11 bit10 bit9 bit8 bit7

变体 uleb128p1 用于表示一个有符号值,其表示法是编码为 uleb128 的值加 1。这使得 -1 的编码(或被视为无符号值 0xffffffff)成为一个单字节(但没有任何其他负数),并且该编码在下面这些情况下非常实用:所表示的数值必须为非负数或 -1(或 0xffffffff);不允许任何其他负值(或不太可能需要使用较大的无符号值)。

以下是这类格式的一些示例:

编码序列 As sleb128 As uleb128 编码为 uleb128p1 0000-1 01110 7f-1127126 80 7f-1281625616255 文件版式 名称 格式 说明 header header_item 标头 string_ids string_id_item[] 字符串标识符列表。这些是此文件使用的所有字符串的标识符,用于内部命名(例如类型描述符)或用作代码引用的常量对象。此列表必须使用 UTF-16 码位值按字符串内容进行排序(不采用语言区域敏感方式),且不得包含任何重复条目。 type_ids type_id_item[] 类型标识符列表。这些是此文件引用的所有类型(类、数组或原始类型)的标识符(无论文件中是否已定义)。此列表必须按 string_id 索引进行排序,且不得包含任何重复条目。 proto_ids proto_id_item[] 方法原型标识符列表。这些是此文件引用的所有原型的标识符。此列表必须按返回类型(按 type_id 索引排序)主要顺序进行排序,然后按参数列表(按 type_id 索引排序的各个参数,采用字典排序方法)进行排序。该列表不得包含任何重复条目。 field_ids field_id_item[] 字段标识符列表。这些是此文件引用的所有字段的标识符(无论文件中是否已定义)。此列表必须进行排序,其中定义类型(按 type_id 索引排序)是主要顺序,字段名称(按 string_id 索引排序)是中间顺序,而类型(按 type_id 索引排序)是次要顺序。该列表不得包含任何重复条目。 method_ids method_id_item[] 方法标识符列表。这些是此文件引用的所有方法的标识符(无论文件中是否已定义)。此列表必须进行排序,其中定义类型(按 type_id 索引排序)是主要顺序,方法名称(按 string_id 索引排序)是中间顺序,而方法原型(按 proto_id 索引排序)是次要顺序。该列表不得包含任何重复条目。 class_defs class_def_item[] 类定义列表。这些类必须进行排序,以便所指定类的父类和已实现的接口比引用类更早出现在该列表中。此外,对于在该列表中多次出现的同名类,其定义是无效的。 call_site_ids call_site_id_item[] 调用站点标识符列表。这些是此文件引用的所有调用站点的标识符(无论文件中是否已定义)。此列表必须按 call_site_off 以升序进行排序。 method_handles method_handle_item[] 方法句柄列表。此文件引用的所有方法句柄的列表(无论文件中是否已定义)。此列表未进行排序,而且可能包含将在逻辑上对应于不同方法句柄实例的重复项。 data ubyte[] 数据区,包含上面所列表格的所有支持数据。不同的项有不同的对齐要求;如有必要,则在每个项之前插入填充字节,以实现所需的对齐效果。 link_data ubyte[] 静态链接文件中使用的数据。本文档尚未指定本区段中数据的格式。此区段在未链接文件中为空,而运行时实现可能会在适当的情况下使用这些数据。 位字段、字符串和常量定义 DEX_FILE_MAGIC 在 header_item 中嵌入

常量数组/字符串 DEX_FILE_MAGIC 是字节列表,这类字节必须出现在 .dex 文件的开头,以便系统将其原样识别。该值会特意包含一个换行符("\n" 或 0x0a)和空字节("\0" 或 0x00),以便协助检测某些形式的损坏问题。该值还可以将格式版本号编码为 3 个十进制数字;随着格式的演变,预计该值会单调递增。

ubyte[8] DEX_FILE_MAGIC = { 0x64 0x65 0x78 0x0a 0x30 0x33 0x39 0x00 } = "dex\n039\0"

注意:Android 9.0 版本中新增了对 039 版格式的支持,其中引入了两个新字节码 const-method-handle 和 const-method-type。(字节码集合的总结表中介绍了这些字节码。)在 Android 10 中,版本 039 扩展了 DEX 文件格式,以包含仅适用于启动类路径上的 DEX 文件的隐藏 API 信息。

注意:Android 8.0 版本中新增了对 038 版格式的支持。038 版本中添加了新字节码(invoke-polymorphic 和 invoke-custom)和用于方法句柄的数据。

注意:Android 7.0 版本中新增了对 037 版格式的支持。在 037 版本之前,大多数 Android 版本都使用过 035 版格式。035 版与 037 版之间的唯一区别是,是否添加默认方法以及是否调整 invoke。

注意:至少有两种早期版本的格式已在广泛提供的公开软件版本中使用。例如,009 版本已用于 M3 版 Android 平台(2007 年 11 月至 12 月),013 版本已用于 M5 版 Android 平台(2008 年 2 月至 3 月)。在有些方面,这些早期版本的格式与本文档中所述的版本存在很大差异。

ENDIAN_CONSTANT 和 REVERSE_ENDIAN_CONSTANT 在 header_item 中嵌入

常量 ENDIAN_CONSTANT 用于表示在文件中发现的字节序。虽然标准的 .dex 格式采用小端字节序,但具体实现可能会选择执行字节交换。如果实现遇到其 endian_tag 为 ENDIAN_CONSTANT(而非 REVERSE_ENDIAN_CONSTANT)的头文件,则会识别该文件已从预期格式进行过字节交换。

uint ENDIAN_CONSTANT = 0x12345678; uint REVERSE_ENDIAN_CONSTANT = 0x78563412; NO_INDEX 在 class_def_item 和 debug_info_item 中嵌入

常量 NO_INDEX 用于表示索引值不存在。

注意:此值不会被定义为 0,因为实际上此值通常是一个有效索引。

NO_INDEX 的选定值可表示为 uleb128p1 编码中的单个字节。

uint NO_INDEX = 0xffffffff; // == -1 if treated as a signed int access_flags 定义 在 class_def_item、encoded_field、encoded_method 和 InnerClass 中嵌入

这些标志的位字段用于表示类和类成员的可访问性和整体属性。

名称 值 对于类(和 InnerClass 注释) 对于字段 对于方法 ACC_PUBLIC 0x1 public:全部可见 public:全部可见 public:全部可见 ACC_PRIVATE 0x2 *private:仅对定义类可见 private:仅对定义类可见 private:仅对定义类可见 ACC_PROTECTED 0x4 *protected:对软件包和子类可见 protected:对软件包和子类可见 protected:对软件包和子类可见 ACC_STATIC 0x8 *static:无法通过外部 this 引用构造 static:对定义类全局可见 static:不采用 this 参数 ACC_FINAL 0x10 final:不可子类化 final:构建后不可变 final:不可替换 ACC_SYNCHRONIZED 0x20     synchronized:调用此方法时自动获得关联锁定。

注意:这一项仅在同时设置 ACC_NATIVE 的情况下才有效。

ACC_VOLATILE 0x40   volatile:有助于确保线程安全的特殊访问规则   ACC_BRIDGE 0x40     桥接方法,由编译器自动添加为类型安全桥 ACC_TRANSIENT 0x80   transient:不会通过默认序列化保存   ACC_VARARGS 0x80     最后一个参数应被编译器解译为“rest”参数 ACC_NATIVE 0x100     native:在原生代码中实现 ACC_INTERFACE 0x200 interface:可多倍实现的抽象类     ACC_ABSTRACT 0x400 abstract:不可直接实例化   abstract:不通过此类实现 ACC_STRICT 0x800     strictfp:严格的浮点运算规则 ACC_SYNTHETIC 0x1000 不在源代码中直接定义 不在源代码中直接定义 不在源代码中直接定义 ACC_ANNOTATION 0x2000 声明为注解类     ACC_ENUM 0x4000 声明为枚举类型 声明为枚举值   (未使用) 0x8000       ACC_CONSTRUCTOR 0x10000     构造函数方法(类或实例初始化程序) ACC_DECLARED_SYNCHRONIZED 0x20000     声明了 synchronized。

注意:此项对执行没有任何影响(除了反映此标志本身之外)。

*仅允许用于 InnerClass 注解,且一律不得在 class_def_item 中使用。

MUTF-8(修改后的 UTF-8)编码

考虑到继续对旧版提供支持,.dex 格式会采用按实际标准修改后的 UTF-8 形式(下文称为 MUTF-8)对其字符串数据进行编码。除以下几点以外,此形式与标准 UTF-8 形式是完全相同的:

仅使用单字节、双字节和三字节编码。 U+10000 … U+10ffff 范围中的码位被编码为代理对,其中每个码位均表示为一个三字节编码值。 码位 U+0000 采用双字节格式形式编码。 纯 null 字节(值 0)表示字符串的末尾,这是标准的 C 语言解释。

上述前两项可以概括为:MUTF-8 是用于 UTF-16 的编码格式,而不是用于 Unicode 字符的更直接的编码格式。

后两项说明,MUTF-8 既可在字符串中包含代码点 U+0000,同时仍可将其作为 C 样式的 Null 终止字符串进行操作。

不过,特殊编码 U+0000 意味着,与一般 UTF-8 不同的是,针对一对 MUTF-8 字符串调用标准 C 函数 strcmp() 的结果并不一定表示不相等字符串的带正确符号的比较结果。当需要考虑排序问题(而不仅仅是相等问题)时,用于比较 MUTF-8 字符串的最简单方法是对其字符进行逐个解码,然后比较解码后的值。(不过,也许会有更智能的实现方式。)

如需详细了解字符编码,请参阅 Unicode 标准。实际上,MUTF-8 比 UTF-8 本身更接近相对而言不太为人熟知的编码 CESU-8。

encoded_value 编码 在 annotation_element 和 encoded_array_item 中嵌入

encoded_value 是(几乎)任意层次结构数据的编码片。这种编码非常精简,易于解析。

名称 格式 说明 (value_arg = 0x0a) 运算码清除。 DBG_SET_EPILOGUE_BEGIN 0x08 (无) 设置 epilogue_begin 状态机寄存器;表示所添加的下一个位置条目应被视为方法结尾的开头(要在方法退出之前暂停执行的适当位置)。epilogue_begin 寄存器会被任何特殊的 (>= 0x0a) 运算码清除。 DBG_SET_FILE 0x09 uleb128p1 name_idx name_idx:源文件名称的字符串索引;如果未知,则此项为 NO_INDEX 表示所有后续行号条目均引用此源文件名称,而不是 code_item 中指定的默认名称 特殊运算码 0x0a…0xff (无) 使 line 和 address 寄存器指向下一个地址,发出一个位置条目,并清除 prologue_end 和 epilogue_begin。请参阅下文中的说明。 特殊运算码

值在 0x0a 和 0xff(含)之间的操作码会将 line 和 address 寄存器移动一小部分,然后发出一个新的位置表条目。这些增量的公式如下所示:

DBG_FIRST_SPECIAL = 0x0a // the smallest special opcode DBG_LINE_BASE = -4 // the smallest line number increment DBG_LINE_RANGE = 15 // the number of line increments represented adjusted_opcode = opcode - DBG_FIRST_SPECIAL line += DBG_LINE_BASE + (adjusted_opcode % DBG_LINE_RANGE) address += (adjusted_opcode / DBG_LINE_RANGE) annotations_directory_item 引用自 class_def_item 出现在 data 区段中 对齐:4 个字节 名称 格式 说明 class_annotations_off uint 从文件开头到直接在该类上所做的注解的偏移量;如果该类没有任何直接注解,此值为 0。该偏移量(如果为非零值)应该是到 data 区段中某个位置的偏移量。数据格式由下文的“annotation_set_item”指定。 fields_size uint 此项所注释的字段数量 annotated_methods_size uint 此项所注释的方法数量 annotated_parameters_size uint 此项所注释的方法参数列表的数量 field_annotations field_annotation[fields_size](可选) 所关联字段的注释列表。该列表中的元素必须按 field_idx 以升序进行排序。 method_annotations method_annotation[methods_size](可选) 所关联方法的注释列表。该列表中的元素必须按 method_idx 以升序进行排序。 parameter_annotations parameter_annotation[parameters_size](可选) 所关联方法参数的注释列表。该列表中的元素必须按 method_idx 以升序进行排序。

注意:所有元素的 field_id 和 method_id 都必须引用相同的定义类。

field_annotation 格式 名称 格式 说明 field_idx uint 字段(带注解)标识的 field_ids 列表中的索引 annotations_off uint 从文件开头到该字段的注解列表的偏移量。偏移量应该是到 data 区段中某个位置的偏移量。数据格式由下文的“annotation_set_item”指定。 method_annotation 格式 名称 格式 说明 method_idx uint 方法(带注解)标识的 method_ids 列表中的索引 annotations_off uint 从文件开头到该方法注解列表的偏移量。偏移量应该是到 data 区段中某个位置的偏移量。数据格式由下文的“annotation_set_item”指定。 parameter_annotation 格式 名称 格式 说明 method_idx uint 方法(其参数带注解)标识的 method_ids 列表中的索引 annotations_off uint 从文件开头到该方法参数的注解列表的偏移量。偏移量应该是到 data 区段中某个位置的偏移量。数据格式由下文的“annotation_set_ref_list”指定。 annotation_set_ref_list 引用自 parameter_annotations_item 出现在 data 区段中 对齐:4 个字节 名称 格式 说明 size uint 列表的大小(以条目数表示) list annotation_set_ref_item[size] 列表的元素 annotation_set_ref_item 格式 名称 格式 说明 annotations_off uint 从文件开头到所引用注释集的偏移量;如果此元素没有任何注释,则该值为 0。该偏移量(如果为非零值)应该是到 data 区段中某个位置的偏移量。数据格式由下文的“annotation_set_item”指定。 annotation_set_item 引用自 annotations_directory_item、field_annotations_item、method_annotations_item 和 annotation_set_ref_item 出现在 data 区段中 对齐:4 个字节 名称 格式 说明 size uint 该集合的大小(以条目数表示) entries annotation_off_item[size] 该集合的元素。这些元素必须按 type_idx 以升序进行排序。 annotation_off_item 格式 名称 格式 说明 annotation_off uint 从文件开头到注解的偏移量。该偏移量应该是到 data 区段中某个位置的偏移量,且该位置的数据格式由下文的“annotation_item”指定。 annotation_item 引用自 annotation_set_item 出现在 data 区段中 对齐:无(字节对齐) 名称 格式 说明 visibility ubyte 此注释的预期可见性(见下文) annotation encoded_annotation 已编码的注释内容,采用上文中“encoded_value 编码”下的“encoded_annotation 格式”所述的格式。 可见性值

以下是 annotation_item 中 visibility 字段的选项:

名称 值 说明 VISIBILITY_BUILD 0x00 预计仅在构建(例如,在编译其他代码期间)时可见 VISIBILITY_RUNTIME 0x01 预计在运行时可见 VISIBILITY_SYSTEM 0x02 预计在运行时可见,但仅对基本系统(而不是常规用户代码)可见 encoded_array_item 引用自 class_def_item 出现在 data 区段中 对齐:无(字节对齐) 名称 格式 说明 value encoded_array 用于表示已编码数组值的字节,采用上文中“encoded_value 编码”下的“encoded_array 格式”指定的格式。 hiddenapi_class_data_item

此部分包含每个类使用的受限接口的数据。

注意:隐藏的 API 功能是在 Android 10.0 中引入的,这些功能仅适用于启动类路径中类的 DEX 文件。未来版本的 Android 中可能会扩展下述标志列表。如需了解详情,请参阅针对非 SDK 接口的限制。

名称 格式 说明 size uint 区段的总大小 offsets uint[] 由 class_idx 编入索引的偏移量数组。索引 class_idx 中的零数组意味着此 class_idx 没有任何数据,或者所有隐藏 API 标记均为零。否则,数组条目为非零值,并且包含从区段开头到此 class_idx 的隐藏 API 标记数组的偏移量。 flags uleb128[] 每个类的隐藏 API 标志的级联数组。可能的标志值如下表所述。标志的编码顺序与字段和方法在类数据中的编码顺序相同。

限制标记类型:

名称 值 说明 whitelist 0 此列表中的接口已在 Android 框架软件包索引中正式记录,它们是受支持的接口,您可以自由使用。 greylist 1 包含可以使用的非 SDK 接口的列表(无论应用的目标 API 级别是什么)。 blacklist 2 包含不能使用的非 SDK 接口的列表(无论应用的目标 API 级别是什么)。访问其中任何一个接口都会导致运行时错误。 greylist‑max‑o 3 此列表中包含的是可用于 Android 8.x 及更低版本(除非受到限制)的非 SDK 接口。 greylist‑max‑p 4 此列表中包含的是可用于 Android 9.x(除非受到限制)的非 SDK 接口。 greylist‑max‑q 5 此列表中包含的是可用于 Android 10.x 的非 SDK 接口(除非这些接口受到限制)。 greylist‑max‑r 6 此列表中包含的是可用于 Android 11.x 的非 SDK 接口(除非这些接口受到限制)。 系统注解

系统注解用于表示关于类(以及方法和字段)的各种反射信息。这类信息通常只能通过客户端(非系统)代码来间接获取。

系统注解在 .dex 文件中表示为注解,可见性设为 VISIBILITY_SYSTEM。

dalvik.annotation.AnnotationDefault 在注释界面的方法中显示

AnnotationDefault 注解会附加到各个注解接口,用于表示默认绑定。

名称 格式 说明 value Annotation 此注解的默认绑定,表示为此类型的注解。该注解不需要包含由注解定义的所有名称;缺少的名称根本没有默认值。 dalvik.annotation.EnclosingClass 在类中显示

EnclosingClass 注解会附加到各个类,这些类会被定义为其他类本身的成员,或者匿名显示但不在方法正文中定义(例如,合成的内部类)。具有此注解的各个类还必须具有 InnerClass 注解。此外,一个类不得同时具有 EnclosingClass 和 EnclosingMethod 注释。

名称 格式 说明 value Class 在词法作用域最接近此类的类 dalvik.annotation.EnclosingMethod 在类中显示

EnclosingMethod 注解会附加到已在方法正文中定义的各个类。具有此注解的各个类还必须具有 InnerClass 注解。 此外,一个类不得同时具有 EnclosingClass 和 EnclosingMethod 注释。

名称 格式 说明 value Method 在词法作用域最接近此类的方法 dalvik.annotation.InnerClass 在类中显示

InnerClass 注解会附加到已在其他类定义的词法作用域中定义的各个类。具有此注解的所有类还必须具有 EnclosingClass 注解或 EnclosingMethod 注解。

名称 格式 说明 name String 此类最初声明的简单名称(不包含任何软件包前缀)。如果此类是匿名类,则名称为 null。 accessFlags int 此类最初声明的访问标志(由于源语言与目标虚拟机之间的执行模型不匹配,该标志可能与有效标志不同) dalvik.annotation.MemberClasses 在类中显示

MemberClasses 注解会附加到声明成员类(成员类是指具有名称的直接内部类)的各个类。

名称 格式 说明 value Class[] 成员类的数组 dalvik.annotation.MethodParameters 在方法中显示

注意:此注释在 Android 7.1 之后的版本中添加。早期 Android 版本中存在的这类注释将被忽略。

MethodParameters 注解是可选项,并可用于提供参数元数据(例如参数名称和修饰符)。

当运行时不需要参数元数据时,可在方法或构造函数中放心地省略这项注解。java.lang.reflect.Parameter.isNamePresent() 可用于检查某个参数中是否存在元数据;如果不存在这种信息,关联的反射方法(例如 java.lang.reflect.Parameter.getName())将在运行时回退到默认行为。

如果编译器包含参数元数据,则必须包含已生成类(如枚举)的信息,因为参数元数据会指明参数是合成参数还是强制参数。

MethodParameters 注释仅用于描述单个方法的参数。因此,为了权衡代码大小和运行时效率,编译器可能会完全省略不含参数的构造函数和方法的注解。

下面记录的数组必须与该方法所关联的 method_id_item dex 结构具有相同的大小,否则运行时会抛出 java.lang.reflect.MalformedParametersException。

即:method_id_item.proto_idx -> proto_id_item.parameters_off -> type_list.size 必须与 names().length 和 accessFlags().length 相同。

由于 MethodParameters 说明了所有形式方法参数,甚至包括源代码中没有明确声明或隐式声明的参数,因此数组的大小可能不同于签名或其他元数据信息(仅基于源代码中声明的显式参数)的大小。此外,MethodParameters 也不包含任何关于实际方法签名中不存在的类型注释接收器参数的信息。

名称 格式 说明 names String[] 关联方法的形式参数的名称。数组不得为空;但如果没有任何形式参数,该项必须为空。如果使用该索引的形式参数没有名称,数组中的值必须为 null。 如果参数名称字符串为空或包含“.”“;”“[”或“/”,运行时将会抛出 java.lang.reflect.MalformedParametersException。 accessFlags int[] 关联方法的形式参数的访问标志。数组不得为空;但如果没有任何形式参数,该项必须为 null。 该值是包含以下值的位掩码: 0x0010:final,表示该参数被声明为 final 0x1000:synthetic,表示该参数由编译器引入 0x8000:mandated,表示该参数是合成参数,但同样由语言规范所暗示 如果任何位在此集合之外进行设置,运行时将会抛出 java.lang.reflect.MalformedParametersException。 dalvik.annotation.Signature 在类、字段和方法中显示

Signature 注解会附加到各个类、字段或方法(按照比 type_id_item 所表示的类型更复杂的类型进行定义)。.dex 格式不定义签名的格式;它仅仅能够表示源语言成功实现该语言的语义所需要的任何签名。因此,签名通常不会通过虚拟机实现进行解析(或验证)。这些签名只会传递给更高级别的 API 和工具(如调试程序)。因此,每次使用签名时都应该记录下来,以免就只接收有效签名作出任何假设,从而明确防止出现句法无效的签名。

由于签名字符串往往包含很多重复内容,因此 Signature 注解会被定义为字符串数组,其中的重复元素会自然地引用相同的基本数据,而签名则被视为该数组中所有字符串的串联。对于如何将签名分割成单独的字符串,没有相关规定;这完全取决于生成 .dex 文件的工具。

名称 格式 说明 value String[] 此类或成员的签名,表示为要串联在一起的字符串的数组 dalvik.annotation.Throws 在方法中显示

Throws 注释会附加到已声明要抛出一个或多个异常类型的各个方法。

名称 格式 说明 value Class[] 抛出的异常类型的数组


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3