ARM-v7 程序计数器PC的相关指令与应用

1. 前言

        如图1所示,R14是连接寄存器(Link Register),在汇编指令中通常也写为LR,用于存储函数调用和异常等的返回信息,复位时,默认值为0xFFFFFFFF;

图1 Core register 

        R15是程序计数器(PC,Program Counter),复位后初始值为Vector Table(中断向量表)的首地址加上0x04(Reset向量),其bit[0的值为必须1,并会加载到EPSR(Execution Program Status Register)的T字段(Thumb state bit),表示处于Thumb状态。ARM-v7只支持在Thumb下执行指令,在T字段为0的情况下,执行任何指令都将导致错误或锁定。

        如下所示,向量表的首地址存放的是MSP的初始地址,偏移四字节后即是Reset_Handler,也就是说代码复位后是从Reset_Handler开始运行的。

       const pFunc __VECTOR_TABLE[256] __VECTOR_TABLE_ATTRIBUTE = {(pFunc)(&__INITIAL_SP),                   /*     Initial Stack Pointer */Reset_Handler,                            /*     Reset Handler */NMI_Handler,                              /* -14 NMI Handler */HardFault_Handler,                        /* -13 Hard Fault Handler */MemManage_Handler,                        /* -12 MPU Fault Handler */BusFault_Handler,                         /* -11 Bus Fault Handler */UsageFault_Handler,                       /* -10 Usage Fault Handler */0,                                        /*     Reserved */0,                                        /*     Reserved */0,                                        /*     Reserved */0,                                        /*     Reserved */SVC_Handler,                              /*  -5 SVCall Handler */DebugMon_Handler,                         /*  -4 Debug Monitor Handler */0,                                        /*     Reserved */PendSV_Handler,                           /*  -2 PendSV Handler */SysTick_Handler,                          /*  -1 SysTick Handler *//* Interrupts */Interrupt0_Handler,                       /*   0 Interrupt 0 */Interrupt1_Handler,                       /*   1 Interrupt 1 */Interrupt2_Handler,                       /*   2 Interrupt 2 */Interrupt3_Handler,                       /*   3 Interrupt 3 */Interrupt4_Handler,                       /*   4 Interrupt 4 */Interrupt5_Handler,                       /*   5 Interrupt 5 */Interrupt6_Handler,                       /*   6 Interrupt 6 */Interrupt7_Handler,                       /*   7 Interrupt 7 */Interrupt8_Handler,                       /*   8 Interrupt 8 */Interrupt9_Handler                        /*   9 Interrupt 9 *//* Interrupts 10 .. 255 are left out */
};

        对于PC来说,其相关的表达式或标签(label)指示着一条指令或数据的地址(目标位置),如果PC当前位置到目标位置的偏移量大的过分,编译器会报错。由于ARM-v7采用了指令流水线技术,所以读PC的返回值是当前指令地址+4,且返回值的LSB为0(Thumb指令至少半字对齐),例如:

0x1000: MOV R0, PC ; R0 = 0x1004

        具体来说:

        ①对于B、BL、CBNZ和CBZ指令,PC的值是当前指令地址加上4字节; 

        ②对于其他使用label的指令来说,PC的值是当前指令地址加上4字节,且指令执行后PC的值的bit[1]会被强制清零,以保证其值按字长(word)对齐。       

        此外,向PC中写数据,就会引起一次程序分支(不更新LR寄存器),但无论是直接写PC还是使用分支转移指令,都必须保证加载到PC的值的LSB为1,即bit[0]为1,用以表明是在Thumb状态下执行;

2.相关汇编指令

2.1 PUSH/POP

        PUSH和POP指令适用于寄存器的压栈和出栈,且必须是满减栈(full descending stack):

表1 PUSH/POP指令
PUSH <condition>  {reglist}reglist中不可包含PC(独一无二的PC不允许有影子的存在,说一不二)
POP <condition>  {reglist}reglist中不可同时包含PC和LR(既生瑜何生亮)

        其中:

        ①conditon为条件码,可选;

        ②reglist为非空寄存器列表,列表元素可以是寄存器或寄存器子列表(range,如"R0-R2"表示R0,R1,R2),如果包含多个寄存器或寄存器子列表,则以逗号分隔;

        ③reglist不可包含SP(医者不能自医啊);       

        ④当 reglist中存在PC时,则在POP指令完成时就会跳转到PC所对应的地址执行(该地址必须半字对齐);同时,PC对应出栈值的bit[0]会用来更新APSR的T字段(T-bit),且该bit的值必须为1,以指示Thumb状态;此外,如果该POP指令带有条件码,则必须是IT指令块的最后一条指令。

        通常来说,PUSH和POP会成对使用,且 在PUSH和POP的过程中,SP的值会按堆栈的使用规则自动调整。例如,如满减栈情况下,PUSH的同时SP自减,POP的同时SP递增;

        注意:在寄存器列表中,不管寄存器序列如何,汇编器都将把它们升序排序,优先 PUSH序号大的寄存器,优先 POP序号小的寄存器,例如:

PUSH {R0,R4-R7} ; Push R0,R4,R5,R6,R7 onto the stack
PUSH {R2,LR}    ; Push R2 and the link-register onto the stack
POP {R0,R6,PC}  ; Pop r0,r6 and PC from the stack, then branch to the new PC.

         这样就意味着,R0最后入栈,最先出栈,这应该也利于R0的频繁使用吧。

        值得一提的是,STMDB和LDMIA在以R13(SP)为目的寄存器时,可以达到与PUSH/POP相同的效果:

STMDB SP!, {R0-R3, LR} ;等效于 PUSH {R0-R3, LR}
LDMIA SP!, {R0-R3, PC} ;等效于 PUSH {R0-R3, PC}

 2.2 分支(branch)指令

表2 分支指令(branch instrctions)
指令跳转范围说明
B label-16MB ~ +16MB立即跳转(通过立即数或表达式)
B<cond> lable (IT指令块外)-1MB ~ +1MB立即跳转
B<cond> lable (IT指令块内)-16MB ~ +16MB立即跳转
BL{cond} label-16MB ~ +16MB立即跳转,同时将返回地址存储到LR
BX{cond} RmRm中的任意值通过寄存器间接跳转
BLX{cond} RmRm中的任意值通过寄存器间接跳转,同时将返回地址存储到LR

        其中: 

        ①由于PC的值为当前指令地址+4,着也就意味着向前跳转的范围多了4个字节;

        ②label是一个PC相关的表达式,表示要跳转到的地址;

        ③ BX 和 BLX中,Rm寄存器的值为跳转的目的地址,bit[0]指示跳转后CPU要进入的状态,且如前文所述,该值的bit[0]必须为1,生成地址时会忽略该bit(置0),如果BL和BLX指令中Rm的bit[0]不为1,则会产生一个用法错误异常(UsageFault exception);

        ④BL和BLX指令会将当前下一条指令的地址存储到LR中,以提供返回信息;

        ⑤B<cond> lable是唯一在IT指令块内外都可以使用的条件分支指令,对于其余的分支指令,在IT指令块内部必须是带条件的(IT指令块内部的指令都是条件指令),在IT指令块外则必须是无条件的;

        ⑥在IT指令块内部使用分支指令时,则该分支指令必须时IT指令块的最后一条指令;

        ⑦BLX指令中不可使用PC;

        ⑧使用 .W后缀可以拓展分支跳转范围;

3.通过PC控制程序执行

3.1通过 MOV指令

MOV PC, Rn ; branch to the address indicated in Rn

         当使用MOV指令将Rn中存储的值赋给PC时,该值的bit[0]将会被忽略,并跳转到Rn给出的地址中。此外,使用MOV指令对PC进行赋值时,MOV后不可使用S条件后缀,且Rn必须是一个没有移位的寄存器。虽然MOV指令可实现分支跳转,但BX或BLX指令更专业,移植性也更好。

3.2 通过分支指令       

B loopA     ; Branch to loopA
BLE ng      ; Conditionally branch to label ng
B.W target  ; Branch to target within 16MB range
BEQ target  ; Conditionally branch to target
BEQ.W target; Conditionally branch to target within 1MB
BL funC     ; Branch with link (Call) to function funC, return address stored in LR
BX LR       ; Return from function call
BXNE R0     ; Conditionally branch to address stored in R0
BLX R0      ; Branch with link and exchange (Call) to a address stored in R0.

3.3 通过LDR指令        

LDR PC, [Rn] ;转移地址存储在 Rn 所指向的存储器中

3.4 通过POP指令

        既然LR在子程序调用过程中的唯一用处就是存储返回地址,那就直接绕过LR,将返回地址传给PC,返回子程序调用处,例如:

push {r0-r3, lr}    ;子程序入口
pop  {r0-r3, pc}    ;子程序出口

4. PC跳转的应用

 4.1 程序加载后跳转到resetHandler

       /**************************************************************************************************Local Functions**************************************************************************************************/uint32 resetHandlerAddr;void Device_Deinit(void);status_t bootUpCurrentCore(uint32_t entryPoint){/* entryPoint为中断向量表(vectortable)的首地址, vectortable[1]的地址为resetHandlerAddr */resetHandlerAddr =*((uint32_t*)entryPoint+1);         Device_Deinit();S32_SysTick->CSRr = S32_SysTick_CSR_ENABLE(0u);__asm("ldr r0, =resetHandlerAddr");        __asm("ldr r1, [r0]");  /* r1 = *resetHandlerAddr; 即r1 = resetHandler */__asm("mov pc, r1");    /* pc = resetHandler, 即跳转到resetHandler函数 */return STATUS_SUCCESS;}

4.2 Reset_Handler函数完成系统初始化

/*----------------------------------------------------------------------------Reset Handler called on controller reset
*----------------------------------------------------------------------------*/
void __attribute__((naked,__noreturn__)) Reset_Handler(void)
{__EARLY_INIT();/* Stack pointer initialisation */__set_CONTROL(0);                       /* MSP with privilege mode*/__set_PSP(0);__set_BASEPRI(0);__set_MSP((uint32_t)&__INITIAL_SP);SystemInit();                             /* CMSIS System Initialization */__PROGRAM_START();                        /* Enter PreMain (C library entry point) */
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/734118.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vscode 配置 c 语言 问题解决

1.VS code调试时显示Unable to start debugging.The value of miDebuggerPath is invalid。 解决方法: VS code调试时显示Unable to start debugging.The value of miDebuggerPath is invalid_unable to start debugging. the value of midebugger-CSDN博客 2.VSCode运行C终端…

提示词工程技术:类比、后退、动态少样本、自动生成CoT

类比提示 “类比提示”利用类比推理的概念&#xff0c;鼓励模型生成自己的例子和知识&#xff0c;从而实现更灵活和高效的解决问题。 后退提示 “后退提示”专注于抽象&#xff0c;引导模型推导出高级概念和原理&#xff0c;进而提高其推理能力。 使用一个基本的数学问题来…

isdigit 是 Python 中字符串对象的一个方法,用于检查字符串中的所有字符是否都是数字。

如果字符串中的所有字符都是数字&#xff0c;则返回 True&#xff0c;否则返回 False。这个方法只能用于检查整数&#xff0c;并且它只能识别 0-9 的数字字符。 这里有一个使用 isdigit 方法的例子&#xff1a; s "12345" if s.isdigit(): print("字符串只包…

npm下载时下载失败解决方法

1.清楚缓存 npm cache clean --force2.切换下载镜像 1.查看当前使用的镜像地址命令 npm config get registry切换为淘宝镜像命令&#xff08;安装一些package容易报错&#xff09; npm config set registry https://registry.npm.taobao.org或官方&#xff1a; npm config…

分类算法(Classification algorithms)

逻辑回归(logical regression&#xff09;&#xff1a; 逻辑回归这个名字听上去好像应该是回归算法的&#xff0c;但其实这个名字只是在历史上取名有点区别&#xff0c;但实际上它是一个完全属于是分类算法的。 我们为什么要学习它呢&#xff1f;在用我们的线性回归时会遇到一…

读书·基于RISC-V和FPGA的嵌入式系统设计·第3章

72.8051单片机的弊端和指令集架构CISC的缺点 76.RV指令集的特征&#xff08;⭐&#xff09; 特权架构和特权指令集是相关但不完全相同的概念。 特权架构&#xff08;Privileged Architecture&#xff09;指的是计算机体系结构中用于实现特权级操作的硬件和软件机制。特权架构定…

RabbitMQ——死信队列

RabbitMQ——死信队列 死信队列&#xff08;Dead Letter Queue&#xff0c;DLQ&#xff09;是 RabbitMQ 中的一种重要特性&#xff0c;用于处理无法被消费的消息&#xff0c;防止消息丢失。 死信的来源 在消息队列中&#xff0c;当消息满足一定条件而无法被正常消费时&#xf…

电商运营常用名词解释

电商运营中的基础名词解释 GMV∶成交总额&#xff0c;含拍下未支付订单金额 ROl:投入产出比&#xff0c;ROl交易额/花费&#xff0c;投入产出比越高越好 uV︰独立访客&#xff0c;统计1天内访问某站点的用户数 PV:访问量&#xff0c;即页面浏览量或点击量。一个顾客浏览了两次…

前端框架的发展历史介绍

前端框架的发展历史是Web技术进步的一个重要方面。从最初的简单HTML页面到现在的复杂单页应用程序&#xff08;SPA&#xff09;&#xff0c;前端框架和库的发展极大地推动了Web应用程序的构建方式。以下是一些关键的前端框架和库&#xff0c;以及它们的发布年份、创建者和主要特…

java-ssm-jsp的问卷调查系统的设计与实现

java-ssm-jsp的问卷调查系统的设计与实现 获取源码——》公主号&#xff1a;计算机专业毕设大全

抖音商家活动信息未在商详展示会有哪些处罚?

一、什么是「违规玩法-活动信息未在商详展示」? 什么是「违规玩法-活动信息未在商详展示」?由于当前平台未提供官方营销工具(例如免单、返现等)&#xff0c;但是创作者在进行商品推广(不仅限口播、画面、标题文案等)宣传该类营销玩法&#xff0c;未在商品商详页展示说明&…

第十五章垃圾回收相关算法

第十五章垃圾回收相关算法 文章目录 第十五章垃圾回收相关算法1. 垃圾标记阶段的算法之引用计数算法1.1 垃圾标记阶段&#xff1a;对象存货判断1.2 方式一&#xff1a;引用计数算法循环引用 1.3 小结 2. 垃圾标记阶段的算法之可达性分析算法2.1 方式二&#xff1a;可达性分析&a…

Qt 定时器事件

文章目录 1 定时器事件1.1 界面布局1.2 关联信号槽1.3 重写timerEvent1.4 实现槽函数 启动定时器 2 定时器类 项目完整的源代码 QT中使用定时器&#xff0c;有两种方式&#xff1a; 定时器类&#xff1a;QTimer定时器事件&#xff1a;QEvent::Timer&#xff0c;对应的子类是QTi…

sys内建模块

一、概述 sys 模块是 Python 标准库中的一个内置模块&#xff0c;提供了与 Python 解释器及其运行时环境交互的函数和变量。它允许你访问和操作与解释器状态相关的信息 1、需要导包 不会自动导入&#xff0c;需要显示的将sys模块导入 import sys 二、常用方法 1、sys.exit(…

Linux命令-cp命令(将源文件或目录复制到目标文件或目录中)

说明 cp命令 用来将一个或多个源文件或者目录复制到指定的目的文件或目录。它可以将单个源文件复制成一个指定文件名的具体的文件或一个已经存在的目录下。cp命令还支持同时复制多个文件&#xff0c;当一次复制多个文件时&#xff0c;目标文件参数必须是一个已经存在的目录&am…

HttpURLConnection详解及使用

HttpURLConnection 请求响应流程 设置连接参数的方法 setAllowUserInteractionsetDoInputsetDoOutputsetIfModifiedSincesetUseCachessetDefaultAllowUserInteractionsetDefaultUseCaches 发送URL请求 建立实际连接之后&#xff0c;就是发送请求&#xff0c;把请求参数传到…

docker-swarm集群搭建

目录 一、docker swarm介绍 二、部署docker 三、搭建集群 3.1 工作模式 3.2 将当前主机作为leader 3.3 将第二个节点slave1加入到worker 3.4 将第三个节点slave2也加入到worker 3.5 将第四个节点(slave3)加入到manager 四、总结 一、docker swarm介绍 Docker Swarm…

python图像处理,opencv笔记汇总

基本图像处理 翻转 使用python翻转图片 按比例缩放&#xff0c;拼接 【opencv】指定宽或高按比例缩放图片 & 拼接图片 待更新

java中{ }对变量可用scope的限制

改变变量定义位置可解决 y定义在{}内&#xff0c;属于局部变量&#xff0c;只能再在{}其中有效使用&#xff0c;因此第二个输出报错。 将int y6放在main()后&#xff0c;{}前可解决

Toyota Programming Contest 2024#3(AtCoder Beginner Contest 344)(A,B,C,D,E,F)

比赛链接 这场偏简单&#xff0c;C是暴力&#xff0c;D是变种背包&#xff0c;E是map链表&#xff0c;F是四维dp。DF出的很好&#xff0c;建议做。 A Spoiler 题意&#xff1a; 给你一个由小写英文字母和 | 组成的字符串 S S S。 S S S 中保证包含两个 |。 请删除两个|之间…