找回密码
 加入
搜索
查看: 4795|回复: 6

[效率算法] 关于P版的汇编高效处理字符串的升级问题【已解决】

[复制链接]
发表于 2012-12-21 22:39:57 | 显示全部楼层 |阅读模式
本帖最后由 gto250 于 2012-12-22 22:43 编辑

P版的字符串比较汇编代码(点击跳转)

我试着改过代码,但是总是内存错误,因为对汇编不怎么熟悉,所以还是到论坛上来求租。
问题基本相同,有
$str1="1a2b3c4d4d3c2b1a……4d3c2b1a"
$str2="1a2b3c4d1a2b3c4d……1a2b3c4d"
这样的两个长度相同的字符串,当然内容各不相同,由数字和字母组成,字符串很长。
现在打算每8位比较一次,比较厚相同的返回相同的内容,不同的返回“11223344”
如上面的字串返回的就是“1a2b3c4d11223344……11223344”


其实上面的字串是一个二进制的字串,如“0x1a2b3c4d4d3c2b1a……4d3c2b1a”,因为在上面的链接中我问过P版关于那机器码的相关问题,研究过很长时间,所以还是想用字符串的方式进行比较,因为比较好理解一点。
如果哪位觉得用二进制比较容易的话,也可以贴相关的代码,供学习一下
发表于 2012-12-22 18:44:08 | 显示全部楼层
004001E1  /.  55            push    ebp
004001E2  |.  8BEC          mov     ebp, esp
004001E4  |.  56            push    esi
004001E5  |.  57            push    edi
004001E6  |.  8B75 08       mov     esi, dword ptr [ebp+8]
004001E9  |.  8B7D 0C       mov     edi, dword ptr [ebp+C]
004001EC  |.  8B4D 10       mov     ecx, dword ptr [ebp+10]
004001EF  |.  8B55 14       mov     edx, dword ptr [ebp+14]
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 [esi-4], 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中返回。
 楼主| 发表于 2012-12-22 20:12:15 | 显示全部楼层
回复 2# pusofalse


    谢谢P版,我先试着自己使用一下
 楼主| 发表于 2012-12-22 21:27:34 | 显示全部楼层
感谢P版的汇编代码,虽然不知道是什么意思,但是还是根据这机器码写出了au3的代码
以下就是应用的FUNC,不知道有没有同样需求的兄弟们需要使用。

最后,如果P版有空的话,能否解释一下汇编代码
我只知道shr 攀挀砀, 2这句是右移2位的意思,就是除以4的意思,因为是按照四个字节比较
如果是三个字节比较的话,应该就不能这么写了吧?,如果我要改成三个字节比较的话,要怎么修改呢?

$Data1 = "ff12345601020304ff12345605060708"

$Data2 = "ff12345605060708ff12345601020304"


$r = cmps($Data1, $Data2, "0x12345678")
MsgBox(0, "替换次数" & $r[0] & "次", $r[1])


Func cmps($dst, $src, $replace)
        Local $r[2]
        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[0]
        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[0] = $Ret[0]
        $r[1] = DllStructGetData($dst_Buffer, 1)
        Return $r
EndFunc   ;==>cmps
发表于 2012-12-22 21:43:26 | 显示全部楼层
回复 3# gto250


    测试代码如下。函数是以你说的二进制方式比较的,非字符串方式。
#include <Thread.au3>

Local $bBinary = "0x558BEC56578B75088B7D0C8B4D108B551433C0C1E902FCF3A775065F5EC9C210008956FC403BC0EBEECCCC"

Local $pStart = _RTVirtualAlloc(4096)
Local $tStart = DllStructCreate("ubyte[4096]", $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[0]), 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 [ebp+8]
004001E9  |.  8B7D 0C       mov     edi, dword ptr [ebp+C]
004001EC  |.  8B4D 10       mov     ecx, dword ptr [ebp+10]
004001EF  |.  8B55 14       mov     edx, dword ptr [ebp+14]
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 [esi-4], edx
00400205  |.  40            |inc     eax
00400206  |.  3BC0          |cmp     eax, eax
00400208  \.^ EB EE         \jmp     short 004001F8
0040020A      CC            int3
0040020B      CC            int3
#CE
发表于 2012-12-22 21:57:05 | 显示全部楼层
回复 4# gto250


    汇编中有3个字符串比较指令,分别是cmpsb, cmpsw,cmpsd,含义分别是按字节比较,按字比较,按双字比较,64位汇编中应该还会有个cmpsq指令,按四字比较(?)。这些个指令中,能一次比较1、2、4、8个字节,唯独没有你说的按3个字节对齐进行比较。如果一次要比较3个、5个或7个,总之,要比较的数量没有现成的CPU指令支持,代码就要全部改动了。
 楼主| 发表于 2012-12-22 22:35:21 | 显示全部楼层
回复 6# pusofalse


    谢谢
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-5-18 23:20 , Processed in 0.098375 second(s), 24 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表