堆栈的概念————————ARM微控制器与嵌入式系统(清华大学慕课记录)

堆栈、堆、栈的概念

  1. 堆:堆可以被看成是一棵树。堆是在程序运行时,申请某个大小的存储空间。即动态分配内存,对其访问和对一般内存的访问没有区别。
  2. 栈:栈是一种运算受限的线性表。仅允许在栈的一端进行插入和删除操。这一端称为栈顶,相对的,另一端称为栈底。遵循先入后出的原则。
  3. 堆栈:堆栈本身就是栈,只是由于现代汉语言喜欢用两个字表示一个事物,因此用了“堆栈”的说法来代替栈。

CPU中为什么要引入堆栈的机制

程序在执行程序时,相对应是PC指针的变化,PC指针永远指向下一条待执行的指令。但是PC指针不是永远都是一条一条逐一递增的,再遇到函数嵌套调用时,函数跳转时(比如遇到 if…else这样的语句时),PC指针会发生跳转。
在这里插入图片描述
在发生函数调用的时候,函数调用结束需要使CPU回到原来的位置,也就是使PC指针发生一个跳转,PC指针的跳转也就要给PC指针赋值,给PC指针赋的这个值也就是函数的返回地址。那CPU应该从何处获得这个返回地址呢?早期的CPU设计是设计了一个返回地址寄存器
返回地址寄存器的作用就是为了存储函数调用时的返回地址,从而使得函数调用结束时,将此寄存器的值赋值给PC指针寄存器,完成函数的返回。但是函数调用可能会嵌套好几层,第一次调用的返回地址要进行存储,第二次调用的返回地址仍然需要进行存储,在使用C语言时,会使用到库函数,在使用库函数的过程当中,就可能发生多层的函数调用,因此会造成返回地址寄存器不够用的情况,因此也就引入了一种更加智能的机制,也就是堆栈(stack)

堆栈的特点及作用

特性

  1. 堆栈是一段连续的存储空间
  2. 堆栈按照先入后出的方式进行工作
  3. 只能向/从堆栈的顶部加入或取出数据
  4. 堆栈能够保存数据的顺序
    补充: 堆栈的存储器是自下向上使用,所谓的“顶部”是数据最后放入的位置
    且对于大部分的CPU而言,“顶部”指低位的存储空间

基本操作方式

压栈(PUSH):将内容加入到堆栈顶端
出栈(POP): 将堆栈顶端的内容取出

堆栈的三种作用

  1. C语言编译器使用堆栈来完成参数传递和返回值传递——C语言的函数调用
  2. 汇编程序可以使用堆栈来保存局部变量,寄存器的值
  3. CPU硬件使用堆栈来保存返回地址寄存器上下文

解决函数调用返回地址存储的方法

有了堆栈这样的机制,就能很好地处理函数跳转及函数嵌套调用的问题。
在发生函数嵌套调用的时候,当发生一级函数调用的时候,就把当前的PC指针寄存器的值压入堆栈,当函数调用还没有返回时,又再次发生函数调用时,需要把第二次发生函数调用的当前的PC指针寄存器的值压入堆栈,当第二层函数调用需要返回时,只需要从栈顶取出数据即可,这个值也就是第二次函数调用时的返回地址,将其赋值给PC指针寄存器,就可以完成第二层函数的返回。而发生第一层函数返回时,只需要再次从栈中取出一个值赋值给PC指针寄存器即可,这样就能完成第一层函数的返回。
综上,就是函数调用时的全部过程,完美的运用了堆栈先入后出的机制。

局部变量与堆栈的关系

C语言中函数的参数、返回值的传递是使用栈的,C语言中的局部变量也会根据编译器在栈中占据一定量的存储空间,因此堆栈会依据C语言的使用而逐渐地消耗,局部变量存储在栈中这一点也很好地印证了局部变量有生命周期,因为当函数调用结束,函数返回。局部变量的存储空间将逐一释放,逐一弹出,不再继续使用,局部变量的值也就被释放了。

堆栈溢出

堆栈的位置

上述描述了堆栈的作用,那堆栈又在哪里呢?对于CPU来讲,CPU采用一段连续的片外存储空间来充当堆栈,而CPU又如何找到这段存储空间呢?这里引入了堆栈指针寄存器的概念,堆栈指针寄存器指定栈顶位置,也就是片外存储器用于堆栈这一段存储空间的栈顶。

堆栈溢出的原理

在介绍堆栈溢出原理之前先指出一点,堆,全局变量的存储位置就是在堆上
堆栈存储空间和变量空间(堆)是使用同一端存储器空间,针对于堆栈存储空间和变量空间分别具有以下特性:

  1. 变量空间从低地址向高地址划分(C语言编程时使用的全局变量)
  2. 堆栈空间从高地址向低地址增长
    下图是变量空间和堆栈空间在存储器上的示意图

在这里插入图片描述
因此在程序运行的时候,伴随着各种函数的调用,因此堆栈空间是处于一个上下涨落的状态,堆也在上面使用内存,考虑极限情况,当全局变量定义的过多,函数嵌套的过深,可能出现的情况就是堆空间和堆栈空间产生了交集,从而导致PC指针从堆栈中取了一个值作为返回地址,但取到的值却不是返回地址,而是一个全局变量,从而造成程序跑飞。这也就是堆栈溢出的原理

堆栈运行例子

S12MCU

例子涉及到的汇编指令:
NOP:不执行任何操作
LDS:给堆栈指针赋一个值
PSHx:把寄存器x中的数值放入堆栈中
JSR:跳到子分支
RTS:从子分支中返回

下图中是CPU的一段内存:
在这里插入图片描述
下图是几条待执行的指令:

指令执行的第一步

在这里插入图片描述
蓝色箭头指向的是上一步已经执行结束的指令。
在上一步指令执行结束之后,我们可以看到指令中涉及到的变量有了如下的变化:
SP = undefined
PC = 0x3006
A = 0X34
B = 0X56

在上述变量中,我们可以看到SP的值是未定义的,而PC指针的值是0x3006,也就是蓝色箭头指向指令的下一条,也印证了PC指针的作用是指向即将执行的指令的地址。,A 和 B是CPU的通用寄存器,保存着即将送入CPU逻辑单元的操作数。

指令执行的第二步

在这里插入图片描述
在执行了第二条指令后,CPU的内存空间发生了一些变化,在其最底部出现了一个红色箭头,红色箭头指向1FFFF往下一个地址,也就是2000,在看所运行的指令,我们发现此时蓝色箭头所指向的指令的意思是给堆栈指针赋值2000,因此红色箭头指向的是堆栈指针寄存器的值,也就是说红色箭头以上的内存空间是堆栈可以使用的内存空间,因此,这段指令的意思就是:完成了堆栈的初始化,指定了地址从2000开始往上所可以使用的内存空间,将其作为堆栈使用,从这条语句开始程序也就有堆栈可以使用了。
在这里插入图片描述
上述指令所涉及的变量发生了如下改变:
SP = 0x2000
PC = 0x3008
A = 0x34
B = 0x56

堆栈指针正如上述所分析的,SP = 0x2000,PC指针指向了指令中下一条待执行指令的地址,也就是3008,A和B寄存器的值不变。

指令执行的第三步

在这里插入图片描述
在执行了第三条指令之后,指令的意思是将寄存器A的值压入堆栈,指令执行结束之后,CPU的内存空间发生了一些变化,变化如下:
在这里插入图片描述
执行指令之后,相关的变量变化如下:
SP = 0x1FFF
PC = 0x3009
A = 0x34
B = 0x56

也就是说堆栈的空间被用了一个,现在可用的堆栈空间是0x1FFF以上的空间,PC指针指向的下一条待执行的指令。

指令指向的第三步

在这里插入图片描述
这条指令的作用是将寄存器B的值进行压栈,压栈后的CPU内存空间变为:
在这里插入图片描述
涉及到的变量变为:
SP = 0x1FFFE
PC = 0x300A
A = 0x34
B = 0x56

指令执行的第四步

在这里插入图片描述
这条指令的作用是跳转到子函数去执行,执行这条指令后,发生了很多变化,涉及到的相关变量发生了如下的变化:
SP = 0x1FFC
PC = 0x4050
A = 0x34
B = 0x56

SP堆栈指针变为了0x1FFC,PC指针指向了0x4050,从PC指针的值也可以清楚地看到下一条指令就要跳转到子函数执行子函数,4050也就是子函数对应的可执行指令的第一条指令。相应地,在执行了子函数,也就是发生了函数调用,那么就需要存储函数返回地址,这样才能够正确地从子函数返回。
因此,在CPU内存空间发生了如下的变化:
在这里插入图片描述
从上图可以看到0x30,和0x0C压入了堆栈,而这两个指令是由一个16位的地址拆开的两个8位的地址,将2个8位的地址合起来就是一个16位的地址,这个16位的地址就是调用子函数返回后即将执行的指令所在的地址。
总结来说,也就是在发生函数调用后,PC指针指向子函数的第一条指令所在的地址,然后堆栈会自动的压入函数返回地址,SP指针也会因为函数返回地址压入堆栈的原因,SP指针的值相应地会减少

指令执行的第五步

在这里插入图片描述
这条指令什么也没干,相应发生变化的是PC指针,PC指针指向了下一条待执行的指令的地址,也就是0x4052。
SP = 0x1FFC
PC = 0x4052
A = 0x34
B = 0x56

指令执行的第六步

在这里插入图片描述
这条指令的意思是从子函数返回,执行这条指令后,涉及到的变量发生了如下的变化:
SP = 0x1FFE
PC = 0x300C
A = 0x34
B = 0x56

从上述变化我们可以看到SP的指针相对于上一次增加了,PC指针并没有指向子函数的下一条指令,而是指向了主函数中的指令的地址,也就是刚刚自动压入堆栈的地址。相应的函数返回后,堆栈中压入的函数返回地址也自动出栈,堆栈的变化如图所示:
在这里插入图片描述
由上图所知,虽然堆栈的值自动加2,堆栈可使用的空间也增加了2,但是0x30和0x0c的值仍然存在于堆栈中,只是不被堆栈所承认。下次再往堆栈中放数据的时候就直接覆盖了原来的数据。
总结来说,也就是函数调用结束之后,将堆栈顶部的数据取出来赋值给PC指针寄。SP指针的值加2。

指令执行的第7步

在这里插入图片描述
指令的意思是从堆栈中弹出一个数,弹出到A寄存器,涉及到的变量变化为:
SP = 0x1FFF
PC = 0x300D
A = 0x56
B = 0X56

SP指针的值加2,PC指针的值指向下一条指令,A寄存器的值变为0x56
对应的内存空间的变化为:
在这里插入图片描述

指令执行的第8步

在这里插入图片描述
指令的意思是从堆栈中弹出一个数赋值给B寄存器,相应的变量变化为:、
SP = 0x2000
PC = 0x300E
A = 0x56
B = 0x34

相应的内存空间的变化是:
在这里插入图片描述

总结

回顾上述步骤,我们可以看到最终发生的变化是将A和B寄存器的值发生了一个调换,可想而知这么一个简单的操作需要执行将近10条指令,但是对于CPU来说,却是非常迅速的,CPU执行一条指令的时间是ns级的,执行一个数据交换虽然对于我们来说,指令数也不少,但是对于CPU来讲,却是电光火石之间的事。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ARM Cortex-M23 控制器是一款由英国半导体公司ARM设计的低功耗控制器,广泛应用于物联网设备、可穿戴设备等领域。下面将从原理和实践两个方面进行介绍。 首先是原理方面,ARM Cortex-M23 控制器采用了ARMv8-M架构,具备了较强的处理能力和低功耗特性。它支持指令和数据的16位或32位宽度,配备了两个堆栈指针,可以实现非常高效的中断响应。此外,Cortex-M23 还具备了硬件调试功能,可以实现实时追踪和调试,方便开发人员对代码的调试和优化。 其次是实践方面,ARM Cortex-M23 控制器可以通过集成开发环境(IDE)进行编程和开发。常见的IDE有Keil MDK、IAR Embedded Workbench等。开发人员可以使用C编程语言进行开发,通过编写程序来控制外设和实现各种功能。此外,Cortex-M23 还支持多任务操作系统(RTOS),可以实现多任务的并发执行,提高系统的效率。 在实践中,ARM Cortex-M23 控制器可以广泛应用于物联网设备和智能家居等领域。它可以通过与各种传感器和执行器的连接,实现对环境的监测和控制。例如,可以使用它来实现温度传感器的读取和风扇的控制,实现智能的温控系统。此外,Cortex-M23 还可以通过与无线通信模块的连接,实现设备间的互联和远程控制。 综上所述,ARM Cortex-M23 控制器具有强大的处理能力和低功耗特性,在物联网设备和可穿戴设备等领域有着广泛的应用前景。通过编程和开发,可以实现对外设的控制和功能的实现。它为物联网的发展提供了一种高效、可靠的解决方案。 ### 回答2: Arm Cortex-M23控制器是一款高性能、低功耗的控制器,采用了Armv8-M架构。它广泛用于物联网设备、传感器和控制器应用开发中。 Cortex-M23具有先进的安全性能,支持TrustZone技术,可以实现软件和硬件隔离,保护敏感数据和代码。它还具有内置的硬件加密引擎,可以提供高效的加密和解密功能,确保数据的安全传输和存储。 Cortex-M23采用了Harvard架构,具有分离的指令和数据总线,可以实现高效的并行数据访问。它还支持高密度的存储器,包括闪存和RAM,可以满足复杂应用的存储需求。 Cortex-M23控制器具有先进的能源管理功能,可以通过动态电压和频率调整以及睡眠模来降低功耗。这使得它非常适合电池供电的应用场景,并能够延长电池寿命。 在实践中,开发者可以使用ARM提供的开发工具链来开发和调试Cortex-M23控制器的应用程序。开发者可以使用C语言或汇编语言编写程序,并通过标准接口将其部署到控制器上。 此外,ARM还提供了丰富的软件库和例程,帮助开发者快速开发各种应用。开发者可以利用这些资源来构建各种功能丰富的应用程序,如传感器数据采集、通信控制和数据处理等。 总之,Cortex-M23控制器是一款强大的控制器,具有先进的安全性能、高效的能源管理和丰富的软件支持。它为开发者提供了一个理想的平台,用于开发物联网设备和传感器应用,并满足对性能、低功耗和安全性的高要求。 ### 回答3: ARM Cortex-M23控制器是一种面向嵌入系统的32位处理器,采用ARMv8-M架构。它被设计用于支持物联网设备和安全应用,具有低功耗、高效能和可靠性的特点。 Cortex-M23控制器的原理主要包括以下几个方面: 1. 处理器核心:Cortex-M23采用了有限指令集计算机(RISC)架构,具有高效的操作和处理能力。它具有基于线程(Thread)的执行模型,可同时支持两个线程,实现更高的并行处理能力。 2. 安全特性:Cortex-M23支持硬件隔离技术,如TrustZone技术,可以将系统分为安全和非安全两个域,实现不同级别的安全保护。这样可以有效地防止恶意软件攻击和信息泄露。 3. 低功耗设计:Cortex-M23采用了先进的节能设计,具有多种节能模。它可以根据应用需求灵活地选择不同的运行模,并通过动态电压和频率调整技术来降低功耗,延长电池寿命。 在实践方面,使用Cortex-M23控制器可以进行各种应用的开发。开发者可以使用ARM提供的开发工具和软件包,如Keil MDK、IAR Embedded Workbench,或者使用第三方开发工具进行软件开发。 Cortex-M23支持多种编程语言,如C、C++等,开发者可以根据需要选择适合的语言进行应用程序的编写。通过编写应用程序,结合相关的硬件外设,可以实现各种功能,如智能家居、工业自动化、医疗设备等。 总之,ARM Cortex-M23控制器是一种高性能、低功耗、安全可靠的控制器,可以广泛应用于物联网设备和安全应用领域。开发者可以利用其强大的处理能力和丰富的开发工具进行实践,实现各种应用的开发。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值