ARM中的ldr指令与adr、ldr伪指令之间的区别
ldr指令和adr、ldr伪指令的区别:ldr指令属于load-store指令,用于读取标号地址中的值;adr、ldr伪指令用于获取标号的地址。
adr和ldr伪指令的区别:adr是获取相对PC的地址,与程序当前运行的位置相关,是小范围的地址读取伪指令;ldr是获取绝对地址,绝对地址是在link的时候确定的,它与程序当前运行位置无关,是大范围读取地址伪指令。
下面通过分析一段代码以及对应的反汇编接过来说明他们的区别。
ldr r0,_start
adr r0,_start
ldr r0,=_start
_start:
b _start
编译的时候设置r0为0x30000000,下面是反汇编的结果:
0x00000000:e59f0004ldr r0,[pc,#4];0xc
0x00000004:e28f0000add r0,pc,#0;0x0
0x00000008:e59f0000ldr r0,[pc,#0];0x10
0x0000000c:eafffffeb0xc
0x00000010:3000000candcc r0,r0,ip
这是一条指令,从内存地址_start的位置装载该地址存放的数据。
在这里_start是一个标号(是一个相对程序的表达式),汇编程序计算相对于PC的偏移量,并生成相对于PC的前索引的指令:ldr r0,[pc,#4]。指令执行后,r0=0xeafffffe(计算方法:r0 = [pc(0x00000000+8)+4]= [0x0000000c] = 0xeafffffe)。
ldr r0,_start是根据_start对当前PC的相对位置读取其所在地址的值,因此可以在和_start标号的相对位置不变的情况下获取数据值。
这是一条伪指令,总是会被汇编程序会变为一个指令,汇编程序尝试产生单个ADD或SUB指令来装载该地址。如果不能在一个指令中构造该地址,则生成一个错误,并且汇编失败。
这里是取得标号_start的地址到r0,因为地址是相对程序的,因此adr的产生依赖于位置的代码,在此例中被汇编成:add r0,pc,#0。因此该代码可以在和标号相对位置不变的情况下移动。
假如这段代码在0x30000000运行,那么adr r0,_start得到r0 = 0x3000000c;如果在地址0运行,那么就是0x0000000c了。
通过这一点可以判断程序在什么地方运行。U-Boot中那段relocate代码就是通过adr实现当前程序是在RAM中还是FLASH中。
这是一条伪指令,_start是一个绝对地址(也即运行地址)。这个绝对地址是在链接的时候确定的,它占用2个32bit的空间,一条是指令,另一条是文字池中存放_start的绝对地址。在此例中生成的指令为:ldr r0,[pc,#0],对应文字池中的地址以及值为:0x00000010:3000000c,因此该伪指令执行后r0的值为0x3000000c。因此可以看出,不管这段代码将来在什么地方运行,它的结果都是r0=0x3000000c。
由于ldr r0,=_start取得的是_start的绝对地址,这句代码可以在_start标号的绝对位置不变的情况下移动,如使用寄存器pc在程序中可以实现绝对转移。
ARM中ldr指令adrldr伪指 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)