前言
在 ARM 汇编学习中,绝大多数人会卡在同一个逻辑悖论:
为什么 LDR 用 [Rx] 是取数据,STR 用 [Rx] 又是操作地址空间?
这会让人误以为[Rx] 的含义会随指令变化,时而代表数据、时而代表内存空间。
实际上硬件层面定义完全统一、从未改变。本文给出唯一、自洽、无歧义的标准定义,彻底根治该问题。
一、核心标准定义(全文总纲)
1. Rx
寄存器中保存的数值,仅代表内存地址。
作用:定位内存位置,只是一个位置编号,不是空间,也不是数据。
2. [Rx]
以 Rx 存放的地址为索引,寻址得到的内存存储单元(内存空间)。
恒定不变规则:
[Rx]永远代表内存空间本身,它既不是地址,也不是数据。
地址 = Rx(位置编号)
空间 = [Rx](存储容器)
数据 = 空间中存放的内容(操作产物)
二、LDR 与 STR 统一逻辑拆解
1. LDR(内存读指令)
指令格式:LDR Rd, [Rx]
标准语义:读取 [Rx] 内存单元中存储的数据,送入寄存器 Rd。
执行流程:
读取 Rx 的值,得到有效内存地址;
根据地址选中对应的内存存储单元 [Rx];
读出该单元内部的数据,加载到目标寄存器。
✅ 关键点:
LDR 获取的是空间内的数据,但[Rx] 本身依然是内存空间,并未变成数据。
日常口语“[Rx] 是数据”,只是对读取结果的简化描述,不是符号定义。
2. STR(内存写指令)
指令格式:STR Rs, [Rx]
标准语义:将寄存器 Rs 的数据,写入 [Rx] 内存单元。
执行流程:
读取 Rx 的值,得到有效内存地址;
根据地址选中对应的内存存储单元 [Rx];
用寄存器数据覆盖该内存单元原有内容。
✅ 关键点:
STR 直接操作内存空间本体,因此可以直观看出:[Rx] 是存储空间。
三、矛盾彻底闭环解释
不存在语义切换,不存在两套规则。
[Rx] 自始至终都是内存存储单元。
读操作(LDR):使用空间里的内容 → 结果是数据
写操作(STR):操作空间本身 → 目标是地址空间
符号不变,变的只是操作行为,不是定义。
四、与 C 语言指针语义完全对齐
ARM 的[Rx]等价于 C 语言的*p解引用。
int *p = &a; // Rx = 地址 int val = *p; // LDR:读取空间内容 *p = val; // STR:写入空间C 语言中*p在右为取值、在左为空间,所有人都默认合法;
ARM 汇编[Rx]逻辑完全一致,不存在任何冲突。
五、三大经典错误认知修正
错误1:[Rx] 是地址
正确:地址是 Rx,[Rx] 是地址对应的内存空间。
错误2:LDR 时 [Rx] 是数据,STR 时 [Rx] 是空间
正确:[Rx] 永远是空间。读取内容、写用容器,定义统一不变。
错误3:不带 [] 是地址,带 [] 是数据
正确:
取地址专用:
LDR Rd, =label(伪指令)访存专用:
[Rx]代表内存空间数据只是访存后的结果,不是符号本身的含义
六、完整标准代码演示
LDR R0, =_addr_a ; 伪指令:R0 = 变量a的地址 LDR R1, [R0] ; 读内存:从 [R0] 空间取出数据 STR R2, [R0] ; 写内存:向 [R0] 空间存入数据七、最终总结
1.Rx存放地址,是位置编号;
2.[Rx]恒为内存存储单元,是存储空间;
3.LDR读取空间内的数据;
4.STR改写空间内的数据;
5.符号定义永不改变,仅读写行为不同。