So I am taking an assembly language course and I am stuck on this problem from the book:
Using the windows 32 console (so I have an io.h
to use), I am supposed to t
If you need to convert a character (for simplicity, say, in upper case) representing a hex digit into the value of that digit you need to do this:
IF char >= 'A'
value = char - 'A' + 10
ELSE
value = char - '0'
ENDIF
If you need to do the reverse, you do the reverse:
IF value >= 10
char = value - 10 + 'A'
ELSE
char = value + '0'
ENDIF
Here you exploit the fact that the ASCII characters 0
through 9
have consecutive ASCII codes and so do the ASCII characters A
through F
.
There are some bugs in your code.
First, in 0 ... 9 string to integer conversion code, you don't do ASCII to binary conversion as you should do, but instead you do and ebx,0Fh
, which is incorrect. You need to subtract '0'
(30h
) from each ASCII character, like this:
mov bl,[esi] sub bl,'0' ; sub bl,30h
Then, also in 0 ... 9 string to integer conversion code:
and eax, ebx
If the number consists of only 0...9 digits, and eax, ebx
will produce always 0. It should be:
or al,bl
Then, you do shl eax,4
, even if you don't know if there will be more digits. That means that the number will be 16 times bigger than it should.
Then, you give the example input with spaces, but your code does not handle spaces (20h
) properly, it ends reading input for any value below '0'
(30h
), it seems to accept only leading spaces (skip this if you don't want to accept spaces in between).
So, the entire code block above should be:
WhileDigitD: cmp byte ptr [esi], ' ' ; delete this if you don't want spaces in between. je next_char ; delete this if you don't want spaces in between. cmp BYTE PTR [esi],'0' ; compare next character to '0' jb EndWhileDigitD ; not a digit if smaller than '0' cmp BYTE PTR [esi],'9' ; compare to '9' ja TestForHexD mov bl,[esi] ; ASCII character to BL sub bl,'0' ; sub bl,30h -> convert ASCII to binary. shift_eax_by_4_and_add_bl: shl eax,4 ; shift the current value 4 bits to left. or al,bl ; add the value of the current digit. next_char: inc esi jmp WhileDigitD
I also added labels next_char
and shift_eax_by_4_and_add_bl
. The reason for next_char
should be evident, shift_eax_by_4_and_add_bl
is to minimize duplicate code of 0...9 and A...F code blocks, see below.
You don't check that that the hexadecimal A...F digit is within range A ... F, only that it's below or equal to F. Otherwise it has same bug with shl eax,4
. And as usually duplicate code should be avoided, I added shift_eax_by_4_and_add_bl
label to minimize duplicate code.
So I think it should be:
Edit: corrected sub bl,31h
-> sub bl,('A'-0Ah)
.
TestForHexD: cmp BYTE PTR [esi], 'A' jb EndWhileDigitD cmp BYTE PTR [esi], 'F' ja EndWhileDigitD mov bl,[esi] sub bl,('A'-0Ah) ; sub bl,55 -> convert ASCII to binary. jmp shift_eax_by_4_and_add_bl