关于P版的汇编高效处理字符串的升级问题【已解决】
本帖最后由 gto250 于 2012-12-22 22:43 编辑P版的字符串比较汇编代码(点击跳转)
我试着改过代码,但是总是内存错误,因为对汇编不怎么熟悉,所以还是到论坛上来求租。
问题基本相同,有
$str1="1a2b3c4d4d3c2b1a……4d3c2b1a"
$str2="1a2b3c4d1a2b3c4d……1a2b3c4d"
这样的两个长度相同的字符串,当然内容各不相同,由数字和字母组成,字符串很长。
现在打算每8位比较一次,比较厚相同的返回相同的内容,不同的返回“11223344”
如上面的字串返回的就是“1a2b3c4d11223344……11223344”
其实上面的字串是一个二进制的字串,如“0x1a2b3c4d4d3c2b1a……4d3c2b1a”,因为在上面的链接中我问过P版关于那机器码的相关问题,研究过很长时间,所以还是想用字符串的方式进行比较,因为比较好理解一点。
如果哪位觉得用二进制比较容易的话,也可以贴相关的代码,供学习一下 004001E1/.55 push ebp
004001E2|.8BEC mov ebp, esp
004001E4|.56 push esi
004001E5|.57 push edi
004001E6|.8B75 08 mov esi, dword ptr
004001E9|.8B7D 0C mov edi, dword ptr
004001EC|.8B4D 10 mov ecx, dword ptr
004001EF|.8B55 14 mov edx, dword ptr
004001F2|.33C0 xor eax, eax
004001F4|.C1E9 02 shr ecx, 2
004001F7|.FC cld
004001F8|>F3:A7 /repe cmpsd
004001FA|.75 06 |jnz short 00400202
004001FC|.5F |pop edi
004001FD|.5E |pop esi
004001FE|.C9 |leave
004001FF|.C2 1000 |retn 10
00400202|>8956 FC |mov dword ptr , edx
00400205|.40 |inc eax
00400206|.3BC0 |cmp eax, eax
00400208\.^ EB EE \jmp short 004001F8
0040020A CC int3
0040020B CC int3使用DllCallAddress函数调用这段汇编代码。原型为:
func(dst, src, len, replace)
每4个字节进行比较dst和src中的数据,总共比较Int(len/4)次,如果某处内容不同,将替换为replace所指定的值。
参数分别是:
dst - 内存1的起始地址。
src - 内存2的起始地址。
len - 需要比较的长度,以字节为单位。
replace - 将不同处的内容替换为此值。
函数返回值为替换的次数,替换后的内容,将在dst中返回。 回复 2# pusofalse
谢谢P版,我先试着自己使用一下 感谢P版的汇编代码,虽然不知道是什么意思,但是还是根据这机器码写出了au3的代码
以下就是应用的FUNC,不知道有没有同样需求的兄弟们需要使用。
最后,如果P版有空的话,能否解释一下汇编代码
我只知道shr 攀挀砀, 2这句是右移2位的意思,就是除以4的意思,因为是按照四个字节比较
如果是三个字节比较的话,应该就不能这么写了吧?,如果我要改成三个字节比较的话,要怎么修改呢?
$Data1 = "ff12345601020304ff12345605060708"
$Data2 = "ff12345605060708ff12345601020304"
$r = cmps($Data1, $Data2, "0x12345678")
MsgBox(0, "替换次数" & $r & "次", $r)
Func cmps($dst, $src, $replace)
Local $r
If StringLeft($replace, 2) = '0x' Then
$replace = StringRegExpReplace(StringTrimLeft($replace, 2), '(\w{2})(\w{2})(\w{2})(\w{2})', '0x$4$3$2$1')
Else
$replace = StringRegExpReplace($replace, '(\w{2})(\w{2})(\w{2})(\w{2})', '0x$4$3$2$1')
EndIf
$Opcode = Binary("0x558BEC56578B75088B7D0C8B4D108B551433C0C1E902FCF3A775065F5EC9C210008956FC403BC0EBEECCCC")
$CodeBufferPtr_return=DllCall("kernel32.dll", "ptr", "VirtualAlloc", "ptr", 0, "ulong_ptr", BinaryLen($Opcode), "dword", 0x00001000, "dword",0x00000040)
Local $CodeBufferPtr = $CodeBufferPtr_return
Local $CodeBuffer = DllStructCreate("byte[" & BinaryLen($Opcode) & "]", $CodeBufferPtr)
DllStructSetData($CodeBuffer, 1, $Opcode)
If IsBinary($dst) = False Then $dst = Binary("0x" & $dst)
Local $dst_BufferLen = BinaryLen($dst)
Local $dst_Buffer = DllStructCreate("byte[" & $dst_BufferLen & "]")
DllStructSetData($dst_Buffer, 1, $dst)
If IsBinary($src) = False Then $src = Binary("0x" & $src)
Local $src_BufferLen = BinaryLen($src)
Local $src_Buffer = DllStructCreate("byte[" & $src_BufferLen & "]")
DllStructSetData($src_Buffer, 1, $src)
Local $Ret = DllCallAddress("uint", $CodeBufferPtr, "ptr", DllStructGetPtr($dst_Buffer), "ptr", DllStructGetPtr($src_Buffer), "uint", $dst_BufferLen, "uint", $replace)
DllCall("kernel32.dll", "bool", "VirtualFree", "ptr", $CodeBufferPtr, "ulong_ptr", 0, "dword", 0x00008000)
$r = $Ret
$r = DllStructGetData($dst_Buffer, 1)
Return $r
EndFunc ;==>cmps 回复 3# gto250
测试代码如下。函数是以你说的二进制方式比较的,非字符串方式。
#include <Thread.au3>
Local $bBinary = "0x558BEC56578B75088B7D0C8B4D108B551433C0C1E902FCF3A775065F5EC9C210008956FC403BC0EBEECCCC"
Local $pStart = _RTVirtualAlloc(4096)
Local $tStart = DllStructCreate("ubyte", $pStart)
DllStructSetData($tStart, 1, Binary($bBinary))
Local $bBinary1 = Binary("0x1111111133333333EEEEEEEE") ; 字符串1
Local $bBinary2 = Binary("0x1111111133333333FFFFFFFF") ; 字符串2
Local $tDst = DllStructCreate("ubyte [" & BinaryLen($bBinary1) & "]")
Local $tSrc = DllStructCreate("ubyte [" & BinaryLen($bBinary2) & "]")
DllStructSetData($tDst, 1, $bBinary1)
DllStructSetData($tSrc, 1, $bBinary2)
Local $pDst = DllStructGetPtr($tDst)
Local $pSrc = DllStructGetPtr($tSrc)
Local $iResult = DllCallAddress("long", $pStart, "ptr", $pDst, "ptr", $pSrc, "long", BinaryLen($bBinary1), "dword", 0x44444444)
MsgBox(0, StringFormat("Replaced %d DWORD(s).", $iResult), DllStructGetData($tDst, 1))
#CS
004001E1/.55 push ebp
004001E2|.8BEC mov ebp, esp
004001E4|.56 push esi
004001E5|.57 push edi
004001E6|.8B75 08 mov esi, dword ptr
004001E9|.8B7D 0C mov edi, dword ptr
004001EC|.8B4D 10 mov ecx, dword ptr
004001EF|.8B55 14 mov edx, dword ptr
004001F2|.33C0 xor eax, eax
004001F4|.C1E9 02 shr ecx, 2
004001F7|.FC cld
004001F8|>F3:A7 /repe cmpsd
004001FA|.75 06 |jnz short 00400202
004001FC|.5F |pop edi
004001FD|.5E |pop esi
004001FE|.C9 |leave
004001FF|.C2 1000 |retn 10
00400202|>8956 FC |mov dword ptr , edx
00400205|.40 |inc eax
00400206|.3BC0 |cmp eax, eax
00400208\.^ EB EE \jmp short 004001F8
0040020A CC int3
0040020B CC int3
#CE 回复 4# gto250
汇编中有3个字符串比较指令,分别是cmpsb, cmpsw,cmpsd,含义分别是按字节比较,按字比较,按双字比较,64位汇编中应该还会有个cmpsq指令,按四字比较(?)。这些个指令中,能一次比较1、2、4、8个字节,唯独没有你说的按3个字节对齐进行比较。如果一次要比较3个、5个或7个,总之,要比较的数量没有现成的CPU指令支持,代码就要全部改动了。 回复 6# pusofalse
谢谢
页:
[1]