You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARM汇编中LDR R2, =ioadr为何加载值而非地址?

ARM汇编LDR Rd, =symbol伪指令的常见疑问

先澄清你代码里的核心逻辑误区:
你给出的代码中,ioadr .word 0x20001000是在内存中开辟一个存储单元,里面存的是0x20001000,而ioadr这个符号本身代表的是这个存储单元的地址,不是0x20001000。如果按照你写的LDR R2, =ioadr,实际加载到R2的是ioadr的地址,执行STR R1, [R2]后,7会被写到ioadr这个单元里(覆盖原来的0x20001000),而不是写到0x20001000地址。你描述的执行结果,对应的正确代码应该是LDR R2, [ioadr](从ioadr单元加载0x20001000到R2),再执行STR。

下面针对你的疑问逐一解释:

1. 为什么LDR R2, =ioadr加载的不是ioadr的地址?

不对,它加载的就是ioadr的地址——除非你用.equ ioadr, 0x20001000把ioadr定义成了立即数常量。

LDR Rd, =expr是ARM汇编的伪指令,作用是把expr的数值加载到寄存器:

  • 如果expr是立即数(比如0x20001000),汇编器会判断它能不能用MOV/MVN指令直接加载,能的话就转成MOV Rd, #expr,不能的话就把expr放到代码段的字面量池,转成LDR Rd, [PC, #偏移]来读取。
  • 如果expr是符号(比如ioadr),这个数值默认是符号对应的内存地址(也就是.word定义的那个单元的位置)。

你觉得它加载的是ioadr的值(0x20001000),大概率是把LDR R2, =ioadr和LDR R2, [ioadr]搞混了:后者是真正的内存加载指令,会从ioadr地址对应的单元里读出值(也就是0x20001000)。

2. 汇编器是否能识别ioadr是常量而非变量?

汇编器完全能区分:

  • 用.word/DCD定义的符号,是内存单元的地址,属于可修改的“变量”——你可以用STR指令往这个单元写新值。
  • 用.equ(或.set)定义的符号,是立即数常量,汇编时会直接替换成对应数值,不存在对应的内存单元,自然无法被修改。

比如你如果写:

.equ ioadr, 0x20001000
MOV R1, #7
LDR R2, =ioadr
STR R1, [R2]

这时候LDR R2, =ioadr才会直接加载0x20001000,执行后7会被写到0x20001000地址,和你描述的结果一致。

3. 是否存在加载地址的情况?

当然存在,而且就是LDR Rd, =symbol的默认行为(当symbol是标签时):

  • 如果你想加载ioadr这个单元的地址到R2,用LDR R2, =ioadr,或者用更高效的ADR R2, ioadr(ADR是小范围地址加载伪指令,适用于地址在PC偏移范围内的情况)。
  • 如果你想加载ioadr单元里存的值,用LDR R2, [ioadr](这是真正的内存访问指令,不是伪指令)。

内容的提问来源于stack exchange,提问作者user394334

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 16:24:12