Converting An Integer To Decimal – Assembly Style

I know this is one of the most trivial things to implement in a high level language. In C it goes like this:

void print_integer(unsigned int x)
{
if ((x / 10) != 0) pi(x / 10);
putch((x % 10) + ‘0’);
}

The annoying thing is that you have to div twice and do a modulo once. Which in reality can be merged into a single X86 instruction. Another thing is that if you want to be able to print a normal result for an input of 0 you will have to test the result of the division instead of checking simply x itself. The conversion is done from the least significant digit to the most. But when we display the result (or put it in a buffer) we have to reverse it. Therefore the recursion is so handy here. This is my go in 16bit, it’s a code that I wrote a few years ago, and I just decided I should put it here for a reference. I have to admit that I happened to use this same code for also 32bits or even different processors and since it’s so elegant it works so well and easy to port. But I leave it for you to judge ;)

bits 16
mov ax, 12345
call print_integer
xor ax, ax
call print_integer
ret

print_integer:
; base 10
push byte 10
pop bx
.next:; make a 32 bits division, remainder in dx, quotient in ax
xor dx, dx
div bx
push dx ; push remainder
or ax, ax ; if the result if 0, we will stop recursing
jz .stop
call .next ; now this is the coolest twist ever, the IP that is pushed onto the stack…
.stop:
pop ax ; get the remainder (in reversed order)
add al, 0x30 ; convert it to a character
int 0x29 ; use (what used to be an undocumented) interrupt to print al
ret ; go back to ‘stop’ and read the next digit…

I urge you to compile the C code with full optimization and compare the codes for yourself.

4 Responses to “Converting An Integer To Decimal – Assembly Style”

  1. Peter Ferrie says:

    print_integer:
    aam
    call .next
    .next
    xchg ah, al
    add al, ‘0’
    int 0x29
    ret

  2. arkon says:

    Ofc Peter :) but now its input is a byte rather than a word(/dword)… it’s cute nevertheless

  3. arkon says:

    Though it seems you missed a few lines…oi?

  4. Peter Ferrie says:

    It just needs a push/pop. Here’s the whole thing:

    mov ax, 12345
    call print_integer
    xor ax, ax
    call print_integer
    ret

    print_integer:
    push ax
    xchg ah, al
    call .next1
    pop ax
    .next1:
    aam
    call .next2
    .next2:
    xchg ah, al
    add al, 0x30
    int 0x29
    ret

Leave a Reply