ldr和adr 并分析为什么adr加载的是运行地址,ldr加载的是运行地址

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可以加载不同的地址了

猜你喜欢

转载自blog.csdn.net/baidu_37973494/article/details/82862928
LDR