本篇主要描述.dex文件中用到的LEB128,关于.dex文件的具体格式下篇再讲。
.dex文件中使用的数据类型如下图所示:
这里我们可以看到出现了几个我们不熟悉的类型sleb128, usleb128, usleb128p1.
通过他们的描述文件可以了解到这几个类型都是基于LEB128,那下面我们就先来了解一下LEB128是个啥东东。
其实,LEB128就是一种利用编程编码(variable-length code)压缩数据的一种格式,它能够以较少的字节存储任意大小的数字。有2种类型的LEB128:有符号的LEB128(signed LEB128)和无符号的LEB128(unsigned LEB128 )。下面以无符号LED128为例说明计算过程。
unsigned LEB128
编码:
在对一个无符号数编码之前首先将其表示成二进制形式,然后将二进制表示每7位分为一组(不足的位补0)。将分组后的每一组添加一个最高位(第一组补0,其他各组补1)形成每组8bits,最后将每个组表示成16进制形式即可完成编码。
我们可以看到,原本需要4个字节的数字被压缩为3个字节表示。
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;
}