ldr和adr的区别
ldr和adr都是伪指令,区别是ldr是长加载、adr是短加载。
重点:adr指令加载符号地址,加载的是运行地址;ldr指令在加载符号地址时,加载的是运行地址。
ldr和adr的使用格式(举例说明)
adr r0, _start // adr加载时就叫短加载 ,注意这里没有“=”号,这是与ldr伪指令用法的区别
ldr r1, =_start // ldr加载时如果目标寄存器是pc就叫长跳转,如果目标寄存器是r1等就叫长
深入分析为什么adr加载的是运行地址,ldr加载的是运行地址
在运用时只要知道adr和ldr分别用于加载运行地址和链接地址,从而可以判断是否需要重定位即可;根本不需知道为什么adr和ldr是这样子,但是我们还是给大家扩展讲下为什么adr和ldr可以加载不同的地址。下面开始分析:
adr r0, _start
ldr r1, =_start
ldr r2, =bss_start
d002401c: e24f0024 sub r0, pc, #36 ; 0x24 //r0 = pc - 0x24 //执行完这句后r0=d0020000
d0024020: e59f1048 ldr r1, [pc, #72] ; d0024070 <run_on_dram+0x10>
d0024024: e59f2048 ldr r2, [pc, #72] ; d0024074 <run_on_dram+0x14>
解析:上面三行代码时汇编指令,下面三行是对应的反汇编文件中看到的指令。可以看到adr指令在反汇编指令中用sub代替了。
在反汇编指令中可以看到如下区别
1、sub r0, pc, #36是直接寻址(加载的是运行地址);
这句话意思是当前pc的值d0024024(d002401c+0x08,也就是往下移两个地址)减去0x24(十进制为36)等于d0024000。咦奇怪了,为什么r0的地址会与ldr r1, [pc, #72]执行后r1的地址一样的呢?都是链接地址?(先说结论,其实此时pc当前值为d0020024)
解析:r0和r1的地址其实不一样(因为这两条语句,一个是直接寻址,一个是间接寻址)。考虑到直接寻址与间接寻址,这时sub r0, pc, #36指令中的pc的地址真的是d0024024吗?不是的,因为我们整个代码下载的时候是下载到 d0020010这个地址的,那么pc怎么可能等于d0024024呢?不是的,pc永远是跟当前运行地址相关,所以说,执行sub r0, pc, #36指令时,pc的地址实际是运行地址d0020024(为什么呢?当我们执行完代码重定位后,实际上在SRAM中有2份代码的镜像(一份是我们下载到0xd0020010处开头的,另一份是重定位代码复制到0xd0024000处开头的),这两份内容完全相同,仅仅地址不同),此时d0020024减去0x24(十进制为36)等于d0020000
2、ldr r1, [pc, #72]是间接寻址(加载的是链接地址);
由反汇编中代码可以看出,经过了上面反汇编代码的第二句ldr r1, [pc, #72]之后,r1的地址d0024070,r1值是d0024000。
到此为止,向大家解析清楚了为什么adr和ldr可以加载不同的地址了