ARMv8:使用 ARMv8 汇编语言将十进制转换为二进制

Posted

技术标签:

【中文标题】ARMv8:使用 ARMv8 汇编语言将十进制转换为二进制【英文标题】:ARMv8: convert decimal to binary using ARMv8 assembly language 【发布时间】:2018-11-29 00:22:13 【问题描述】:

如何使用 ArmV8 汇编语言将十进制转换为二进制示例:输入:43 输出:101011

我主要不知道怎么做十进制到二进制的转换部分

或如何将其从任何编程语言翻译成 ARMv8

这就是我所拥有的

ARMv8 汇编语言代码

.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

这是我在java中的代码

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

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

            count++;

            decimal = decimal/2;

        

我似乎无法理解如何将其翻译成 arm

【问题讨论】:

你的 Java 算法太奇怪了。您正在创建一个整数,其十进制表示是您想要解释为二进制的数字字符串。相反,您可以直接创建一串 ASCII 数字。创建一个巨大的整数是有问题的,因为它可能会溢出一个 32 位整数(因此您无法处理所有可能的 32 位输入),并且要打印它,您需要一个函数来再次将其分成十进制数字。 【参考方案1】:

由于您正在编写汇编,我假设您已经了解该数字已经以二进制格式存储在内存和寄存器中,并且操作它的每个操作也是二进制操作。

您所拥有的 java 代码所做的是创建一个与其无符号二进制表示具有完全相同的数字的整数,该整数当然具有不同的值,因此其二进制表示本身也不同。我发现很难想象你可以用这个生成的整数做什么,除了打印它,但在 java 中已经有内置函数: Print an integer in binary format in Java

事实上,此类函数的第一步是将每个数字转换为其对应的字符,以便按原样打印。这与您构造的整数的打印过程相同。因此,创建这样一个整数对我来说似乎是多余的。所以问题是:“这是你真正想做的吗?”

【讨论】:

我想打印二进制中输入的任何数字,我只是不知道该怎么做【参考方案2】:

如果您问这个问题是因为您有一个任务,那么您的目标可能应该是花费尽可能多的时间来构建您自己的、有效的解决方案:在我看来,这是最好的学习方式..

这比使用qemu-system-aarch64aarch64-elf-asaarch64-elf-ldaarch64-elf-gdb 逐步组装、链接和调试aarch64 程序要容易。

这可以在 Linux 和 Windows 上完成 - 我使用的是 Windows 环境。 工具链是从here 下载的,qemu-system-aarch64 是从here 下载的。

如果您对基数/基数转换感到不舒服,请先在 Internet 上查找教程,例如 this one。只有这样,您才能开始寻找解决问题的方法。

“探索工具”中的documention ARM is providing 绝对是最好的,恕我直言,当它来详细解释 aarch63 指令集时。

你的问题可以分为两部分:

将ASCII 中的字符串(即“43”)转换为其二进制表示形式101011。 将 101011 二进制数转换为其字符串表示形式,即“101011”。

下面的示例不对输入执行任何验证,它通常应该做什么:

/* ----------------------------------------------------
   * 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

组装/链接示例:

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

启动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

启动 GDB(在其他 Windows 控制台/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.

您现在可以逐步执行程序,并使用stepip/x $x0, $x1, $x2, $x3x/s binarysz 命令检查寄存器和输出缓冲区。

当你到达 done: 时,你可以检查结果,然后退出 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

【讨论】:

以上是关于ARMv8:使用 ARMv8 汇编语言将十进制转换为二进制的主要内容,如果未能解决你的问题,请参考以下文章

在汇编ARMv8中符号扩展后逻辑左移丢失位

armv8-a:测试 SIMD 寄存器是不是为 != 0

在运行 64 位 linux 的 Armv8 (aarch64) 上编译并运行 32 位二进制文​​件

armv8 memory translation

ARMV8 datasheet学习笔记4:AArch64系统级体系结构之VMSA

armv8 和 arm64 是一样的吗?