单片机堆栈知识总结

堆栈

在片内RAM中,常常要指定一个专门的区域来存放某些特别的数据
它遵循顺序存取和后进先出(LIFO/FILO)的原则,这个RAM区叫堆栈。

其实堆栈就是单片机中的一些存储单元,这些存储单元被指定保存一些特殊信息,比如地址(保护断点)和数据(保护现场)。

堆栈特点

1、这些存储单元中的内容都是程序执行过程中被中断打断时,事故现场的一些相关参数。如果不保存这些参数,单片机执行完中断函数后就无法回到主程序继续执行了。

2、这些存储单元的地址被记在了一个叫做堆栈指针(SP)的地方。
3、栈是从高到低分配,堆是从低到高分配。

堆栈分类

我们一般说的堆栈指的栈。堆栈又分硬堆栈和软堆栈,硬堆栈即SP,从片内RAM的顶部向下生长。软堆栈在硬堆栈跟全局变量区之间的空间,C51函数调用通过R0-R7和栈来实现。

堆栈作用

1)子程序调用和中断服务时CPU自动将当前PC值压栈保存,返回时自
动将PC值弹栈。
2)保护现场/恢复现场
3)数据传输

堆栈原理:

单片机堆栈知识总结

单片机堆栈知识总结
单片机堆栈知识总结
由上述可见:SP的内容就是栈顶单元的地址。
堆栈的操作:入栈和出栈
入栈:PUAH DIRECT
功能:先SP+1→SP,(DIRECT)→((SP))
设(SP)-60H,则执行指令PUSH Acc后,·SP)=6H,(61H)=(Acc)
即将累加器A的内容如栈了。
出栈:POP DIRECT
功能:先(DIRECT)→((SP),SP-1→SP
用法同上。
注:上述操作主要用于子程序和中断服务子程序中的现场保护。而断
点保护是由硬件自动完成的。

堆栈操作由PUSH,POP两条指令来完成;

堆栈操作的操作数均为子类型(两个字节)进行操作。

程序内存可以分为几个区,栈区(stack),堆区(Heap),全局区(static),文字常亮区,程序代码区。

单片机堆栈知识总结

一个进程运行时,所占用的内存,可以分为如下几个部分:

1、栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等。
2、堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS释放。
3、全局变量、静态变量:初始化的全局变量和静态变量放在一块区域,未初始化的全局变量和和未初始化的静态变量在相邻的的另一块区域。程序结束后由系统自动释放。
4、文字常量:常量字符串就是存放在这里的,程序结束后由系统释放。
5、程序代码:存放函数体的二进制代码。

经典例子:

单片机堆栈知识总结
在MDK编译环境下,可在map文件的”Memory Map of the image”–>”Execution Region RW_IRAM1″内容中查看程序的RAM占用及分配情况,如下
单片机堆栈知识总结

不知道你是否有点明白了,堆和栈的第一个区别就是申请方式不同:栈(英文名称是stack)是系统自动分配空间的,例如我们定义一个 char a;系统会自动在栈上为其开辟空间。而堆(英文名称是heap)则是程序员根据需要自己申请的空间,例如malloc(10);开辟十个字节的空间。由于栈上的空间是自动分配自动回收的,所以栈上的数据的生存周期只是在函数的运行过程中,运行后就释放掉,不可以再访问。而堆上的数据只要程序员不释放空间,就一直可以访问到,不过缺点是一旦忘记释放会造成内存泄露。

网上一个很好的比喻,摘抄下来,以便理解:

使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。

使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

; STM32堆栈位置

此部分引用文章:如有侵权请联系作者删除
https://blog.csdn.net/m0_37845735/article/details/103301528
首先看一下STM32的地址空间映射【图三】,STM32的堆栈就是存放在片上静态SRAM中的,地址分配可以见Keil的编译map文件的”Memory Map of the image”【图四】;可见堆的地址为0x20000a08,大小为0x200,栈的地址为 0x20000c08,大小为0x400,可推算栈顶地址为:0x20000c08 + 0x400 = 0x20001008。而程序在刚运行的时候,主堆栈指针MSP指向的是程序所占用内存的最高地址【图五】,也就是栈的栈顶地址。

单片机堆栈知识总结
单片机堆栈知识总结

; 程序举例

栈是内存中一段连续的物理地址组成的一个 后进先出(LF0)的数据结构,这种栈结构大小确定,满了就溢出,所以底部确定,被称为 栈底,我们向里边写入数据被称为压栈(PUSH),读取数据被称为出栈(POP),我们每次POP都是拿栈的最后一个数据,被称为 栈顶栈底地址最大,因为每次从栈顶拿数据,可以减少寻址时间。

单片机堆栈知识总结
函数 A 在调用 B 的时候,需要传输一些参数数据,这些参数数据在寄存器不够用的时候也会被压入栈中。整个函数 A 所占用的所有内存空间,就是函数 A 的栈帧(Stack Frame)。

以一段程序作为举例

int static add(int a, int b)
{
    return a+b;
}

int main()
{
    int x = 5;
    int y = 10;
    int u = add(x, y);
}

汇编为

int static add(int a, int b)
{
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   89 7d fc                mov    DWORD PTR [rbp-0x4],edi
   7:   89 75 f8                mov    DWORD PTR [rbp-0x8],esi
    return a+b;
   a:   8b 55 fc                mov    edx,DWORD PTR [rbp-0x4]
   d:   8b 45 f8                mov    eax,DWORD PTR [rbp-0x8]
  10:   01 d0                   add    eax,edx
}
  12:   5d                      pop    rbp
  13:   c3                      ret
0000000000000014 <main>:
int main()
{
  14:   55                      push   rbp
  15:   48 89 e5                mov    rbp,rsp
  18:   48 83 ec 10             sub    rsp,0x10
    int x = 5;
  1c:   c7 45 fc 05 00 00 00    mov    DWORD PTR [rbp-0x4],0x5
    int y = 10;
  23:   c7 45 f8 0a 00 00 00    mov    DWORD PTR [rbp-0x8],0xa
    int u = add(x, y);
  2a:   8b 55 f8                mov    edx,DWORD PTR [rbp-0x8]
  2d:   8b 45 fc                mov    eax,DWORD PTR [rbp-0x4]
  30:   89 d6                   mov    esi,edx
  32:   89 c7                   mov    edi,eax
  34:   e8 c7 ff ff ff          call   0 <add>
  39:   89 45 f4                mov    DWORD PTR [rbp-0xc],eax
  3c:   b8 00 00 00 00          mov    eax,0x0
}
  41:   c9                      leave
  42:   c3                      ret

这里需要先介绍几个专用的寄存器,简要介绍如下:
·ax(accumulator):可用于存放函数返回值
·bp(base pointer):用于存放执行中的函数对应的栈帧的栈底地址
·sp(stack poinger)):用于存放执行中的函数对应的栈帧的栈顶地址
·ip(instruction pointer):指向当前执行指令的下一条指令

从汇编代码中可以看出一个函数被c调用,首先默认要完成以下动作:

   push   rbp
   mov    rbp,rsp

1将调用函数的栈帧栈底地址入栈,即保存调用函数的栈帧的栈底地址
2.建立新的栈帧,把rsp这个栈指针(Stack Pointer)的值复制到rbp里,并保存rsp的值,而
sp始终会指向栈顶。这个命令意味着,rbp这个栈帧指针指向的地址,变成当前最新的栈顶。
而调用结束栈帧出栈,跳转到方法调用方的调用位置的下一个位置,即call的下一行继续执行。

//以下两步等同于leave
mov    rsp,rbp
pop    rbp
//以下两步等同于ret
pop rip
jmp rip

所以一个完整的方法调用过程

调用方使用call指令调用方法,此时rip中存放的是call的下一条指令的地址,将rip压栈到栈底,生成新的栈帧,将栈帧压栈,执行方法,栈帧弹出,弹出rip,跳转到rip继续运行调用方的方法。

已知入栈顺序,总结出栈顺序的规律

引用文章https://blog.csdn.net/tiansheshouzuo/article/details/86604600
规律:
出栈的每一个元素的后面,其中比该元素先入栈的一定按照入栈逆顺序排列。
举例说明:
已知入栈顺序: 1 2 3 4 5
判断出栈顺序: 4 3 5 1 2
结果:不合理,原因是出栈元素3之后有 5 1 2 这三个元素,其中1 2 是比3先入栈的,根据规律,这两个出栈的顺序必须和入栈顺序相反,也就是 2 1 出栈,不可能按照1 2 顺序出栈。

已知入栈顺序: 1 2 3 4 5
判断出栈顺序: 2 1 3 5 4
结果:合理,逐个判断,2后面比它先入栈的是”1″,单个元素当然可以;1后面无比它先入栈的,故不需要比较;3后面无比它先入栈的,故不需要比较;5后面比它先入栈的是”4″,单个元素当然可以,4后面没有元素,不需要比较。

Original: https://blog.csdn.net/weixin_44057803/article/details/128728046
Author: 不熬夜,早点睡
Title: 单片机堆栈知识总结

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/812126/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • matplotlib之直方图

    文本以及后续的系列文章中均会使用到numpy这个库,numpy是Python的一种开源的数值计算扩展,主要用来生产一些随机数作为绘图的原始数据。具体和安装matplotlib类似,…

    Python 2023年8月30日
    051
  • 发现几个好玩的游戏编程平台,与君共勉!

    俗话说:兴趣是最好的老师,编程也是。如果你一开始就接触到了枯燥的编码,有些人难免会放弃,而最好的方法就是感兴趣,一步一步地变得更好。 [En] As the saying goes…

    Python 2023年5月24日
    067
  • Python代码阅读(第49篇):限制一个数在指定范围内

    本篇阅读的代码实现了将一个数限制在指定范围内的功能,如果这个数在另外两个数所指定的范围内,将保持自己的值,否则返回离这个数最近的值。 本篇阅读的代码片段来自于30-seconds-…

    Python 2023年11月9日
    062
  • RDD中的依赖关系

    宽依赖 1.有shuffle2.父RDD的一个分区会被子RDD的多个分区所依赖(父一对多) 窄依赖 1.没有shuffle2.父RDD的一个分区只会被子RDD的1个分区所依赖(一对…

    Python 2023年6月3日
    077
  • django的auth模块学习

    auth 1.&#x6211;&#x4EEC;&#x5728;&#x5F00;&#x53D1;&#x4E00;&#x4E2A…

    Python 2023年10月30日
    038
  • SPL工业智能:发现时序数据的异常

    基本问题 工业生产过程中会产生大量的数据,比如电压、温度、流量等等,它们随时间推移而不断产生,这些数据在多数情况下是正常的,否则生产无法正常进行;少数情况下,数据是异常的,生产效率…

    Python 2023年11月7日
    041
  • 1-pytest-创建第一个测试

    pytest * – + 安装 pytest + 创建第一个测试 + 运行多个测试 安装 pytest 打开命令行 pip install -U pytest 查看是否…

    Python 2023年9月14日
    055
  • python面向对象-2 继承

    面向对象-继承 经典类:不由任意内置类型派生出的类,称之为经典类新式类:python面向对象的继承指的是多个类之间的所属关系,即子类默认继承父类的所有属性和方法。 class A(…

    Python 2023年9月23日
    035
  • 【数据结构与算法】LinkedList与链表

    ✨个人主页:bit me✨当前专栏:数据结构✨每日一语:假如困境有解,何须心烦意乱;倘若困境无解,又何须郁郁寡欢。每个人都有两次生命,当你意识到你只有一次生命的时候,你的第二次生命…

    Python 2023年9月30日
    060
  • 【Python】关于 Pandas 常用语法合集

    【Python】关于 Pandas 常用语法合集 仅个人常用且常忘记 不断更新中 1、合并/连接 数据框 df1=pd.DataFrame([[1,2,3],[2,3,4]],co…

    Python 2023年8月22日
    071
  • 数据清洗(二):python数据清洗

    Pandas数据清洗流程: 1.数据的读写:read_csv、read_excel、to_csv to_excel 2.数据的探索与描述:info、head、describe、sh…

    Python 2023年8月8日
    067
  • pytest篇9-失败重试机制

    01 — 引言 上一篇总结了pytest的skip和skipif的使用,skip是无条件的跳过用例,skip是当条件为真时,会跳过测试用例,可以灵活运用起来。 当部分用例因为一些偶…

    Python 2023年9月11日
    041
  • 关联规则apriori算法_使用Apriori挖掘购物小票关联规则

    01 啤酒与尿布 说到关联规则,有一个很有名的案例——啤酒与尿布。说,美国一家连锁店发现很多男性会在周四购买尿布和啤酒,这两种看似不相干的商品之间显现出强相关性,于是商家可以将啤酒…

    Python 2023年8月21日
    049
  • 精选20个爆火的Python实战项目(含源码),直接拿走不谢

    今天给大家介绍20个非常实用的Python项目,帮助大家更好的学习Python。 ① 猜字游戏 在这个游戏中,你必须一个字母一个字母的猜出秘密单词。 如果你猜错了一个字母,你将丢掉…

    Python 2023年7月31日
    038
  • ORM 操作

    增加 models.类.objects.create(name=’aa’,age=18) modes.类.object.create( **dic) obj…

    Python 2023年6月12日
    071
  • Django ModelForm(组件)之save()保存数据

    文章目录 一、ModelForm是什么? 二、使用步骤 1.导入form库 2.定义自己的ModelForm 3.在自己的views.py里面定义自实列自己的ModelForm 4…

    Python 2023年8月3日
    058
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球