LDR 和 ADR 彻底详解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LDR 和 ADR 彻底详解相关的知识,希望对你有一定的参考价值。
0.什么是位指令?
答:伪指令(Pseudo instruction)是用于告诉汇编程序如何进行汇编的指令。它既不控制机器的操作也不被汇编成机器代码,
只能为汇编程序所识别并指导汇编如何进行。
1.LDR 大范围的地址读取伪指令(当有=号时为伪指令)
LDR 伪指令将一个32位的常数或者一个地址值读取到寄存器中。
语法格式
LDR{cond} register,={expr | label -expr}
其中,cond为可选的指令执行条件
register 为目标寄存器
expr 为32位的常量。编译器将根据expr的取值情况,决定如果处理LDR指令
①当expr表示的地址值没有超过MOV或MVN指令中的地址取值范围时,编译器用适当的MOV或MVN指令翻译LDR 指令
②当expr表示的地址值超过了MOV或者MVN指令中的地址取值范围时,编译器将该常数放在数据缓冲区中,同时用一条
基于PC的LDR指令读取该常数
也就是说,LDR伪指令要么翻译为MOV指令,要么翻译为LDR指令
label -expr为基于PC的地址表达式或者是外部表达式
①当label -expr为基于PC的地址表达式时,编译器将label -expr表示的数值放在数据缓冲区中,同时用一条基于PC的
LDR指令读取该数值
②当label -expr为外部表达式,或者非当前段的表达式时,汇编编译器将在目标文件中插入连接重定位伪操作,这样链
接器将在链接时生成该地址
使用说明
LDR伪指令主要有以下两种用途
①当需要读取到寄存器中的数据超过了MOV或MVN指令可以操作的范围时,可以使用LDR伪指令将数据读取到该寄存器中
②将一个基于PC的地址值或者外部的地址值读取到寄存器中。由于这种地址是在链接时确定的,所以这种代码不是位置无关的。
同时LDR伪指令处的PC值到缓冲区中的目标数据所在的地址的偏移量要小于4KB
示例
例1 将0xff0读取到R1中
LDR R1,=0xff0 汇编后将会得到 MOV R1,0xff0
例2 将0xfff读取到R1中
LDR R1,=0xfff
汇编后将会得到
LCD R1,[PC,OFFSET_TO_LPOOL]
...
LPOOL DCD 0xFFF
例3 将外部地址ADDR1读到R1中
LDR R1,=ADDR1
汇编后将会得到
LDR R1,[PC,OFFSET_TO_LPOOL]
...
LPOOL DCD ADDR1
实验
1.在keil-MDK中编写如下代码
注:代码是下载到内存运行的,地址为0x3000,0000
1 AREA Init, CODE ,READONLY 2 ENTRY 3 _start 4 ldr r0,copy ;这里是ldr指令,用于获取copy标号对应地址的内容 5 ldr r0,=copy ;这里是ldr伪指令,用于获取copy标号的绝对地址 6 mov r1,r0 7 mov r1,r0 8 copy 9 mov r0,r0 10 mov r0,r0 11 test1 12 b test1 13 14 END
经过反汇编得到的结果如下
1 4: ldr r0,copy 2 0x30000000 E59F0008 LDR R0,[PC,#0x0008];此处R0中装的值应为地址值为(PC值+0x0008)指向的内容,PC指针值为 ;0x3000,0000 + 8,即地址值为0x3100,0010,内容为E1A00000 3 5: ldr r0,=copy ;这是一条伪指令,这一条指令被翻译成了两条语句,一条是在END后 4 0x30000004 E59F0010 LDR R0,[PC,#0x0010];定义了一个变量值,另一条是读取这个变量值,地址为 5 6: mov r1,r0 ;0x3000,0004 + 8 + 0x10 = 0x3000,001c 此工程的最后一条指令地 6 0x30000008 E1A01000 MOV R1,R0 ;址为0x3000,0018 ,即END其实并不表示汇编程序的结尾 7 7: mov r1,r0 8 8: copy ;在ARM汇编中,标号没有实际的意义 9 0x3000000C E1A01000 MOV R1,R0 ;注意这里,KEIL反汇编的一个缺陷,看了半天才看懂,copy标号的 10 9: mov r0,r0 ;地址实际应为0x3000,0010,KEIL把copy 和上一条指令mov r1,r0连在 11 0x30000010 E1A00000 NOP ;一起进行翻译了 12 10: mov r0,r0 13 11: test1 14 0x30000014 E1A00000 NOP 15 12: b test1 16 0x30000018 EAFFFFFE B 0x30000018
2.ADR(小范围的地址读取指令)
该指令将基于PC的地址值或者基于寄存器的地址值读取到寄存器中
语法格式
ADR{cond} register,expr
expr 为基于PC或者寄存器的地址表达式,其取值范围如下
①当地址值不是字对齐的,其取值范围为 -255 ~ 255
②当地址值是字对齐的,其取值范围为 -1020 ~ 1020
使用说明
在汇编程序处理源程序时,ADR伪指令被编译器替换成一条合适的指令。通常,编译器用一条ADD指令或者SUB指令来实现
该伪指令的功能。
如果不能用一条指令来实现ADR伪指令的功能,编译器将报错
因为ADR伪指令中的地址基于PC或者基于寄存器的,所以ADR读取到的地址为位置无关的地址。当ADR伪指令中的地址是基
于PC时,该地址与ADR伪指令必须在同一代码段中
示例
1 start 2 MOV r0,#10 ; 因为PC值为当前指令地址加8字节 3 ADR r4,start ; 本ADR伪指令将被编译替换成 SUB r4,pc,#0xc
实验
1 AREA Init, CODE ,READONLY 2 ENTRY 3 _start 4 adr r0,copy 5 mov r1,r0 6 mov r1,r0 7 copy 8 mov r0,r0 9 mov r0,r0 10 test1 11 b test1 12 13 END
经过反汇编后
4: adr r0,copy 0x30000000 E28F0004 ADD R0,PC,#0x00000004 ;R0 = 0x3000,0000 + 8 + 0x04 = 0x3000000c,正好是copy标号的地址 5: mov r1,r0 0x30000004 E1A01000 MOV R1,R0 6: mov r1,r0 7: copy 0x30000008 E1A01000 MOV R1,R0 8: mov r0,r0 0x3000000C E1A00000 NOP 9: mov r0,r0 10: test1 0x30000010 E1A00000 NOP 11: b test1 0x30000014 EAFFFFFE B 0x30000014
以上是关于LDR 和 ADR 彻底详解的主要内容,如果未能解决你的问题,请参考以下文章