魔数字段,主要就是Dex文件的标识符,它占用4个字节,在目前的源码里是 “dex\n”,它的作用是用来区别其它文件的,比如有一个文件也叫Dex结尾的文件,就可以认为它是Davlik虚拟机运行的文件吗?当然不行,因此这四个字节,就起到与别的结尾也是Dex文件的区分。还有Davlik虚拟机也有优化的Dex,也是通过个字段来区分的,当它是优化的Dex文件时,它的值就变成”dey\n”了。根据这四个字节,就可以识别不同类型的Dex文件了。到这里,已经搞清楚什么是魔数的作用了。
版本字段,主要用来标识Dex文件的版本。目前支持的版本号为“035\0”,不管是否优化的版本,都是使用这个版本号。
检验码字段,主要用来检查从这个字段开始到文件结尾,这段数据是否完整,有没有人修改过,或者传送过程中是否有出错等等。我们知道常常用来检查数据是否完整算法,有CRC32、有SHA128等,但这里采用都不是这两类,而采用一个比较特别的算法,叫做adler32,这是在开源zlib里常用的算法,用来检查文件是否完整性。这个算法是由MarkAdler发明的,它的可靠程度跟CRC32差不多,不过还是弱一点点,不过它有一个特好的优点,就是使用软件来计算检验码时比较CRC32要快很多。可见Android系统,就算法上就已经为移动设备进行优化了。
Adler32算法的源码如下:
#defineZLIB_INTERNAL
#include"zlib.h"
#defineBASE 65521UL /* largest prime smaller than 65536 */
#defineNMAX 5552
/*NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <=2^32-1 */
#defineDO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
#defineDO2(buf,i) DO1(buf,i); DO1(buf,i+1);
#defineDO4(buf,i) DO2(buf,i); DO2(buf,i+2);
#defineDO8(buf,i) DO4(buf,i); DO4(buf,i+4);
#defineDO16(buf) DO8(buf,0); DO8(buf,8);
/*use NO_DIVIDE if your processor does not do division in hardware */
#ifdefNO_DIVIDE
# define MOD(a) \
do{ \
if(a >= (BASE << 16)) a -= (BASE << 16); \
if(a >= (BASE << 15)) a -= (BASE << 15); \
if(a >= (BASE << 14)) a -= (BASE << 14); \
if(a >= (BASE << 13)) a -= (BASE << 13); \
if(a >= (BASE << 12)) a -= (BASE << 12); \
if(a >= (BASE << 11)) a -= (BASE << 11); \
if(a >= (BASE << 10)) a -= (BASE << 10); \
if(a >= (BASE << 9)) a -= (BASE << 9); \
if(a >= (BASE << 8)) a -= (BASE << 8); \
if(a >= (BASE << 7)) a -= (BASE << 7); \
if(a >= (BASE << 6)) a -= (BASE << 6); \
if(a >= (BASE << 5)) a -= (BASE << 5); \
if(a >= (BASE << 4)) a -= (BASE << 4); \
if(a >= (BASE << 3)) a -= (BASE << 3); \
if(a >= (BASE << 2)) a -= (BASE << 2); \
if(a >= (BASE << 1)) a -= (BASE << 1); \
if(a >= BASE) a -= BASE; \
}while (0)
# define MOD4(a) \
do{ \
if(a >= (BASE << 4)) a -= (BASE << 4); \
if(a >= (BASE << 3)) a -= (BASE << 3); \
if(a >= (BASE << 2)) a -= (BASE << 2); \
if(a >= (BASE << 1)) a -= (BASE << 1); \
if(a >= BASE) a -= BASE; \
}while (0)
#else
# define MOD(a) a %= BASE
# define MOD4(a) a %= BASE
#endif
/*=========================================================================*/
uLongZEXPORT adler32(adler, buf, len)
uLongadler;
constBytef *buf;
uIntlen;
{
unsignedlong sum2;
unsignedn;
/*split Adler-32 into component sums */
sum2= (adler >> 16) & 0xffff;
adler&= 0xffff;
/*in case user likes doing a byte at a time, keep it fast */
if(len == 1) {
adler+= buf[0];
if(adler >= BASE)
adler-= BASE;
sum2+= adler;
if(sum2 >= BASE)
sum2-= BASE;
returnadler | (sum2 << 16);
}
/*initial Adler-32 value (deferred check for len == 1 speed) */
if(buf == Z_NULL)
return1L;
/*in case short lengths are provided, keep it somewhat fast */
if(len < 16) {
while(len--) {
adler+= *buf++;
sum2+= adler;
}
if(adler >= BASE)
adler-= BASE;
MOD4(sum2); /* only added so many BASE's */
returnadler | (sum2 << 16);
}
/*do length NMAX blocks -- requires just one modulo operation */
while(len >= NMAX) {
len-= NMAX;
n= NMAX / 16; /* NMAX is divisible by 16 */
do{
DO16(buf); /* 16 sums unrolled */
buf+= 16;
}while (--n);
MOD(adler);
MOD(sum2);
}
/*do remaining bytes (less than NMAX, still just one modulo) */
if(len) { /* avoid modulos if none remaining */
while(len >= 16) {
len-= 16;
DO16(buf);
buf+= 16;
}
while(len--) {
adler+= *buf++;
sum2+= adler;
}
MOD(adler);
MOD(sum2);
}
/*return recombined sums */
returnadler | (sum2 << 16);
}