ldr和adr的区别
创始人
2025-05-28 02:35:55

本文整理于博文ARM指令ldr和adr的区别_ldr adr,有修改。

一、使用格式

我们先弄清楚ldr与adr的使用格式。adr是伪指令,而ldr根据使用的格式可分为ldr指令与ldr伪指令。

1、adr伪指令

格式:adr{cond} Rd,addr

功能:将基于PC相对偏移的地址值或者基于寄存器相对偏移的地址值,读取到目标寄存器Rd中。

2、ldr指令

格式:ldr{cond} Rd,addr

功能:将addr这个存储器地址对应的存储单元中的数据,加载到目标寄存器Rd中。

3、ldr伪指令

格式:ldr{cond} Rd,=addr

功能:将一个32位的立即数,或者一个地址值,加载到目标寄存器Rd中。

从上面的描述中可以看出,ldr作为加载指令时,Rd这个寄存器中存储的是addr这个地址对应的存储单元中的数据(指针所指向的内容)。而ldr作为伪指令时,它与adr伪指令一样,Rd这个寄存器中存储的就是addr这个地址(即指针)。这也是ldr伪指令、adr伪指令又叫作(大范围/小范围)地址读取伪指令的原因,因为它们就是用来获取一个地址(至于为什么有前缀“大范围”“小范围”,是因为它们获取地址的方式不一样,导致能够获取的地址范围不同。这有点废话,不过确实如此。见接下来的描述)。

二、两者的区别 

比如有一个汇编文件test_adr.S,其内容如下:

.text             //伪操作
.globl _start     //伪操作,将_start这个标号导出,即作为全局变量_start: //这是一个标号,这个标号表示一个地址,就好比门牌号ldr r0,test   @ 指令 ,表示r0寄存器存储的是test这个地址对应的存储单元中的数据adr r0,test   //伪指令,表示r0寄存器存储的是test这个地址(或者说标号,标号即地址) ldr r0,=test  //伪指令,表示r0寄存器存储的是test这个地址(或者说标号,标号即地址)nop
test:nop

 另外有一个Makefile文件,其内部对test_adr.S进行汇编、链接与反汇编: 

all:test_adr.S#汇编:将汇编文件test_adr.S转换成目标文件test_adr.o@ arm-linux-gcc -c -o test_adr.o test_adr.S #链接:将目标文件的集合,组合成可执行程序test_adr.elf@ arm-linux-ld -Ttext 0x00000000 -g test_adr.o -o test_adr.elf#复制:将可执行程序test_adr.elf从一种二进制格式(elf)转换成另外一种格式(bin)@ arm-linux-objcopy -O binary -S test_adr.elf test_adr.bin #反汇编:将可执行文件test_adr.elf反汇编,并将结果输出到test_adr.dis文件(否则输出至终端)@ arm-linux-objdump -d -m arm test_adr.elf > test_adr.disclean:@ rm -f test_adr.dis test_adr.bin test_adr.elf *.o

注意到 adr r0,test 与 ldr r0,=test 都是将test这个标号所在的地址存储到r0寄存器中,它们有什么区别呢?

我们看一下反汇编生成的test_adr.dis文件的内容:

xjh@ubuntu:~/iot/tmp$ cat test_adr.dis test_adr.elf:     file format elf32-littlearmDisassembly of section .text:
//因为链接地址是00000000,所以这里显示为00000000
00000000 <_start>:0:	e59f0008 	ldr	r0, [pc, #8]	; 10 4:	e28f0004 	add	r0, pc, #48:	e59f0004 	ldr	r0, [pc, #4]	; 14 c:	e1a00000 	nop			        ; (mov r0, r0)00000010 :10:	e1a00000 	nop			        ; (mov r0, r0)14:	00000010 	.word	0x00000010
xjh@ubuntu:~/iot/tmp$ 

首先要明白,为了提高处理的效率,ARM采用了流水线技术,使用最广泛的是三级流水线,这意味着取指操作与执行操作相差两个周期,因为每个周期4个字节,所以差8个字节。因为PC总是指向取指的指令,而非指向正在执行的指令或者正在译码的指令,所以PC值=当前程序执行位置+8。

(1)由反编译结果可知,代码 ldr r0,test 等价于 ldr r0, [pc, #8] 指令。ldr r0, [pc, #8] 这条指令对应的二进制码e59f0008,它存放在地址0对应的存储单元中,也就是执行到这指令时,当前程序执行位置是0,则PC值=0+8(即指向了指令ldr r0, [pc, #4])。而[pc,#8]表示PC的值再加上8,所以[pc,#8]表示0+8+8=0d16=0x10这个地址所对应的存储单元中的数据([  ]表示间接寻址)。我们到0x10这个地址,看到它对应的存储单元中的数据是e1a00000,这个数据其实是指令nop对应的二进制码。

(2)由反编译结果可知,代码 adr r0,test 等价于 add r0, pc, #4 指令。注意这条指令的位置是4,也就是执行到这条指令时,当前执行位置是4,那么PC值=4+8(即指向了第一个指令nop)。add r0, pc, #4 指令表示将PC的值再加上4,然后存储到r0寄存器中,那么r0中存储的内容就是4+8+4=0d16=0x10。这个0x10表示的是一个地址,也就是test这个标号所在的地址。总结之,adr r0,test 就是把标号test所在的地址取出来,存储到r0寄存器中。 

(3)由反编译结果可知,代码 ldr r0,=test 等价于 ldr r0, [pc, #4] 指令。注意这条指令的位置是8,也就是执行到这条指令时,当前执行位置是8,那么PC值=8+8。[pc, #4]表示PC的值再加上4,所以[pc, #4]表示8+8+4=0d20=0x14这个地址所对应的存储单元中的数据。我们到0x14这个地址,看到它对应的存储单元中的数据是00000010,这个数据表示test这个标号所在的地址。总结之,ldr r0,=test就是把标号test所在的地址取出来,存储到r0寄存器中。 

总结

从上面的描述可知,adr伪指令中r0寄存器所存储的数据,我们(根据反汇编代码)可以明确地知道它是一个地址。标号所在的地址=(标号所在的地址-当前执行指令的地址)+当前执行指令的地址。当前执行指令的地址是PC的值-8,虽然不直接就是PC,但依然是一个与PC有关的值。也就是说,使用adr伪指令获取某个标号的地址时,这个标号的地址是与运行地址(体现为PC)有关的,或者说,它是基于PC相对偏移的地址值。

ldr伪指令获取某个标号的地址时,这个标号的地是与链接地址有关的。链接脚本写好并执行链接之后,可执行文件中各条指令、各个标号的地址就已经定下来了。

当链接地址与运行地址一致时,使用adr伪指令与使用ldr伪指令,它们获取的标号地址是一样的。

当链接地址与运行地址不同时,使用adr伪指令获取的是程序实际运行时标号所在的地址,而使用ldr伪指令获取的是链接脚本指导下的该标号所在的地址。

我们可以利用这两个伪指令取址时的差异,判断是否需要重定位。见博客https://xiefor100.blog.csdn.net/article/details/70135880。

相关内容

热门资讯

NOI2019模拟赛 T1牛油... 题目描述 牛油果是一种神秘的水果,其具有一个坚固程度x≥0x\geq 0x≥0...
嵌入式软件开发之Linux下C... 目录 前沿 Hello World! 编写代码 编译代码 GCC编译器  gcc 命...
云原生|Rancher与Ope... 目录一、Rancher(一)介绍(二)优点&...
如何突破卫星影像建模难点?重建... 日前,由重建大师生成的首个“珞珈三号01星”卫星影像三维模型一经发出,引...
L1-085 试试手气 L1... 我们知道一个骰子有 6 个面,分别刻了 1 到 6 个点。下面给你 6 个骰子的初始状...
SpringSecurity客... 概述 FilterChainProxy是spring-security的入口,包含默认...
数据结构--二叉树 目录1.树概念及结构1.1数的概念1.2数的表示2.二叉树概念及结构2.1二叉树的概念2.2数据结构...
Qt之QUrl和QUrlQue... QUrlQUrl 类提供了一个方便的接口使用 URLs。最常见的使用QUrl 的方式是通过构造函数来...
函数指针二三事 1 什么是函数指针? ​ 函数指针,顾名思义,它是一个指向...
[ 红队知识库 ] Windo... 🍬 博主介绍 👨‍🎓 博主介绍:大家好...
【PowerBI】PowerB... 目的: 陈述PowerBI连接Mysql数据库的坑。 方法1:直接使用【...
BI数据可视化|可自动刷新的可... BI数据可视化大屏和其他的BI报表一样,都是可用于日常的决策中,因此除了...
Linux 练习十二 (Lin... 文章目录1 计算机网络基础知识1.1 OSI参考模型和TCP/IP参考模型1.2 TCP 协议1.2...
SQL语言基础教学 | Mys... SQL语言基础教学SQL(Structured Query Languageÿ...
pandas数据分析(三) 书接pandas数据分析(二) 文章目录DataFrame数据处理与分...
DC-DC升压模块隔离高压稳压... 特点● 效率高达 80%● 2*2英寸标准封装● 单双电压输出● 价格低● 大于600V高压,稳压输...
Java【多线程基础2】 Th... 文章目录前言一、Thread类1, 构造方法2, 常用成员属性3, 常用成员方法3.1, start...
TDK| 电源——反激变压器设... 电源参数根据功率、输入输出的情况,我们选择反激电源拓扑。反激式变压器的优点有:1、 电...
Python:判断语句 目录一、布尔类型1.1定义1.2获取二、逻辑运算符2.1and运算符2.2or运算符2.2not运算...
协程池加disruptor加e... 先说一下disrutor和协程的实现。然后介绍服务器具体分析,以及迭代过程,项目困难,学到东西,压测...
selenium(2)----... 操作界面上的元素: 先选中元素再进行调用下面的方法 1)click(),点击对象 2)...
第九章:C语言数据结构与算法初... 系列文章目录 文章目录系列文章目录前言一、堆的定义二、堆的实现三、堆的接口函数1、初始化2、销毁3...
< Linux > 多线程(单... 目录 1、单例模式         饿汉方式实现单例模式         懒汉方式实现单例模式   ...
MXNet中使用卷积神经网络t... 在图像识别领域,卷积神经网络是非常常见和有用的,我们试图将它应用到文本的...
用python写《外星人入侵》... 昨天的文章,我们设置好了本地环境。 现在,我们有了 python...
QD Laser用视网膜投影方... 一提到视网膜投影,我们常常将它与AR眼镜联想起来,作为一种成像技术&#x...
ubuntu解决中文乱码 1、查看当前系统使用的字符编码 ~$ locale LANG=en_US LANGUAGE&...
【vue.js】在网页中实现一... 文章目录前言效果电脑效果手机效果说明完整代码index.html 前言 诶?这有一个按...
tert-butyl 3-am... 相关类别:交联剂,Fine Chemicalstert-butyl 3-...
处理窄区路径规划的业务问题 系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手...