首先,看ARM官方的手册:
对于 ADR 指令:
看 Operation 即可看出作用,Xd 赋值为 $PC + imm
要求 label 和 $PC 位置在 正负1MB的范围内(这个数值和上面提到的imm有关)
而 LDR x5, =label 是一条伪指令, 对于该指令,没有找到合适的官方文档,不影响以下的结论(重要):
这两条指令都可以获得地址,但是 ldr 获取的地址是编译时就确定的,adr 是根据运行时确定的
adr 指令:pc(运行时)+ offset(编译时确定)
ldr 伪指令: pc(运行时)+ offset(编译时确定),然后从这个地址取出编译时指定的地址(编译时将其存在字面量池里面,运行时读取)
以上偏移的范围由 指令格式 决定,不同的是 LDR伪指令 得到的地址不受该 偏移的影响,因为其是从内存中读取的内容作为地址。
以下是实践过程中遇到的,拿过来分析,该实例是 Bao Hypervisor 的启动代码中的设置页表的部分:
其中 0xfd8000000000 是在链接器脚本中指定的虚拟地址,改地址是通过 ldr 伪指令从内存中读取出来的,如果使用 adr 指令是不可以的,偏移超过了指令的范围,adr 获取的地址与当前 PC 有关系,此时运行在物理地址空间,所以 adr 得到的是物理地址。