您的位置 首页 编程

ARM指令LDR和ADR的一些差异

之前在阅读arm的汇编代码时,碰到了adr指令,查arm的指令手册,只说该指令是采用相对地址的,但这个相对地址应该怎么理解,却没有具体说

之前在阅览 arm的汇编代码时,碰到了adr指令,查arm的指令手册,只说该指令是选用相对地址的,但这个相对地址应该怎样了解,却没有详细阐明。之后在网上以 adr指令为关键字进行查找,也没有找到进一步的常识。成果,今天在查找android材料的时分,意外的发现了adr指令与ldr指令的不同,一会儿解 决了心中的问题。以adr指令与ldr指令比照作为关键字,乃至能够搜到好几篇文章,实在是…… 居然困扰了自己那么长期。

将两篇转来,作为备忘吧。
一、adr和ldr的差异
同学们在学习ARM指令时,大都都会对adr和ldr这两个指令发生疑问,那他们终究有什么差异呢?
其实这两个都是伪指 令:adr是小范围的地址读取伪指令,ldr是大范围的读取地址伪指令。可实际上adr是将根据PC相对偏移的地址值或根据寄存器相对地址值读取的为指 令,而ldr用于加载32为当即数或一个地址到指定的寄存器中。到这儿就会看到其间的差异了。假如在程序中想加载某个函数或许某个在联接时分指定的地址时 请运用adr,例如在lds中需求从头定位的地址。当加载32为的当即数或外部地址时请用ldr。
我给咱们先举个比如:
AREA test,CODE,READONLY
ENTRY
ldr r0,_start
adr r0,_start
ldr r0,=_start
nop
_start
nop
END
这段代码并无实际意义,仅仅为了便利阐明。咱们反汇编一下看看:
4: ldr r0,_start
0x00000000 E59F0008 LDR R0,[PC,#0x0008]
5: adr r0,_start
0x00000004 E28F0004 ADD R0,PC,#0x00000004
6: ldr r0,=_start
0x00000008 E59F0004 LDR R0,[PC,#0x0004]
7: nop
8:
9:
10: _start
0x0000000C E1A00000 NOP
11: nop
ldr r0, _start
从内存地址 _start 的当地把值读入。履行这个后,r0 = 0xe1a00000
adr r0, _start
获得 _start 的地址到 r0,可是请看反编译的成果,它是与方位无关的。其实获得的时相对的方位。例如这段代码在 0x00000000 运转,那么 adr r0, _start 得到 r0 = 0x00000010;
ldr r0, =_start
这个获得标号 _start 的肯定地址。这个肯定地址是在 link 的时分确认的。看上去这仅仅一个指令,可是它要占用 2 个 32bit 的空间,一条是指令,另一条是 _start 的数据(由于在编译的时分不能确认 _start 的值,并且也不能用 mov 指令来给 r0 赋一个 32bit 的常量,所以需求多出一个空间寄存 _start 的真实数据,在这儿便是 0x0000000c)。
因而能够看出,这个是肯定的寻址,不论这段代码在什么当地运转,它的成果都是 r0 = 0x0000000c。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/linweig/archive/2010/03/24/5411655.aspx
二、ldr和adr在运用标号表达式作为操作数的差异
http://blog.sina.com.cn/s/blog_4b5210840100c80i.html
http://blog.sina.com.cn/s/blog_4b5210840100c80i.html
ARM汇编有ldr指令以及ldr、adr伪指令,他门都能够将标号表达式作为操作数,下面经过剖析一段代码以及对应的反汇编成果来阐明它们的差异。
ldr r0, _start
adr r0, _start
ldr r0, =_start
_start:
b _start
编译的时分设置 RO 为 0x30000000(如同有问题),下面是反汇编的成果:
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 :读取指定地址中的值
ldr在此是一条指令,把内存地址 _start 方位中的值读入r0。(_start为指针之意,读取指针的值)
在这儿_start是一个标号(是一个相对程序的表达式),汇编程序核算相对于 PC 的偏移量,并生成相对于 PC的前索引指令:ldr r0, [pc, #4]。履行指令后,r0 = 0xeafffffe。
能够在和_start标号的相对方位不变的状况下移动( 也便是说整段代码从flash中拷贝到ram中仍然能够正常运转)。
2.adr r0, _start :将指定地址赋到r0中
ADR是小范围的地址读取伪指令.ADR 指令将根据PC 相对偏移的地址值读取到寄存器中.在汇编编译源程序时,ADR 伪指令被编译器替换成一条适宜的指令.一般,编译器用一条
ADD 指令或SUB 指令来完成该ADR 伪指令的功用,若不能用一条指令完成,则发生过错,
编译失利.
r0的值为((标号_start 的地址与此指令的间隔差)+(此指令的地址))。在此例中被汇编成:add r0, pc, #0。该代码能够在和标号相对方位不变的状况下移动(也便是说整段代码从flash中拷贝到ram中仍然能够正常运转);
假设这段代码在 0x30000000 运转,那么 adr r0, _start 得到 r0 = 0x3000000c;假如在地址 0 运转,便是 0x0000000c 了。
经过这一点能够判别程序在什么当地运转。U-boot中那段relocate代码便是经过adr完成判别当时程序是在RAM中仍是flash中。
3.ldr r0, =_start :将指定标号的值赋给r0
ldr在此是一条伪指令,_start(即:label-expr)是一个相对程序的或外部的表达式。汇编程序将相对程序的标号表达式 label-expr 的值放在一个文字池中,并生成一个相对程序的 LDR 指令来从文字池中装载该值,在此例中生成的指令为:ldr r0, [pc, #0],对应文字池中的地址以及值为:0x00000010: 3000000c。假如 label-expr 是一个外部表达式,或许未包括于当时段内,则汇编程序在方针文件中放置一个链接程序重定位指令。链接程序在链接时生成地址。
因而获得的是标号 _start 的肯定地址,这个肯定地址(运转地址)是在衔接的时分确认的。它要占用 2 个 32bit 的空间,一条是指令,另一条是文字池中寄存_start 的肯定地址。因而能够看出,不论这段代码将来在什么当地运转,它的成果都是 r0 = 0x3000000c。由于ldr r0, =_start获得的是_start的肯定地址,这句代码能够在_start标号的肯定方位不变的状况下移动;假如运用寄存器pc在程序中能够完成肯定转 移。(1.肯定地址;2.标号对应的值)
举例:
GPFCON EQU 0x56000050
ldr r0,=GPFCON
GPFCON :标号
0x56000050 :标号的值
http://blog.chinaunix.net/u2/72383/showart_1071068.html
ldr的确是个杂乱的指令,现总结一下:
首先要判别咱们用的是ldr arm指令仍是伪指令。 当咱们用的是arm指令时,它的效果不是向寄存器里加载当即数,而是将某个地址里的内容加载到寄存器。而伪指令ldr的效果便是向寄存器里加载当即数。
(1) ldr伪指令
ldr伪指令的格局是 ldr Rn, =expr
其间,expr是要加载到Rn中的内容,一般能够是当即数或许label。
假如expr能够用8bit数据向右移偶数位得到,那么这条伪指令就被编译器翻译成mov指令。详细的移位状况能够去查阅材料。反之假如当即数很大,超 过了12bit的表明领域,那么就不能用一条mov指令了,究竟arm指令最大只要32bit的空间可用(RISC的arm一切的指令长度是共同的,功率 较高,当然咱们并不关怀16bit的thumb指令)。假如不能用一条32bit的指令乘下来,那么就只能另辟蹊径了,新开一段缓冲,将当即数expr放 到里边,然后将其地址(暂时标记为addr)拿来运用:
ldr Rn, addr
xxx (xxx便是expr)
xxx
由于编译器一般来说新组织的存储这个当即数expr的缓冲的方位是在相应代码的邻近(这个应该能够操控,如同是运用.ltorg伪指令)。咱们从addr地址加载数据到Rn不就能够了。
(2)ldr arm 指令
便是将一个地址的内容加载到寄存器。不能用mov,由于arm里的mov仅仅在寄存器之间传输数据,不支持在寄出器和memory之间传递数据。因而就 呈现了ldr/str指令。如ldr Rn, addr,留意这儿的addr的值也是有约束的。这个label应该间隔当时指令的间隔不超越4k。由于咱们知道label在详细运用的时分应该是被翻译 成了相对偏移,假如这个label长度不超越12bit,那么就不该超越4k,咱们能够这样做:
ldr pc, _start_armboot
_start_armboot: .word arm_startboot
这样label _start_armboot就在指令下方,因而肯定是合法的。

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

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

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

微信扫一扫关注我们

返回顶部