typedef struct { u1 magic[MAGIC_LENGTH]; /* includes version number */ u4 checksum; /* adler32 校驗剩餘長度的文件 */ u1 signature[kSHA1DigestLen]; /* SHA-1 文件簽名 */ u4 fileSize; /* length of entire file */ u4 headerSize; /* offset to start of next section */ u4 endianTag; u4 linkSize; u4 linkOff; u4 mapOff; u4 stringIdsSize; //字符串表大小 偏移 u4 stringIdsOff; u4 typeIdsSize; //類型表 大小偏移 u4 typeIdsOff; u4 protoIdsSize; //原型表 大小 偏移 u4 protoIdsOff; u4 fieldIdsSize; //字段表 大小 偏移 u4 fieldIdsOff; u4 methodIdsSize; //函數表 大小 偏移 u4 methodIdsOff; u4 classDefsSize; //類定義表 大小 偏移 u4 classDefsOff; u4 dataSize; //數據段 大小 偏移 u4 dataOff; }DexHeader;
DexHeader因爲是定長結構 直接格式化就好html
每一個LEB128由1到5個字節組成,全部字節組合到一塊兒表明一個32位值。除了最後一個字節的最高標誌位爲0,java
其它的爲1.剩下的7位爲有效負荷,第二個字節的7位接上。有符號LEB128的符號由最後字節的有效負荷最高位決定。android
例如:0x7f80git
01111111 10000000github
按無符號leb128解析 0x3f80
按有符號leb128解析 -128 (注意先轉補碼)算法
具體解析算法在示例代碼中函數
字符串表包含了dex文件/代碼中使用到的字符串this
字符串表存放的是StringId,具體字符串值在數據段data中編碼
typedef struct { u4 stringDataOff; /* string_data_item 偏移 */ }DexStringId; struct string_data_item { u2 uleb128; //字符串長度 u1 str[1]; //字符串內容 }
string_data_item 起始2字節是uleb128編碼,解碼後可獲得字符串的長度prototype
typedef struct { u4 descriptorIdx; /* 指向一個string_id的index */ }DexTypeId;
typedef struct { u2 classIdx; /* index into typeIds list for defining class */ u2 typeIdx; /* index into typeIds for field type */ u4 nameIdx; /* index into stringIds for field name */ }DexFieldId;
Field描述的是一個類中的成員變量/靜態變量
typedef struct { u4 shortyIdx; /* index into stringIds for shorty descriptor */ u4 returnTypeIdx; /* index into typeIds list for return type */ u4 parametersOff; /* file offset to type_list for parameter types */ }DexProtoId;
Proto原型描述的是一個函數的返回類型 參數類型列表
因爲參數多是多個 parametersOff指向的是一個 type_list結構
typedef struct { u2 typeIdx; /* index into typeIds */ }DexTypeItem; typedef struct { u4 size; /* #of entries in list */ DexTypeItem list[1]; /* entries */ }DexTypeList;
若是parametersOff爲0 表示該函數沒有參數
typedef struct { u2 classIdx; /* index into typeIds list for defining class */ u2 protoIdx; /* index into protoIds for method prototype */ u4 nameIdx; /* index into stringIds for method name */ }DexMethodId;
Method描述的是函數所在類 原型 名稱
typedef struct{ u4 classIdx; /* index into typeIds for this class */ u4 accessFlags; u4 superclassIdx; /* index into typeIds for superclass */ u4 interfacesOff; /* file offset to DexTypeList */ u4 sourceFileIdx; /* index into stringIds for source file name */ u4 annotationsOff; /* file offset to annotations_directory_item */ u4 classDataOff; /* file offset to class_data_item */ u4 staticValuesOff; /* file offset to DexEncodedArray */ }DexClassDef;
superclassIdx 爲0表示父類是 java/lang/Object
interfacesOff/annotationsOff/classDataOff/staticValuesOff 都由多是0 表示類中沒有該類型的數據,例如一個標記類 可能classDataOff就會爲0 由於沒有定義任何函數/字段
sourceFileIdx 可能會是一個無效的id
#define kDexNoIndex 0xffffffff /* not a valid index value */
classDataOff 表示類數據的偏移 指向的是class_data結構
struct class_data{ u4_uleb128 staticFieldsSize; u4_uleb128 instanceFieldsSize; u4_uleb128 directMethodsSize; u4_uleb128 virtualMethodsSize; DexField staticFields[staticFieldsSize]; DexField instanceFields[instanceFieldsSize]; DexMethod directMethods[directMethodsSize]; DexMethod virtualMethods[virtualMethodsSize]; } //encoded field typedef struct { //origin type is uleb128 u4 fieldIdx; /* 指向一個字段表裏的index */ u4 accessFlags; }DexField; //encoded method typedef struct{ //origin type is uleb128 u4 methodIdx; /* 指向一個函數表裏的index */ u4 accessFlags; u4 codeOff; /* DexCode 偏移*/ }DexMethod; typedef struct { u2 registersSize; //代碼塊內使用到的寄存器個數 u2 insSize; //入參字數 u2 outsSize; //出參字數 u2 triesSize; //try_catch個數 u4 debugInfoOff; /* file offset to debug info stream */ u4 insnsSize; /*字節碼數目*/ u2 insns[1]; //字節碼內容 //下面的內容都是當 triesSize>0的時候纔會出現 //padding 使try-handler-table 和 字節碼之間 四字節對齊 /* followed by optional u2 padding */ //try_cat處理表內容 這裏實現的是class文件中的try-handler-table /* followed by try_item[triesSize] */ /* followed by uleb128 handlersSize */ /* followed by catch_handler_item[handlersSize] */ }DexCode;
dex字節碼的翻譯和class字節碼翻譯差很少,對着規範翻譯就好
android vm 採用dex字節碼而不是class字節碼的優點?