Printing Integers in x86_64 Assembly

I finally got the assembly for printing numbers working. It was somewhat tricky as each individual digit needs to be extracted, converted to ASCII, and then printed. Here's how it works:

  1. Suppose we want to print the number 123.
  2. We need to divide that number by 10 and put the remainder in the stack. We do this until our result equals 0:

    123 / 10 = 12 with a remainder or 3
    12 / 10 = 1 with a remainder of 2
    1 / 10 = 0 with a remainder of 1
    
  3. We need to add 48 to the digit because 48 is the ASCII value for 0. So we're offsetting the ASCII character for 0 by the value of the digit.
  4. Now we can iterate through each value and print it.

Here's the final code with some comments to help make whats happening clearer:

section .text
    global _start

_start:
    ;; Move the number we want to print into rax
    mov rax, 123
    call _printInt

    ;; Exit
    mov rax, 60
    mov rdi, 0
    syscall

_printInt:
    ;; r8 will keep a count of how many bytes to print
    mov r8, 0
    call _pushDigitsOnStack
    ret

_pushDigitsOnStack:
    ;; Divide rax by 10 and add 48. 
    ;; This extracts the digit and converts it to ascii.
    ;; 48 is the ascii value for 0.
    xor rdx, rdx
    mov rbx, 10
    div rbx
    add dl, 48

    ;; Allocate 1 byte on the stack for the digit
    ;; and place it in the stack.
    ;; Then increment the count
    sub rsp, 1
    mov byte [rsp], dl
    inc r8

    ;; If rax is equal to 0 then we're done
    cmp rax, 0
    jne _pushDigitsOnStack

_printDigitsOnStack:
    ;; Add the newline character to the stack
    ;; and increment the number of bytes we need to print
    ;; to take into account this newline character
    mov byte [rsp+r8], 10
    inc r8

    ;; Print all the bytes in the stack
    mov rax, 1
    mov rdi, 1
    mov rsi, rsp
    mov rdx, r8
    syscall

    ;; Move the stack pointer back to the location
    ;; of the return instruction
    dec r8
    add rsp, r8
    ret