ART深入浅出6--了解Dex文件格式(3)
来源:互联网 发布:php xss 编辑:程序博客网 时间:2024/05/20 13:15
本文基于Android 7.1,不过因为从BSP拿到的版本略有区别,所以本文提到的源码未必与读者找到的源码完全一致。本文在提供源码片断时,将按照 <源码相对android工程的路径>:<行号> <类名> <函数名> 的方式,如果行号对不上,请参考类名和函数名来找到对应的源码。
本节介绍Dex Code的格式。DexCode是Dex虚拟机的核心。
CodeItem
CodeItem结构的内容
Method的内容都放在CodeItem结构中,它的定义是这样的
art/runtime/dex_file.h:281
// Raw code_item. struct CodeItem { uint16_t registers_size_; // the number of registers used by this code // (locals + parameters) uint16_t ins_size_; // the number of words of incoming arguments to the method // that this code is for uint16_t outs_size_; // the number of words of outgoing argument space required // by this code for method invocation uint16_t tries_size_; // the number of try_items for this instance. If non-zero, // then these appear as the tries array just after the // insns in this instance. uint32_t debug_info_off_; // file offset to debug info stream uint32_t insns_size_in_code_units_; // size of the insns array, in 2 byte code units uint16_t insns_[1]; // actual array of bytecode...... };
这是一个开放结构,最后一个insns_是指令数组的起始地址。 ins_size_是指令的大小,单位是2字节。指令总大小是ins_size_*2.
registers_size_ 是该函数用到的总寄存器总个数。ins_size_是参数的个数。outs_size_是该函数调用子函数的大小
假设registers_siez_的大小是N, ins_size_为M,则参数寄存器序列是 (N-M ~ N - 1) 。
而且 必须outs_size_ <= registers_size_。 因为dex代码只能通过寄存器传递参数,所以,被用作传递参数的寄存器数量也包含在总寄存器中。
一个DexMethod需要的寄存器总大小是registers_size_ * 4。一个Long/Double型为8字节,必须占用两个寄存器。这样两个寄存器就合并成一个Wide寄存器。考虑到效率,Wide寄存器需要从偶数开始。
tries_size_ 是TryItem结构的大小,这个大小是用来记录try-cache/finally信息的。
debug_info_off_ 是调试信息,从文件头开始的。
insns_隐含的信息
insns_其实是由两部分组成:指令和Trycatch信息
TryCatch
TryCatch的数据结构,有TryItem和Handler两种数据。
TryItem
TryItem的定义如下:
art/runtime/dex_file.h:300
struct TryItem { uint32_t start_addr_; uint16_t insn_count_; uint16_t handler_off_; .... };
start_addr_ 是try 模块开始的dex pc,相对于CodeItem.insns_,单位是2字节。
insn_count_ 是从start_addr_开始的代码try 模块的数量
hander_off_ 是 hander结构的偏移,这个偏移是从codeItem.insns_ + sizeof(TryItem ) * codeItem.tries_size_ 开始的。
handler的结构
handler结构是一个不定长的结构,在TryItem数组之后有一个handler_size的leb128编码的数据,表示handler的结构。
一个handler结构包含多个catch块和finally块。catch块和finally块本质上没有什么区别,只是finally块没有指定Throwable对象。
art里面,通过CatchHandlerIterator对象可以遍历所有的Handler。
一个catch/finally块的结构定义在CatchHandlerIterator中,
art/runtime/dex_file.h:1635 CatchHandlerIterator
struct CatchHandlerItem { uint16_t type_idx_; // type index of the caught exception type uint32_t address_; // handler address } handler_;
type_idx_ 是DexFile内的TypeIds数组的索引,表示一个Exception对象。
address_ 是基于CodeItem.insns_的位置,表示catch/finally的代码部分。
当是finally块时,type_idx_值为kNoDexIndex (0xffff)。
以上是解码后的数据,实际上,都是以leb128格式存储的。finally块是放在最后的,而且finally只有address_值,没有type_idx_的值。
多个catch块放在一起,是一个handler对象,结构是(伪代码)
leb128_int remaining_count;struct { leb128_uint16 type_idx; leb128_uint32 address_idx;}catchs[N];leb128_uint32 finally_address_idx;
leb128前缀表示该项数据是leb128的编码。
remaining_count表示catch/finally块的个数。如果remaining_count <= 0表示最后一个是finally块。如果 remaining_count > 0表示只有catch块。
remaining_count的绝对值表示catch块的个数。如果remaining_count == 0表示没有catch块,只有finally块
一个handler块对应一个TryItem,共同组成try catch/finally块。
有多个try-catch/finally就有多个handler块组成。
Switch
switch在dex中分为packed switch和sparse switch两种。packed switch是针对 case的值相差只有1的情况。sparse switch针对的是case值之间差不相等的情况。
packed switch
指令的格式是 packed-switch vAA, +BBBBBBBB
BBBBBBBB 表示packed-switch数据的偏移,这是一个32位有符号整数,相对与当前指令的偏移。
packed-switch数据的格式是
该结构的总大小 是size * 4 + 4 + 4
targets的值是相对于 代码开始位置。可以直接用作dexPC。
sparse switch
指令的格式是sparse-switch vAA, +BBBBBBBB
+BBBBBBBB的格式同上。
sparse-switch的格式是
keys列表是按照从小到达的顺序排列的。
计算方法是,从keys中查找vAA的值对应的索引,用这个索引取targets对应的值。
Table
java代码中有很多数组填充的代码,这些代码在dex中对应的是fill-array-data数据。指令的格式是
fill-array-data vAA, +BBBBBBBB
vAA是一个array数组对象。+BBBBBBBB表示fill-array-data-payload,这个结构是
data数据是可以直接拷贝到array数组内的数组。所以,这种格式只能用在元素为非object对象的array对象中。
- ART深入浅出6--了解Dex文件格式(3)
- ART深入浅出4--了解Dex文件格式(1)
- ART深入浅出5--了解Dex文件格式(2)
- ART深入浅出3--了解Boot.art和boot-*.art
- Dex文件格式
- dex文件格式
- DEX文件格式
- dex文件格式
- DEX文件格式
- Dex文件格式
- Dex文件格式
- ART深入浅出2 -- 认识和了解Runtime Options
- Art下DexClassLoader将dex转化为oat文件格式的过程
- dex & oat & ELF & art
- Android培训班(62)dex文件格式3
- Android DEX 文件格式
- DEX文件格式解析
- Dex 文件格式详解
- MySQL数据恢复和复制对InnoDB锁机制的影响
- CentOS系统yum源使用报错:Error: Cannot retrieve repository metadata (repomd.xml) for repository: rpmforge.
- 商城项目第一天
- 网页端禁止文字复制
- leetcode 153. Find Minimum in Rotated Sorted Array
- ART深入浅出6--了解Dex文件格式(3)
- session与cookies 面试笔记
- Authorize.net 支付流程
- opencv3.0访问像图像的像素值并显示
- 读《ECMAScript 6 入门 —— 阮一峰》(上)
- Handler通信
- Freedom Trail [LeetCode 514]
- 【DBSDFZOJ 4409】a(离散化+树状数组)
- Partition By/row_number()/rank()