本篇主要描述.dex文件中用到的LEB128,關於.dex文件的具體格式下篇再講。 編程
.dex文件中使用的數據類型以下圖所示: 編碼
這裏咱們能夠看到出現了幾個咱們不熟悉的類型sleb128, usleb128, usleb128p1. spa
經過他們的描述文件能夠了解到這幾個類型都是基於LEB128,那下面咱們就先來了解一下LEB128是個啥東東。 code
其實,LEB128就是一種利用編程編碼(variable-length code)壓縮數據的一種格式,它可以以較少的字節存儲任意大小的數字。有2種類型的LEB128:有符號的LEB128(signed LEB128)和無符號的LEB128(unsigned LEB128 )。下面以無符號LED128爲例說明計算過程。 it
unsigned LEB128 io
編碼: 數據類型
在對一個無符號數編碼以前首先將其表示成二進制形式,而後將二進制表示每7位分爲一組(不足的位補0)。將分組後的每一組添加一個最高位(第一組補0,其餘各組補1)造成每組8bits,最後將每一個組表示成16進制形式便可完成編碼。 二進制
下面以數字624485 爲例說明: 方法
咱們能夠看到,本來須要4個字節的數字被壓縮爲3個字節表示。 im
Dalvik中編碼過程爲:
DEX_INLINE u1* writeUnsignedLeb128(u1* ptr, u4 data)
{
while (true) {
u1 out = data & 0x7f; //提取數據的低7位bit
if (out != data) {
*ptr++ = out | 0x80; //置最高位爲1
data >>= 7;
} else {
*ptr++ = out;
break;
}
}
return ptr;
}
解碼:
解碼過程當中,每次讀取一個字節(8bits)判斷其最高位是否爲1(爲1說明還有其餘字節,0說明是最後一個字節,解碼結束),而後提取出低7位。處理完全部的字節便可獲得原來保存的值。
Dalvik解碼的代碼爲:
DEX_INLINE int readUnsignedLeb128(const u1** pStream) {
const u1* ptr = *pStream;
int result = *(ptr++);
if (result > 0x7f) { //判斷第一個字節的高位是否爲1
int cur = *(ptr++); //cur指向第二個字節
//result爲第一個字節的7位加上第二個字節的7位
result = (result & 0x7f) | ((cur & 0x7f) << 7);
if (cur > 0x7f) {
cur = *(ptr++); //cur指向第三個字節
result |= (cur & 0x7f) << 14;
if (cur > 0x7f) {
cur = *(ptr++); //cur指向第四個字節
result |= (cur & 0x7f) << 21;
if (cur > 0x7f) {
/*
* Note: We don't check to see if cur is out of
* range here, meaning we tolerate garbage in the
* high four-order bits.
*/
cur = *(ptr++); //cur指向第五個字節
result |= cur << 28;
}
}
}
}
代碼中與0x7f比較是爲了判斷最高位是否爲1 (由於若是值大於0x7f的話其最高位確定爲1 )。
cur & 0x7f是爲了獲取cur中低7位。
對於有符號的數,編碼過程基本類似。只是其二進制爲補碼錶示,編碼後最高字節的次高位表示符號位。
Dalvik沒有給出編碼signedLeb128的方法(不知爲啥,繼續研究),
下面給出Wiki上的僞代碼以示說明:
more = 1;
negative = (value < 0);
size = no. of bits in signed integer;
while(more) {
byte = low order 7 bits of value;
value >>= 7;
/* the following is unnecessary if the implementation of >>= uses an
arithmetic rather than logical shift for a signed left operand */
if (negative)
value |= - (1 <<(size - 7)); /* sign extend */
/* sign bit of byte is second high order bit (0x40) */
if ((value == 0 && sign bit of byte is clear) || (value == -1 && sign bit of byte is set))
more = 0;
else
set high order bit of byte; //置最高位爲1
emit byte;
}