请用带语法高亮的编辑器查看,可读性将大大增强,若边查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