您的位置 首页 模拟

伪指令ADR和LDR的差异

ARM汇编有ldr指令以及ldr、adr伪指令,他门都可以将标号表达式作为操作数,下面通过分析一段代码以及对应的反汇编结果来说明它们的区别。

ARM汇编有ldr指令以及ldr、adr伪指令,他门都能够将标号表达式作为操作数,下面经过剖析一段代码以及对应的反汇编成果来阐明它们的差异。 ldr r0, _start

adr r0,_start
ldr r0, =_start
_start:
b _start
编译的时分设置 RO 为 0x30000000(运转地址,runaddress),下面是反汇编的成果: 0x00000000: e59f0004 ldr r0, [pc, #4] ; 0xc 0x00000004: e28f0000 add r0, pc, #0 ; 0x0 0x00000008: e59f0000 ldr r0, [pc, #0] ; 0x10 0x0000000c: eafffffe b 0xc 0x00000010: 3000000c andcc r0, r0, ip -------------------------------------- 1.ldr r0, _start: 简略的说便是把 _start地址寄存的值读出来。汇编程序计算出当时方位履行到_start(这儿是一个标号,相对程序的方位表达式)方位pc所要添加的数值#4,然后由当时pc(其实是当时地址+2个指令字节长)加上偏移量#4,得到_start地点内存地址,然后将内存地址的值去出来放在r0中。只需此指令和标号_start的相对方位不变,R0的值相同 0xeafffffe 2.adr r0, _start 简略的说便是把 _start地址读出来,并且这个地址是相对当时pc的,所以和当时程序运转地址相关,假如在0x30000000运转,r0 = pc(0x30000004 + 0x08) + #0 = 0x3000000C;假如在0x00000000运转, r0 = pc(0x00000004 + 0x08) + #0 = 0x0000000C,所以在不同的方位运转,r0所得到的成果是不一样的,仅有确认的相对偏移量。 U-boot中那段relocate代码便是经过adr完成当时程序是在RAM中仍是flash中,下面进行扼要剖析。 ——————————————————————————– relocate: // 把U-Boot从头定位到RAM // adr r0, _start // r0是代码的当时方位 // // adr伪指令,汇编器主动经过当时PC的值算出 假如履行到_start时PC的值,放到r0中: 当此段在flash中履行时r0 = _start = 0;当此段在RAM中履行时_start = _TEXT_BASE(在board/smdk2410/config.mk中指定的值为0x30000000,即u-boot在把代码拷贝到RAM中去履行的代码段的开端) // ldr r1, TEXT_BA_SE // 测验判别是从Flash发动,仍是RAM // // 此句履行的成果r1始终是0x30000000,由于此值是又编译器指定的(ads中设置,或-D设置编译器参数) // cmp r0, r1 // 比较r0和r1,调试的时分不要履行重定位 // ——————————————————————————– 3. ldr, r0, =_start 这是一条伪指令,获得得是_start的肯定地址,不论在身当地运转,r0 = 0x3000000C ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 看《嵌入式linux使用开发》第六章实例中看到个句: adrl r2,men_cfg_val 开始对adr1适当不解,后来发现,那个不是数字1,而是字母l(仔细看头部,有点差异的) 这儿记录下ADRL的用法:功用:将相关于程序或相关于寄存器的地址载入寄存器中。 与 ADR 指令类似。ADRL 生成两个数据处理指令,因而它比 ADR 加载的地址规模要宽。 语法 ADRL{cond} Rd,label 其间: cond:是一个可选的条件代码。Rd:是要加载的寄存器。label:是相关于程序或寄存器的表达式。上面给出的规模是相关于坐落当时指令地址后的、间隔当时指令四个字节(在 Thumb 代码中)或两个字(在 ARM 代码中)远的点而言的。假如对齐为 16 字节,或与此点的相关性更高,则长途地址的规模可更大。检查ADRL的一起,看到篇叙述ldr与adr的差异的博文,感觉写的很好,摘抄下来。 http://coon.blogbus.com/logs/2738861.html ldr r0, _start adr r0, _start ldr r0, =_start nop mov pc, lr _start: nop 编译的时分设置 RO 为 0x0c008000 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 0c008000 <_start-0x14>: c008000: e59f000c ldr r0, [pc, #12] ; c008014 <_start> c008004: e28f0008 add r0, pc, #8 ; 0x8 c008008: e59f0008 ldr r0, [pc, #8] ; c008018 <_start+0x4> c00800c: e1a00000 nop (mov r0,r0) c008010: e1a0f00e mov pc, lr 0c008014 <_start>: c008014: e1a00000 nop (mov r0,r0) c008018: 0c008014 stceq 0, cr8, [r0], -#80 剖析: ldr r0, _start 从内存地址 _start 的当地把值读入。履行这个后,r0 = 0xe1a00000 adr r0, _start 获得 _start 的地址到 r0,可是请看反编译的成果,它是与方位无关的。其实获得的时相对的方位。例如这段代码在 0x0c008000 运转,那么 adr r0, _start 得到 r0 = 0x0c008014;假如在地址 0 运转,便是 0x00000014 了。 ldr r0, =_start 这个获得标号 _start 的肯定地址。这个肯定地址是在 link 的时分确认的。看上去这仅仅一个指令,可是它要占用 2 个 32bit 的空间,一条是指令,另一条是 _start 的数据(由于在编译的时分不能确认 _start 的值,并且也不能用 mov 指令来给 r0 赋一个 32bit 的常量,所以需求多出一个空间寄存 _start 的真实数据,在这儿便是 0x0c008014)。 因而能够看出,这个是肯定的寻址,不论这段代码在什么当地运转,它的成果都是 r0 = 0x0c008014 看此文最大的收成不在于说懂了这几个指令的用法,要害却在于反汇编的运用,有反汇编看出不同用法的详细不同。注:反汇编用arm—linux_objdump就能够完成了。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/zhishi/moni/263388.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部