1、数据处理指令的操作数的寻址方式
- 立即数方式
MOV R0, #100 ;将100放到R0中
- 寄存器方式
MOV R0, R1 ;将R1的值放到R0中
ADD R0, R1, R2 ;将R1 + R2的值放到R0中
- 寄存器移位方式
ASR 算术右移(arithmetic shift right)
ASL 逻辑左移(logic shift left)
ASR 逻辑右移(logic shift right)
ROR 循环右移(rotate right)
RRX 扩展的循环右移( Rotate Right eXtended)
MOV R0, R1 LSL #3 ; R0 = R1 * (2 ** 3)
ADD R0, R1, R1 LSL #3 ; R0 = R1 + R1 * (2 ** 3)
SUB R0, R1, R2 LSR #4 ; R0 = R1 + R2 / (2 ** 4)
MOV R0, R1, ROR R2 ; R0 = R1 循环右移R2位
2、 字及无符号字节的 Load/Store 指令的寻址方式
Load 指令用于从内存中读取数据放入寄存器中; Store 指令用于将寄存器中的数据保存到内存。 ARM 有两大类的 Load/Store 指令:一类用于操作 32 位的字类型数据以及 8 位无符号的字节类型数据;另一类用于操作 16 位半字类型的数据以及 8 位的有符号字节类型的数据。这里介绍的是第 1 种类型的 Load/Store 指令的寻址方式。
Load/Store 指令的寻址方式由两部分组成,一部分为一个基址寄存器;另一部分为一个地址偏移量。基址寄存器可以为任一个通用寄存器;地址偏移量可以有以下 3 种格式。
- 立即数
- 寄存器
- 寄存器及一个移位常数
同样,寻址方式的地址计算方法有如下 3 种:
- 偏移量方法 这种方法,基址寄存器中的值和地址偏移量作加减运算,生成操作数的地址
- 事先跟新方法 这种方法,基址寄存器中的值和地址偏移量作加减运算,生成操作数的地址。指令执行后,这个生成的操作数的地址被写入基址寄存器。
- 事后更新方法 这种方法,指令将基址寄存器的值作为操作数的地址执行内存访问。基址寄存器中的值和地址偏移量做加减运算,生成操作数的地址。指令执行后,这个生成的操作数地址被写入基址寄存器。
2.1 示例
- 立即数
LDR R0, [R1, #4] ;将内存单元 R1 + 4 中的字读取到寄存器 R0 中
LDR R0, [R1, #-4] ;将内存单元 R1 - 4 中的字读取到寄存器 R0 中
- 寄存器
LDR R0, [R1, R2] ;将内存单元 R1 + R2 中的字读取到寄存器 R0 中
LDR R0, [R1, -R2] ;将内存单元 R1 - R2 中的字读取到寄存器 R0 中
- 寄存器及一个移位常数
LDR R0, [R1, R2, LSL #2] ;将 R1 + R2 * 4 中的数据读取到 R0 中
- 事先访问方式(pre-indexed)+ 立即数
指令的内存访问完成后进行基址寄存器内容更新的方式为事先访问方式。
LDR R0, [R1, #4] ! ; 将内存单元 (R1 + 4) 中数据读取到 R0 中,同时 R1 = R1 + 4
- 事先访问方式(pre-indexed) + 寄存器
LDR R0, [R1, R2] ! ;将内存单元 (R1 + R2) 中数据读取到 R0 中,同时 R1 = R1 + R2
- 事先访问方式(pre-indexed) + 寄存器及一个移位常数
LDR R0, [R1, R2, LSL #2] ! ; 将内存单元 (R1 + R2 * 4) 中数据读取到 R0 中,同时 R1 = R1 + R2 * 4
- 事后访问方式(post-indexed) + 立即数
指令使用基址寄存器 Rn 的值作为实际内存访问的地址。访问完成后,将基址寄存器的值 +/- offset 写入基址寄存器 Rn 中。这种在指令的内存访问完成计算新地址的方式称为事后访问方式。
LDR R0, [R1], #4 ; 将地址为 R1 的内存单元数据读取到 R0 中,然后 R1 = R1 + 4
- 事后访问方式(post-indexed) + 寄存器
LDR R0, [R1], R2 ; 将地址为 R1 的内存单元数据读取到 R0 中,然后 R1 = R1 + R2
- 事后访问方式(post-indexed) + 寄存器及一个移位常数
LDR R0, [R1], R2, LSL #2 ; 将地址为 R1 的内存单元数据读取到 R0 中,然后 R1 = R1 + R2 * 4
3、杂类 Load/Store 指令的寻址方式
这里所说的杂类 Load/Store 指令包括:操作数为半字(无符号或带符号数)数据的 Load/Store 指令;操作数为带符号的字节数据的 Load 指令;双子的 Load/Store 指令。
LDR|STR{<cond>}H|SH|SB|D <Rd>, <addressing_mode>
其中, <addressing_mode>是指令中内存单元的寻址方式,具体有以下 6 中格式:
[<Rn>, #+/-<offset_8>]
[<Rn>, #+/-<offset_8>]!
[<Rn>], #+/-<offset_8>
[<Rn>, +/-<Rm>]
[<Rn>, +/-<Rm>]!
[<Rn>], +/-<Rm>
- LDRH 半字无符号 Load, 高 16 位填充 0
- LDRSH 半字带符号 Load, 高 16 位填充该半字的符号位
- LDRSB 字节带符号 Load,高 24 位填符号位
- LDRD 双字Load
4、批量Load/Store指令的寻址方式
一条批量Load/Store指令可以实现在一组寄存器和一块连续的内存单元之间传输数据。
这类指令的语法格式为:
LDM|STM{<cond>}<addressing_mode> <Rn>{!}, <registers>{^}
其中,<addressing_mode>表示地址的变化方式,具体有以下4种形式:
IA(Increment After) 事后递增方式
IB(Increment Before) 事先递增方式
DA(Decrement After) 事后递减方式
DB(Decrement Before) 事先递减方式
示例
LDMIA R0, {R5-R8} ; 将内存单元(R0)到(R0+12)4个字的数据读取到R5~R8的4个寄存器中
LDMIB R0, {R5-R8} ; 将内存单元(R0+4)到(R0+16)4个字的数据读取到R5~R8的4个寄存器中
LDMDA R0, {R5-R8} ; 将内存单元(R0-12)到(R0)4个字的数据读取到R5~R8的4个寄存器中
LDMDB R0, {R5-R8} ; 将内存单元(R0-16)到(R0-4)4个字的数据读取到R5~R8的4个寄存器中
对应于栈操作的寻址方式
FD(Full Descending)
ED(Empty Descending)
FA(Full Ascending)
EB(Empty Ascending)
根据栈指针的指向:
栈指针指向栈顶元素(即最后一个入栈的数据元素)时称为FULL栈
栈指针指向与栈顶元素相邻的一个可用数据单元时称为EMPTY栈
根据数据栈的增长方向:
当数据栈向内存地址减少的方向增长时,称为DESCENDING栈
当数据栈向内存地址增加的方向增长时,称为ASCENDING栈
5、协处理器Load/Store指令的寻址方式
一条协处理器Load/Store指令可以实现在ARM处理器和协处理器之间传输数据。
这类指令的语法格式为:
<opcode>{<cond>}{L} <coproc>, <CRd>, <addressing_mode>
其中,<addressing_mode>表示地址的变化方式,具体有以下4种形式:
[<Rn>, #+/-<offset_8>*4]
[<Rn>, #+/-<offset_8>*4]!
[<Rn>], #+/-<offset_8>*4
[<Rn>], <option>