2

This program prints small numbers fine but not big numbers and I don't know why.

For example print 1346269 will print out as "c1346269" and print 40000 will print out as "40000" just like it's supposed to.

Here's the macro:

%macro print 1
    mov rax, %1

    %%printInt:
        mov rcx, digit      ; set rcx to digit memory address
        mov rbx, 10         ; moving a newline into rbx
        mov [rcx], rbx      ; setting digit to rbx
        inc rcx             ; increment rcx position by one byte

    %%storeLoop:
        xor rdx, rdx        ; zero out rdx
        mov rbx, 10         
        div rbx             ; rax / rbx (10)

                            ; rdx holds the remainder of the divison
        add rdx, 48         ; add 48 to rdx to make in ascii character
                            
        mov [rcx], dl       ; get the character part of rdx
        inc rcx             ; increment digit position again

        cmp rax, 0
        jnz %%storeLoop     ; continue looping until rax is 0

    %%printLoop:
        push rcx

        ;perform sys write
        mov rax, SYSWRITE
        mov rdi, 1
        mov rsi, rcx
        mov rdx, 1
        syscall

        pop rcx
        dec rcx
        cmp rcx, digit      ; first byte of digit (10)
        jge %%printLoop

%endmacro

And here is how I use it:

    _start:
        
        print 40000
        exit
Sep Roland
  • 33,889
  • 7
  • 43
  • 76
user259137
  • 85
  • 1
  • 1
  • Related: [How do I print an integer in Assembly Level Programming without printf from the c library?](https://stackoverflow.com/a/46301894). Are you sure you want `mov [rcx], rbx` to store 8 bytes? Also, you're storing your string backwards, opposite of printing order, which forces you to `write` each digit separately. At least that means your 8-byte store is only touching bytes inside the buffer, not 7 past the end like if you'd started by storing a newline to the end and decrementing a pointer. – Peter Cordes Jun 02 '22 at 18:57
  • Also, you don't need to destroy the caller's RBX here; the loop can use the same registers you need for your `syscall`. (Which also destroys RCX and R11, BTW, so use any register other than those for the loop logic. e.g. use RBX. Or use RSI since Linux's `syscall` ABI doesn't destroy RSI, unlike with function calls.) – Peter Cordes Jun 02 '22 at 18:59

1 Answers1

3

The storeLoop ends with an inc rcx, leaving RCX behind the last character. Therefore, the printLoop must pre-decrement the pointer before invoking the syscall.

%%printLoop:
    dec  rcx
    push rcx
    ...
    pop rcx
    cmp rcx, digit      ; first byte of digit (10)
    ja  %%printLoop

The difference between 'long' and 'short' numbers is purely because of what happens to be in memory at the first address that you print from (garbage).

Sep Roland
  • 33,889
  • 7
  • 43
  • 76