Hi guys
can someone test this string comparation function i made ? I have no idea how fast/slow is it.
In theory it should be twice as fast as strcmp from msvcrt, but i´m unable to benchmark it.
UPDATED VERSION 29/01/2013
Proc FastStringCompare:
Arguments @String1, @String2
Uses esi, ecx, ebx, edx
mov esi D@String1
mov ecx 0
mov eax 0
mov ebx D@String2
mov edx D$esi
cmp edx D$ebx ; just to force the zero flags. if we have a match zero flag is settled. But we need to check if the last byte at string1 is zero.
jz L0> ; The 1st 4 bytes are not zero, jmp over
mov ecx 3
shr edx 8 | jz L1> ; If string is only 1 byte len. ecx = 3
inc ecx | jmp L1> ; else, ecx = 4
L0:
test dh dh | jz L1> ; the last byte of the 1st string is zero. We reached the end of the search. Contunue computing the remaining bytes at "L1"
lea ecx D$ecx+4 ; compute the len of the string1
mov edx D$esi+ecx
cmp D$ebx+ecx edx
jz L0<
jmp L3>> ; strings definitelly dont match
L1:
lea ebx D$ebx+ecx | mov edx D$ebx-3
lea esi D$esi+ecx
cmp D$esi-3 edx; if both words on string1 and string2 don´ match jmp over. Otherwise, continue analysing the remaining bytes
jnz L3>>
; We are almost there. If ecx = 0, means that the string1 have only 2 byte len. So let´t search for the 2nd byte of string2
;;
; so far all bytes are equal. Let´t see if teh string2 is null terminated as it is on string1. Ex: str1) "guga1" | str2) "guga1" Or if it is str1) "guga1" | str2) "gugaM"...
; On the dword, we need to check the byte after the dx like: 00XX_0000
If B$ebx-1 = 0
inc eax
End_If
Note for me, i commented it out, because the above assumption is wrong. In fact, when we reach here we have analysed all the string
and both are exactly the same.
;;
; In mine tests no matter what bytes gets here, because it always means that we fully analysed the strings, and they always matches
inc eax
L3:
EndP
Tested strings:
call FastStringCompare {"1", 0}, {"g", 0}
call FastStringCompare {"g", 0}, {"g", 0}
call FastStringCompare {"gu", 0}, {"gu", 0}
call FastStringCompare {"gug", 0}, {"gug", 0}
call FastStringCompare {"guga", 0}, {"guga", 0}
call FastStringCompare {"guga1", 0}, {"guga1", 0}
call FastStringCompare {"guga12", 0}, {"guga12", 0}
call FastStringCompare {"guga123", 0}, {"guga123", 0}
call FastStringCompare {"guga1234", 0}, {"guga1234", 0}
call FastStringCompare {"guga12345", 0}, {"guga12345", 0}
call FastStringCompare {"guga123456", 0}, {"guga123456", 0}
call FastStringCompare {"1234", 0}, {"5678", 0}
call FastStringCompare {"1", 0}, {"g", 0}
call FastStringCompare {"gustavo trigu", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"g", 0}, {"gu", 0}
call FastStringCompare {"gu", 0}, {"gu", 0}
call FastStringCompare {"gu", 0}, {"guu", 0}
call FastStringCompare {"guuu", 0}, {"guu", 0}
call FastStringCompare {"guu", 0}, {"guuu", 0}
call FastStringCompare {"gug", 0}, {"guga", 0}
call FastStringCompare {"g44564", 0}, {"112345g", 0}
call FastStringCompare {"gu", 0}, {"g", 0}
call FastStringCompare {"gu", 0}, {"gu", 0}
call FastStringCompare {"g", 0}, {"gu", 0}
call FastStringCompare {"g", 0}, {"g", 0}
call FastStringCompare {"1", 0}, {"g", 0}
call FastStringCompare {"g1stavo trigueiros e guilherme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gu1tavo trigueiros e guilherme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gus1avo trigueiros e guilherme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gust1vo trigueiros e guilherme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gusta1o trigueiros e guilherme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustav1 trigueiros e guilherme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustavo1trigueiros e guilherme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustavo 1rigueiros e guilherme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustavo trigueiros e guilherm1", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustavo trigueiros e guilher1e", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustavo trigueiros e guilhe1me", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustavo trigueiros e guilh1rme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustavo trigueiros e guil1erme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustavo trigueiros e gui1herme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustavo trigueiros e gu1lherme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustavo trigueiros e g1ilherme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustavo trigueiros e 1uilherme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustavo trigueiros e1guilherme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustavo trigueiros 1 guilherme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustavo trigueiros1e guilherme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustavo trigueiro1 e guilherme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustavo trigueir1s e guilherme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"gustavo trigueiros e guilherme", 0}, {"gustavo trigueiros e guilherme", 0}
call FastStringCompare {"guga", 0}, {"guga1", 0}
call FastStringCompare {"guga1", 0}, {"guga", 0}
________________________________________________________________________________________________
________________________________________________________________________________________________
________________________________________________________________________________________________
________________________________________________________________________________________________
________________________________________________________________________________________________
OLDER VERSION 29/01/2013 - Aligned data. It is fast, but the above one is faster.
Proc FastStringCompare:
Arguments @String1, @String2
Uses esi, ecx, ebx, edx
mov esi D@String1
mov ecx 0
mov eax 0
mov ebx D@String2
mov edx D$esi
cmp edx D$ebx ; just to force the zero flags. if we have a match zero flag is settled. But we need to check if the last byte at string1 is zero.
jz L0> ; The 1st 4 bytes are not zero, jmp over
mov ecx 3
shr edx 8 | jz L1> ; If string is only 1 byte len. ecx = 3
inc ecx | jmp L1> ; else, ecx = 4
L0:
cmp dh 0 | jz L1> ; the last byte of the 1st string is zero. We reached the end of the search. Contunue computing the remaining bytes at "L1"
lea ecx D$ecx+4 ; compute the len of the string1
mov edx D$esi+ecx
cmp D$ebx+ecx edx
jz L0<
jmp L3>> ; strings definitelly dont match
L1:
lea ebx D$ebx+ecx | mov edx D$ebx-3
lea esi D$esi+ecx
cmp edx D$esi-3 ; if both words on string1 and string2 don´ match jmp over. Otherwise, continue analysing the remaining bytes
jnz L3>>
; We are almost there. If ecx = 0, means that the string1 have only 2 byte len. So let´t search for the 2nd byte of string2
;;
; so far all bytes are equal. Let´t see if teh string2 is null terminated as it is on string1. Ex: str1) "guga1" | str2) "guga1" Or if it is str1) "guga1" | str2) "gugaM"...
; On the dword, we need to check the byte after the dx like: 00XX_0000
If B$ebx-1 = 0
inc eax
End_If
Note for me, i commented it out, because the above assumption is wrong. In fact, when we reach here we have analysed all the string
and both are exactly the same.
;;
; In mine tests no matter what bytes gets here, because it always means that we fully analysed the strings, and they always matches
inc eax
L3:
EndP
OLDER VERSION 28/01/2013 - Unaligned data and some mistake when the string is only 1 byte len
; Return values:
; Eax = 0. Strings don´t match
; Eax = 1. Strings matches
Proc FastStringCompare:
Arguments @String1, @String2
Uses esi, ecx, ebx, edx
mov esi D@String1
xor ecx ecx
xor eax eax
xor edx edx
mov ebx D@String2
mov ax W$ebx
mov dx W$esi
xor ax dx ; just to force the zero flags. if we have a match zero flag is settled. But we need to check if the last byte at string1 is zero.
L0:
or dh 0 | jz L1> ; the last byte of the 1st string is zero. We reached the end of the search. Contunue computing the remaining bytes at "L1"
lea ecx D$ecx+2 ; compute the len of the string1
mov dx W$esi+ecx
cmp W$ebx+ecx dx
jz L0<
L1:
lea ebx D$ebx+ecx | mov ax W$ebx-1
lea esi D$esi+ecx | mov dx W$esi-1
xor ax dx ; if both words on string1 and string2 don´ match jmp over. Otherwise, continue analysing the remaining bytes
jz L1> | L2: | xor eax eax | ExitP | L1:
; We are almost there. If ecx = 0, means that the string1 have only 2 byte len. So let´t search for the 2nd byte of string2
L1:
; do again for the last bytes
; so far all bytes are equal
mov eax &TRUE
.If ecx = 0 ; when len (ecx) is zero it means that we the string is smaller then 2 bytes (including null terminated)
If B$ebx+1 <> 0 ; so all we need is analyse if the last byte if the string2 is zero (Because the 1st one of both matches)
xor eax eax
End_If
.Else_If B$ebx <> 0
xor eax eax
.End_If
EndP
Code examples
call FastStringCompare {"g", 0}, {"gu", 0}
call FastStringCompare {"gu", 0}, {"gu", 0}
call FastStringCompare {"gu", 0}, {"guu", 0}
call FastStringCompare {"guuu", 0}, {"guu", 0}
call FastStringCompare {"guu", 0}, {"guuu", 0}
call FastStringCompare {"gug", 0}, {"guga", 0}
call FastStringCompare {"g44564", 0}, {"112345g", 0}
call FastStringCompare {"gu", 0}, {"g", 0}
call FastStringCompare {"gu", 0}, {"gu", 0}
call FastStringCompare {"g", 0}, {"gu", 0}
call FastStringCompare {"g", 0}, {"g", 0}
mov ecx 0-1
Do
call FastStringCompare {"gustavo trigueiros e guilherme", 0}, {"gustavo trigueiros e guilherme", 0}
dec ecx
Loop_Until ecx = 0
call FastStringCompare {"guga", 0}, {"guga1", 0}
call FastStringCompare {"guga1", 0}, {"guga", 0}