计组与微机控制
3.5 寄存器间接寻址
3.5寄存器间接寻址和前后索引取指令:

寄存器间接寻址:操作数的地址保存在寄存器中。也就是说,指令中的寄存器不是操作数本身,而是“指针”。
典型形式:
LDR r1, [r0]含义:
r0 中保存一个地址,CPU 到这个地址对应的内存单元取数据,取出的数据写入 r1
RTL:[r1] <- [[r0]]
第一层 `[r0]` 表示 r0 的内容,也就是地址;第二层 `[[r0]]` 表示该地址指向的内存内容。这和 C 语言指针完全对应:r1 = *r0_pointer;
还强调 ARM 的立即数偏移量为 12 位。这里的 12 位是真正用于地址偏移的 12 位,不是数据处理指令中那种“8 位立即数 + 循环移位”的编码形式。(上一节有讲具体无需知道计算原理)
1. MOV r1, #0x0000FF00
· 二进制指令中立即数编码是 0xCFF(12 位)
· 低 8 位 0xFF = 255(基本数值)
· 高 4 位 0xC = 12(对齐码)
· 实际移位次数 = 12 × 2 = 24 次循环右移
· 计算:0xFF 循环右移 24 位
· 在 32 位中,循环右移 24 位 = 循环左移 8 位
· 0xFF 左移 8 位 → 0xFF00(高位补零,低位原是0xFF左移后变为0xFF00)
· 结果就是 0x0000FF00,符合预期。
2. MOV r2, #0xFF000000
· 有就是说:左移 6 次十六进制 → 二进制左移 24 次
· 等价于循环右移 8 次(因为 32-24=8)
· 对齐码 = 移位次数的一半 = 8/2 = 4
· 编码为 0x4FF(高 4 位=4,低 8 位=0xFF)
· 实际过程:0xFF 循环右移 8 位
· 循环右移 8 位 = 高 8 位被移到底部
· 32 位中 0xFF 是 0x000000FF,循环右移 8 位 → 0xFF000000
大概就是说我们如果知道0XCFF和0X4FF把这个12位拆成4位和8位,4位按公式带入左移相当于循环32-右移次数
总结
· 立即数在机器码中只占 12 位,格式为 旋转量(4位) + 8位数值。
· 实际 32 位数值 = 8 位数值 循环右移 (旋转量 × 2) 位。
· 例子:
· #0xFF00 → 编码 0xCFF(旋转12,数值0xFF)
· #0xFF000000 → 编码 0x4FF(旋转4,数值0xFF)

### 立即偏移
LDR R0, [R1, #4]含义:从 `R1 + 4` 的地址读取数据到 R0,R1 本身不变。
带偏移量的寄存器间接寻址
本页引入带偏移量的寄存器间接寻址,也叫基址加位移寻址。
典型形式:
LDR r0, [r1, #4]有效地址:
EA = [r1] + 4
特点:
- r1 是基址寄存器;
- `#4` 是偏移量;
- 访问的是基址后 4 字节处的数据;
- 默认情况下 r1 自身不改变。
这在结构体、数组、栈帧访问中非常常见。
### 前变址 前索引也就是先变
LDR R0, [R1, #4]!含义:先 `R1 = R1 + 4`,再从新地址取数。
用数组 A、B、C 相加说明自动前索引的便利。
代码思想:
ADR r0, A-4
ADR r1, B-4
ADR r2, C-4
Loop
LDR r3, [r0, #4]!LDR r4, [r1, #4]!ADD r3, r3, r4STR r3, [r2, #4]!为什么初始地址是 `A-4`:
因为自动前索引会先加 4 再访问。如果想第一次访问 A[0],初始指针要放在 A 前一个字的位置。
预先偏移 -> 访问 -> 写回更新指针
### 后变址 后索引也就是后变
LDR R0, [R1], #4含义:先从 R1 指向地址取数,再 `R1 = R1 + 4`。
易混点:
- 中括号里带 `!`:先改地址,再访问。
- 中括号外有偏移:先访问,再改地址。
- 没有 `!` 且偏移在括号内:只计算地址,不修改基址寄存器。
和自动前索引对比:
| 形式 | 访问地址 | 是否更新基址 |
| `[r1,#8]` | r1+8 | 不更新 |
| `[r1,#8]!` | r1+8 | 更新为 r1+8 |
| `[r1],#8` | r1 | 更新为 r1+8 |
总结 ARM 基址寄存器、偏移量、目的寄存器之间的组合。
必须熟练区分:
LDR r0, [r1, #12]LDR r0, [r1, #12]!LDR r0, [r1], #12判断规则:
- 偏移在括号内:参与访问地址计算;
- 有 `!`:访问后写回基址;
- 偏移在括号外:先访问原地址,再写回基址;
- 没有 `!` 且偏移在括号内:只算 EA,不写回。
PC 相对寻址
本页介绍程序计数器相对寻址。
ARM 中 r15 是 PC。
格式:LDR r0, [r15, #100]
含义:EA = PC + 100 r0 <- Memory[EA]
用途:
- 访问常量池;
- 支持位置无关代码;
- 程序整体搬移后不必重新计算绝对地址。
和伪指令联系:
LDR r0, =0x12345678汇编器可能把常量放到附近的常量池,再生成 PC 相对的 `LDR` 去取。
