ARMv8: convert decimal to binary using ARMv8 assembly language

2.8k Views Asked by At

how to convert decimal to binary using ArmV8 assembly language Example: input: 43 output: 101011

I mainly dont know how to do the conversion part from decimal to binary

or how to translate it from any programming language to ARMv8

this is what I have

ARMv8 assembly language code

.data

decimal: .asciz "%s"

binary: .asciz "%d"

   newline:       .asciz "\n"

   string_input_buffer: .space 256

   userPrompt: .asciz "Input an integer: \n"

.text

.global main

main:

   # Load the input prompt and print it out

   ldr x0, =userPrompt

   bl printf

   # Take in the input and save it in the buffer

   ldr x0, =decimal

   ldr x1, =string_input_buffer

   bl scanf

   bl decToBin

done:

   mov x0, #0

   mov x8,#93

   svc #0

decToBin:

// Convert Decimal to Binary

this is the code that I have in java

while(decimal != 0)
        {
            a = decimal%2;

            b += a* Math.pow(10, count);

            count++;

            decimal = decimal/2;

        }

I cant seem to understand how to translate it to arm

2

There are 2 best solutions below

1
On

Since you are writing Assembly I assume you already understand that the number is already stored in the memory and the registers in a binary format and each operation manipulating it, is a binary operation as well.

What the java code you have does, is creating an integer with the exact same digits of its unsigned binary representation, which of course has a different value and as a result a different binary representation itself. I find it very hard to imagine what you can do with this produced integer except for printing it, but in java there are already built-in functions for that: Print an integer in binary format in Java

In fact, the first step of such a function is converting each of the digit to its corresponding character in order to be printed as such. This is the same process which would be followed for your constructed integer as well in order to be printed. Thus, creating such an integer seems redundant to me. So the question is: "Is this what you really want to do?"

0
On

If you asked the question because you had an assigment, your goal should probably have been to spend as much time as needed to build your own, working, solution: this is the best way to learn in my humble opinion..

This is easy than to assemble, link and debug an aarch64 program step by step using qemu-system-aarch64, aarch64-elf-as, aarch64-elf-ld and aarch64-elf-gdb.

This can be done on Linux and Windows - I used a Windows environment in my case. The toolchain was downloaded from here, and qemu-system-aarch64 from here.

If you don't feel comfortable enough with base/radix conversions, look for a tutorial on the internet first, such as this one. Only then should you start working on finding a solution to your problem.

The documention ARM is providing in its 'Exploratory Tools' is definitively the best,IMHO, when its comme to explain the aarch63 instruction set in details.

Your problem can be divided into two parts:

  • converting a string in ASCII, i.e. "43", into its binary representation, 101011.
  • converting the 101011 binary number into its string representation, i.e. "101011".

The example hereafter does not perform any validation on the inputs, what its should normally do:

/* ----------------------------------------------------
   * A minimalist section of code for converting a
   * zero-terminated string representating a decimal
   * number into a zero-terminated string representating
   * a binary number.
   * --------------------------------------------------*/ 
                    .title "dec2bin.s"
                    .arch armv8-a
                    .text
                    .section .text.startup,"ax"    
                    .globl Reset_Handler            
     Reset_Handler:  ldr x0, =decimalsz       // load address of decimalsz into x0.
                     mov x2, xzr              // use x2 for computing the binary value - initial value is zero.
    decascii2bin:    ldrb w1, [x0], #1        // load byte pointed by x0, then increment x0 by 1.
                     cbz  x1, bin2binascii    // if x1 does contain zero, we reached the end of the input buffer.
                     sub w1, w1, #'0'         // x1 does contain the ASCII value for character '4' or '3' - substracting ASCII value for '0'.
                     // we need to multiply the previous result by 10, then add the current digit:
                     add x3, xzr, x2, lsl #3  // x3 = 0 + x2 << 3, i.e.  8 * x2 
                     add x2, x3, x2, lsl #1   // x2 = x3 + x2 < 1, i.e. 8 * x2 + 2 * x2 = 10 *x2
                     add x2, x2, x1           // if we are processing '4', x2 = x2 (0) * 10 + 4 = 4. if we are processing '43, x2 = x2 (40) * 10 + 3 = 43.
                     bl  decascii2bin
     bin2binascii:                            // x2 does now contain 43.           
                     ldr x0, =binarysz        // load address of binarysz into x0.
                     add x0, x0, #64          // x0 points to the byte which would contain the zero-termination if 32 bits were to be displayed.
                     clz x1, x2               // retrieve the number of bits set to zero for the number contained in x2.
                     sub x0, x0, x1           // number 43 begins with 58 zero bits, therefore we will only display 64 - 58 = 6 bits.
                     strb wzr, [x0], #-1      // store zero at binarysz + 6.
                     movk x3, #'0'            // store '0' in x3.
     nextbit:        bfxil  x3, x2, #0, #1    // extract 1 from x2 starting from most significant bit 0, and insert at low end of x3, leaving other bits unchanged.
                     strb w3, [x0], #-1       // store '0' or '1' to the byte location pointed by x0, then decrement x0 by one.
                     lsr x2, x2, #1           // shift x2 to the right by one bit.
                     add x1, x1, #1           // increment number of leading zero bits + number of bits processed, 58 + 1 at first pass, up to 64.
                     cmp x1, #64              // we are done of 64 bits were leading zero bits or processed.
                     b.ne nextbit
    done:            b.al  done

                    .balign 16
                     // maximum possible value for un unsigned uint_64_t in decimal is:
                     // 18446744073709551615.               
    decimalsz:      .asciz "43"
                     // maximum possible value for un unsigned uint_64_t in binary is:
                     // 1111111111111111111111111111111111111111111111111111111111111111.
                     // we need at most 65 bytes for  64 digits and a \0.
    binarysz:       .asciz "0000000000000000000000000000000000000000000000000000000000000000"
                    .end

Assembling/linking the example:

aarch64-elf-as -g -adhln -o dec2bin.o dec2bin.s  > dec2bin.lst
aarch64-elf-ld -gc-sections -g -e Reset_Handler -Ttext-segment=0x42000000 -Map=dec2bin.map -o dec2bin.elf dec2bin.o

Starting qemu:

qemu-system-aarch64  -m 256M -semihosting -machine virt,gic-version=2,secure=on,virtualization=on -S -gdb tcp::1234,ipv4 -monitor telnet:127.0.0.1:1235,server,nowait -cpu cortex-a53 -nographic -kernel dec2bin.elf

Starting GDB (in an other Windows console/Linux shell):

aarch64-elf-gdb dec2bin.elf

GNU gdb (GDB) 8.2
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=x86_64-w64-mingw32 --target=aarch64-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from src\dec2bin\dec2bin.elf...done.
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
Reset_Handler () at dec2bin.s:13
13                       ldr x0, =decimalsz              // load address of decimalsz into x0.

You can now execute the program step by step, and examining the registers and the output buffer using stepi, p/x {$x0, $x1, $x2, $x3} and x/s binarysz commands.

At the time you will reach done:, you can examine the result, then quit GDB:

35      done:           b.al  done
(gdb) p/x {$x0, $x1, $x2, $x3}
$9 = {0x42000062, 0x40, 0x0, 0x31}
(gdb) x/s binarysz
0x42000063 <binarysz>:  "101011"
(gdb) kill
Kill the program being debugged? (y or n) y
[Inferior 1 (Remote target) killed]
(gdb) quit