Print integer to console in x86 assembly
When I add two values in 16 bit assembly, what is the best way to print the result to console?
At the moment I have this code:
;;---CODE START---;;
mov ax, 1 ;put 1 into ax
add ax, 2 ; add 2 to ax current value
mov ah,2 ; 2 is the function number of output char in the DOS Services.
mov dl, ax ; DL takes the value.
int 21h ; calls DOS Services
mov ah,4Ch ; 4Ch is the function number for exit program in DOS Services.
int 21h ; function 4Ch doesn't care about anything in the registers.
;;---CODE END---;;
I think that dl value should be in ASCII code, but I'm not sure how to convert ax value after addition into ASCII.
Solution 1:
You basically want to divide by 10, print the remainder (one digit), and then repeat with the quotient.
; assume number is in eax
mov ecx, 10
loophere:
mov edx, 0
div ecx
; now eax <-- eax/10
; edx <-- eax % 10
; print edx
; this is one digit, which we have to convert to ASCII
; the print routine uses edx and eax, so let's push eax
; onto the stack. we clear edx at the beginning of the
; loop anyway, so we don't care if we much around with it
push eax
; convert dl to ascii
add dl, '0'
mov ah,2 ; 2 is the function number of output char in the DOS Services.
int 21h ; calls DOS Services
; now restore eax
pop eax
; if eax is zero, we can quit
cmp eax, 0
jnz loophere
As a side note, you have a bug in your code right here:
mov ax, 1 ;put 1 into ax
add ax, 2 ; add 2 to ax current value
mov ah,2 ; 2 is the function number of output char in the DOS Services.
mov dl, ax ; DL takes the value.
You put 2
in ah
, and then you put ax
in dl
. You're basically junking ax
before printing it.
You also have a size mismatch since dl
is 8 bits wide and ax
is 16 bits wide.
What you should do is flip the last two lines and fix the size mismatch:
mov ax, 1 ;put 1 into ax
add ax, 2 ; add 2 to ax current value
mov dl, al ; DL takes the value.
mov ah,2 ; 2 is the function number of output char in the DOS Services.
Solution 2:
Just fixing the order of @Nathan Fellman 's code
PrintNumber proc
mov cx, 0
mov bx, 10
@@loophere:
mov dx, 0
div bx ;divide by ten
; now ax <-- ax/10
; dx <-- ax % 10
; print dx
; this is one digit, which we have to convert to ASCII
; the print routine uses dx and ax, so let's push ax
; onto the stack. we clear dx at the beginning of the
; loop anyway, so we don't care if we much around with it
push ax
add dl, '0' ;convert dl to ascii
pop ax ;restore ax
push dx ;digits are in reversed order, must use stack
inc cx ;remember how many digits we pushed to stack
cmp ax, 0 ;if ax is zero, we can quit
jnz @@loophere
;cx is already set
mov ah, 2 ;2 is the function number of output char in the DOS Services.
@@loophere2:
pop dx ;restore digits from last to first
int 21h ;calls DOS Services
loop @@loophere2
ret
PrintNumber endp
Solution 3:
The basic algorithm is:
divide number x by 10, giving quotient q and remainder r
emit r
if q is not zero, set x = q and repeat
Note that this will yield the digits in the inverse order, so you are probably going to want to replace the "emit" step with something that stores each digit, so that you can later iterate in reverse over the stored digits.
Also, note that to convert a binary number between 0 and 9 (decimal) to ascii, just add the ascii code for '0' (which is 48) to the number.
Solution 4:
mov dl, ax
This won't work as dl
and ax
have different bit sizes. What you want to do is create a loop in which you divide the 16 bit value by 10, remember the rest on the stack, and then continue the loop with the integer division result. When you reach a result of 0, clean up the stack digit by digit, adding 48 to the digits to turn them into ASCII digits, then print them.