I am working on 64-bit assembly code (yasm), trying to output arbitrarily large decimal values so that they read correctly, and not as weirdness, or as a single digit. I had a look around but can't seem to find any suitable solutions online. My code currently outputs a 2-value decimal figure (output quotient, output remainder when divided by 10). For larger values I was thinking along the lines of a do-while loop construction that would repeatedly divide by 10 and output the remainder while the remainder is not zero. Problem with this method is that it would output the result in reverse, adding additional complexity to the code to try and reverse this. Does anyone know of a solution that would work? I had a look at aaa, aam etc but I don't entirely get how they work and suspect these are available to 32-bit operations only.
The code structure is as follows:
section .data
nl db "",2,0
nlf db "",10,0
input db '',2,0
fact dq 1
y db 10
store dq 0
rem dq 0
quot dq 0
check dq 0
section .text
global _start
_start:
; reading input value
mov rax, 0 ; system read
mov rdi, 0 ; STD IN
mov rsi, input ; address first byte in output
mov rdx, 1 ; load length into rdx
syscall
; reading newline
mov rax, 0 ; system read
mov rdi, 0 ; STD IN
mov rsi, nl ; address first byte in output
mov rdx, 1 ; load length into rdx
syscall
mov rbx, [input] ; for calculating factorial
sub rbx, '0'
call calc_fact
call de_ASCII_fy
;add rax, 30h
mov rax, 1
mov rdi, 1
mov rsi, nlf
mov rdx, 1
syscall
; exit
xor rdi, rdi
push 0x3c
pop rax
syscall
calc_fact:
cmp bl, 1
jg do_calculation
mov rax, 1
ret
do_calculation:
dec bl
call calc_fact
inc bl
mul bl
ret
de_ASCII_fy:
mov [fact], rax
movzx rax, byte [fact]
cmp rax, 0
je decimal_loop
movzx rbx, byte [y]
xor rdx, rdx
div rbx
xor rcx, rcx
mov rcx, rdx ; store remainder
add rax, '0'
add rdx, '0'
mov [rem], rdx
mov [quot], rax
cmp rcx, 0
jnz full_print
mov rax, 1 ; system write
mov rdi, 1
mov rsi, rem
mov rdx, 1
syscall
ret
full_print:
mov rax, 1 ; system write
mov rdi, 1
mov rsi, quot
mov rdx, 1
syscall
mov rax, 1 ; system write
mov rdi, 1
mov rsi, rem
mov rdx, 1
syscall
jmp endif
endif:ret
decimal_loop:
ret
I am calculating a factorial value, trying to display the output for 4! as 24 and 5! as 120. Now, at the moment I can only get to show two decimal values (for some reason the first part of the full_print condition gets skipped, so 3! is printed as 06 instead of 6), but 24 gets printed correctly. I have been racking my brain for a simple way to print out a 3-digit decimal value, but it starts to get very messy with conditionals.
Take a look at this example:
global _start
section .bss
decimal resb 32
section .data
number dq 10000000000000000000
lf db 10
section .text
_start:
mov rdi, decimal
mov rsi, [number]
call IntegerToDecimal
mov eax, 1 ; sys_write
mov edi, 1 ; STDOUT
mov rsi, decimal ; String address
mov edx, 32 ; Max. string length
syscall
mov eax, 1 ; sys_write
mov edi, 1 ; STDOUT
mov rsi, lf ; Line Feed address
mov edx, 1 ; Max. string length
syscall
mov eax, 60 ; sys_exit
xor edi, edi ; return 0 (success)
syscall
IntegerToDecimal:
mov rax, rsi
mov ebx, 10 ; Divisor
xor ecx, ecx ; RCX=0 (Anzahl der Ziffern)
.Loop_1:
xor edx, edx
div rbx ; RDX:RAX / RBX = RAX Remainder RDX
push dx ; LIFO
add cl, 1
or rax, rax ; RAX == 0?
jnz .Loop_1 ; no: once more
.Loop_2:
pop ax ; Get back pushed digits
or al, 00110000b ; Convert to ASCII
mov [rdi], al ; Store character
add rdi, 1 ; Increment target address
loop .Loop_2 ; Until there are no digits left
mov byte [rdi], 0 ; ASCIIZ-null-terminator
ret
BTW: You had got the example yesterday, if I had known the OS (Windows or Linux) and assembly style (Nasm or Gas). ;-)