现在咱们现已把握了一切常识,能够编写简略的ARM汇编程序,但假如要编写较为杂乱的ARM程序,就必须把握更多的寻址形式和指令,这便是本文的要点地点。
咱们在“根本寻址形式与根本指令”一文中学习了最常用的3种寻址方法。下面介绍其它寻址方法。
1、基址寻址
基址寻址便是将基址寄存器的内容与指令中给出的偏移量相加,构成操作数的有用地址。基址寻址用于拜访基址邻近的存储单元,常用于查表、数组操作、功用部件寄存器拜访等。基址寻址指令举例如下:
LDR R1,[R2,#0x0C]
R2的值+0x0C构成内存地址,读取内存中该地址上的内容,放入R1
其它额定需求了解的内容:
§零偏移。 如:LDR R0,[R1]
§前索引偏移。 如:LDR R0,[R1,#0x04]!,表明将R1的值加上4后作为内存地址,而且指令履行结束时,R1自身的值也要加4。这儿!表明要回写
§程序相对偏移。 如:LDR R0,labe1,表明将标号label所代表的地址处寄存的内容放入R0,相当于LDR R0, [PC, #某个常数]
§后索引偏移。 如:LDR R0,[R1],#0x04,表明将R1的值作为内存地址,而且指令履行结束时,R1自身的值要加4
2、多寄存器寻址
多寄存器寻址一次可传送几个寄存器值,答应一条指令传送16个寄存器的任何子集或一切寄存器。多寄存器寻址指令举例如下:
LDMIA R1!,{R2-R4,R6} ,它是ldr的多寄存版别,将内存中的4个字放入寄存器R2,R3,R4,R6中
两点阐明:
1)、R1!中的!号表明在指令履行完结后,要改动(回写)基址寄存器(R1)的值
2)、寄存器列表{R2-R4, R6}中的次序并不要紧。终究寄存器与内存地址的对应联系是:编号小的寄存器与内存的低地址相对应
两点问题:
1)、为什么内存起地址是0x40000000,而不是0x40000004
2)、为什么内存地址是从0x40000000 —- 0x4000000C,而不是从0x3FFFFFF4 —-
要解说上面2个问题,其实也很简略。其实多寄存加载指令ldm总共有4个:ldmia、 ldmib、 ldmda、 ldmdb。ia的意思是increase after,ib的意思是increase before,da的意思是decrease after,db的意思是decrease before。以LDMIA R1!, {R2-R4, R6}为比如,这儿的ia是指就事(将内存中的数加载到寄存器)之后添加基址寄存器(R1)的值。这条指令的履行进程从逻辑上看,如下:
1)、先就事:将R1的值(0x40000000)作为内存地址,到该地址处取得数(0x01),加载到寄存器R2中
2)、后添加:将R1的值从0x40000000添加为0x40000004
再重复上面的操作3次,别离将内存中的数0x02、0x03、0x04放到寄存器中R3、R4、R6中,最终R1的值变为0x40000010。
这个比如中,假如将ldmia改为ldmib,则R2、R3、R4、R6中寄存的是0x02、0x03、0x04、内存0x40000010处的内容,最终R1的值为0x40000010。
除了4条多寄存器加载指令外,还有4条相似的多寄存器存储指令,别离是stria、 strib、 strda、 strdb
3、仓库寻址
因为ARM指令集没有专门的出栈和入栈指令,所以ARM汇编程序是选用SP作为栈指针,以stm指令完结入栈操作,以ldm指令完结出栈操作。
以入栈后SP的值是添加仍是削减为根据,可将仓库类型划分为递加仓库(向上成长)和递减仓库(向下成长);
以SP所指向的内存处寄存的是栈顶元素仍是下一非必须入栈的元素,可将仓库类型划分为满仓库和空仓库
那么当仓库类型为空递减仓库时分,入栈操作应该运用什么指令?出栈操作应该运用什么指令?进一步,假如仓库类型为空递加、满递加、满递减仓库,又将怎么呢?假如你不看下面的答案,我相信你一定会让这几个问题折磨得做许多的脑力体操,然后感叹ARM指令集的设计者太不为你这样的程序员考虑了,给了你本不应该由你承当的负荷。但事实上正相反,ARM指令集的设计者充沛理解了你作为程序员的苦恼,请看下面的答案。
数据块传送 | 仓库操作 | 阐明 |
存储 | 压栈 | |
STMDA | STMED | 空递减 |
STMIA | STMEA | 空递加 |
STMDB | STMFD | 满递减 |
STMIB | STMFA | 满递加 |
数据块传送 | 仓库操作 | 阐明 |
加载 | 出栈 | |
LDMDA | LDMFA | 满递加 |
LDMIA | LDMFD | 满递减 |
LDMDB | LDMEA | 空递加 |
LDMIB | LDMED | 空递减 |
这2张表的榜首、三列答复了前面你费尽心机答复的问题。而第二列则表现了ARM指令集的设计者对作为程序员的你的充沛关心。第二列中的ED、EA、FD、FA别离表明empty descend(空递减)、 empty ascend(空递加)、 full descend(满递减)、 full ascend(满递加),其意义是说,假如你选用的是空递减(空递加、满递减、满递加)仓库的话,入栈操作则运用指令STMED(STMEA、STMFD、STMFA),出栈操作则运用指令LDMED(LDMEA、LDMFD、LDMFA)。从此你再也不会为你应该运用ia、ib、da仍是db来实现出、入栈操作而苦恼了。