简体   繁体   English

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

[英]How can I print Numbers with aarch64, without using C

As the question states, I want to print numbers, that are multiple digits, in aarch64.正如问题所述,我想在 aarch64 中打印多位数字。

Usually when solving proplems I python them first to see if they work, especially since I am very new to anything assembly.通常在解决问题时我先 python 看看它们是否有效,特别是因为我对任何组装都很陌生。 My pythonic solution was我的pythonic解决方案是

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

The way I tried to impement this in AARCH64:我试图在 AARCH64 中实现这一点的方式:

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, x17, x16, x12        /* thanks to: https://stackoverflow.com/questions/35351470/obtaining-remainder-using-single-aarch64-instruction */
        sub  x12, x12, x13             /* x13 is what above is digit, x12 is number */
        udiv x12, x12, x16
        add  x13, x13, #48             /* digit to string, possible error source 1 */

        mov  x0,  #1                   /* the print part */
        mov  x1,  x13                  /* the other part where I suspect a mistake */
        mov  x2,  #1
        mov  w8,  #64
        svc  #0

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

State of the code: It compiles and runs without problems, though it prints nothing, I cannot debug since I Program this with an actual aarch64 device and am not using an emulator (though I am sure there is a way I don't know off)代码的 State :它编译并运行没有问题,虽然它什么也没打印,但我无法调试,因为我使用实际的 aarch64 设备进行编程并且没有使用模拟器(尽管我确信有一种我不知道的方法)

I hope it is clear what I am trying to do, I am aware of some issues, like I should be using the stack for some of those things, but I can get that to work I hope.我希望很清楚我想要做什么,我知道一些问题,比如我应该将堆栈用于其中一些事情,但我希望我可以让它发挥作用。 I also hope it is visible that I put some effort into this and have tried to look for a solution like this, but can not find anyone who does it like this, or any other non-c-lib way that prints numbers (note that I don't need the number as str, I really only want to print it)我也希望可以看出我为此付出了一些努力并试图寻找这样的解决方案,但找不到任何这样做的人,或者任何其他打印数字的非 c-lib 方式(请注意我不需要数字作为str,我真的只想打印它)

As Jester points out, the reason you can't print is that the write system call expects a pointer to the data to be written in x1 , not the data itself.正如 Jester 指出的那样,您无法打印的原因是write系统调用需要一个指向要写入x1的数据的指针,而不是数据本身。 You need to store your character to some appropriate address in memory ( strb ) and pass that address in x1 .您需要将角色存储到 memory ( strb ) 中的某个适当地址,并将该地址传递给x1

One approach would be to use the stack;一种方法是使用堆栈; just subtract from the stack pointer (in multiples of 16, for alignment) to allocate some memory for yourself, and remember to put it back when you're done.只需从堆栈指针中减去(以 16 的倍数,用于对齐)为自己分配一些 memory,并记住在完成后将其放回。 Here's an example that should work;这是一个应该有效的示例; XXX are the lines I added or changed. 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, x12, x13             /* x13 is what above is digit, x12 is number */
        udiv x12, 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, sp, #16               /* XXX restore stack before returning */
        ret                            /* XXX */

I also fixed an unrelated bug: in your msub , x17 should be x14 , since that's where the quotient is.我还修复了一个不相关的错误:在您的msub中, x17应该是x14 ,因为那是商所在的位置。

Another approach would be to reserve a byte in static memory:另一种方法是在 static memory 中保留一个字节:

        .bss
dataToWrite:
        .resb 1
        .text
printNumberEntry:                      /* XXX */
        adr  x1, dataToWrite           /* XXX keep address in x1 throughout */
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, x12, x13             /* x13 is what above is digit, x12 is number */
        udiv x12, x12, x16
        add  x13, x13, #48             /* digit to string, possible error source 1 */

        strb w13, [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,  #1
        mov  w8,  #64
        svc  #0

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

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

The downside is this will make your function unusable for signal handlers, multiple threads, etc, as they will all try to use the same byte.缺点是这将使您的 function 无法用于信号处理程序、多线程等,因为它们都会尝试使用相同的字节。

Other notes:其他注意事项:

  • The digits print in reverse order, of course.当然,数字以相反的顺序打印。 That's something I guess you will work on later.那是我想你以后会做的事情。

  • The sub and second udiv are unnecessary, because the first udiv already produces the rounded-down quotient (like Python's x14 = x12 // 10 ). sub和第二个udiv是不必要的,因为第一个udiv已经产生了四舍五入的商(如 Python 的x14 = x12 // 10 )。 So you could replace those two instructions with just mov x12, x14 .所以你可以用mov x12, x14替换这两条指令。

  • Several of your registers hold constant values throughout the whole function ( x16, x1, x2, x8 ), so you could initialize them outside the loop instead of redundantly redoing it on every iteration.您的几个寄存器在整个 function ( x16, x1, x2, x8 ) 中保持恒定值,因此您可以在循环外初始化它们,而不是在每次迭代时都重复地重做它。 (Note x0 is overwritten with the system call's return value, so you do need to reinitialize it each time.) (注意x0被系统调用的返回值覆盖,所以每次都需要重新初始化。)

  • You really want to find a way to be able to use a debugger.真的想找到一种能够使用调试器的方法。 Otherwise, get ready for a lot more instances where you spend half an hour writing a StackOverflow question and waiting many more hours for an answer, for a bug that you could have found yourself in three minutes with a debugger.否则,请为更多的情况做好准备,在这些情况下,您花费半小时编写 StackOverflow 问题并等待更多小时以获得答案,因为您可以在三分钟内使用调试器发现自己的错误。 If you can't install gdb on your Android device, then consider setting up another Linux AArch64 box (say a Raspberry Pi 4, or a cloud server, or even a qemu emulator) where you can.如果你不能在你的 Android 设备上安装gdb ,那么考虑设置另一个 Linux AArch64 盒子(比如一个树莓派 4 或云服务器)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM