>科技>>正文

Linux技术解析:arm指令adr adrl ldr mov是什么,ldr 和adr区别在哪里?

原标题:Linux技术解析:arm指令adr adrl ldr mov是什么,ldr 和adr区别在哪里?

ARM指令:什么是adr adrl ldr mov?

ADR是一条小范围的地址读取伪指令,它将基于PC的相对偏移的地址值读到目标寄存器中。格式:ADR register,exper。

编译源程序时,汇编器首先计算当前PC值(当前指令位置)到exper的距离,然后用一条ADD或者SUB指令替换这条伪指令,

例如:ADD register,PC,#offset_to_exper。

注意,标号exper与指令必须在同一代码段。

比如:adr r0, _start ://将指定地址赋到r0中

……

_start:

b _start

r0的值为标号_start与此指令的距离差 + PC值。

ADRL:

这是一条中等范围的地址读取伪指令,它将基于PC的相对偏移的地址值读到目标寄存器中。格式:ADRL register,exper。编译源程序时,汇编器会用两条合适的指令替换这条伪指令。

比如:

ADD register,PC,offset1

ADD register,register,offset2

与ADR相比,它能读取更大范围的地址。

注意,标号exper与指令必须在同一代码段。

接下来是LDR,首先要说两个家伙,他们都叫LDR。

一个是LDR伪指令,一个是LDR指令,名字相同却不是一个东西。

区分的方法就是看第二个参数,如果有等号,就是伪指令。

LDR指令:

例: ldr r0, 0x12345678

是把0x12345678这个地址中的值存放到r0中。而mov不能干这个活,mov只能在寄存器之间移动数据,或者把立即数移动到寄存器中。

LDR伪指令:

例1(立即数): ldr r0, =0x12345678

这样,就把0x12345678这个地址写到r0中了。所以,ldr伪指令和mov是比较相似的。只不过mov指令限制了立即数的长度为8位,也就是不能超过512。而ldr伪指令没有这个限制。如果使用ldr伪指令,后面跟的立即数没有超过8位,那么在实际汇编的时候该ldr伪指令会被转换为mov指令。

例2(标号): ldr r0, =_start //将指定标号的值赋给r0

这里取得的是标号_start的绝对地址,这个绝对地址(运行地址)是在链接的时候确定的。它要占用 2 个32bit的空间,一条是指令,另一条是文字池中存放_start 的绝对地址。

对比adr r0, _start和 ldr r0, =_start

它们的目的一样,都是把标签的赋给r0,区别---左边是相对地址,右边绝对地址。目的一样,但结果不一定相同。结果是否相同,要看PC值是否和链接地址相同。

ldr 和 adr 的区别在哪里?

很多人在写简单的裸机代码或分析uboot时,常常遇到adr ldr指令。却分不清这2者的区别,今天就来谈谈adr与ldr指令。

参照韦老师的代码和Makefile写了test_adr.S

Makefile:

反汇编test_adr.S得到test_adr.dis:

很显然,ldr获取的是内存的值(至于这个内存存的是数据还是地址,不是问题重点),像指针一样间接寻址(看到了[]符号咯),而adr是得到一个与PC有关的值,必定是个地址。

韦老师举了个例子:

adr r0, _start,r0就是_start对应指令当前的地址

对于“_start对应指令当前的地址”,我理解了很久,终于想清楚,比如在uboot中,_start标号对应的指令(即b reset)的链接地址是0x33f80000确凿无疑。

如果从NOR Flash启动,b reset被烧在NOR Flash 0地址,那么b reset相对于此时的PC来说,它的地址就是0。

如果u-boot被直接下载到SDRAM的0x33f80000处运行,那么b reset自然处在SDRAM的0x33f80000。

所谓“当前”---是以运行时的PC为参照。

下面基于以上理解,分析test_adr.dis

1、先分析第一条指令ldr r0,test被编译成ldr

r0, [pc, #8],即到当前PC+8的存储器取值,运行第一条指令时,PC其实已经是8了(流水线决定的)。

那么8+8等于0x10,所以r0等于e1a00000,此指令的作用就是读取test地址处存放的值。由于此处放了一条nop,即得到nop的机器码。

2、第二条adr r0,test被编译成add r0, pc, #4

这显然是依赖程序执行到此处的PC值ADR是小范围地址读取伪指令,会将基于PC 相对偏移的地址值读取到寄存器中,此指令在4地址,PC是4+8=0xc再加4,于是r0=0x10。

从结果上来看,test自身的值(标号值),被读到了r0,这个值是以PC为参考的,也就是test对应的指令(第二个nop)当前的地址。r0=(标号test的地址与此指令的距离差)+(此指令的地址)=((0x10-0x4=12)+(4))=16=0x10。

假如在0x30000000以上运行,r0=((12)+(0x30000004))= 0x30000010。

3、ldr r0,=test被编译成两个字,一个指令,一个文字池

执行到这里PC=8, 8+8+4=0x14,所以在14地址取值,编译器在14地址处放了0x00000010,0x00000010是test的值,假如在Makefile指定连接地址是0x30000000,那么编译器放在这里的就是0x30000010,可见,这个值是编译时确定的。

最后一行andeq r0, r0, r0, lsl r0大概是编译器的机械动作,把一个数字翻译成了指令。

总结

ADR是小范围的地址读取伪指令,它将基于PC 相对偏移的地址值读取到寄存器中。而ldr获取的是内存的值,像指针一样间接寻址。

历经一年的磨砺与锤炼,韦东山及其团队为您带来最新Linux ARM裸机1期加强版。

相比与去年原版ARM裸机课程,本期课程以1主线、2辅线展开讲解。以ARM裸板为主线,硬件知识、C语言为辅线。学习过程中,更加加深硬件知识与C语言的锻炼,完全不用担心零基础学不会!

只有C语言基础?没有关系!

ARM裸机课程会从最基本的Linux操作、硬件知识、汇编知识等内容讲解,课程目录科学详尽,只要您按照视频顺序依次学习即可。

为了给学员们加深课程所学知识巩固与实践,我们开辟了学员专属qq群+学院直播答疑,并在每期学习后布置练习作业,让您对自己目前的学习状态、学习效果了如指掌,课程疑问与问题得到讲师及时有效的回馈!

【学嵌入式的你是否也有以下困扰?】

1. 不会Linux命令,不懂单片机、硬件,怎么学习嵌入式?

2. 老师教的单片机简单没竞争力,要多熟练单片机才能学嵌入式?

3. 苦寻完整例程、系统的ARM裸机课程未果

4. 会移植就行了?还是要根据寄存器描述从0写出来?

5. 如何快速掌握陌生外设模块?

ARM裸机1期加强版】将以上问题一扫而光!

【学习本课程,你能GET哪些技能?】

1. 深入理解ARM裸板程序原理,通吃所有单片机开发:ARM Linux入门,使用keil、MDK轻而易举。

2. 掌握基本硬件知识。

3. 能看懂原理图、芯片手册。

5. 理解各种硬件协议(i2c, spi, lcd等)。

6. 掌握编写程序操作硬件的方法。

7. 实战编程操练玩转触摸屏和传感器等各个模块。

【特色——完全0基础】

1. 延续现场编码、调试的风格

2. 假设学员0基础:只懂C。讲解基本LINUX操作、硬件知识、汇编等。目录详细,0基础的人完全按照视频顺序学习,有基础的根据目录挑选感兴趣的章节

3. 以1条主线、2条辅线来讲解:ARM裸板为主线,硬件知识、C为辅线。

学习过程中加深硬件知识和C的煅炼,不用担心0基础学不会。

【适合人群】

1.会简单C语言,没有单片机基础、硬件知识,想成为嵌入式工程师的

2.有Windows单片机开发经验,想深入理解内部机制的

3.想提升职业能力的单片机工程师;

4.想转行从事软件开发的硬件工程师;

5.想学习嵌入式Linux驱动的。

现在就加入韦东山ARM裸机1期实战课程吧!

立即报名【ARM裸机1期加强版】课程!

返回搜狐,查看更多

责任编辑:

声明:该文观点仅代表作者本人,搜狐号系信息发布平台,搜狐仅提供信息存储空间服务。
阅读 ()
投诉
免费获取
今日搜狐热点
今日推荐