最近碰到一个项目需要对内存数据进行检测,确定是否和原始值一样,看了现成的算法MD5 CRC 等,感觉速度不太理想,因此动手自己写了用于检测内存数据的高速算法.
该算法利用了CPU的MMX微指令的单指令多数据优点来提高校验速度.对于大数据量校验尤其明显.
1
.获取原始内存数据校验值算法:
function GetMemoryValue(aSource: Pointer; aSize: DWORD): PInt64; { 获取指定内存MMX运算码和CheckMemory配对用 }
asm
mov esi, aSource // 开始地址
mov ecx, aSize // 长度
shr ecx, 6 // 除64
mov eax, 0
emms
pxor mm0,mm0
pxor mm1,mm1
pxor mm2,mm2
pxor mm3,mm3
pxor mm4,mm4
pxor mm5,mm5
pxor mm6,mm6
pxor mm7,mm7
@XorLoop:
pxor mm0, qword ptr [esi + eax]
pxor mm1, qword ptr [esi + eax + $ 8 ]
pxor mm2, qword ptr [esi + eax + $ 10 ]
pxor mm3, qword ptr [esi + eax + $ 18 ]
pxor mm4, qword ptr [esi + eax + $ 20 ]
pxor mm5, qword ptr [esi + eax + $ 28 ]
pxor mm6, qword ptr [esi + eax + $ 30 ]
pxor mm7, qword ptr [esi + eax + $ 38 ]
add eax,$ 40 // 64
sub ecx, 1
jnz @XorLoop
pxor mm0,mm1
pxor mm0,mm2
pxor mm0,mm3
pxor mm0,mm4
pxor mm0,mm5
pxor mm0,mm6
pxor mm0,mm7
lea eax,[ESP + $ 8 ] // MMXValue
movq qword ptr [eax], mm0 // 保存MMX运算值结果
Sfence
Emms
end ;
2 .检测内存数据校验值算法:
function CheckMemory(aSource: Pointer; aSize: DWORD; MMXValue: PInt64): Boolean;
{ 内存校验检测,MMXVaule为内存正常值由GetMemoryValue获得,被修改返回True }
asm
mov esi, aSource // 开始地址
mov ecx, aSize // 长度
shr ecx, 6 // 除64
mov eax, 0
emms
pxor mm0,mm0
pxor mm1,mm1
pxor mm2,mm2
pxor mm3,mm3
pxor mm4,mm4
pxor mm5,mm5
pxor mm6,mm6
pxor mm7,mm7
@XorLoop:
pxor mm0, qword ptr [esi + eax]
pxor mm1, qword ptr [esi + eax + $ 8 ]
pxor mm2, qword ptr [esi + eax + $ 10 ]
pxor mm3, qword ptr [esi + eax + $ 18 ]
pxor mm4, qword ptr [esi + eax + $ 20 ]
pxor mm5, qword ptr [esi + eax + $ 28 ]
pxor mm6, qword ptr [esi + eax + $ 30 ]
pxor mm7, qword ptr [esi + eax + $ 38 ]
add eax,$ 40 // 64
sub ecx, 1
jnz @XorLoop
pxor mm0,mm1
pxor mm0,mm2
pxor mm0,mm3
pxor mm0,mm4
pxor mm0,mm5
pxor mm0,mm6
pxor mm0,mm7
mov eax,[ESP + $ 8 ] // MMXValue
movq mm1, qword ptr [eax] // 读值比较
pxor mm0,mm1
movq qword ptr [eax], mm0 // 保存结果
Sfence
Emms
xor esi,esi
cmp dword ptr [eax], esi
Jne @Fal
cmp dword ptr [eax + 4 ], esi
Jne @Fal
xor eax,eax // 检验成功
jmp @exit
@Fal: // 检验失败
mov eax, 1
@Exit:
end ;
function GetMemoryValue(aSource: Pointer; aSize: DWORD): PInt64; { 获取指定内存MMX运算码和CheckMemory配对用 }
asm
mov esi, aSource // 开始地址
mov ecx, aSize // 长度
shr ecx, 6 // 除64
mov eax, 0
emms
pxor mm0,mm0
pxor mm1,mm1
pxor mm2,mm2
pxor mm3,mm3
pxor mm4,mm4
pxor mm5,mm5
pxor mm6,mm6
pxor mm7,mm7
@XorLoop:
pxor mm0, qword ptr [esi + eax]
pxor mm1, qword ptr [esi + eax + $ 8 ]
pxor mm2, qword ptr [esi + eax + $ 10 ]
pxor mm3, qword ptr [esi + eax + $ 18 ]
pxor mm4, qword ptr [esi + eax + $ 20 ]
pxor mm5, qword ptr [esi + eax + $ 28 ]
pxor mm6, qword ptr [esi + eax + $ 30 ]
pxor mm7, qword ptr [esi + eax + $ 38 ]
add eax,$ 40 // 64
sub ecx, 1
jnz @XorLoop
pxor mm0,mm1
pxor mm0,mm2
pxor mm0,mm3
pxor mm0,mm4
pxor mm0,mm5
pxor mm0,mm6
pxor mm0,mm7
lea eax,[ESP + $ 8 ] // MMXValue
movq qword ptr [eax], mm0 // 保存MMX运算值结果
Sfence
Emms
end ;
2 .检测内存数据校验值算法:
function CheckMemory(aSource: Pointer; aSize: DWORD; MMXValue: PInt64): Boolean;
{ 内存校验检测,MMXVaule为内存正常值由GetMemoryValue获得,被修改返回True }
asm
mov esi, aSource // 开始地址
mov ecx, aSize // 长度
shr ecx, 6 // 除64
mov eax, 0
emms
pxor mm0,mm0
pxor mm1,mm1
pxor mm2,mm2
pxor mm3,mm3
pxor mm4,mm4
pxor mm5,mm5
pxor mm6,mm6
pxor mm7,mm7
@XorLoop:
pxor mm0, qword ptr [esi + eax]
pxor mm1, qword ptr [esi + eax + $ 8 ]
pxor mm2, qword ptr [esi + eax + $ 10 ]
pxor mm3, qword ptr [esi + eax + $ 18 ]
pxor mm4, qword ptr [esi + eax + $ 20 ]
pxor mm5, qword ptr [esi + eax + $ 28 ]
pxor mm6, qword ptr [esi + eax + $ 30 ]
pxor mm7, qword ptr [esi + eax + $ 38 ]
add eax,$ 40 // 64
sub ecx, 1
jnz @XorLoop
pxor mm0,mm1
pxor mm0,mm2
pxor mm0,mm3
pxor mm0,mm4
pxor mm0,mm5
pxor mm0,mm6
pxor mm0,mm7
mov eax,[ESP + $ 8 ] // MMXValue
movq mm1, qword ptr [eax] // 读值比较
pxor mm0,mm1
movq qword ptr [eax], mm0 // 保存结果
Sfence
Emms
xor esi,esi
cmp dword ptr [eax], esi
Jne @Fal
cmp dword ptr [eax + 4 ], esi
Jne @Fal
xor eax,eax // 检验成功
jmp @exit
@Fal: // 检验失败
mov eax, 1
@Exit:
end ;
需要说明的是该算法有个缺陷,就是需要字节按64byte对齐,否则检测将不完整,可能出现对最后1-63byte不检测的情况,当然也可以修改上面算法让他自动适应.上面代码也还有优化余地,比如加入cache高速缓存预读处理prefetchnta预读优化速度.由于时间紧张未能加入.