zstrstr proc uses ecx edx _str:DWORD, _key:DWORD, _klen:DWORD
mov edx, 17 ; (1)edx中保存步进长度 16 - _klen + 1
mov ecx, _key ; (1)加载key
mov eax, _str ; 读取字符串指针到寄存器中
movdqu xmm0, xmmword ptr [ecx] ; (2)加载key
sub edx, _klen ; (2)edx中保存步进长度 16 - _klen + 1 = 15
; 打乱顺序,减少前后语句的依赖性,方便并行执行
redo:
pcmpistri xmm0, [eax], 12
jc checkfound ;不一定是真的找到了,还要进一步确认,这里采用判断ecx的方法
jz exitPos ;被搜索的字符串都到\0了都还没找到,那真的就是找不到了
checkfound:
add eax, ecx ;无论是不是真的找到目标字符串,都要+ecx
.if ecx < edx
ret ;如果是真找到了,要返回eax+ecx这个位置
.endif
jmp redo ;如果没找到,则要从eax+ecx这个位置继续搜索
exitPos:
xor eax, eax
ret
zstrstr endp
__declspec(align(16)) unsigned char str[21] = "aaaaaaaaaaaaaaaaaaaa";
__declspec(align(16)) unsigned char key[16] = "bb";
char *p = NULL;
__asm
{
mov ebx, 15 ;步长 16-2(bb)+1(找过的地方的下一个位置开始继续找)
mov eax, 2
mov edx, LENGTH str
movdqu xmm0, key
lea esi, str
redo:
pcmpestri xmm0, [esi], 12 ;这里没有pcmpistri的zero标记进行判断了,只能根据edx中的长度进行退出循环
jc checkfound
go_on:
add esi, ebx
sub edx, ebx
jg redo
mov p, NULL ;可能这里用 [p] 更方便理解一些
jmp exitpos
checkfound:
cmp ecx, ebx
jae go_on
lea eax, [esi+ecx]
mov p, eax
exitpos:
}
要注意有一个坑,pcmpXstrY的搜索是循环的,如下面的 :
__declspec(align(16)) unsigned char str[21] = "baaaaaaaaaaaaaaa";
__declspec(align(16)) unsigned char key[16] = "ab";
这时,会认为在15的位置找到了目标字符串ab,所以要判断找到的ECX是不是合法的,即要 ECX <= (16-2) 或者 ECX < (16 - 2 + 1)
关于步长:
__declspec(align(16)) unsigned char str[21] = "baaaaaaaaaaaaaaA";
__declspec(align(16)) unsigned char key[16] = "ab";
最后一个匹配的位置是aa,所以下一次搜索的起始位置是A,也就是步长为 16 - 2 + 1