LEB128格式的说明
LEB128(Little-Endian Base 128)是一种基于小端法表示的128位、可变长度的编码格式。它既可以表示无符号整数(uleb128,unsigned LEB128),也可以表示有符号的整数(sleb128,signed LEB128)。在Android系统的Dex文件格式中,LEB128只使用了32位进行编码。每一个LEB128编码包含1到5个字节(bytes),所有的字节合起来表示一个32位的值。Android系统在Dex文件中使用LEB128格式编码的主要目的是为了减少Dex文件的体积。
LEB128格式的数据类型如下图1所示。
图1 LEB128格式的数据类型
uleb128中每个字节只有7位为有效位,如果第一个字节的最高位为1,表示LEB128需要使用第二个字节,如果第二个字节的最高位为1,表示会使用到第三个字节,以此类推,直到最后的字节最高位为0,当然LEB128最多使用到5个字节,如果读取5个字节后下一个字节最高位仍为1,则表示该Dex文件无效,Dalvik虚拟机遇到这种情况是直接报错。
图2 uleb128解码过程
例如LEB128编码格式的值“80 7f”,表示成二进制形式为“1000 0000,0111 1111”。因为第一个字节的最高位为1,所以这个值会用到第二个字节,第二个字节的最高位为0,所以这个值只有两个字节。又因为LEB128是小端法表示的,所以最终的结果表示成二进制为“11 1111,1000 0000”,表示成十进制为16256。解码过程如图3-4所示。 对于有符号的sleb128来说,计算方法与uleb128是一样的。只是对uleb128的最后一个字节的最高有效位进行了符号扩展。将上面的例子中的“80 7f”按照sleb128进行解读。“80 7f”的二进制形式不变,还是"1000 0000,0111 1111",这个值的最后一个字节的最高有效位为1,所以这个值是个负数。所以这个值的最终结果为“-1 1111,1000 0000”。我们还知道计算机中的数都是用补码表示的,所以这个值转化为原码表示“-1000 0000”,所以我们得到的值是“-128”。
解码过程如图3所示。
图3 sleb128解码过程
LEB128编码格式中还有一种特殊的编码格式uleb128p1(unsigned LEB128 plus 1),这种编码格式的值为uleb128的值加上1。所以计算uleb128p1格式的值时,通常将这个值转换为uleb128格式,然后这个值的基础上减去一,得到的值就是uleb128p1格式的值。引入uleb128p1编码格式的目的是为了表示“-1”这个值,“-1”这个值也是最小的,例如LEB128编码“00”,使用uleb128格式进行解析,获得的值是0,所以uleb128p1格式的值为0减去1,等于-1。这也是uleb128p1表示的最小的值。