A Horrible Conversion from Binary to Decimal in (ARM64) Assembly

This is not my finest code. It is the worst case of “just make it work” I’ve produced all week.

But it runs.

What does it do? It takes the first binary number in an array, and converts it to decimal. It assumes that the number is no more than 3 digits long.

It divides that number by 100 to get the 100s digit. Then it multiples that number by 100, assuming that it has gotten truncated. It subtracts that value from the original number to chop off the 100s digit, and divides the result by 10 to get the 10s digit.

Similar process to get the 1s digit.

EDIT: Here is the plan for how to do it better:

It sticks these character by character into the Hello World Buffer, and calls the write system call.

    Array: .word  503,87,61,908,170,897,709,901,271,528,834,154,231,303,435,707,424,861
    ArrayLen = . - Array
        .ascii        "Hello, World!\n"
    len = . - msg
// app entry point 
.globl _start
    /*syscall write(int fd, const void *buf, size_t count) */
    mov  x0, #1   /* fd := STDOUT_FILENO */
    ldr  x1, =msg  /* buf := msg */
    ldr  x2, =len /* count = len */
    /* make a copy of the buffer pointer, as we are going to be writing to it character by 
       character, and we need to advance the pointer.  Yes, we could reuse x1 and just reset
       it at the end.  That would be better. */
    ldr x8,=msg
    /*read the first value out of the array.  In the final implementation, I need to be able 
      to advance this pointer value by bvalue */
    ldrsw x3, =Array
    ldrsw x4, [x3]     
    /* Divide by 100 to isolate the 100s digit */
    mov x5, #100
    sdiv x7, x4, x5    
    ADD w6, w7, #48
    strb w6, [X8]
    /*advance the write buffer pointer, so next time we write to the second character */
    ADD X8, X8, #1
    ldrsw x4, [x3]
    /* restore the  hundreds digit to the hundreds place so we can chop it off the original
       number */
    mul x7, x7, x5
    sub w4, w4, w7
    /* divide the result by 10 to isolate just the 10s digit */
    mov x5, #10
    sdiv x6, x4, x5
    ADD w6, w6, #48
    strb w6, [X8]
    ADD X8, X8, #1
    ldrsw x4, [x3]
    /* if we remove the #48 we can reuse this register.  Should have done this last time */
    sub w6, w6, #48
    /* get the 10s digit back into the 10s place */
    mul x6, x6, x5     
    add x7, x7, x6
     /*at this point, the x7 register has the original value without the 1s digit. */
    sub w6, w4, w7
    ADD w6, w6, #48
    strb w6, [X8]
    mov  w8, #64   /* write is syscall #64 */
    svc  #0        /*invoke syscall */
    /* syscall exit (int status) */
    mov    x0, #0    /* status  := 0 */
    mov    w8,  #93  /* exit is syscall #1 */
    svc    #0

Here is the output.

$ make shellsort ; ./shellsort 
as -g -o shellsort.o shellsort.s
ld -o shellsort shellsort.o
503lo, World!

I promise I will clean this up.


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.