我很难尝试在一个循环中调用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,但似乎无法绕开它。我敢肯定,这可能只是在正确的位置或类似位置推入和弹出寄存器的简单解决方案,但我已经坚持了好几天,却无法继续前进。该程序甚至不需要输出参数-循环用于计算长度,但是我想弄清楚它,并在此基础上学习。
这不是每个人说的作业问题,但实际上是我调试我需要做的更大任务的一部分的一种方法。
任何帮助将不胜感激!
答案 0 :(得分:3)
您的代码实际上存在一些问题,它们都与调用边界中保留的内容有关。
@Jester的注释就您的直接问题而言是正确的:PSR(包含状态标志)未保留在整个呼叫边界内,因此CMP
的结果令人难以理解由BL
。
但是也值得注意的是lr
也阻塞了BL
,因此,当您到达main()
的末尾时,BX lr
将分支回到该行在BL
之后。您的评论表明您知道r0-r3
被呼叫了。但是r12
和lr
也是,因此如果您使用它们,则需要保留它们; main()
和其他函数一样,因此需要通过保留r4-r11
来遵守调用约定。
当前,main()
破坏了r4
和r5
,因此需要将它们lr
与lr
一起推入堆栈并在末尾弹出(以避免BL
被main:
PUSH {r4-r6,lr}
破坏的问题)。 ARM ABI要求跨不同转换单元的调用边界进行8字节堆栈对齐,因此,您还必须同时推入并弹出另一个寄存器,以使其成为偶数。
因此,一开始,您会想要的
POP {r4-r6,lr}
BX lr
最后
POP {r4-r6,pc}
或等效地
lr
其中orderId
的堆积值直接弹出到程序计数器中,这会导致分支。