Hey,
I wouldn't say I'm much of a beginner but I've been trying to convert a dword to hexa for the past few hours and haven't really succeeded.
Basically what I'm doing is this.
I get a value (type dword) from a pointer.
My objective is to convert this dword to hexadecimal. E.g. if value is 16, I want to convert it to 10 in hex.
I'm not exactly sure how one might do this in MASM32 since I only started probably a few months back, but I do know, in visual basic you can use the modulus and integer division operators to do it. I.e.
16 div 16 = 1
16 mod 16 = 0 (remainder)
1 div 16 = 0
1 mod 16 = 1 (remainder)
Reading remainder's backwards, decimal 16 = hexadecimal 10.
Does anyone know how to do this in MASM32? I'd greatly appreciate it.
Thanks,
-Sean
Sean,
Welcome on board.
Cheat, See how its done in the masm32 library.
Hi Sean,
Welcome to the forum. There are multiple methods, and two possibilities are the dw2hex and dw2h_ex procedures. The source files are dw2hex.asm and dw2h_ex.asm in the m32lib directory.
Thanks guys, however I did look at these previously and I didn't really understand what the code is doing, e.g. "nibbling."
dw2hex proc source:DWORD, lpBuffer:DWORD
push esi
mov edx, lpBuffer
mov esi, source
xor eax, eax
xor ecx, ecx
mov [edx+8], al ; put terminator at correct length
mov cl, 7 ; length of hexstring - 1
@@:
mov eax, esi ; we're going to work on AL
and al, 00001111b ; mask out high nibble
cmp al,10
sbb al,69h
das
mov [edx + ecx], al ; store the asciihex(AL) in the string
shr esi, 4 ; next nibble
dec ecx ; decrease counter (one byte less than dec cl :-)
jns @B ; eat them if there's any more
pop esi
ret
dw2hex endp
or
dw2hex_ex proc src:DWORD,buf:DWORD
movzx ecx, BYTE PTR [esp+4]
mov edx, DWORD PTR [ecx+ecx+hex_table]
mov eax, [esp+8] ; load buffer address
shl edx, 16
movzx ecx, BYTE PTR [esp+5]
mov dx, WORD PTR [ecx+ecx+hex_table]
movzx ecx, BYTE PTR [esp+6]
mov [eax+4], edx ; write 2nd DWORD
mov ecx, DWORD PTR [ecx+ecx+hex_table]
movzx edx, BYTE PTR [esp+7]
shl ecx, 16
mov cx, WORD PTR [edx+edx+hex_table]
xor edx, edx
mov [eax], ecx ; write 1st DWORD
mov BYTE PTR [eax+8], dl
ret 8
dw2hex_ex endp
Could one of you possibly go through the algorithm with me, showing how say, 10 (type byte) would be converted into A (hex) and where it would be stored?
Thanks,
-Sean
The first thing to notice is that four binary-bits map directly on to each hex digit, so you can chop the number up into 'nibble' sized chunks and convert them one at a time (so there's no need to mess around with division - though you can still do it that way if you really want to; and it is necessary for other conversion like to decimal.)
So, a 32-bit dword then becomes: 0101 1010 0000 1111 0110 0100 1111 1101 -- representing the numbers 5, 10, 0, 15, 6, 4, 15, 13.
Now the task is to convert each of these into a hex digit - '0' to '9' for values 0 to 9, and 'A' to 'F' for values 10 to 15.
There are two common ways to do it (we'll leave out any black magic unless you want your brain to hurt :wink):
The first is to take advantage of the way ascii is set out and just add '0' (that's the ascii value of the character zero, not the value zero) which will magically convert 0 into '0' and 9 into '9' (and all the numbers in between) unfortunately this doesn't help with values above 9. So you do another trick for those numbers and add on 'A'-10 (the ascii value of the letter A minus ten; same as subtracting ten and adding 'A', but in one step). But before you convert each digit you need to decide which method to use, which is as simple as comparing it against 9.
The other way is to have a string of the ascii hex digits "0123456789ABCDEF" and then use the value you're converting as an index into it. So hexstring[5] will, amazingly, give you '5', and hexstring[13] gives 'D'.
After converting each digit, you'll need to store them in an array/string so you can print them out or do whatever you want to do with them. Usually you'll be converting the right-most digit first, so you'll need to either store the characters in reverse, or print it backwards one character at a time; or do the left-most first.
(The binary string above represents: 5A0F64FD -- do a conversion by hand so it sinks in :wink)
Sean,
Be careful with the _ex version, you have clipped off important directives because this procedure is written without a stack frame. The leading and trailing "OPTION" statements must be there or the procedure will not run. It uses a cruder but faster method of a preset table for the hex bytes but the price is its larger due to the table size.
align 16
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
dw2hex_ex proc src:DWORD,buf:DWORD
movzx ecx, BYTE PTR [esp+4]
mov edx, DWORD PTR [ecx+ecx+hex_table]
mov eax, [esp+8] ; load buffer address
shl edx, 16
movzx ecx, BYTE PTR [esp+5]
mov dx, WORD PTR [ecx+ecx+hex_table]
movzx ecx, BYTE PTR [esp+6]
mov [eax+4], edx ; write 2nd DWORD
mov ecx, DWORD PTR [ecx+ecx+hex_table]
movzx edx, BYTE PTR [esp+7]
shl ecx, 16
mov cx, WORD PTR [edx+edx+hex_table]
xor edx, edx
mov [eax], ecx ; write 1st DWORD
mov BYTE PTR [eax+8], dl
ret 8
dw2hex_ex endp
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
Well someone helped me out with this and I think we've solved it..this should work:
I had made a mistake in my original post. I had mistakingly thought that dword was type decimal. What I wanted to do is convert decimal #'s to hexadecimal #'s.
.data
lpHexString db "0123456789ABCDEF"
.code
Dec2Hex proc dwValue:DWORD, lpBuffer:DWORD
mov edi, lpBuffer
mov eax, dwValue
mov ecx, 8
.repeat
mov esi, eax
and esi, 0F0000000h
shr esi, 28
movzx edx, byte ptr [lpHexString+esi]
mov byte ptr [edi], dl
shl eax, 4
inc edi
.untilcxz
ret
Dec2Hex endp
Example:
invoke Dec2Hex, 1337C0DEh, addr lpBuffer
A MMX version without loops.
hold dd 91234567h
buffer db 16 dup (0)
nines db 8 dup (57)
sevens db 8 dup (7)
szCap db "DWord to Hex string MMX",0
.code
start:
mov esi, hold
mov edi, offset buffer
mov eax, esi
shr eax, 4
and eax, 0f0f0f0fh
or eax, 30303030h
bswap eax
mov [edi], eax
mov eax, esi
and eax, 0f0f0f0fh
or eax, 30303030h
bswap eax
mov [edi+4], eax
movq mm1, [edi]
movq mm0, mm1
movq mm3, qword ptr nines
movq mm4, qword ptr sevens
psllq mm1, 32
punpckhbw mm1, mm0
movq mm2, mm1
pcmpgtb mm2, mm3
pand mm2, mm4
paddb mm1, mm2
movq [edi], mm1
[attachment deleted by admin]
Two things:
1. Don't forget to add a null (zero byte) to the end of your string; if you're lucky and do this into an empty buffer there will already be one left over, but you should generally do it in any case.
2. In the code you have, there's "and esi, 0F0000000h" followed by "shr esi, 28" - the 'and' is unnecessary since the shift removes the lower bits anyway (and the upper bits are filled with zeroes.)
(Okay three things..)
3. "movzx edx, byte ptr [lpHexString+esi]" may as well be "mov dl, [lpHexString+esi]" since you're only using dl anyway.
(By the by, that is the method I explained :P)
And in your procedure don't forget uses esi,edi
SS