如何使用Raspberry pi的ARM Assembly从C库调用putchar?

时间:2019-01-11 01:16:21

标签: assembly raspberry-pi arm

我很难尝试在一个循环中调用putchar,该循环打印通过ARM Assembly编写的针对树莓派的程序发送的第一个参数。例如 ./ myprog1你好在运行时应在控制台中输出“ hello”

代码如下:

    .text
   .balign 4
   .global main
   main:
       LDR r4, [r1, #4]    @ base address for argv[1] 
       MOV r5, #0          @ counter for loop

   loop:
       LDRB r0, [r4], #1   @ read each char byte in and increment
       CMP r0, #0          @ #0 representing null terminator
       BL putchar
       ADDNE r5, r5, #1
       BNE loop
   end:
       MOV r0, #0
       BX lr

我知道有明显的问题,但是对于不确定的地方。例如。 BL putchar应该调用putchar并将下一条指令放在链接寄存器中,但是弄乱后我得到的只是第一个字符。

我已经咨询了以下资源:

https://thinkingeek.com/arm-assembler-raspberry-pi/http://bob.cs.sonoma.edu/IntroCompOrg-RPi/intro-co-rpi.html,但似乎无法绕开它。我敢肯定,这可能只是在正确的位置或类似位置推入和弹出寄存器的简单解决方案,但我已经坚持了好几天,却无法继续前进。该程序甚至不需要输出参数-循环用于计算长度,但是我想弄清楚它,并在此基础上学习。

这不是每个人说的作业问题,但实际上是我调试我需要做的更大任务的一部分的一种方法。

任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:3)

您的代码实际上存在一些问题,它们都与调用边界中保留的内容有关。

@Jester的注释就您的直接问题而言是正确的:PSR(包含状态标志)未保留在整个呼叫边界内,因此CMP的结果令人难以理解由BL

但是也值得注意的是lr也阻塞了BL,因此,当您到达main()的末尾时,BX lr将分支回到该行在BL之后。您的评论表明您知道r0-r3被呼叫了。但是r12lr也是,因此如果您使用它们,则需要保留它们; main()和其他函数一样,因此需要通过保留r4-r11来遵守调用约定。

当前,main()破坏了r4r5,因此需要将它们lrlr一起推入堆栈并在末尾弹出(以避免BLmain: PUSH {r4-r6,lr} 破坏的问题)。 ARM ABI要求跨不同转换单元的调用边界进行8字节堆栈对齐,因此,您还必须同时推入并弹出另一个寄存器,以使其成为偶数。

因此,一开始,您会想要的

    POP {r4-r6,lr}
    BX lr

最后

    POP {r4-r6,pc}

或等效地

lr

其中orderId的堆积值直接弹出到程序计数器中,这会导致分支。