本系列文章节选自本人所著《深入浅出嵌入式底层软件开发》。
现在我们已经掌握了所有知识,可以编写简单的ARM汇编程序,但如果要编写较为复杂的ARM程序,就必须掌握更多的寻址模式和指令,这就是本节的重点所在。
我们在“基本寻址模式与基本指令”中学习了最常用的3种寻址方式。下面介绍其它寻址方式。
1.6.1 其它常见寻址模式
1. 基址寻址
基址寻址就是将基址寄存器的内容与指令中给出的偏移量相加,形成操作数的有效地址。基址寻址用于访问基址附近的存储单元,常用于查表、数组操作、功能部件寄存器访问等。基址寻址指令举例如下:
LDR R1,[R2,#0x0C]
R2的值+0x0C形成内存地址,读取内存中该地址上的内容,放入R1
其它额外需要了解的内容:
l 零偏移。 如:LDR R0,[R1]
l 前索引偏移。 如:LDR R0,[R1,#0x04]!,表示将R1的值加上4后作为内存地址,将该内存处存放的数读出送给R0;并且指令执行结束时,R1本身的值也要加4。这里!表示要回写R1
l 程序相对偏移。
如:LDR R0,labe1,表示将标号label所代表的内存地址处存放的内容放入R0,相当于
LDR R0, [PC, #某个常数]
ldr r0, label
......
label DCD 0x12345678
l 后索引偏移。 如:LDR R0,[R1],#0x04,表示将R1的值作为内存地址,将该内存处存放的数读出送给R0;并且指令执行结束时,R1本身的值要加4
2. 多寄存器寻址
多寄存器寻址一次可传送几个寄存器值,允许一条指令传送16个寄存器的任何子集或所有寄存器。多寄存器寻址指令举例如下:
LDMIA R1!,{R2-R4,R6} ,它是ldr的多寄存器版本,将内存中连续存放的4个字加载到寄存器R2,R3,R4,R6中。R1中存放的是内存地址。
图1 - 64 LDMIA指令执行前 图1 - 65 LDMIA指令执行后
两点说明:
(1)R1!中的!号表示在指令执行完成后,要改变(回写)基址寄存器(R1)的值
(2)寄存器列表{R2-R4, R6}中的顺序并不要紧。最终寄存器与内存地址的对应关系是:编号小的寄存器与内存的低地址相对应
两点问题:
(1)为什么内存起地址是0x40000000,而不是0x40000004
(2)为什么内存地址是从0x40000000 ---- 0x4000000C,而不是从0x3FFFFFF4 ---- 0x40000000
要解释上面2个问题,其实也很简单。其实多寄存加载指令ldm总共有4个:ldmia、ldmib、 ldmda、ldmdb。ia的意思是increaseafter,ib的意思是increasebefore,da的意思是decreaseafter,db的意思是decreasebefore。以LDMIA R1!, {R2-R4, R6}为例子,这里的ia是指办事(将内存中的数加载到寄存器)之后增加基址寄存器(R