1

This is how to print out a number, but how do I print out 2 digit numbers?

section .data
    num: db 9,10

section .text
global _start
_start:
    mov rax,[num]
    add rax,48
    mov [num],al
    mov rax,1
    mov rdi,1
    mov rsi,num
    mov rdx,2
    syscall

    mov rax,60
    mov rdi,0
    syscall

This simply prints out 9, but if I make num 12 it gives me a '<'. I believe it is printing out the ascii character for 60, which is '<'.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Elmo YT
  • 19
  • 6
  • You need to convert the integer into a numeral. Similar to what `itoa` does. There are plenty of examples on SO. The general approach is to mathematically extract each digit and reduce the problem to converting a digit to a numeral. Can you find an iterative algorithm to extract all digits from a finite-size number? – Margaret Bloom Dec 30 '22 at 21:53
  • If you're looking for something that *also* works for integers with any number of decimal digits (not always exactly 2), see [How do I print an integer in Assembly Level Programming without printf from the c library? (itoa, integer to decimal ASCII string)](https://stackoverflow.com/a/46301894) – Peter Cordes Dec 31 '22 at 03:55

1 Answers1

1
mov rax,[num]

Because num just holds a byte, better not read this as a qword. Use the movzx eax, byte [num] instruction. You don't need the movzx rax, byte [num] instruction because all writing to a dword register already zeroes the high dword anyway.

but how do I print out 2 digit numbers?

Next code can do just that, printing numbers from the range [10,99].
Note that there's a placeholder right in front of the newline.

section .data
    num: db 12, 0, 10

section .text
global _start
_start:
    movzx eax, byte [num]  ; Value LT 100
    xor   edx, edx
    mov   ebx, 10
    div   ebx              ; Quotient in EAX, Remainder in EDX
    mov   ah, dl
    add   ax, '00'         ; Convert to ASCII
    mov   [num], ax        ; Stores 'tens' followed by 'ones'
    mov   rax, 1
    mov   rdi, 1
    mov   rsi, num
    mov   rdx, 3           ; 3 instead of 2
    syscall

For a general approach you could first study Displaying numbers with DOS. It explains the methodology, but of course you'll need to adapt the code to 64-bit.
Even better info is at https://stackoverflow.com/a/46301894.

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • 1
    The "even better" link ([How do I print an integer in Assembly Level Programming without printf from the c library? (itoa, integer to decimal ASCII string)](https://stackoverflow.com/a/46301894)) has a working `print_uint32` function for x86-64 Linux ready to go, in NASM syntax, so the only thing that makes this not a duplicate is being specifically about the 2-digit special case. You could have used `div bl` because we know this is a 2-digit number. (It can't #DE fault since even 255/10 fits in AL, just printing garbage if `high_digit = num/10 + '0'` isn't in the `'0'..'9'` range.) – Peter Cordes Dec 31 '22 at 03:49
  • 1
    The fun way is `movzx eax, byte [rel num]` / `mov ecx, 10` / `div cl` / ```add eax, `00\n` ;cvt to ascii and append newline``` ; `push rax` / `mov rsi, rsp` / .. other args for `write(1, rsp, 3)` / `syscall`. (NASM does C escapes inside backticks, not single or double quotes.) – Peter Cordes Dec 31 '22 at 03:51