传送单一数据
运用单一数据传送指令(STR 和 LDR)来装载和存储单一字节或字的数据从/到内存。寻址是十分灵敏的。
首要让咱们检查指令格局:
LDR{条件} Rd, <地址>STR{条件} Rd, <地址>LDR{条件}B Rd, <地址>STR{条件}B Rd, <地址>
指令格局
这些指令装载和存储 Rd 的值从/到指定的地址。假设象后边两个指令那样还指定了‘B’,则只装载或存储一个单一的字节;关于装载,寄存器中高端的三个字节被置零(zeroed)。
地址可所以一个简略的值、或一个偏移量、或者是一个被移位的偏移量。能够还能够把组成的有用地址写回到基址寄存器(去除了对加/减操作的需求)。
各种寻址办法的示例:
译注:下文中的 Rbase 是表明基址寄存器,Rindex 表明变址寄存器,index 表明偏移量,偏移量为 12 位的无符号数。用移位选项表明份额因子。规范寻址办法 – 用 AT&T 语法表明为 disp(base, index, scale),用 Intel 语法表明为 [base + index*scale + disp],中的变址(连带份额因子)与偏移量不行兼得。
STR Rd, [Rbase] 存储 Rd 到 Rbase 所包括的有用地址。STR Rd, [Rbase, Rindex] 存储 Rd 到 Rbase + Rindex 所组成的有用地址。 STR Rd, [Rbase, #index] 存储 Rd 到 Rbase + index 所组成的有用地址。index 是一个当即值。例如,STR Rd, [R1, #16] 将把 Rd 存储到 R1+16。STR Rd, [Rbase, Rindex]! 存储 Rd 到 Rbase + Rindex 所组成的有用地址,而且把这个新地址写回到 Rbase。STR Rd, [Rbase, #index]! 存储 Rd 到 Rbase + index 所组成的有用地址,而且而且把这个新地址写回到 Rbase。STR Rd, [Rbase], Rindex 存储 Rd 到 Rbase 所包括的有用地址。把 Rbase + Rindex 所组成的有用地址写回 Rbase。STR Rd, [Rbase, Rindex, LSL #2] 存储 Rd 到 Rbase + (Rindex * 4) 所组成的有用地址。STR Rd, place 存储 Rd 到 PC + place 所组成的有用地址。
你当然能够在这些指令上运用条件履行。但要留意条件标志要先于字节标志,所以假设你期望在成果是等于的时分装载一个字节,要用的指令是LDREQB Rx, (不是LDRBEQ…)。
假设你指定预先变址寻址(这儿的基址和变址都在方括号中),用是否存在‘!’来操控写回操作。上面的第4和第5个比方中运用了这个标志。你能够运用它来在内存中主动正向或反向移动。一个字符串打印例程将变成:
.loopLDRB R0, [R1, #1]!SWI "OS_WriteC"CMP R0, #0BNE loop
而不是:
.loopLDRB R0, [R1]SWI "OS_WriteC"ADD R1, R1, #1CMP R0, #0BNE loop
关于往后变址寻址‘!’是无效的(这儿的变址在方括号外面,比方上面的比方6),由于写回是暗含的。
好像你见到的那样,变址能够被移位来完成份额缩放。除此之外,能够从基址上减去偏移量。在这种情况下,你能够运用如下代码:
LDRB R0, [R1, #-1]
虽然你能够存储或装载 PC,但你不能够用装载或存储指令来修正 PSR。要装载一个被存储的‘状况’并正确的康复它,请运用:
LDR R0, [Rbase]MOVS R15, R0
假设你在有特权的方式下,MOVS 将导致 PSR 的位被更改。
对 PC 运用MOVS不遵照 32-bit 系统,你需求运用 MRS 和 MSR 来处理 PSR。
按照 ARM 汇编手册:
译注:下文所叙说内容针对的是小端字节序装备,对大端字节序装备在手册中还有专门叙说。
- 假设供给的地址在一个字鸿沟上,则字节装载(LDRB)运用在 0 至 7 位上的数据,假设在一个字地址加上一个字节上,则运用 8 至 15 位,以此类推。挑选的字节被放入方针寄存器的低端 8 位中,并把寄存器中其他的位用零填充。
- 字节存储(STRB)在数据总线上重复源寄存器的的低端 8 位 4 次。由外部的内存系统来激活恰当的字节子系统来存储数据。
- 字装载(LDR)或字存储(STR)将生成一个字对齐的地址。运用一个非字对齐的地址将有不明显和未规则的成果。实际上提示的是你不能运用 LDR 从一个非对齐的地址装载一个字。
传送多个数据
运用大都据传送指令(LDM 和 STM)来装载和存储多个字的数据从/到内存。
LDM/STM 的主要用途是把需求保存的寄存器到栈上。如咱们曾经见到过的STMFD R13!, {R0-R12, R14}。
指令格局是:
xxM{条件}{类型} Rn{!}, <寄存器列表>{^}
‘xx’是 LD 表明装载,或 ST 表明存储。
再加 4 种‘类型’就变成了 8 个指令:
栈 其他LDMED LDMIB 预先添加装载LDMFD LDMIA 往后添加装载LDMEA LDMDB 预先削减装载LDMFA LDMDA 往后削减装载 STMFA STMIB 预先添加存储STMEA STMIA 往后添加存储STMFD STMDB 预先削减存储STMED STMDA 往后削减存储
指令格局
汇编器照顾怎么映射这些助记符。留意 ED 不同于 IB;只关于预先削减装载是相同的。在存储的时分,ED 是往后削减的。
FD、ED、FA、和 EA 指定是满栈仍是空栈,是升序栈仍是降序栈。一个满栈的栈指针指向前次写的最终一个数据单元,而空栈的栈指针指向第一个闲暇单元。一个降序栈是在内存中反向添加(就是说,从应用程序空间完毕处开端反向添加)而升序栈在内存中正向添加。
其他方式简略的描绘指令的行为,意思分别是往后添加(Increment After)、预先添加(Increment Before)、往后削减(Decrement After)、预先削减(Decrement Before)。
RISC OS 运用传统的满降序栈。在运用契合 APCS 规则的编译器的时分,它一般把你的栈指针设置在应用程序空间的完毕处并接着运用一个 FD (满降序 – Full Descending)栈。假设你与一个高档言语(BASIC 或 C)一同作业,你将别无挑选。栈指针(传统上是 R13)指向一个满降序栈。你有必要持续这个格局,或则树立并办理你自己的栈(假设你是死硬派人士那么你或许喜爱这样做!)。
‘基址’是包括开端地址的寄存器。在传统的 RISC OS 下,它是栈指针 R13,但你能够运用除了 R15 之外的任何可获得的寄存器。
假设你想把操作后栈顶的当时的内存地址保存到栈指针中,能够简略的在栈指针寄存器后边设置一个写回标志‘!’。
寄存器列表放在{花括号}中。不论你用什么次第在其中指定寄存器,寄存器按从最低到最高的编号次第与到从低端到高端的内存之间传送数据。而且由于用指令中的一个单一的位来表明是否保存一个寄存器,不行能指定某个寄存器两次。它的副作用是不能用下面这样的代码:
STMFD R13!, {R0, R1}LDMFD R13!, {R1, R0}
来交流两个寄存器的内容。
供给了一个有用的简写。要包括一个规模的寄存器,能够简略的只写第一个和最终一个,并在其间加一个横杠。例如R0-R3同等与R0, R1, R2, R3,仅仅愈加规整和沉着罢了…
在把 R15 存储到内存中的时分,还保存了 PSR 位。在从头装载 R15 的时分,除非你要求不然不康复 PSR 位。要求的办法是在寄存器列表后跟从一个‘^’。
STMFD R13!, {R0-R12, R14}...LDMFD R13!, {R0-R12, PC}
这保存一切的寄存器,做一些工作,接着从头装载一切的寄存器。从 R14 装载 PC,它由一个 BL 或此类指令所设置。不触及 PSR 标志。
STMFD R13!, {R0-R12, R14}...LDMFD R13!, {R0-R12, PC}^
这保存一切的寄存器,做一些工作,接着从头装载一切的寄存器。从 R14 装载 PC,它由一个 BL 或此类指令所设置。改变 PSR 标志。
正告: 这些代码不遵照 32 bit 系统。你需求运用 MRS 和 MSR 来处理 PSR,你不能运用‘^’后缀。
留意在这两个比方中,R14 被直接装载到 PC 中。这节省了对 MOV(S) R14 到 R15 中的需求。
正告: 运用 MOVS PC,… 不遵照 32 bit 系统。你需求运用 MRS 和 MSR 来处理 PSR。
SWP : 单一数据交流
(Swap)
SWP{条件}{B}, , [ ]
指令格局
SWP将:
- 从操作数 2 所指向的内存装载一个字并把这个字放置到意图寄存器中。
- 把寄存器操作数 1 的内容存储到同一个地址中。
假设意图和操作数 1 是同一个寄存器,则把寄存器的内容和给定内存方位的内容进行交流。
假设供给了B后缀,则将传送一个字节,不然传送一个字。