test:
ldr r0, [r1, #4]
bl printf
ldr r2, [r1, #4]
ldrb r0, [r2], #1
cmp r0, #32
beq test
#32是空格的十进制ASCII码
使用以下代码编译代码
arm-none-eabi-gcc a.s -T generic-hosted.ld
然后运行
arm-none-eabi-run a.out "abcde"
arm-none-eabi-run a.out " bcde"
我想第一个命令将打印一次“ abcde”,第二个带空格的命令应该打印两次“ bcde”。但是我两次都打印一次,这是什么问题?
答案 0 :(得分:1)
printf可能会修改r0,r1,r2,r3和r12。
您将需要使用调用保留寄存器(并在返回之前将其还原),或将值保存在堆栈中。
答案 1 :(得分:0)
Timothy Baldwin's answer是准确的,但我认为我会对此做一点扩展。 ARM应用程序二进制接口(ABI),尤其是procedure call standard,定义了如何跨过程调用边界对待每个寄存器。
总而言之,r0-r3
用于传递参数和返回值,并且必须由调用方与“内部过程调用暂存寄存器” r12
一起保存。所有其他通用寄存器必须由 callee 保存。因此,如果您要用汇编语言编写自己的函数,则在调用任何其他函数的同时,除了r4-r11
(lr
)之外,还必须推送您使用的r14
中的任何一个必须确保您对堆栈的使用是“平衡的”,以便sp
(r13
)的退出值与进入的值相同。
大多数编译器(至少在禁用优化的情况下)会在推入被调用者保留寄存器之后立即从开始将所有函数参数移出r0-r3
来生成满足这些要求的代码;通过在返回之前将任何返回值移动到r0
中;并且仅通过使用r0-r3
来在函数执行过程中将参数传入和传出被调用函数。
此外,跨不同目标文件(即,不同源文件)中的函数,堆栈必须是8字节对齐的,因此,始终保持8字节对齐是一个好习惯,因为它很容易做到并且是免费的(出于与缓存相关的原因)。为此,请确保每次与堆栈的交互(每个PUSH
和POP
)都涉及偶数个寄存器,并在必要时推入并弹出其他寄存器以构成偶数。