由于这里是反汇编,是加载到内存中的,没有标号,跳转的时候指定的是跳转目标地址,这里将地址放到语句之后。
这里可以看到,反汇编代码和我们之前看到的明显不同,应该就是之前包含进来的代码了。那么,它都做了些什么呢?
在这里,我们从intel文档中查看几个命令:
pshuflw:
movlhps:
movdqu:
pxor:
pcmpeqb:
pmovmskb:
cmovne:
bsf:
第一行和第二行,是一个判断,我们看到,如果 ds:[7BEB92DCh] 处的值大于或等于1,则跳转到第 34 行(7BEA4348),为什么会有这个跳转呢?我们看看34行代码,并和之前看到的汇编代码作比较:
我们发现,后面的代码和之前我们看到的汇编源代码一模一样。所以,这里我们可以认为是在判断是否支持SSE,至于为什么如此判断,暂时还没有调查清楚,如果有清楚的,麻烦在评论区回复下,不胜感激。
在了解到执行代码后面部分一致的情况下,我们此时就可以将重点放在前半部分了,为了方便,我们这里再次引用反汇编得到的代码前面部分,并忽略第一句,如下:
movzx eax,byte ptr [esp+8] ; 7BEA42E9 mov edx,eax ; 7BEA42EE shl eax,8 ; 7BEA42F0 or edx,eax ; 7BEA42F3 movd xmm3,edx ; 7BEA42F5 pshuflw xmm3,xmm3,0 ; 7BEA42F9 movlhps xmm3,xmm3 ; 7BEA42FE mov edx,dword ptr [esp+4] ; 7BEA4301 mov ecx,0Fh ; 7BEA4305 or eax,0FFFFFFFFh ; 7BEA430A and ecx,edx ; 7BEA430D shl eax,cl ; 7BEA430F sub edx,ecx ; 7BEA4311 movdqu xmm1,xmmword ptr [edx] ; 7BEA4313 pxor xmm2,xmm2 ; 7BEA4317 pcmpeqb xmm2,xmm1 ; 7BEA431B pcmpeqb xmm1,xmm3 ; 7BEA431F por xmm2,xmm1 ; 7BEA4323 pmovmskb ecx,xmm2 ; 7BEA4327 and ecx,eax ; 7BEA432B jne 7BEA4337 ; 7BEA432D or eax,0FFFFFFFFh ; 7BEA432F add edx,10h ; 7BEA4332 jmp 7BEA4313 ; 7BEA4335 bsf eax,ecx ; 7BEA4337 add eax,edx ; 7BEA433A movd edx,xmm3 ; 7BEA433C xor ecx,ecx ; 7BEA4340 cmp dl,byte ptr [eax] ; 7BEA4342 cmovne eax,ecx ; 7BEA4344 ret ; 7BEA4347
1 - 4行:原理和之前类似,[esp+8] 处为要查找的目标字符值,到第四行,将edx寄存器的0-7位,和8-15位均设置为查找目标字符。
5 - 7行:将 xmm3 寄存器的每字节均设置为目标字符值,如果我们查找 'x' 字符,则 xmm3 的值为 "xxxxxxxxxxxxxxxx"。
8 - 13行:将查询的源字符串的地址进行16位对齐,并指向源字符串地址之前。并将 eax 值左移目标字符串地址的低四位值(意味着将eax作为之后取值的mask);
14 - 31 行:是查询的主要逻辑,下面我们详细讨论。
第14行,将edx指针指向内存开始的16字节复制到 xmm1寄存器中;
第15行,将xmm2寄存器所有字节设置为0;
第16行,将xmm1中所有的字节与xmm2字节做比较,比较结果放到xmm2中(如果xmm1中字节和xmm2中字节相等,则xmm2对应字节将被设置为0xff,否则将被设置为0x00);
第17行,将xmm3(每个字节值均为目标字符值)和xmm1中的字节做比较,结果放置到xmm1中,如果是第一次做比较,则xmm1中可能存有查找字符串之前的内容,而且有可能包含查找的目标字符,这种情况将在第20行进行处理;
第18行,将xmm1中(源字符串中16个字符或者字符串n个字节内容+字符串前n个字符和要查找的目标字符的比对结果,即前n个字符的擦护照结果)和xmm2中内容执行字节或运算。并将结果放到 xmm2 中。
第19行,按照xmm2中字节内容,生成一个 mask值,并将其放到 ecx 寄存器;
第20行,将ecx和eax(如果第一次,有效位被第12行设置为1,无效位被置为0)执行 and 运算;
第21行,如果20行执行结果不为0(说明找到了目标值),跳转到第25行;
第22行,eax 所有位均置为1;
第23行,将源字符串指针前移16(10h)个字节;
第24行,跳转到循环初始位置,开始新的一轮循环;
第25行,查找ecx中为1的位的编号,并将编号放置到eax;
第26行,将源字符串指针前移eax个字节,这就是目标字符所在位置了;
第27行,从xmm3(每个字节均为查找目标字符)中读取4个字节,并将值放置到edx中;
第28行,置ecx为0,以备返回(目标字符未找到);
第29行,比较dl(edx最低字节)和eax指向的字符;
第30行,如果29行比较结果不相等,说明没有找到目标字符,就置eax为0,否则eax不变;
第31行,返回;
这里可以看到,因为使用了 xmm 寄存器,我们每次都处理了16个字节,那为什么效率提升不是16倍呢?只能归结为xmm寄存器增加了电路复杂性,使得处理周期增加了一倍吧。
本文地址:百科问答频道 https://www.neebe.cn/wenda/903427_2.html,易企推百科一个免费的知识分享平台,本站部分文章来网络分享,本着互联网分享的精神,如有涉及到您的权益,请联系我们删除,谢谢!