I was writing an x86 assembly program to output a number in hexadecimal. The program was assembled using nasm and the image file ran by qemu. The behavior of the program confused me a lot. As the working program below suggests, I wouldn't have to add 0x30 to a digit to get it to print the character of that digit.
; Boot sector code offset: 0x7c00
[org 0x7c00]
mov dx, 0x1fb6 ; The hexadecimal to be printed
call print_hex ; call the function
jmp $ ; jump infinitely
%include "print_string.asm" ; Include the print_string function
print_hex:
pusha ; push all registers to stack
mov ax, 0x4 ; rotate through the number four times
print_hex_loop:
cmp ax, 0x0 ; compare the counter with 0
jle print_hex_end ; if it is zero then jump to the end
mov cx, dx ; move dx to cx
and cx, 0x000F ; take the lower four binary digits of cx
cmp cx, 0xa ;compare the digits with 0xa
jge print_hex_letter ; if it is larger than a, jump to printing character
add cx, 0x0 ; otherwise print the ascii of a number
jmp print_hex_modify_string ; jump to routine for modifing the template
print_hex_letter:
add cx, 0x7 ; print the ascii of a letter
print_hex_modify_string:
mov bx, HEX_OUT ; bring the address of HEX_OUT into dx
add bx, 0x1 ; skip the 0x
add bx, ax ; add the bias
add byte [bx], cl ; move the character into its position
shr dx, 4 ; shift right 4 bits
sub ax, 0x1 ; subtract 1 from the counter
jmp print_hex_loop ; jump back to the start of the function
print_hex_end:
mov bx, HEX_OUT ; move the address of HEX_OUT to bx
call print_string ; call the function print_string
popa ; pop all registers from stack
ret ; return to calling function
HEX_OUT:
db '0x0000',0 ; The template string for printing
times 510-($-$$) db 0 ; fill zeros
dw 0xaa55 ; MAGIC_FLAG for boot
boot_sect.asm
print_string:
pusha
mov ah, 0x0e
mov al, [bx]
print_string_loop:
cmp al, 0x0
je print_string_end
int 0x10
add bx, 0x1
mov al, [bx]
jmp print_string_loop
print_string_end:
popa
ret
print_string.asm
The output of this program is what I expected, but when I tried to add 0x30 on the numerals to get the ASCII code of the digits, the output was gibberish. Is there some trick to it or am I missing some key points here?
Thanks!
HEX_OUT: db '0x0000'is a string that represents the ASCII characters for '0' already. Don't need to add 0x30 to values that were initialized to ASCII0. Also note that callingprint_hexmore than once won't work because the way this code was written, it was expected thatHEX_OUTis initialized to the string0x0000.add byte [bx], cl.. if you would domov byte [bx], cl, you would have to add'0'or'A'-10to it first.