跳转指令
顺序、选择、循环是构建程序的基本结构,任何一个逻辑复杂的程序基本上都可以由这三种程序结构组合而成。而跳转指令,则在子程序调用、选择、循环程序结构中被大量使用。程序的跳转是如何实现的呢?在了解这个机制之前,我们需要先了解一下程序计数器PC。
程序计数器PC,是CPU的寄存器列表中最重要的一个寄存器。它就像一杆枪,指哪打哪:你给PC指针赋值哪个地址,CPU就会到PC指针指向的这个地址去取指令、翻译指令、执行指令。一般情况下,当你没有给PC指针赋新地址时,CPU在PC指针指向的地址取完指令后,PC计数器会自动加一,指向下一条指令,程序可以自动执行下去。当我们需要跳转时,可以直接给PC指针赋一个新地址,于是CPU就会跳转到新地址去执行了。
在ARM中,常见的跳转指令有B、BL、MOV、LDR等。不同的指令,它们的使用条件、使用场合是不同的,今天就给大家总结一下它们的区别及各自使用的场合。
1B跳转指令
B指令是ARM中最基本的跳转指令,它的使用方法如下:
B label
上面语句表示跳转到label的标号处去执行。B跳转指令是ARM中最简单的指令,只是单纯的跳转,而且是相对跳转。它可以跳到以当前位置PC为基址,前后32MB的地址空间范围,所以B指令只是在临近的代码块、标号之间跳转。
B指令跳转,大多数时候是单向的,跳过去就不再返回来了。但是我们可以通过添加一些标号来实现一些控制逻辑:比如循环、选择程序结构:
;循环结构示例
LOOP
SUB R0,R0,#1
...
CMP R0,#0
BNE LOOP
;选择结构示例
MOV R1,#10
MOV R2,#20
CMP R1,R2
BEQ HERE
...
B END
HERE
...
END
...
在上面的程序中,我们使用B跳转指令实现了选择、循环这两种基本的程序结构。B指令像ARM的其它指令一样,可以根据CPSR状态寄存器的标志位,有条件的执行。这样,可以减少指令数目、提高代码密度和运行效率。如BNE、BEQ就是当结果相等、不相等时的条件跳转。
当前程序状态寄存器:
各种各样的条件码:
2BL指令
BL指令跟B不同:在跳转之前,会先将当前指令的下一条指令地址保存到LR寄存器中,然后才跳转到标号执行。这样做的好处是:当我们想从标号地方返回时,可以直接将LR寄存器中的返回地址赋值给PC,程序就可以返回到原来的程序中继续执行了。
BL跳转指令一般用在子程序的调用中。无论是汇编语言子程序,还是C语言子程序,在跳转到子程序之前,都要将返回地址保存起来。当子程序执行完毕,将LR寄存器保存的返回地址,重新赋值给PC,处理器就可以返回到主程序继续执行了。
BEGIN
MOV R0,#SRC
MOV R1,#DST
MOV R2,#100
BL COPY
NOP
...
COPY
SUB R2,R2,#1
LDR R3,[R0],#1
STR R3,[R1],#1
CMP R2,#0
BNE COPY
MOV PC,LR
上面的汇编代码段,我们定义了一个汇编子程序COPY,实现了数据拷贝的功能。当我们使用BL指令调用这个子程序COPY时,CPU会首先将当前指令的下一条指令:NOP 的地址保存到LR寄存器中,然后才跳转到COPY子程序去执行。在COPY子程序中,处理完数据搬运后,通过
MOV PC,LR
这条语句,将保存在LR寄存器中的返回地址,重新赋值给PC,这样我们就可以返回到原来的程序中继续执行了。
在上面的汇编代码中,LR,即R14,连接寄存器,常用来存放程序的返回地址;PC,即R15,程序计数器,表示当前指令地址。LR和PC都是ARM汇编器为了方便程序员编程,预定义的一些宏。你在程序中使用这些助记符其实就是相当于操作R14和R15寄存器。除此之外,ARM中常用的助记符有:
- FP:栈帧基址寄存器,即R12
- SP:栈指针寄存器,即R13
- LR:链接寄存器,即R14
- PC:程序计数器,即R15
同样,在C语言调用子函数的过程中,在跳转子函数执行之前,CPU也会将当前指令的下一条指令地址保存到LR寄存器中,然后再跳转到子函数中执行。因为在子函数运行过程中,也有可能会用到ARM的一些寄存器,也有可能会调用其它的子函数,会覆盖掉保存在LR寄存器中的返回地址,所以,我们一般在运行子函数之前,会首先将LR寄存器压入子函数的栈帧,相当于将返回地址保存到了栈上。当子函数运行结束时,再通过出栈操作,将保存在栈中的返回地址弹出到PC指针中,这样程序就成功从子程序中返回了,直接返回到原来的函数中继续执行。
int main(void)
{
func();
printf("Hello!\\n");
return 0;
}
;对应的汇编代码
main
BL func
BL printf
func
PUSH LR
...
pop pc
;func子函数返回
3MOV指令
通过上面的学习,我们可以看到,无论是B指令、还是BL指令,都是相对寻址。其本质都是以当前指令地址PC为基址,然后加上一个[0,32M]的偏移,达到修改PC的目的。
除此之外,我们也可以直接给PC指针赋值,达到跳转的目的。如上面的 func 子程序返回,就是直接通过
MOV PC,LR
这条指令,将LR寄存器中的返回地址,直接赋值给PC,直返回到原来的主函数去执行。
MOV指令主要用来在寄存器之间传输数据,或者将一个立即数传送到寄存器。但是MOV指令有一个硬伤,就是传递的立即数只能是8位数,有大小的限制。这是为什么呢?很简单,ARM是RISC架构,在一个32位的ARM中,指令通常都是32位的。而一个指令中,通常要包括操作码+操作数,如下图:
一条指令,总共有32个bit空间,MOV这个操作码要占几位吧,Rd寄存器编码要占据几位吧,剩下的留给立即数的空间就不多了,所以这也就限定了MOV指令能传递的立即数的大小了。而一般的32位程序中,无论是变量还是函数,它们的地址一般都是32位的,如果使用MOV指令,将他们的地址传送到PC,使用下面的形式:
MOV PC,#0x30008000
你会发现,立即数#0X30008000这个地址就已经32位了,在加上MOV指令这个操作码,已经超过32位了,编译器是无法翻译这个指令的,所以说,当一个变量或函数地址为32位时,使用MOV指令给PC直接赋值,行不通,那怎么办呢?
4LDR伪指令
办法总是有的,比如,我们就可以通过伪指令LDR,直接将一个32位的立即数地址,传送到PC:
LDR PC,=0x30008000
LDR伪指令的功能和MOV一样,都可以将一个立即数传送到寄存器。唯一区别的就是,MOV指令只能传送8位的,而LDR可以传送一个32位的立即数或地址。
这里需要注意一下,立即数 0X30008000 的前面有一个等于号“=”,这表示前面的LDR指令是一个伪指令。除此之外,在ARM中,LDR还有另外一个意思,用来将内存中的数据加载到寄存器。我们知道,ARM是RISC架构,使用LDR/STR架构,不能直接修改内存中的数据。如果我们要修改内存中的一个变量,要首先使用LDR指令将内存中的变量加载到寄存器中,接着对寄存器进行操作,最后再使用STR指令将寄存器中的变量回写到内存中。所以,LDR可以看作是一个伪指令,也可以看做是普通的一个LDR指令,判定他们的区别就是看前面的等于号。
普通的LDR指令主要使用寄存器间接寻址,常用的使用方式如下:
LDR R0,[R1]
LDR R0,0x30008000
这里注意后面一句,是将地址0x30008000地址上的内容传动到寄存器R0,而不是直接将这个地址传送到R0,这里一定要注意其跟LDR伪指令的区别,这一点没有注意到,你在分析程序时就可能误入歧途了。
在《C语言嵌入式Linux高级编程》第二期中,我们已经探讨了CPU、指令集、伪指令的基本概念,这里就不赘述了。简单来说,伪指令并不是真正的ARM指令,并不属于ARM指令集中的标准指令。它只是编译器为了方便我们程序员开发程序,定义的一些助记符。在编译时,这些伪指令还是会使用指令集中的标准指令来实现。
比如上面的LDR伪指令,程序在编译时,看到这个伪指令,会使用ARM指令集中标准的指令实现。如果LDR伪指令中的立即数小于8位,它就会转换为MOV指令来实现:
LDR R0,=200
MOV R0,#200
如果LDR伪指令中,立即数大于8bit表示的数据范围,比如说是一个32位的立即数或地址,那就不能使用MOV指令来实现了,可以采用文字池的形式,先将这个地址常量单独存放在存储单元中,然后使用相对寻址,曲线救国,完成这个32位地址或立即数与寄存器之间的传输,这些细节在教程视频中都有讲到,就不再赘述了。
5小结
通过上面的学习,我们基本上理清了ARM系统中常见的几种跳转指令,以及它们的区别。只有彻底理解他们的底层机制及实现细节,才有可能在使用反汇编分析程序时,达到事半功倍的效果,从而大大提高我们的工作效率。否则,这些基本的细节和概念搞不清,将会永远成为你学习和工作上的障碍。
-
计数器
+关注
关注
32文章
2283浏览量
95852 -
程序结构
+关注
关注
1文章
7浏览量
6976 -
程序调用
+关注
关注
0文章
3浏览量
883
发布评论请先 登录
arm汇编跳转指令总结
ARM汇编语言跳转指令的特殊用法还有吗
arm汇编语言跳转指令有何特殊用法呢?
ARM嵌入式系统的中断服务例程跳转

硬件原理图学习笔记
这一个星期认真学习了硬件原理图的知识,做了一些笔记,方便以后查找。硬件原理图分为三类1.管脚类(gpio)和门电路类输入输出引脚,上拉电阻,三极管与门,或门,非门上拉电阻:正向标志作用,给悬空的引脚一个确定的状态三极管:反向三极管(gpio输出高电平,NP两端导通,被控制端导通,电压为0)->NPN正向三极管(gpio输出低电平,PN两端导通,被控制端导通,

TurMass™ vs LoRa:无线通讯模块的革命性突破
TurMass™凭借其高传输速率、强大并发能力、双向传输、超强抗干扰能力、超远传输距离、全国产技术、灵活组网方案以及便捷开发等八大优势,在无线通讯领域展现出强大的竞争力。

RZT2H CR52双核BOOT流程和例程代码分析
RZT2H是多核处理器,启动时,需要一个“主核”先启动,然后主核根据规则,加载和启动其他内核。本文以T2H内部的CR52双核为例,说明T2H多核启动流程。

干簧继电器在RF信号衰减中的应用与优势
在电子测试领域,RF(射频)评估是不可或缺的一部分。无论是研发阶段的性能测试,还是生产环节的质量检测,RF测试设备都扮演着关键角色。然而,要实现精准的RF评估,测试设备需要一种特殊的电路——衰减电路。这些电路的作用是调整RF信号的强度,以便测试设备能够准确地评估RF组件和RF电路的各个方面。衰减器的挑战衰减器的核心功能是校准RF信号的强度。为了实现这一点,衰

ElfBoard嵌入式教育科普|ADC接口全面解析
当代信息技术体系中,嵌入式系统接口作为数据交互的核心基础设施,构成了设备互联的神经中枢。基于标准化通信协议与接口规范的技术架构,实现了异构设备间的高效数据交换与智能化协同作业。本文选取模数转换接口ADC作为技术解析切入点,通过系统阐释其工作机理、性能特征及重要参数,为嵌入式学习者爱好者构建全维度接口技术认知框架。

深入理解C语言:C语言循环控制
在C语言编程中,循环结构是至关重要的,它可以让程序重复执行特定的代码块,从而提高编程效率。然而,为了避免程序进入无限循环,C语言提供了多种循环控制语句,如break、continue和goto,用于改变程序的执行流程,使代码更加灵活和可控。本文将详细介绍这些语句的作用及其应用场景,并通过示例代码进行说明。Part.1break语句C语言中break语句有两种

第 21 届(顺德)家电电源与智能控制技术研讨会圆满落幕--其利天下斩获颇丰
2025年4月25日,其利天下应大比特之邀出席第21届(顺德)家电电源与智能控制技术研讨会,已圆满落幕。一、演讲回顾我司研发总监冯建武先生在研讨会上发表了主题为《重新定义风扇驱动:一套算法兼容百种电机的有效磁链观测器方案》的演讲,介绍了我司研发自适应技术算法(简称),该方案搭载有效磁链观测器,适配百种电机类型,结合FOC算法可实现免调参稳定启动、低速静音控制

来自资深工程师对ELF 2开发板的产品测评
来自资深工程师对ELF 2开发板的使用测评

飞凌嵌入式2025嵌入式及边缘AI技术论坛圆满结束
飞凌嵌入式「2025嵌入式及边缘AI技术论坛」在深圳深铁皇冠假日酒店盛大举行,此次活动邀请到了200余位嵌入式技术领域的技术专家、企业代表和工程师用户,共享嵌入式及边缘AI技术的盛宴!

常用运放电路总结记录
一、电压跟随器电压跟随器,电路图如下:电路分析:(本文所有的运放电路分析,V+表示运放同向输入端的电压,V-表示反向输入端的电压。)1.1电压跟随器反馈电阻需不需要?在上面的电压跟随器示例中,我画上了一个反馈电阻R99,大家在学习的运放的时候,可能很多地方也会提一下这个反馈电阻,很多地方会说可加可不加,效果一样。电阻需不需要加:但是本文这里个人建议使用电压跟

运放-运算放大器经典应用电路大全-应用电路大全-20种经典电路
20种运放典型电路总结,电路图+公式1、运放的符号表示2、集成运算放大器的技术指标(1)开环差模电压放大倍数(开环增益)大Ao(Ad)=Vo/(V±V-)=107-1012倍;(2)共模抑制比高KCMRR=100db以上;(3)输入电阻大ri>1MW,有的可达100MW以上;(4)输出电阻小ro=几W-几十W3、集成运放分析方法(V+=V-虚短,ib-=ib

RDK X3新玩法:超沉浸下棋机器人开发日记
一、项目介绍产品中文名:超沉浸式智能移动下棋机器人产品英文名:Hackathon-TTT产品概念:本项目研发的下棋机器人,是一款能自主移动、具备语音交互并能和玩家在真实的棋盘上进行“人机博弈”的移动下棋平台,能够带给对弈者如同真人对弈的完美沉浸式体验——棋开得胜团队。该智能下棋机器人具备3个显著优点:真实棋盘棋子对弈:通过使用真实棋子、棋盘和机械臂,给对弈者

芯对话 | 微处理器监控电路革新:CBM70X系列 重构系统可靠性
总述在工业自动化、消费电子、汽车电子等领域,微处理器作为系统核心,其稳定运行依赖可靠的电源监控。据统计,65%的系统故障源于电源异常——工业控制设备因电压波动导致的停机频率每月平均达3.2次,便携式设备因电池管理不当造成的续航缩水普遍超过25%,汽车电子ECU因电源扰动引发的误判率在复杂工况下高达18%。传统监控方案的三大核心痛点极端电压适应性不足:当电压低

喜讯!米尔电子与安路科技达成IDH生态战略合作,共筑FPGA创新生态
以芯为基,智创未来。近日,领先的嵌入式模组厂商-米尔电子正式与国产FPGA企业安路科技达成IDH生态战略合作。双方将围绕安路科技飞龙SALDRAGON系列高性能FPSoC,联合开发核心板、开发板及行业解决方案,助力开发者开发成功,加速工业控制、边缘智能、汽车电子等领域的创新应用落地。米尔电子&安路科技IDH生态合作证书硬核技术+生态协同安路科技作为

FOC控制算法详解
一、基本概念:FOC(field-orientedcontrol)为磁场导向控制,又称为矢量控制(vectorcontrol),是一种利用变频器(VFD)控制三相电机的技术,利用调整变频器的输出频率、输出电压的大小及角度,来控制电机的输出。由于处理时会将三相输出电流及电压以矢量来表示,因此称为矢量控制。二、控制原理:FOC控制的其实是电机的电磁场方向。转子的
评论