微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在不使用 C 的情况下使用 aarch64 打印数字

如何解决如何在不使用 C 的情况下使用 aarch64 打印数字

正如问题所述,我想在 aarch64 中打印多位数的数字。

通常在解决 proplems 时,我首先使用 python 来查看它们是否有效,特别是因为我对任何程序集都很陌生。我的pythonic解决方案是

print('Success' if all(v==40 for v in lst) else 'Failure')

我试图在 AARCH64 中实现这一点的方式:

number = 1234

while number != 0:
   digit = 1234 % 10         # always gives me the last digit
   print(digit,end='')      # to print the digit and not the next line
   number = number - digit   # to remove the digit I just got so the last digit is 0
   number = number / 10      # to remove said last digit and shorten number by 1

代码状态:它编译和运行没有问题,虽然它什么都不打印,但我无法调试,因为我使用实际的 aarch64 设备对其进行编程并且没有使用模拟器(尽管我确定有一种方法我不不知道)

我希望很清楚我要做什么,我知道一些问题,比如我应该将堆栈用于其中一些事情,但我希望它可以工作。我也希望看到我为此付出了一些努力并试图寻找这样的解决方案,但找不到任何这样做的人,或者任何其他打印数字的非 c-lib 方式(请注意我不需要数字作为str,我真的只想打印它)

解决方法

正如 Jester 指出的那样,您无法打印的原因是 write 系统调用需要一个 指针,指向要写入 x1 的数据,而不是数据本身。您需要将您的字符存储到内存中的某个适当地址 (strb) 并将该地址传递到 x1

一种方法是使用堆栈;只需从堆栈指针中减去(16 的倍数,用于对齐)为自己分配一些内存,并记住在完成后将其放回原处。这是一个应该有效的例子; XXX 是我添加或更改的行。

printNumberEntry:                      /* XXX */
        sub  sp,sp,#16               /* XXX allocate 16 bytes of stack space */
printNumber:
        mov  x16,#10                  /* apparently need this for udiv/msub */
        udiv x14,x12,x16             /* x12 is the number I defined above,bc idk what registers are save to use (e.g. when syscall 64,print,happens,0-8 are used) */
        msub x13,x14,x16,x12        /* XXX fix unrelated bug */
        sub  x12,x13             /* x13 is what above is digit,x12 is number */
        udiv x12,x16
        add  x13,x13,#48             /* digit to string,possible error source 1 */

        strb w13,[sp]                 /* XXX Store the low byte of x13/w13 in memory at address sp */

        mov  x0,#1                   /* the print part */
        mov  x1,sp                   /* XXX x1 points to the byte to be written */
        mov  x2,#1
        mov  w8,#64
        svc  #0

        cmp  x12,#0                   /* the loop part */
        beq  exit                      /* genereric exit method I left out */
        b    printNumber

exit:                                  /* XXX */
        add  sp,#16               /* XXX restore stack before returning */
        ret                            /* XXX */

我还修复了一个不相关的错误:在您的 msub 中,x17 应该是 x14,因为那是商所在的位置。

另一种方法是在静态内存中保留一个字节:

        .bss
dataToWrite:
        .resb 1
        .text
printNumberEntry:                      /* XXX */
        adr  x1,dataToWrite           /* XXX keep address in x1 throughout */
printNumber:
        mov  x16,[x1]                 /* XXX Store the low byte of x13/w13 at dataToWrite */

        mov  x0,#1                   /* the print part */
        /* x1 already contains the proper address */
        mov  x2,#0                   /* the loop part */
        beq  exit                      /* genereric exit method I left out */
        b    printNumber

exit:                                  /* XXX */
        ret                            /* XXX */
        /* your code */

缺点是这会使您的函数无法用于信号处理程序、多线程等,因为它们都将尝试使用相同的字节。

其他注意事项:

  • 当然,数字以相反的顺序打印。这是我想你以后会做的事情。

  • sub 和第二个 udiv 是不必要的,因为第一个 udiv 已经产生了四舍五入的商(如 Python 的 x14 = x12 // 10)。所以你可以只用 mov x12,x14 替换这两条指令。

  • 您的多个寄存器在整个函数 (x16,x1,x2,x8) 中都保存着常量值,因此您可以在循环外初始化它们,而不是在每次迭代时重复进行重复操作。 (注意 x0 被系统调用的返回值覆盖,因此您每次都需要重新初始化它。)

  • 真的想要找到一种能够使用调试器的方法。否则,为更多的情况做好准备,在这些情况下,您花费半小时编写 StackOverflow 问题并等待更多小时的答案,因为使用调试器可能会在三分钟内发现自己的错误。如果您无法在 Android 设备上安装 gdb,请考虑在可以的地方设置另一个 Linux AArch64 机器(例如 Raspberry Pi 4,或云服务器,甚至 qemu 模拟器)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。