详细解析STM32中的堆栈机制
- 格式:pdf
- 大小:84.00 KB
- 文档页数:4
STM32内存分配解析及变量的存储位置原⽂内存映射在⼀些桌⾯程序中,整个内存映射是通过虚拟内存来进⾏管理的,使⽤⼀种称为内存管理单元(MMU)的硬件结构来将程序的内存映射到物理RAM。
在对于 RAM 紧缺的嵌⼊式系统中,是缺少 MMU 内存管理单元的。
因此在⼀些嵌⼊式系统中,⽐如常⽤的 STM32 来讲,内存映射被划分为闪存段(也被称为Flash,⽤于存储代码和只读数据)和RAM段,⽤于存储读写数据。
STM32 的 Flash 和 RAM 地址范围笔者标题所说的内存是指 STM32 的 Flash 和 RAM,下图是 ARM Cortex M3 的地址映射图:从图中我们可以看到 RAM 地址是从 0x2000 0000 开始的,Flash地址是从 0x0800 0000 开始的,笔者将在下⽂中着重对这两部分进⾏剖析。
Flash代码和数据是存放在 flash 中的,下⾯是将 flash 内部进⾏细分之后的⼀张图,图中标明了代码段,数据段以及常量在 flash 中的位置。
如上图所⽰,Flash ⼜可以细分为这么⼏个部分,分别是⽂本段 (Text),其中⽂本段中⼜包含可执⾏代码 (Executable Code)和常量 (Literal Value),在⽂本段之后就是只读数据区域 (Read Only Data),当然并不是所有架构的单⽚机都满⾜这样⼀个排布规律,这⾥只针对ARM Cortex M3 系列,只读数据段后⾯接着的就是数据复制段 (Copy of Data Section),第⼀次遇到这个概念的朋友看到数据复制可能会有所疑惑,其实这个段充当的作⽤是存放程序中初始化为⾮ 0 值的全局变量的初始值,之所以要将初始值存放到这⾥,是因为全局变量是存放在 RAM 上的,RAM 上的值掉电便丢失,每次上电后这些变量是要进⾏重新赋值的,⽽重新赋的值就存放在这⾥。
那为什么不存放初始化为 0 的全局变量初始值呢,原因也很简单,既然是初始化为 0,那么在上电后统⼀对存放初始化为 0 的全局变量的那块区域清0就好了。
深入理解STM32双堆栈机制堆栈堆栈,「堆」和「栈」经过无数技术书籍,以及各类技术博主苦口婆心的提醒,恐怕没几个人会再把堆和栈混为一谈,精明的开发者都明白,堆栈堆栈,「堆」和「栈」是不同的两种数据结构,具有各自的内存分配和使用方式。
众所周知,栈由编译器自动分配释放,堆由程序员手动分配释放,栈存放函数形参、局部变量,堆内存申请了记得释放……诸如此类,老生常谈。
众所不周知,在不同的体系结构、裸机/操作系统下,堆栈在内存中的分配方式、内存布局、空间大小、存储内容也存在差异。
本文以 STM32 系列芯片(Cortex-M3 内核)和 RT-Thread 操作系统为例,梳理嵌入式开发过程中,与 MCU 堆栈有关的概念,然而堆栈涉及的知识太多,本文只侧重从内存分布角度阐述,帮助读者整体把握相关技术。
程序为什么需要堆栈堆栈是程序访问内存的一种方式。
程序员在编程处理应用数据时,往往要使用大块连续的内存空间。
程序指令在执行运算的过程中,也有大量中间结果需要临时保存,显然这些数据都是存放在内存当中,堆和栈便提供了这样一种机制:将内存分类管理,提供不同的访问方式。
堆和栈的使用更具体表现为,编程中使用的malloc()函数从堆内存分配空间,利用指针数组或内存函数使用。
程序编译后所包含的大量PUSH和POP指令操作,系统根据SP(堆栈指针)寄存器访问当前对应栈内存,通过栈保存临时数据。
堆和栈在内存中的具体位置,是接下面篇幅中讨论的重点。
当然,内存空间只是连续字节数据的抽象,本身并不区分堆和栈的概念,它做的只是存储和读写信息。
因此,如何定义堆栈、初始化建立堆栈环境,在嵌入式软件运行前便显得尤为重要。
这涉及到处理器提供的堆栈机制、操作系统内存管理和进程切换等方方面面。
程序内存布局在芯片内部存储器中,包含了代码、数据、堆栈等信息,存放在 Flash 和 SRAM 当中,这里有必要说明一下众多内存类型的地址空间分布,其中包含我们的主角 —— 堆栈。
【STM32F429】第5章ThreadXNetXDUO⽹络协议栈介绍第5章 ThreadX NetXDUO⽹络协议栈介绍本章节介绍 ThreadX NetXDUO⽹络协议栈,让⼤家对NetXDUO有⼀个整体的了解。
5.1 初学者重要提⽰5.2 Express Logic公司介绍5.3 ThreadX NetXDUO简介5.4 ThreadX NetXDUO安全认证5.5 ThreadX NetXDUO⽀持的RFC5.6 ThreadX NetXDUO的IxANVL测试5.7 ThreadX NetXDUO的IPv6就绪微标认证5.8 ThreadX NetXDUO各⾏各业应⽤案例5.9 总结5.1 初学者重要提⽰ThreadX是⼩型RTOS的巅峰之作,通过了各⾏各业的安全认证,并且⼤部分都是最⾼安全标准。
作为中间件的NetXDUO协议栈也通过了各种安全认证。
5.2 Express Logic公司介绍ThreadX的作者是William lamie(同样是Nucleus RTOS的原始作者,于1990年发布)。
1996的时候成⽴了Express Logic,并于1997发布⾸版ThreadX RTOS。
ThreadX4发布于2001年,ThreadX5发布于2005年,ThreadX6发布于2020年。
FileX – ThreadX的嵌⼊式⽂件系统于1999年发布⾸版。
NetX – ThreadX的嵌⼊式TCP / IP⽹络协议栈于2002年发布⾸版。
USBX – ThreadX的嵌⼊式USB协议栈于2004年发布⾸版。
2009年推出了适⽤于SMP多核环境的ThreadX。
2011年发布⽀持动态应⽤加载的ThreadX Modules。
GUIX – ThreadX的嵌⼊式UI于2014年发布⾸版。
Microsoft在2019年4⽉18⽇以未公开的价格购买了Express Logic。
5.2.1 ThreadX内核ThreadX⼏乎是⼩型RTOS的巅峰之作,不管你之前⽤的那个OS,如果有精⼒建议还是学习下。
一文解析STM32内存管理和堆栈的认知与理解本文主要介绍了STM32内存管理和堆栈的认知与理解,首先介绍的是内存管理的实现原理及分配、释放原理,其次介绍了stm32的存储器结构,最后阐述了堆栈的认知与理解,具体的跟随小编一起来了解一下吧。
STM32内存管理详解内存管理,是指软件运行时对计算机内存资源的分配和使用的技术。
其最主要的目的是如何高效,快速的分配,并且在适当的时候释放和回收内存资源。
内存管理的实现方法有很多种,他们其实最终都是要实现2 个函数:malloc 和free;malloc 函数用于内存申请,free 函数用于内存释放。
内存管理的实现原理从上图可以看出,分块式内存管理由内存池和内存管理表两部分组成。
内存池被等分为n 块,对应的内存管理表,大小也为n,内存管理表的每一个项对应内存池的一块内存。
内存管理表的项值代表的意义为:当该项值为0 的时候,代表对应的内存块未被占用,当该项值非零的时候,代表该项对应的内存块已经被占用,其数值则代表被连续占用的内存块数。
比如某项值为10,那么说明包括本项对应的内存块在内,总共分配了10 个内存块给外部的某个指针。
内寸分配方向如图所示到低位地址)即首先从最末端开始找空内存。
当内存管理刚初始化的时候,内存表全部清零,表示没有任何内存块被占用。
分配原理当指针p 调用malloc 申请内存的时候,先判断p 要分配的内存块数(m),然后从第n 项开始,向下查找,直到找到m 块连续的空内存块(即对应内存管理表项为0),然后将这m 个内存管理表项的值都设置为m(标记被占用),最后,把最后的这个空内存块的地址返回指针p,完成一次分配。
注意,如果当内存不够的时候(找到最后也没找到连续的m 块空闲内存),则返回NULL 给p,表示分配失败。
释放原理。
学习STM32(⼆)之STM32内存管理(三)STM32内存管理以及堆和栈的理解⾸先,先看⼀下stm32的存储器结构。
以下两种说法都⼀样的,各有着重⽽已,可单看第⼀个说法,第⼆个知道就⾏第⼀个说法:原⽂ :STM32的存储器映射详解存储器映射是指把芯⽚中或芯⽚外的FLASH,,外设,BOOT,BLOCK等进⾏统⼀编址。
即⽤地址来表⽰对象。
这个地址绝⼤多数是由⼚家规定好的,⽤户只能⽤⽽不能改。
⽤户只能在挂外部RAM或FLASH的情况下可进⾏⾃定义。
Corx-M3⽀持4GB的存储空间,它的存储系统采⽤统⼀编址的⽅式; 程序存储器、数据存储器、被组织在4GB的线性地址空间内,以⼩端格式(little-endian)存放。
由于Cortex-M3是32位的内核,因此其PC指针可以指向2^32=4G的地址空间,也就是0x0000_0000——0xFFFF_FFFF这⼀⼤块空间。
见图1:图1:Cortex-M3的存储器映射Cortex-M3内核将0x0000_0000——0xFFFF_FFFF这块4G⼤⼩的空间分成8⼤块:代码、SRAM、外设、外部RAM、外部设备、专⽤外设总线-内部、专⽤外设总线-外部、特定⼚商(见图1)。
这就导致了,使⽤该内核的芯⽚⼚家必须按照这个进⾏各⾃芯⽚的存储器结构设计,如。
图2:Cortex-M3与中密度stm32的存储器映射对⽐图三:图2中可以很清晰的看到,STM32的存储器结构和Cortex-M3的很相似(这是因为stm32本来就是按照cortex_m3内核来设计硬件的),不同的是,STM32加⼊了很多实际的东西,如:Flash、SRAM等。
只有加⼊了这些东西,才能成为⼀个拥有实际意义的、可以⼯作的处理芯⽚——STM32。
STM32的存储器地址空间被划分为⼤⼩相等的8块区域,每块区域⼤⼩为512MB(如:0x20000000~0x40000000)。
对STM32存储器知识的掌握,实际上就是对Flash和SRAM这两个区域知识的掌握。
STM32内存编程在startup_stm32f10x_md.s文件中,它的前面几行就有以上定义,;栈=1KStack_Size EQU 0x00000400;堆=512BHeap_Size EQU 0x00000200Stack_Size不影响Hex,更不影响Hex怎么运行的,只是在Debug调试时会提示错。
栈溢出也有是超过了国界进行活动,只要老外没有意见,你可以接着玩,有老外不让你玩,你就的得死,或是大家都死(互相撕杀),有的人写单片机代码在函数里定义一个大数组int buf[8192],栈要是小于8192是会死的很惨。
Heap_Size可为0,即不使用动态分配。
Heap_Size的大小与malloc所分配的内存有关,当连续分配而又不释放,会导致满堆或内存泄露。
本文源起的诉求,即在object过多的情况下进行解析,程序需要N多次的动态内存分配,而Heap_Size太小,导致无法分配内存。
通过修改Heap_Size的大小解决了诉求。
STM32的内存分配规律从0X20000000开始依次为:静态存储区+堆区(可有可无)+栈区所有的全局变量,包括静态变量之类的,全部存储在静态存储区。
紧跟静态存储区之后的,是堆区(如没用到malloc,则没有该区),之后是栈区。
附录STM32内存地址说明在MDK编译过程中,内存的划分如下:Code是存储程序代码的。
RO-data是存储const常量和指令。
RW-data是存储初始化值不为0的全局变量。
ZI-data是存储未初始化的全局变量或初始化值为0的全局变量。
Flash=Code + RO Data + RW Data;RAM= RW-data+ZI-data;此内存划分暂未包括堆栈,堆栈会在程序运行时,占用RAM。
堆栈的内存占用就是MDK里,RAM分配给RW-data+ZI-data之后的地址开始分配的。
---------------------STM32的堆栈大小在官方文件已经定义好了,分别是:Heap_Size EQU 0x00000200 一共512字节Stack_Size EQU 0x00000400 一共1K字节/***********************************************************************************/但是STM32在keil环境下每次编译后的堆栈起始地址并不是固定的(就算事先已经定义好了堆栈的大小),因为栈的起始地址是由用户程序中事先定义好的变量数目决定的(实测是如此)。
stm32 单机程序栈保护机制
STM32单片机的程序栈保护机制是一种用于保护程序运行时堆栈空间的技术。
在STM32单片机中,堆栈保护可以通过使用硬件和软件相结合的方式来实现。
下面我将从硬件和软件两个方面来介绍STM32单片机的程序栈保护机制。
硬件方面:
STM32单片机的硬件提供了一些特性来保护程序的堆栈空间。
其中最常见的是硬件堆栈保护功能。
在STM32单片机中,可以通过设置相关的寄存器来启用硬件堆栈保护。
这样可以防止堆栈溢出和堆栈破坏,提高系统的稳定性和安全性。
另外,STM32单片机还提供了一些特殊的寄存器和机制,用于监控堆栈的使用情况,比如堆栈指针寄存器(SP)和堆栈溢出检测机制等。
这些硬件特性可以帮助开发人员及时发现和处理堆栈相关的问题,保障程序的正常运行。
软件方面:
除了硬件保护机制,STM32单片机的程序堆栈还可以通过软件
来进行保护。
比如,开发人员可以在编写程序时,合理规划堆栈的
大小,避免出现堆栈溢出的情况。
此外,还可以通过编写堆栈溢出
检测的代码来监控堆栈的使用情况,及时发现并处理堆栈溢出的问题。
另外,开发人员还可以通过使用一些静态分析工具或者动态调
试工具来检测程序中可能存在的堆栈问题,及时进行修复和优化。
总结:
综上所述,STM32单片机的程序堆栈保护机制包括硬件和软件
两个方面。
通过合理配置硬件保护特性和编写规范的软件代码,可
以有效保护程序的堆栈空间,提高系统的稳定性和安全性。
开发人
员在使用STM32单片机时,应该充分了解和掌握这些堆栈保护技术,以确保程序的正常运行。
计算机组成原理中的堆栈简介
计算机组成原理中的堆栈是一种数据结构,它遵循后进先出(LIFO)的原则。
堆栈通常用于存储函数调用、临时变量和其他临
时数据。
在计算机组成原理中,堆栈通常是通过内存中的一段特定
区域来实现的。
堆栈通常由两个主要操作组成,压栈(push)和弹栈(pop)。
压栈操作将数据放入堆栈顶部,而弹栈操作则从堆栈顶部移除数据。
这种操作使得最后压入堆栈的数据最先被弹出,因此堆栈遵循LIFO
原则。
在计算机组成原理中,堆栈经常用于存储函数调用的返回地址
和局部变量。
当一个函数被调用时,当前函数的返回地址会被压入
堆栈,以便在函数执行完毕后能够返回到正确的位置。
同时,函数
内部的局部变量也可以被存储在堆栈中,以便在函数执行期间可以
方便地访问和操作这些变量。
堆栈还可以用于表达式求值和语法分析。
例如,后缀表达式的
求值就可以通过堆栈来实现。
在语法分析中,堆栈可以用于存储和
处理语法规则,以便进行语法分析和语法树的构建。
在计算机硬件中,堆栈通常与栈指针(stack pointer)和基址
寄存器(base pointer)相关联。
栈指针指向当前堆栈顶部的位置,而基址寄存器则指向堆栈的基址,用于定位局部变量和函数参数的
存储位置。
总的来说,堆栈在计算机组成原理中扮演着重要的角色,它不
仅是一种数据结构,还在函数调用、表达式求值和语法分析等方面
发挥着重要作用。
深入理解堆栈的原理和应用对于理解计算机组成
原理和编程语言的工作原理至关重要。
堆栈的名词解释堆栈是计算机领域中一个重要的概念,它是一种数据结构,用于存储和管理数据。
堆栈的特点主要体现在数据存储和访问的方式上,它采用“后进先出”(Last-In-First-Out,简称LIFO)的策略,即最后进入堆栈的数据首先被访问。
1. 堆栈的基本原理堆栈由两个主要操作组成:压入(Push)和弹出(Pop)。
当数据需要被添加到堆栈中时,使用压入操作将数据放置在堆栈的顶部;而当数据需要被访问或移除时,使用弹出操作将顶部的数据取出。
这种方式确保了最后添加的数据能够最先被处理,类似于将数据放置在空心的立方体中,只能从顶部进行操作。
2. 堆栈的实际应用堆栈在计算机领域有着广泛的应用,尤其在编程和算法设计中扮演着重要的角色。
堆栈可以用来解决很多实际问题,比如表达式求值、函数调用、内存管理等。
2.1 表达式求值在数学表达式的求值过程中,堆栈可以帮助解决算术优先级问题。
将表达式的各个操作数和运算符通过压入操作按正确的顺序入栈,然后使用弹出操作依次取出并计算,最终得到求值结果。
2.2 函数调用在程序开发中,函数调用是非常常见的操作。
当一个函数被调用时,所有的局部变量和函数参数将被压入堆栈中,函数执行完毕后再依次通过弹出操作移除。
这种方式保证了函数之间的数据独立性和内存分配的有序性。
2.3 内存管理堆栈也可以用于内存管理。
当程序需要为局部变量分配内存空间时,会通过压栈操作将其保存在堆栈中。
当变量不再需要时,可以通过弹出操作从堆栈中释放内存,从而实现对内存的高效管理。
3. 堆栈的实现方式在计算机中,堆栈可以通过不同的数据结构来实现,比较常见的有数组和链表。
3.1 数组实现使用数组实现堆栈是一种简单且高效的方式。
数组具有随机访问的特性,只需通过指针指向栈顶元素即可。
压入操作只需将元素放置在栈顶指针的下一个位置,而弹出操作则是将栈顶元素移除。
3.2 链表实现链表实现堆栈也是一种常见的方式。
链表中的每个节点都包含一个数据元素和一个指向下一个节点的指针。
一个故事看懂单片机中的堆栈(完整版)因为单片机有CPU、存储器、IO等等,使他(人性化一点以配合下文)看起来就像一个比较小的计算机,所以,在理解单片机的时候如果能把你之前有的那些也许仅仅是直觉上的对计算机的理解融入进来的话,可能会对你学习单片机的概念有极大的帮助,至少对于我是这样的。
我想在关于单片机的众多让你头晕脑胀、摸不着头脑甚至想撞墙的概念里面,“堆栈”可能是其中最可恶的一个,因为即使单单是从汉语的角度来理解这个词就已经让你很晕了,其实我最初也想不通这是哪位大侠的创意,不过不用担心,这里我们完全不去讨论关于这个词的问题(这个词用得其实很好“堆”和“栈”都有他们各自的意思,准确的概括了这个区域的功能,有兴趣可以Baidu一下),这里我会打一个比较有趣的比方,以此来绕过那些令你想撞墙的概念,并使你在直觉上对“堆栈”这个概念有一个深刻的理解。
你基本上应该清楚,单片机里面是有存储区和CPU的,如果你不清楚,那么我刚刚告诉你了,请记住。
现在,请你把单片中的CPU想成一个人(你完全可以把他想成是你宿舍的那个天天和你吵嘴的同学,一会你就会发现这会非常有趣),在这里就叫他C哥吧,不过这个人不同于常人,有一些特点,一会我们会慢慢说清楚,现在要告诉你的关于这个人的第一个特点是:他的记忆能力很差。
下面,请你把存储区想象成一个一个排好的小盒子,这些盒子的作用大致可以分成两类:1、保存写有你命令的纸条,比如你在某个盒子里面的纸条上写着:去洗我的袜子!;2、保存你的一些东西,比如你那双正在污染宿舍空气的臭袜子。
因为C哥是一个记忆力不怎么好的人,所以,这些盒子都有自己的编号,以方便他查找。
那么,现在,我们可以来说明一下单片机是如何工作的了。
首先,你要把所有的命令还有需要处理的东西放进那些小盒子,比如刚才提到的你那双待洗的袜子还有那张纸条,这时你应该发现C哥另一个特点:笨——他只会做你明确告诉他的事情,也就是说,如果你没有在纸条上写“去洗我的袜子!”,那么C哥极有可能会无动于衷地看着你的袜子直到他被熏晕倒,当然,更可能的情况是他根本找不到你的袜子…好了,当你把要做的事情和该怎么做写到盒子里之后,下面的任务就交给C哥了。
详细解析STM32中的堆栈机制
刚拿到STM32时,你只编写一个死循环
编译后,就会发现这幺个程序已用了1600多的RAM,这要是在51单片机上,会心疼死了,这1600多的RAM跑哪儿去了,分析.map文件,你会发现是堆和栈占用的
在startup_stm32f10x_md.s文件中,它的前面几行就有以下定义:
这下明白了吧,STM32在启动的时候,RAM首先分配给使用到的全局变量,还有调用库占用的一些数据(不太清楚是什幺数据),然后再将剩余的空间分配给Heap和Stack。
由于内存空间是启动时实现分配好的,所以当动态分配内存的需求过多的时候,就会产生堆栈空间不足的问题。
查阅网上的资料,理解堆和栈的区别:
- (1)栈区(stack):由编译器自动分配和释放,存放函数的参数值、局部变量的值等,其操作方式类似于数据结构中的栈。