請用帶文法高亮的編輯器查看,可讀性將大大增強,若邊查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
在某個演算法論壇{
tagshow(event)
}">版塊發現有人需要十六進位串轉四字(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