一. Load/Store 指令
1. 前变址
前变址指令是在读取或存储数据时,先根据基址寄存器(Rn)与偏移量(offset)计算出有效地址,再进行数据操作。相关指令及示例如下:
-
LDR R0, [R1, #4]
:从地址R1 + 4
处读取一个字(32 位)到R0
。假设R1 = 0x10000000
,指令执行后R0 = 0x88776655
,R1
的值保持为0x10000000
。 -
LDRB R2, [R1, #4]
:从地址R1 + 4
处读取一个字节(8 位)到R2
,高位补零扩展为 32 位。执行后R2 = 0x00000055
,R1
的值不变。 -
LDRH R3, [R1, #4]
:从地址R1 + 4
处读取一个半字(16 位)到R3
,高位补零扩展为 32 位。执行后R3 = 0x00006655
,R1
的值不变。 -
LDRSB R4, [R1, #7]
:从地址R1 + 7
处读取一个字节,执行符号扩展成 32 位后存入R4
。执行后R4 = 0xFFFFFFFF88
,R1
的值不变。
前变址指令详细说明如下:
指令 | 功能描述 |
---|---|
| 从地址 |
| 从地址 |
| 从地址 |
| 从地址 |
| 把 |
| 把 |
| 把 |
| 把 |
| 字节 / 半字的自动变址加载,并且在加载后执行符号扩展成 32 位 |
2.自动变址
自动变址指令在完成数据操作后,会自动对基址寄存器进行调整。
以 LDR.W R0, [R1, #20]!
为例,执行步骤如下:
-
先计算
R1 = R1 + 20
。 -
然后将计算后的地址
R1
中的数据读取到R0
。
自动变址指令详细说明如下:
指令 | 功能描述 |
---|---|
| 字 / 字节 / 半字 / 双字的自动变址加载(不做带符号扩展,没有用到的高位全部置 0) |
| 字节 / 半字的自动变址加载,并且在加载后执行符号扩展成 32 位整数 |
| 字 / 字节 / 半字 / 双字的自动变址存储 |
3.后变址
后变址指令先以基址寄存器(Rn)的当前值进行数据操作,然后再对基址寄存器进行调整。
以STR.W R0, [R1], #-12
为例,执行步骤如下:
-
先将
R0
的数据存储到地址R1
处。 -
然后计算
R1 = R1 + (-12)
。
后变址指令详细说明如下:
指令 | 功能描述 |
---|---|
| 字 / 字节 / 半字 / 双字的带后索引加载(不做带符号扩展,没有用到的高位全清 0) |
| 字节 / 半字的带后索引加载,并且在加载后执行符号扩展成 32 位整数 |
| 字 / 字节 / 半字 / 双字的带后索引存储 |
后变址应用举例:
-
LDR R0, [R1], #4
:假设R1 = 0x10000000
,先从地址R1
(即0x10000000
)处读取一个字到R0
,R0 = 0x44332211
,然后R1 = R1 + 4 = 0x10000004
。 -
LDRB R2, [R1], #4
:从地址R1
(此时R1 = 0x10000004
)处读取一个字节到R2
,R2 = 0x00000011
,接着R1 = R1 + 4 = 0x10000004
。 -
LDRH R3, [R1], #4
:从地址R1
(0x10000004
)处读取一个半字到R3
,R3 = 0x00002211
,之后R1 = R1 + 4 = 0x10000004
。 -
LDRSB R4, [R1], #7
:从地址R1
(0x10000004
)处读取一个字节并符号扩展到 32 位存入R4
,R4 = 0x00000011
,最后R1 = R1 + 7 = 0x10000007
。
Load/Store 指令综合举例(字序调整):
假设内存地址0x1000
处存储的值为0x12345678ABCDEF00
,执行以下指令:
-
LDR R2, =0x1000
:将地址0x1000
加载到R2
。 -
LDRD.W R0, R1, [R2]
:从地址R2
(即0x1000
)处读取一个双字,R0 = 0xABCDEF00
,R1 = 0x12345678
。 -
STRD.W R1, R0, [R2]
:把R1
(低 32 位)和R0
(高 32 位)存储到地址R2
(0x1000
)处,此时(0x1000) = 0xABCDEF0012345678
。
二. 批量数据传送指令
1. 批量数据 Load/Store 指令
这些指令用于在内存与多个寄存器之间批量传输数据,Rd
后面的!
表示在每次访问前(Before)或访问后(After),要自增(Increment)或自减(Decrement)基址寄存器Rd
的值,增 / 减单位为 1 个字(4 字节)。具体指令如下:
指令 | 功能描述 |
---|---|
| 从 |
| 存储多个字到 |
| 从 |
| 从 |
| 存储多个字到 |
| 存储多个字到 |
例如,当R8 = 0x8000
时:
-
STMIA.W R8!, {R0 - R3}
:每存储一次,R8
的值增加 4 字节,先存储R0 - R3
的值,然后R8
自增。执行后R8
值变为0x8010
。 -
STMDB.W R8!, {R0 - R3}
:每存储一次,R8
的值减少 4 字节,先自减R8
,然后存储R0 - R3
的值。执行后R8
值变为0x7FF0
。
2.堆栈传送类指令
-
STMDB SP!, [R0 - R3, LR]
:等效于PUSH {R0 - R3, LR}
,将寄存器R0 - R3
和链接寄存器LR
的值压入堆栈,堆栈指针SP
在存储前递减。 -
LDMIIA SP!, {R0 - R3, PC}
:等效于POP {R0 - R3, PC}
,从堆栈中弹出数据到寄存器R0 - R3
和程序计数器PC
,堆栈指针SP
在读取后递增。