一、内存访问指令
1.2.LDR / STR
对于内存访问的指令有两个,一个是读 LDR:Load Register,一个是写 STR:Store Register。读指令的结构与其中的类型如下图所示:

写指令的结构与其类型:

MOV R0, #0x20000
MOV R1, #0x10
MOV R2, #0x12
STR R2, [R0] ;R2的值放在R0所示的地址
STR R2, [R0, #4] ;R2的值放在R0+4所示的地址
STR R2, [R0, #8]! ;R2的值放在R0+8所示的地址,感叹号是刷新了R0所存放的值,变成了0x20008
STR R2, [R0, R1] ;R2的值放在R0+R1所示的地址
STR R2, [R0, R1, LSL #4] ;R2的值放在R0+(R1<<4)所示的地址
STR R2, [R0], #0x20 ;R2的值放在R0所示的地址,R0=R0+0x20
MOV R2, #0x34
STR R2, [R0] ;R2的值放在R0所示地址
LDR R3, [R0], +R1, LSL #1 ;将R0+(R1<<1)所示地址上的值放在R3里

1.2. LDM / STM
这两个指令里面的字母 M 表示多个的意思,使用这类指令可以读取或写入多个值在寄存器列表中。
- LDM:Load Multiple Register,下面是该指令的格式,Rn 是地址,其中 addr_mode 是说明该地址是增加还是减小、在变化之前读出数据或是在变化之后读出数据,这两个变数组成了四个搭配

- STM:Store Multiple Register,与上面的同理



下面举例验证一下,注意低标号的寄存器对应低地址:
MOV R1, #1
MOV R2, #2
MOV R3, #3
MOV R0, #0x20000
STMDB R0, {R1-R3} ;将1、2、3依此存放在R0、R0-4、R0-8地址处,DB表示先减小指针,再

这样的情况是否似曾相识,这就是入栈的手段,根据栈指针指向,可分为满(Full)/空(Empty):
- 满SP指向最后一个入栈的数据,需要先修改SP再入栈
- 空SP指向下一个空位置,先入栈再修改SP
根据压栈时SP的增长方向,可分为增/减:
- 增(Ascending):SP变大
- 减(Descending):SP变小
组合后,就有4种方式:满增、满减、空增、空减。接下来是出入栈:
MOV R1, #1
MOV R2, #2
MOV R3, #3
MOV SP, #0x20000 ;将指针指到0x20000上
STMFD SP!, {R1-R3} ;将1、2、3值按顺序压入栈,感叹号目的是刷新SP指针的地址,方便从该地址按顺序读入寄存器
MOV R1, #0 ;将这些寄存器清0,存放别的值
MOV R2, #0
MOV R3, #0
LDMFD SP!, {R1-R3} ;读到寄存器之后,SP的值又回到0x20000
常用的“满减”:
- 入栈时用STMDB,也可以用STMFD,作用一样
- 出栈时用LDMIA,也可以用LDMFD,作用一样

二、数据处理指令
加法指令ADD:
ADD R1, R2, R3 ;R1 = R2 + R3
ADD R1, R2, #0x12 ;R1 = R2 + 0x12
减法指令SUB:
SUB R1, R2, R3 ;R1 = R2 - R3
SUB R1, R2, #0x12 ;R1 = R2 - 0x12
位操作:
AND R1, R2, #(1<<4) ;位与,R1 = R2 & (1<<4)
AND R1, R2, R3 ;位与,R1 = R2 & R3
BIC R1, R2, #(1<<4) ;清除某位,R1 = R2 & ~(1<<4)
BIC R1, R2, R3 ;清除某位,R1 = R2 & ~R3
ORR R1, R2, R3 ;设置某位,R1 = R2 | R3
比较:
CMP R0, R1 ;比较R0-R1的结果
CMP R0, #0x12 ;比较R0-0x12的结果
TST R0, R1 ;测试 R0 & R1的结果
TST R0, #(1<<4) ;测试 R0 & (1<<4)的结果
比较出的结果能影响到程序状态寄存器的位,下图是程序状态寄存器位域的意义:



三、跳转指令
核心指令是B、BL:
- B:Branch,跳转
- BL:Branch with Link,跳转前先把返回地址保持在LR寄存器中
- BX:Branch and eXchange,根据跳转地址的 BIT0 切换为 ARM 或 Thumb 状态 (0:ARM状态,1:Thumb状态)
- BLX:Branch with Link and eXchange 根据跳转地址的BIT0切换为ARM或Thumb状态 (0:ARM状态,1:Thumb状态)
编写一个简单的延迟函数,倒数 5 个数,倒数结束后返回 LR 寄存器所保存的地址,使用 BL 的时候,LR 寄存器会保存跳转前下一行代码的地址,也就是 MOV R0, #1:
BL Delay
MOV R0, #1
Delay
MOV R0, #5
Loop
SUBS R0, R0, #1
BNE Loop
MOV PC, LR
不使用 BL 指令也可以做到相同效果,将 Ret 地址保存到 LR 寄存器里,再将 Delay 地址保存到 PC 寄存器里,PC 地址首先会指到 Delay 函数并运行,最后将 LR 的地址赋给 PC 寄存器,运行MOV R0, #1
ADR LR, Ret
ADR PC, Delay
Ret
MOV R0, #1
Delay
MOV R0, #5
Loop
SUBS R0, R0, #1
BNE Loop
MOV PC, LR
ARM内存与数据处理指令详解
3171

被折叠的 条评论
为什么被折叠?



