WEB开发网
开发学院软件开发VC 由汇编内核的MD5算法编写谈代码优化 阅读

由汇编内核的MD5算法编写谈代码优化

 2010-06-23 20:41:03 来源:WEB开发网   
核心提示:二、内存拷贝优化再观察一下MD5C里面的一段代码:static void MD5_memcpy (unsigned char *output, unsigned int*input, unsigned int len){unsigned int i;for (i = 0; i < len; i++)output[

二、内存拷贝优化

再观察一下MD5C里面的一段代码:

static void MD5_memcpy (unsigned char *output, unsigned int *input, unsigned int len)
{
 unsigned int i;
 for (i = 0; i < len; i++)
  output[i] = input[i];
}

这处的为什么要修改是非常明显的,for循环是非常慢的,我们一般可以把类似的代码替换成为C的库函数或者操作系统的标准函数,如:

CopyMemory ()
memcpy()

这种内存代码你也千万不要尝试自己去实现,那将是一种灾难,在每个操作系统中,内存拷贝可以说是非常频繁的,所以系统的内存拷贝函数基本上都是非常完美的,不信的话你可以自己写一段内存拷贝函数,然后和系统的内存拷贝函数比较一下就知道了,具体原代码可以参考linux中string.lib的实现。

这处代码是特别值得注意的地方,如果你在你的代码的运算密集处写出了类似MD5_memcpy的代码的化,那么性能将会急剧的下降,对你的系统将是灾难性的。

三、使用汇编优化

下面又一段MD5C里面的代码,这种代码每一次md5加密要运算64次,而我们要穷举8位数字的话,就需要运算64000000次,将下面的代码用汇编展开以后大概是23行的汇编代码,也就是这个转换将耗费147200000000,即1472亿个指令周期。

//参考test/test1的原代码
#define UINT4 unsigned int
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define FF(a, b, c, d, x, s, ac) {
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac);
(a) = ROTATE_LEFT ((a), (s));
(a) += (b);
 }

3.1 减少内存的访问次数

把test1的代码反汇编得到代码如下:

mov    eax,dword ptr [ebp-8]
and    eax,dword ptr [ebp-0Ch]
mov    ecx,dword ptr [ebp-8]
not    ecx              <-
and    ecx,dword ptr [ebp-10h]
or    eax,ecx            <-
add    eax,dword ptr [ebp-14h]
add    eax,dword ptr [ebp-1Ch]
mov    edx,dword ptr [ebp-4]
add    edx,eax            <-
mov    dword ptr [ebp-4],edx
mov    eax,dword ptr [ebp-4]
mov    ecx,dword ptr [ebp-18h]
shl    eax,cl            <-
mov    ecx,20h            <-
sub    ecx,dword ptr [ebp-18h]
mov    edx,dword ptr [ebp-4]
shr    edx,cl            <-
or    eax,edx            <-
mov    dword ptr [ebp-4],eax
mov    eax,dword ptr [ebp-4]
add    eax,dword ptr [ebp-8]
mov    dword ptr [ebp-4],eax

从上面的代码可以看到,23条编译后的汇编代码中有16条是涉及内存访问指令,考虑到逻辑运算和四则运算的平均指令周期是4,而内存访问指令平均指令周期是10,所以上叙的内存访问指令将消耗整个程序时间的七成以上。所以,个人认为汇编的优化,其实质就是减少内存的访问,能够在寄存器内部完成的就不要反复的访问内存,此处我采取强制定义的方式使得这段程序基本不访问内存。

考虑到 FF(a, b, c, d, x, s, ac) 中s,ac是常数,x是一个数组,不好强制定义成寄存器,所以这里只强制定义了a,b,c,d四个变量为寄存器,以及tmp1,tmp2两个寄存器类型的临时变量。//参考test/test2的原代码
#define a esi
#define b edi
#define c edx
#define d ebx
#define tmp1 eax
#define tmp2 ecx

Tags:汇编 内核 MD

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接