第2章第3节 ARM7芯片的函数调用标…

ARM芯片、内核、架构、指令集的联系与区别 问题1:单片机和CPU的区别在嵌入式领域ARM芯片和CPU有什么区别呢?其实随着嵌入式科技的不断发展,单片机(像ARM芯片)和CPU的界限越来越模糊,我们暂且可以认为ARM芯片就是一个CPU,或者暂且认为单片机就相当于一个CPU。问题2:什么是ARM芯片凡是采用ARM内核的芯片(或者凡是采用ARM内核的CPU)都是ARM芯片。例如高通的OMAP36X0系列处理器(Droid 2和Droid X用的... 阅读详情

源码请在https://github.com/ifreecoding/MbedRtos.git下载

第3节 ARM7芯片的函数调用标准

在上节,我们最后用汇编语言写了一个函数,但该函数没有入口参数,那么C语言函数、汇编函数之间是如何传递参数和返回值的?函数在执行过程中是如何使用栈的?它们需要遵守什么规则?本节我们将介绍这方面的内容。

如果我们不是在编写操作系统,只是编写正常的C函数,那么我们是不需要关心函数调用的细节,编译器会遵守一定的函数调用规则编译成二进制代码,当所有不同类型的编译器都遵守这个相同的规则时,各种编译器编译出来的程序就可以互相配合运行了。这个规则就是AAPCS——Procedure Call Standard for the ARM Architecture,即附录中的参考文档3。如今,我们编写操作系统需要改变C函数标准的运行方式,但我们仍必须遵守这个规则,这样才能与编译器编译出来的代码配合使用。

AAPCS对ARM结构的一些标准做了定义,在这里我们只重点介绍函数调用部分,如图9所示,AAPCS为ARM的R0~R15寄存器做了定义,明确了它们在函数中的职责:

图 9  AAPCS关于ARM寄存器的定义

函数调用时的规则如下:

1. 父函数与子函数间的入口参数依次通过R0~R3这4个寄存器传递。父函数在调用子函数前先将参数存入到R0~R3中,若只有一个参数则使用R0传递,2个则使用R0和R1传递,依次类推,当超过4个参数时,其它参数通过栈传递。当子函数运行时,根据自身参数个数自动从R0~R3或者栈中读取参数。

2. 子函数通过R0寄存器将返回值传递给父函数。子函数返回时,将返回值存入R0,当返回到父函数时,父函数读取R0获得返回值。

3. 发生函数调用时,R0~R3是传递参数的寄存器,即使是父函数没有参数需要传递,子函数也可以任意更改R0~R3寄存器,无需考虑会破坏它们在父函数中保存的数值,返回父函数前无需恢复其值。AAPCS规定,发生函数调用前,由父函数将R0~R3中有用的数据压栈,然后才能调用子函数,以防止父函数R0~R3中的有用数据被子函数破坏。

4. R4~R11为普通的通用寄存器,若子函数需要使用这些寄存器,则需要将这些寄存器先压栈然后再使用,以免破坏了这些寄存器中保存的父函数的数值,子函数返回父函数前需要先出栈恢复其数值,然后再返回父函数。AAPCS规定,发生函数调用时,父函数无需对这些寄存器进行压栈处理,若子函数需要使用这些寄存器,则由子函数负责压栈,以防止父函数R4~R11中的数据被破坏。

5. 编译器在编译时就确定了函数间的调用关系,它会使函数间的调用遵守3、4条规定。但编译器无法预知中断函数的调用,被中断的函数无法提前对R0~R3进行压栈处理,因此需要在中断函数里对它所使用的R0~R11压栈。对于中断函数,不遵守第3条规定,遵守第5条规定。

6. R12寄存器在某些版本的编译器下另有它用,用户程序不能使用,因此我们在编写汇编函数时也必须对它进行压栈处理,确保它的数值不能被破坏。

7. R13寄存器是堆栈寄存器(SP),用来保存堆栈的当前指针。

8. R14寄存器是链接寄存器(LR),用来保存函数的返回地址。

9. R15寄存器是程序寄存器(PC),指向程序当前的地址。

上述只介绍了本手册中使用到的情形,具体的情况在编写操作系统代码时会涉及到,其它规则请请读者自行查找资料。

接下来我们再通过几个小例子熟悉一下C函数与汇编函数的调用过程。下面的C函数TestFunc1与汇编函数TestFunc2的功能是一样的。

U8 TestFunc1(void)

{

    U8 ucPara1;

    U8 ucPara2;

    U8 ucPara3;

    U8 ucPara4;

    U8 ucPara5;

    U8 ucPara6;

    ucPara1 = 1;

    ucPara2 = 2;

    ucPara3 = 3;

    ucPara4 = 4;

    ucPara5 = 5;

    ucPara6 = 6;

    return ucPara1 + ucPara2 + ucPara3 + ucPara4 + ucPara5 + ucPara6;

}

    .func TestFunc2

TestFunc2:

    STMDB R13!, {R5 - R6, R10}    @R5,R6,R10寄存器压栈

    LDR R1, =1

    LDR R3, =2

    LDR R4, =3

    LDR R5, =4

    LDR R6, =5

    LDR R10, =6

    ADD R0, R1, R3

    ADD R0, R0, R4

    ADD R0, R0, R5

    ADD R0, R0, R6

    ADD R0, R0, R10

    LDMIA R13!, {R5 - R6, R10}    @R5,R6,R10寄存器出栈

    .endfunc

TestFunc2函数使用了R0、R1、R3、R4、R5、R6、R10共7个寄存器,遵循AAPCS规则,在使用R0、R1和R3之前并没有对它们压栈,但对R5、R6和R10寄存器进行了压栈保存,在函数返回前又出栈还原了这3个寄存器,这样TestFunc2函数返回到它的父函数之后,R5、R6和R10寄存器的数值是没有改变的,而R0、R1、R3和R4则分别被改写为了21、1、2和3。

下面我们再来看看C函数TestFunc3调用汇编函数TestFunc4完成1+2的运算。

U8 TestFunc3(void)

{

    return TestFunc4 (1, 2);

}

    .func TestFunc4

TestFunc4:

    ADD R0, R0, R1

    BX R14;

    .endfunc

TestFunc3函数在调用TestFunc4函数前已经将参数1和2分别存入R0和R1,并将返回地址存入到R14中,然后才跳转到TestFunc4函数,发生函数调用。这时程序将运行TestFunc4函数,它将R0和R1相加,将结果放入R0,需要通过R0将返回值返回给TestFunc3函数。此时R14中保存的就是返回TestFunc3函数的返回地址,最后TestFunc4函数跳转到R14就返回到了TestFunc3函数,TestFunc3函数从R0就可以取出TestFunc4函数计算的结果了。

下面我们再来看看汇编函数TestFunc5调用C函数TestFunc6完成1+2的运算。

    .func TestFunc5

TestFunc5:

    MOV R0, #1

    MOV R1, #2

    SUB R13, R13, #4

    STR R14, [R13]

    BL TestFunc6

    LDR R14, [R13]

    ADD R13, R13, #4

    BX R14

    .endfunc

U8 TestFunc6(U8 ucPara1, U8 ucpara2)

{

    return ucPara1 + ucPara2;

}

TestFunc5函数先将参数1和2存入R0和R1寄存器,准备调用TestFunc6函数并传递入口参数,然后将R14寄存器压栈,以防止使用BL指令时存入的R14返回地址破坏R14原有的数据,然后调用TestFunc6函数。在调用TestFunc6函数时BL指令会自动将“LDR R14, [R13]”这条指令的地址存入R14,这样就开始运行TestFunc6函数了。TestFunc6函数会自动从R0和R1寄存器中取出参数,将计算结果存入R0,通过R0将返回值返回给TestFunc5函数。TestFunc6函数跳转回TestFunc5函数后,TestFunc5函数从栈中恢复原有的R14寄存器,完成函数调用,此时R0中的数值就是TestFunc6函数的计算结果。

当函数比较简单,不需要压栈仅使用寄存器便可以完成运算的时候,那么下面的TestFunc7函数,它的返回值是多少?

U8* TestFunc7(void)

{

    U8 ucPara1;

    ucPara1 = 1;

    return &ucPara1;

}

按照上面的分析,对于这个简单的函数,编译器是不会为局部变量ucPara1分配内存空间的,ucPara1只会保存在寄存器中,因此无从谈起它的地址。但这个这么简单的函数却偏偏要获取这个仅在寄存器中的局部变量的地址,遇到这种情况,编译器在编译时会特别为ucPara1专门在栈中分配内存,因此也就可以获取到它的地址了。

当然,这个函数没有任何意义,仅是举一个例子,而且写C语言时要避免发生这种情况,因为TestFunc7函数返回的是栈内局部变量的地址,当TestFunc7函数运行完后,ucPara1这个局部变量所在的栈空间已经被释放,这个栈空间很可能已经被其它变量占用,如果这时候还使用这个地址的话就可能会导致系统崩溃,新手要避免产生这个错误。

5款国产ARM芯片(对标stm32f103c8t6)测试评估 此文转载自:https://blog.youkuaiyun.com/weixin_41565556/article/details/112515813#commentBox 5款国产ARM-Cortex3芯片(对标stm32f103c8t6)兼容性测试评估 前言: ​ 国产arm芯片近年来不断的开疆拓土,建功立业。然而,随着大变局时代的开启,美国对中国科技的打压,对中国芯片的锁脖,ST芯片... 阅读详情

相关推荐

ARM和STM32的区别

STM32与通常ARM的区别经常有人问到STM32和ARM以及ARM7是什么关系这样的问题,其实ARM是一个做芯片标准的公司,它负责的是芯片内核的架构设计,而TI,ST这样的公司,他们并不做标准,他们是芯片公司,他们是根据ARM公司提供的芯片内核标准设计自己的芯片。所以,任何一个做Cortex-M3芯片,他们的内核结构都是一样的,不同的是他们的存储器容量,片上外设,IO 以及其他模块的区别。既然大...

qq_34385566的博客 2万+

SCP-Firmware 核心代码

核心处理 scp-firmware/framework/src/fwk_thread.c noreturn void __fwk_thread_run(void) { for (;;) { while (!fwk_list_is_empty(&ctx.event_queue)) process_next_event(); process_isr(); fwk_log_unbuffer(); } } scp-f

weixin_36406973的博客 2021

ARM 架构、ARM7、ARM9、STM32、Cortex M3 M4 、51、AVR 有啥区别

ARM架构、ARM7、ARM9、STM32、Cortex M3 M4、51、AVR之间有什么区别和联系?ARM架构:由英国ARM公司设计的一系列32位的RISC微处理器架构总称,现有ARMv1~ARMv8种类。ARM7:一类采用ARMv3或ARMv4架构的,使用冯诺依曼结构的内核。ARM9:一类采用ARMv4或ARMv5架构的,使用哈佛结构的内核。Cortex M3:采用了ARMv7架构的,使用哈佛结构的内核。Cortex M4:采用了ARMv7架构的,使用哈佛结构的内核。(较前者最大区:别增加了一个DSP

专注单片机实战教学,分享单片机学习资料 7895

代码 or 指令,浅析ARM架构下的函数的调用过程

摘要:linux程序运行的状态以及如何推导调用栈。 1、背景知识 1、ARM64寄存器介绍: 2、STP指令详解(ARMV8手册): 我们先看一下指令格式(64bit),以及指令对于寄存机执行结果的影响 类型1、STP <Xt1>, <Xt2>, [<Xn|SP>],#<imm> 将Xt1和Xt2存入Xn|SP对应的地址内存中,然后,将Xn|SP的地址变更为Xn|SP + imm偏移量的新地址 类型2、STP <Xt1>.

华为云官方博客 3413

Cortex-M3与ARM7优势比较

Cortex-M3与ARM7优势比较 要使用低成本的 32 位处理器,开发人员面临两种选择基于Cortex-M3 内核或者ARM7TDMI 内核的处理器。如何做出选择?选择标准又是什么? 这里的ARM7TDMI指的是   TDMI 的基本含义为:  T-支持16 位压缩指令集Thumb D-支持片上Debug M-内嵌硬件乘法器(Multiplier)   I-嵌入式ICE

qq_38779753的博客 7011

浅谈ARM架构芯片

ARM架构,曾称进阶精简指令集机器(Advanced RISC Machine)更早称作Acorn RISC Machine,是一个32位精简指令集(RISC)处理器架构。还有基于ARM设计的派生产品,重要产品包括Marvell的XScale架构和德州仪器的OMAP系列。 一、ARM的优势? 1.高性能、低功耗、低价格 把ARM处理器的性能拿来和一些着名的通用处理器(如Pentium)相比是不合适的,因为他们各自针对的应用需求是不同的。Pentium处理器采用多条指令流水线的超标量结构,追..

qq_50270150的博客 2891

ARM软件逆向工程入门 01 - ARM调用约定(Calling Convention)

在计算机科学中,调用约定(Calling Convention)是指一系列规则,用于定义函数调用时参数传递和返回值处理的方式。它规定了函数的参数如何传递给被调用函数,以及被调用函数如何将返回值传递给调用函数。不同的处理器架构通常有不同的调用约定。

weixin_46759000的博客 1330

ARM各版本架构区别,各架构的系列芯片。

先推荐一首歌《梦醒时分》——伍佰。简单说一下ARM架构,以及各芯片对应关系,起码以后茶话夜谈能插一嘴。

weixin_43920383的博客 5118

ARM汇编笔记(2)——函数调用规则

(本文所介绍的各个约定与32位arm Linux系统C语言toolchain一致) 1. 栈 栈保存着函数调用中的参数,寄存器上下文,局部变量。ARM中函数返回地址是寄存器上下文的一部分(lr),无需单列。 栈由高地址向低地址增长,也就是说push会导致栈顶指针指向较低的地址,而pop则相反。 同时约定了栈顶指针指向的是入栈的最后一个值的位置,而非下一个入栈位置。 2. 控制转移和寄存器...

sunty2016的博客 6692

【笔记】ARM架构和ARM芯片(一)

【笔记】ARM架构和ARM芯片(一)

skdhfdfc的博客 3027

ARM学习(17)ARM函数调用规则

ARM 函数调用规则

张一西的博客 2687

第2章第1节&nbsp;ARM7芯片基本结构

源码请在https://github.com/ifreecoding/MbedRtos.git下载 第1节ARM7芯片基本结构 ARM7芯片构架比较简单,32bits线性地址空间统一排列,任何地址都是唯一的,不同的片上资源及外设被分配到不同的地址空间,不同数据结构的指针固定为4字节长度,这相对51芯片来说方便很多也清晰很多,从用户编程的角度来看入手比较简单,因此本手册首先选用

ifreecoding的博客 900

[c语言]用辗转相除法求最大公约数,递归和不递归两种

在c语言的学习中必然会遇到求两个数之间的最大公约数的题目,那么对于其他经典方法,最简便快捷的方式就是利用辗转相除法 辗转相除法又叫做欧几里得算法,目的是为了求两个正整数的最大公约数 定理:gcd(a,b) = gcd(b ,a%b) //在这里用(a,b)表示a和b的最大公约数证明:a可以表示成a = kb + r,则r = a %b 假设d是a,b的一个公约数,则有 d|a, d|b,而r = a - kb,因此d|r //这里的"|"的意思是 :d是b的因数 ,d是a的因数 因此d...

ZZRBlogger的博客 1万+

第2章第2节&nbsp;ARM7汇编语言简介

源码请在https://github.com/ifreecoding/MbedRtos.git下载 第2节ARM7汇编语言简介 ARM7芯片有2种汇编语言指令集,一种叫做ARM指令集,字长为32bits,另一种叫THUMB指令集,字长为16bits。这两种指令集各有优缺点,它们可以单独使用也可以混合在一起使用,在ARM7芯片上,我们将只使用ARM指令集,在后续的Cortex芯片上

ifreecoding的博客 1834

微信小程序订阅消息实战:如何绕过长期订阅限制实现多次发送(附PHP代码)

本文针对微信小程序开发者无法获取长期订阅消息权限的痛点,提供了一套完整的实战解决方案。通过深入剖析一次性订阅与长期订阅的规则差异,结合巧妙的交互设计、稳健的PHP服务端发送引擎(含高并发处理与失败重试机制)以及授权池管理等高级策略,帮助开发者在合规前提下,构建高可用的消息推送系统,有效提升通知触达率与用户体验。

weixin_29008805的博客 620

深入解析Zynq Ultrascale+ RF Data Converter中的PLL配置与时钟管理

本文深入解析了Zynq Ultrascale+ RF Data Converter中PLL配置与时钟管理的核心原理与实践。文章将RFDC时钟系统比作交响乐团,详细阐述了PLL作为指挥的关键作用,以及系统时钟、Tile时钟、参考时钟与采样时钟的层级关系。重点剖析了PLL配置参数(如VCO频率、分频器设置)的计算方法与稳定性考量,并提供了从IP配置使能顺序到多Tile同步、DRP访问等常见问题的实战避坑指南与调试技巧,帮助工程师构建稳定的射频信号处理基石。

7up55的博客 449

ARM、ARM架构、ARM架构芯片

ARM

风高秋月白,雨霁晚霞红 1万+

对称加密中GCM和CBC俩种加密模式的区别

**CBC(Cipher Block Chaining)** 和 **GCM(Galois/Counter Mode)** 是两种常见的对称加密模式。它们的主要区别体现在加密方式、性能和安全性上。

闲人 1107

STM32单片机与ARM7、ARM9、ARM11

本内容详细介绍了 ARM 与 STM32 的关系,STM32 与 ARM7、ARM9、ARM11 的区别,美国芯片巨头英伟达欲收购 ARM 资讯。

让你爱上电路设计 6173

133.在 Vue3 中使用 OpenLayers 实现画多边形、任意编辑、遮罩与剪切处理功能

《Vue3+OpenLayers实现多边形绘制与区域处理》摘要:本文介绍如何基于Vue3+OpenLayers+ol-ext实现地图多边形交互功能。核心功能包括:鼠标绘制任意多边形、拖动顶点编辑边界、遮罩显示(非选区变红)、选区剪切显示及功能重置。技术方案采用OpenLayers处理地图渲染,ol-ext实现高级遮罩/剪切效果,ElementPlus提供UI控件。该方案适用于城市规划、园区展示等需要区域标记的场景,完整代码展示了从初始化、绘制、编辑到特效处理的全流程实现。

小彭的博客 959

【Python】解决 ERROR: Exception:Traceback (most recent call last):(亲测有效)

1、遇到问题2、问题解决

Fanjufei的博客 1万+

对标苹果 M1,谷歌自研 ARM 芯片或将于 2023 年发布?

去年,苹果推出的自研芯片 M1 令世界瞩目,由此苹果也逐渐摆脱对英特尔的依赖。或许是因为看到了 M1 芯片发展势头不错,近来有传闻说谷歌也开始研发自家的 ARM 芯片了。 据《日经亚洲》报道,有三位知情人士透露:谷歌正在开发基于 ARM 架构的 CPU 芯片,主要用于运行 ChromeOS 的笔记本电脑和平板电脑,目标发布日期为 2023 年。 一、苹果给予的灵感? 近年来,谷歌的 Chromebook 在学校中占据一定市场,因为它价格低、易维护并与谷歌服务直接捆绑十分便捷,因此在销量上具有一定优势。同时

m0_50065287的博客 2159

TCP/IP工业通信C#极致实现:工业级TcpClient封装 + 粘包拆包彻底解决 + 高频采集专项优化(完整可投产)

在工业自动化、PLC通信、工业传感器/模块、产线高频数据采集等场景中,TCP/IP是绝对主流的通信方式,相比串口/485,具备传输速率高、距离无限制、布线简单、抗干扰强的优势。但工业TCP通信和普通桌面TCP通信有本质区别,工业场景的核心要求是:✔高可靠:7×24小时不间断运行,断网自动重连、异常自动恢复,绝不崩溃;✔无数据错误:彻底解决「粘包、拆包、半包」问题(工业通信第一大坑,90%的通信异常源于此);✔高频采集优化:支持级别的高频读写PLC/设备,无卡顿、无丢帧、CPU占用极低;✔。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 859

通俗来理解 ARM芯片内核,架构,指令集,软核和硬核之间的关系

1、单片微型计算机: 简称单片机,简单来说就是集CPU(运算、控制)、RAM(数据存储-内存)、ROM(程序存储)、输入输出设备(串口、并口等)和中断系统处于同一芯片的器件,在我们自己的个人电脑中,CPU、RAM、ROM、I/O这些都是单独的芯片,然后这些芯片被安装在一个主板上,这样就构成了我们的PC主板,进而组装成电脑,而单片机只是将这所有的集中在了一个芯片上而已。 2、什么是ARM芯片? ...

howardhaowang的博客 1万+

CloudCompare 二次开发(9)——半径滤波

基于PCL对CloudCompare软件进行二次开发,实现的算法功能是半径滤波

点云侠的博客 1401

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

ARM芯片上电启动流程

自己理解的芯片启动流程

妄想吃透Linux内核源码的xxs 5889

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

上一篇: 第2章第2节&nbsp;ARM7汇编语言简介
下一篇: 第2章第4节&nbsp;Wanlix的文件组织结构
ifreecoding
博客等级 码龄15年 148粉丝 33原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值