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

news2024/10/2 20:24:57

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.coloradmin.cn/o/1505184.html

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

相关文章

从 iPhone 设备恢复误删微信消息的 4 种方法

您的微信消息可能会因无意删除、系统崩溃、卸载微信应用或升级过程失败而被删除。如果您遇到这种情况&#xff0c;您不必担心&#xff0c;因为您可以采取某些步骤来恢复丢失的微信历史记录。这里有 4 种方法可以帮助您从 iPhone恢复丢失的微信消息、群聊历史记录或微信联系人。…

函数柯里化:JavaScript中的高级技巧

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【脚本玩漆黑的魅影】全自动刷努力值

文章目录 原理全部代码 原理 全自动练级&#xff0c;只不过把回城治疗改成吃红苹果。 吃一个可以打十下&#xff0c;背包留10个基本就练满了。 吃完会自动停止。 if img.getpixel(data_attack[0]) data_attack[1] or img.getpixel(data_attack_2[0]) data_attack_2[1]: # …

Solidity Uniswap V2 价格预言机

预言机是连接区块链与链下服务的桥梁&#xff0c;这样就可以从智能合约中查询现实世界的数据。Chainlink 是最大的oracle网络之一&#xff0c;创建于 2017 年&#xff0c;如今已成为许多 DeFi 应用的重要组成部分。https://github.com/XuHugo/solidityproject Uniswap 虽然是链…

matlab双目相机标定-需要什么参数、怎么获得

相机标定目的&#xff1a;获得相机内参、外参、畸变系数&#xff0c;摄像头的内参(f,1/dx,1/dy,cx,cy)、畸变参数(k1,k2,k3,p1,p1)和外参(R,t)&#xff0c;用于接下来的双目校正和深度图生成从而实现二维到三维的转换。 相机标定方法&#xff1a;opencv 双目相机标定以及立体…

Objects类 --java学习笔记

Objects类 Objects是一个工具类&#xff0c;提供了很多操作对象的静态方法给我们使用 Objects类常用的三个方法 Objects.equals 比直接equals更安全&#xff0c;因为Objects.equals里面做了非空校验 Objects.isNull&#xff08;A&#xff09; 等价于 A null Objects.non…

docker部署在线聊天室平台Fiora

Fiora 是一款开源免费的在线聊天系统 https://github.com/yinxin630/fiora 部署 创建docker网络 docker network create fiora-networkdocker-compose部署 vim docker-compose.yml version: 3 services:fiora_redis:image: rediscontainer_name: fiora_redisrestart: alway…

Springboot+vue的医院药品管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的医院药品管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09…

AWS的CISO:GenAI只是一个工具,不是万能钥匙

根据CrowdStrike的年度全球威胁报告,尽管研究人员预计人工智能将放大对防御者和攻击者的影响,但威胁参与者在其行动中使用人工智能的程度有限。该公司上个月在报告中表示:“在整个2023年,很少观察到GenAI支持恶意计算机网络运营的开发和/或执行。” 对于GenAI在网络安全中的…

关于天线综合3(傅里叶变换法)

傅里叶变换法 如果令fd(w)为期望方向图&#xff0c;那么对应的电流分布id(s)为 但是&#xff0c;通常它的范围是无穷大的&#xff0c;所以我们通过近似解来截断id(s)如下 根据傅里叶变化&#xff0c;电流就会产生一个近似方向图f(w)。扩展至整个s域的电流id(s)产生准确的方向图…

CentOS 7.6安装部署Seafile服务器

今天飞飞和你们分享CentOS 7.6上安装基于MySQL/MariaDB的Seafile服务器的方法&#xff0c;包括下载和安装7.0.5版本、配置数据库、启动服务器等步骤。安装成功后&#xff0c;需要通过nginx反向代理才能访问seafile服务。 通过预编译好的安装包来安装并运行基于 MySQL/MariaDB …

【网站项目】109网上手机商城

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

【NR 定位】3GPP NR Positioning 5G定位标准解读(七)- GNSS定位方法

前言 3GPP NR Positioning 5G定位标准&#xff1a;3GPP TS 38.305 V18 3GPP 标准网址&#xff1a;Directory Listing /ftp/ 【NR 定位】3GPP NR Positioning 5G定位标准解读&#xff08;一&#xff09;-CSDN博客 【NR 定位】3GPP NR Positioning 5G定位标准解读&#xff08;…

L2-2 老板的作息表(Python)

作者 陈越 单位 浙江大学 新浪微博上有人发了某老板的作息时间表&#xff0c;表示其每天 4:30 就起床了。但立刻有眼尖的网友问&#xff1a;这时间表不完整啊&#xff0c;早上九点到下午一点干啥了&#xff1f; 本题就请你编写程序&#xff0c;检查任意一张时间表&#xff0c…

excel中去除公式,仅保留值

1.单个单元格去除公式 双击单元格&#xff0c;按F9. 2.批量去除公式 选中列然后复制&#xff0c;选择性粘贴&#xff0c;选值粘贴

边缘计算平台EdgeGallery前端源码分析03-应用测试认证平台

1 首页 &#xff08;1&#xff09;Nav导航栏 代码路径 atp\atp-fe\src\components\layout\Nav.vue &#xff08;2&#xff09;Banner图片区域 代码路径 atp\atp-fe\src\pages\home\Home.vue 点击详情跳转到 测试用例管理 页面&#xff08;后面分析&#xff09; <div cl…

交易平台开发:构建安全/高效/用户友好的在线交易生态圈

在数字化浪潮的推动下&#xff0c;农产品现货大宗商品撮合交易平台已成为连接全球买家与卖家的核心枢纽。随着电子商务的飞速发展&#xff0c;一个安全、高效、用户友好的交易平台对于促进交易、提升用户体验和增加用户黏性至关重要。本文将深入探讨交易平台开发的关键要素&…

ARM中多寄存内存访问概念和栈的种类和应用

多寄存器内存访问指令 多寄存器内存访问指令 MOV R1,#1 MOV R2,#2 MOV R3,#3 MOV R4,#4 MOV R11,#0x40000020 STM R11,{R1-R4} 将R1-R4寄存器中的数据存储到内存以R11为起始地址的内存中 LDM R11,{R6-R9} 将内存中以R11为起始地址的数据读取到R6-R9寄存器中 当寄存器…

一劳永逸的方法解决:LNK1168无法打开 xxx.exe 进行写入 报错问题

这种错误的产生原因&#xff1a; 运行程序退出不是按正常流退出&#xff0c;是按窗口右上角的 “X” 来关闭程序&#xff0c;但是后台的xxx.exe控制台程序还在运行&#xff1b;修改程序的代码后再运行&#xff0c;就会报LNK1168的错误&#xff1b; 报错示例&#xff1a; 解决方…

第十七章垃圾回收器

第十七章垃圾回收器 文章目录 第十七章垃圾回收器1. GC分类与性能指标1.1 垃圾回收器概述1.2 垃圾回收器分类1.3 评估GC的性能指标吞吐量暂停时间吞吐量VS暂停时间 2. 不同的垃圾回收器概述七种经典垃圾回收器七种经典收集器与垃圾分代之间的关系垃圾收集器的组合关系如何查看默…