[分析]快速字符串转DWORD型的函数(MMX指令集)

请用带语法高亮的编辑器查看,可读性将大大增强,若边查MMX指令(我已经注释了),再用OD跟踪mm0, mm1的值(分别对应st(0)和st(1)的低64位),可加深理解!!
可能低版本的ml.exe不支持MMX指令集,我用的是VS2005的ml.exe 版本是8.00.50727  而masm32中的是6.14 版的,替换一下更好...也算是升级了,哈哈!!

;***************************************************
;Hexadecimal String to DWORD OR QWORD(MMX)

;Author bitRAKE
;Analysed  By  G-Spider 
;ml  /c /coff hex.asm  
;link /subsystem:windows hex.obj 
;***************************************************

 .586
 .MMX
 .model flat,stdcall
 option casemap:none
 
 include windows.inc
 include user32.inc
 include kernel32.inc

 includelib user32.lib
 includelib kernel32.lib

;***********************************************
;此宏将数据重复成8字节
;如:mxc(<30>) ;字节级重复
;等价于立即数30 30 30 30 30 30 30 30h
;如: mxc(<0f00>) ;字级重复
;等价于立即数0f00 0f00 0f00 0f00h
;如: mxc(<0f000000>) ;双字级重复
;等价于立即数0f000000 0f000000h

mxc MACRO val:REQ
    LOCAL w,y,z
    z SIZESTR <&val>
    ;; Attempt to compact data
    WHILE (z LT 17) AND (z GT 2)
        z = z/2
        IFDIF @SubStr(<&val>,1,z),@SubStr(<&val>,1+z,z)
            z = z + z + 16
        ENDIF
    ENDM

    IF z GT 16
        z = z - 16
    ENDIF

    w TEXTEQU @SubStr(<&val>,1,z)
    ;; figure out global name for constant
    y CATSTR <__MMX_>,w

    IF (OPATTR(y)) EQ 0 ;; not defined
        CONST$mmx SEGMENT
            y LABEL QWORD
            w CATSTR <0>,w,<h>
            IF z EQ 16
                dq w
            ELSEIF z EQ 8
                dd w,w
            ELSEIF z EQ 4
                dw w,w,w,w
            ELSEIF z EQ 2
                db w,w,w,w,w,w,w,w
            ENDIF
        CONST$mmx ENDS
    ENDIF
    EXITM y
ENDM
;***************************************************
.data
szTitleSave db  'good luck',0
fmt     db      '%X',0 
.data?
buf    db  16  dup(?)

.code
;快速字符串转DWORD型的函数(MMX指令集)
StrHex2bin PROC
    _CONST SEGMENT
        lpString db "89aBcDeF"
        ;//"89aBcDeF"=>38h | 39h || 61h | 42h ||| 63h | 44h || 65h | 46h 
    _CONST ENDS
    movq mm0,QWORD PTR [lpString]
    ;mm0=46 65 44 63 42 61 39 38 h  <==注意取数据为低上位方式
    
    psubusb  mm0,mxc(<30>) ; "0" = 0
    ;mxc(<30>)=30 30 30 30 30 30 30 30 h 
    ;psubusb XMM,XMM/m128
    ;源存储器与目的寄存器按字节对齐无符号饱和相减(目的减去源),内存变量必须对齐内存16字节.
    ;mm0=16 35 14 33 12 31 09 08 h
    
    movq mm1,mm0
    ;movq XMM,XMM/m64
    ;把源存储器低64位内容送入目的寄存器的低64位,高64位清零.
    ;mm1=16 35 14 33 12 31 09 08 h 
    
    pcmpgtb mm1,mxc(<09>) ; letter?
    ;mxc(<09>)=09 09 09 09 09 09 09 09h
    ;pcmpgtb MM,MM/m64
    ;源寄存器与目的寄存器按字节(有符号补码)比较,
    ;当目的寄存器对应字节大于源寄存器就置目的寄存器对应字节为0ffh,否则为00h
    ;mm1=0 ffff ffff ffff 0000h
    pand mm1,mxc(<07>)
    ;pand XMM,XMM/m128
    ;源存储器128个二进制位'与'目的寄存器128个二进制位,结果送入目的寄存器,内存变量必须对齐内存16字节.
    ;mm0=16 35 14 33 12 31 09 08h
    ;mm1=07 07 07 07 07 07 00 00h
    
    psubusb mm0,mm1 ; fix letters
    ;mm0=0f 2e 0d 2c 0b 2a 09 08h

    movq mm1,mm0         
    ;mm1=0f 2e 0d 2c 0b 2a 09 08h    
    pand mm0,mxc(<0F00>) 
    ;mxc(<0F00>)=0f00 0f00 0f00 0f00h
    ;mm0=0f00 0d00 0b00 0900h
    pand mm1,mxc(<000F>) 
    ;mxc(<000F>)=000f 000f 000f 000fh
    ;mm1=000e 000c 000a 0008h
    psrlq mm0,8         
    ;汇编指令:PSRLQ
    ;功能说明:将m1中的整数右移count位,直到变为0才停止。
    ;mm0=000f 000d 000b 0009h
    
    ;mm1=000e 000c 000a 0008h
    packuswb mm1,mm1     
    ;把目的寄存器按字有符号数压缩为字节无符号数放入目的寄存器低32位
    ;把源寄存器按字有符号数压缩为字节无符号数放入目的寄存器高32位
    ;压缩时负数变为00h,大于255的正数变为0ffh.
    ;mm1=0e 0c 0a 08  0e 0c 0a 08 h

    ;mm0=000f 000d 000b 0009h
    packuswb mm0,mm0     
    ;mm0=0f 0d 0b 09  0f 0d 0b 09 h
    
    ;mm1=0e 0c 0a 08  0e 0c 0a 08 h
    psllq mm1,4         
    ;将m1中的整数左移count位,直到变为0才停止
    ;mm1=e0 c0 a0 80  e0 c0 a0 80 h
    ;mm0=0f 0d 0b 09  0f 0d 0b 09 h
    por mm0,mm1         
    ;por MM,MM/m64
    ;64个位'或'操作,结果放入目的寄存器.
    ;mm0=ef ed ab 89  ef cd ab 89 h
    
    movd eax,mm0        
    ;eax=ef cd ab 89h 
    bswap eax
    ;eax=89 ab cd efh    
    ret
StrHex2bin ENDP

start:
    invoke    StrHex2bin
    invoke    wsprintf,offset buf,offset fmt,eax
    invoke  MessageBox,NULL,offset buf,addr szTitleSave,0 

    ret
    end start

 

在某个算法论坛版块发现有人需要十六进制串转四字(64位)或双字型(32位)数据,所以在上面的基础上扩展了一下:
(当初想着考虑用SSE指令集,发现一个最大的困难是无法直接读取16字节数据,尝试了OWORD好像不支持或得不到预期的效果)。

;***************************************************
;Hexadecimal String to DWORD OR QWORD(MMX)

;Author bitRAKE  http://madwizard.org/programming/snippets?id=43
;Updated  By  G-Spider
;ml  /c /coff hex.asm  
;link /subsystem:windows hex.obj 
;***************************************************
 .586
 .MMX
 .model flat,stdcall
 option casemap:none
 
 include windows.inc
 include user32.inc
 include kernel32.inc

 includelib user32.lib
 includelib kernel32.lib

;***************************************************
.data
szTitleSave     db  'good luck',0
fmt             db  '%X%X',0
 
ALIGN 16 
_0fill          db  16  dup(0)            ;Need! When _StringLong<16
_lpString       db "89aBcDeF12aCdEfF",0   ;Test1 <====note! Have Zero End
;_lpString      db "89aBcDeF12",0         ;Test2
;_lpString      db "89aBcDe",0            ;Test3
;_lpString      db "89aBcDeF12345678aD",0 ;Test4
_StringLong     dd $-_lpString-1
  
;_lpString      db "89aBcDeF12345678"     ;<====note!  NO Zero End
;_StringLong    dd $-_lpString  

ALIGN 16        ;<==Note!
_3Hex           qword   3030303030303030h
_9Hex           qword   0909090909090909h
_7Hex           qword   0707070707070707h 
_f0Hex          qword   0f000f000f000f00h  
_0fHex          qword   000f000f000f000fh 

.data?
buf            db  16  dup(?)

.code

StrHex2bin PROC lpString:DWORD

        mov         eax,lpString
        movq        mm0,QWORD PTR [eax]   
        psubusb     mm0,_3Hex  ; "0" = 0    
        movq        mm1,mm0 
        pcmpgtb     mm1,_9Hex   ; letter?      
        pand        mm1,_7Hex
        psubusb     mm0,mm1     ; fix letters
        movq        mm1,mm0   
        pand        mm0,_f0Hex
        pand        mm1,_0fHex
        psrlq       mm0,8   
        packuswb    mm1,mm1     
        packuswb    mm0,mm0     
        psllq       mm1,4         
        por         mm0,mm1            
        movd        eax,mm0         
        bswap       eax   
        ret
StrHex2bin ENDP

StrHex2Qword proc lpString,StringLong

        mov     ebx,lpString
        add     ebx,StringLong
        sub     ebx,16
        push    ebx
        invoke    StrHex2bin,ebx
        mov     edx,eax        ;edx=QuadWord.HiDWord
        pop     ebx
        add     ebx,8
        invoke    StrHex2bin,ebx ;eax=QuadWord.LoDWord
        ret
StrHex2Qword    endp

start:
    invoke  StrHex2Qword,offset _lpString,_StringLong
    
    invoke    wsprintf,offset buf,offset fmt,edx,eax
    invoke  MessageBox,NULL,offset buf,addr szTitleSave,0 

    ret
    end start

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值