最近在网上下载了一些讲ARM体系编程的视频。嗯,看了一下感觉不错啊。正好手头上有一块4412的板子,那,那不如就开始学习啰。写博客来做个学习的记录,也请大家多多指教。
符合APCS规范的调用过程:
我是新手啊。新建了一个汇编文件然后根本不知道要干嘛。嗯,那就最简单的点亮一个LED。于是就写了一个点亮LED的程序,下载到了芯片的0x40007000的地址。因为我和开发板交互用的是uboot,所以一个go指令就能很方便地跳到指定的地址处执行程序。嗯,那不如就写一个小程序,用go来执行我这段程序,然后再跳到0x40007000的地方点亮LED吧。
好不一会儿就写好啦
1 .text
2 .globl _start
3 _start:
4
5 ldr pc, =0x40007000
额,,虽然LED是亮了但感觉有点不靠谱啊。要是如果我这段代码里面的一些寄存器(就例如r0和r1)存了一些很重要的数据,要是后面调用的程序修改了他们那怎么办啊。但看上去也不难吧,找块地给先存起来就行啦。
.text
.globl _start
_start:
ldr r2, =0x30000000
str r0, [r2]
add r2, r2, #4
str r1, [r2]
ldr pc, =0x40007000
ldr r2, =0x30000000
ldr r0, [r2]
add r2, r2, #4
str r1, [r2]
啊感觉好麻烦,不如直接用堆栈来存嘛。还有一个问题,就是去了0x40007000地址执行完了后,一般来说是返回到寄存器LR里存放的地址的。那么好啰,把LR也保存起来吧!
.text
.globl _start
_start:
sub sp, sp, #4
str lr, [sp]
mov lr, pc
ldr pc, =0x40007000
ldr lr, [sp]
add sp, sp, #4
mov pc, lr
嗯这样子,根据4412的栈的特性,先把sp寄存器减4,然后可以存一个数据进去。后面取出数据后,要把sp加回去。在最开始的地方也顺便把LR寄存器的值入栈了吧,这样就不怕回不去uboot执行的地方了。
额,,还有问题来了。。要是我程序比较大,在中间sp减了好几次,每次减了好几百,那把栈里的东西取出来的时候岂不是算地址算到烧饼一样?因为sp是会变的,那不如用上fp寄存器,把它放在一个固定的地方,当存某一个数的时候由fp减一个数,取出来的时候就可以用fp加上原来的那个数就行啦。(相当于放fp的地方是基地址,加减的数是地址偏移的意思)。那么程序稍稍改一改就成了
后来又知道有stmfd和ldmfd这两个指令,为了方便使用ldmfd这个指令,我就先把sp的值存在ip寄存器里,然后再把ip寄存器入栈了,这样就少写了一些东西
嗯,视频上说这样来调用其它程序比较符合APCS的做法,不知道他有没有骗我