STM32 堆栈空间分布
参考
- 运行时访问
__initial_sp
和__heap_base
无RTOS时的情况
在以上配置的情况下,生成工程。在工程的startup.s
文件中,由如下代码:
Stack_Size EQU 0x400AREA STACK, NOINIT, READWRITE, ALIGN=3
__Stack_top ; 自己添加
Stack_Mem SPACE Stack_Size
__initial_spIF :DEF:__MICROLIB EXPORT __initial_spEXPORT __heap_baseEXPORT __heap_limitEXPORT __Stack_top ; 自己添加
ELSEIMPORT __use_two_region_memoryEXPORT __user_initial_stackheap
__user_initial_stackheapLDR R0, = Heap_MemLDR R1, =(Stack_Mem + Stack_Size)LDR R2, = (Heap_Mem + Heap_Size)LDR R3, = Stack_MemBX LRALIGN
ENDIF
通过以上代码可以看出,需要使能MicroLib
才会默认导出__initial_sp
,__Stack_top
,__heap_base
,__heap_limit
这几个变量。(如果不使能MicroLib
,则需要在上面代码的ELSE
下面也添加EXPORT
语句将这几个变量导出)。
然后在main.c
中添加如下代码,查看以上这些变量的值:
extern uint32_t __heap_base, __heap_limit;extern uint32_t __Stack_top, __initial_sp;extern uint32_t __Vectors, __Vectors_End, __Vectors_Size;while (1){// 0x200013A8 ~ 0x200015A8 size:0x200 RAMprintf("heapS[0x%08x], heapE[0x%08x]\r\n", (uint32_t)&__heap_base, (uint32_t)&__heap_limit);// 0x200019A8 ~ 0x200015A8 size:0x400 RAMprintf("stackS[0x%08x], stackE[0x%08x]\r\n", (uint32_t)&__initial_sp, (uint32_t)&__Stack_top); // 0x08000000 ~ 0x080000EC ROMprintf("VectS[0x%08x], VectE[0x%08x], VectSize[0x%x]\r\n\r\n", (uint32_t)&__Vectors, (uint32_t)&__Vectors_End, (uint32_t)&__Vectors_Size);}
从上可以看到,__Stack_top
和__heap_limit
是一样的,说明这里分配的堆和栈是紧邻的。而且地址刚好也和我们在cubeMx
中定义的一致。堆和栈是在RAM
中,而中断向量表是在Flash
中。
添加FreeRTOS
从以上三张图中,可以发现,我们给FreeRTOS总共分配了3072(0xC00) Bytes HEAP
空间。而我们定义了一个defaultTask
并分配了256 * 4 = 1024 Bytes
,但是在最后的FreeRTOS Heap Usage
页面看到,defaultTask
实际使用了1144 Bytes
,剩余3072 - 1144 = 1928 Bytes
。(除了defaultTask
多使用的1144 - 1024 = 120 Bytes
(用于任务控制块TCB
)外,其余都是可以对上的。)
生成工程后,我们还是将之前的那些堆栈指针地址打印出来,看一下MCU是如何进行地址分配的。只是这里还需要添加FreeRTOS
中的堆栈信息了。首先通过追踪configTOTAL_HEAP_SIZE
可以发现,堆空间定义为了一个数组:
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];uint8_t* osHeapPoint = ucHeap; // 由于以上变量是 static 类型,所有这里再定义一个指针指向这个 Heap 地址,以便在外部访问它;
然后我们就可以在defaultTask
任务里面添加输出以上变量地址的代码了:
extern uint32_t __heap_base, __heap_limit;extern uint32_t __Stack_top, __initial_sp;extern uint32_t __Vectors, __Vectors_End, __Vectors_Size;extern uint8_t* osHeapPoint;extern uint32_t local_addr1, local_addr2;void* os_mal_buf = malloc(50);uint32_t tast_local_val = 1;for(;;) {// 0x20002D10 ~ 0x20002F10 size:0x200 RAMprintf("HeapS[0x%08x], HeapE[0x%08x]\r\n", (uint32_t)&__heap_base, (uint32_t)&__heap_limit);// 0x20003310 ~ 0x20002F10 size:0x400 RAMprintf("StackS[0x%08x], StackE[0x%08x]\r\n", (uint32_t)&__initial_sp, (uint32_t)&__Stack_top); // // 0x08000000 ~ 0x080000EC ROMprintf("VectS[0x%08x], VectE[0x%08x], VectSize[0x%x]\r\n", (uint32_t)&__Vectors, (uint32_t)&__Vectors_End, (uint32_t)&__Vectors_Size); // 中断向量表// 0x20002110 size: 3072 Bytes(0xC00)printf("OsHeapPoint[0x%08x]\r\n", (uint32_t)osHeapPoint); // freeRTOS中定义的HEAP数组// 0x20002D18printf("Os_mal_buf[0x%08x]\r\n", (uint32_t)os_mal_buf);// 0x20002504printf("&Os_mal_buf[0x%08x]\r\n", (uint32_t)&os_mal_buf);// 0x20002508printf((char*)buf, "&tast_local_val[0x%08x]\r\n\r\n", (uint32_t)&tast_local_val); // 在freeRTOS任务中定义的局部变量// 0x20000008, 0x2000000Cprintf("&global_var1[0x%08x], &global_var2[0x%08x]\r\n", (uint32_t)&global_var1, (uint32_t)&global_var2); // 函数外部定义的全局变量// 0x20003304, 0x20003308printf("local_addr1[0x%08x], local_addr2[0x%08x]\r\n\r\n", local_addr1, local_addr2); // 这两个全局变量保存了在freeRTOS初始化前,在main()函数中定义的两个局部变量的地址}
根据以上输出总结如下:
- 从
local_addr
的地址(靠近__initial_sp
)可以看出,栈空间的地址值是向下增长的,即栈顶(__initial_sp = 0x20003310
)在高地址; - 从全局变量的地址可以看出,全局变量是默认分配在
RAM
的起始地址; - 在
freeRTOS
任务中定义的局部变量(&tast_local_val = 0x20002508
)存储在定义freeRTOS
时定义的HEAP
里(0x20002110~0x20002D10
); - 再看一下
&tast_local_val = 0x20002508
这个数据,发现0x20002508
大概等于0x20002110 + 256*4 = 0x20002510
。这就再次说明,freeRTOS
定义任务时,是从配置好的HEAP
地址初始空间的开始部分给新任务分配Task stack
的,而在任务中使用这个task stack
时,还是符合栈的使用规范(即从高地址开始分配); - 从
s_mal_buf = 0x20002D18
可以知道,即使在freeRTOS
任务中动态分配,也是在任务之外的堆中分配空间。
疑问
- 通过以上总结,发现在
freeRTOS
任务中定义局部变量和在freeRTOS
任务之外定义局部变量,他们分配的地址空间是不一样的。那么,如果有以下函数:
void addr_test(void)
{uint32_t loc_var = 1;printf("&loc_var = 0x%08x\r\n", (uint32_t)&loc_var);
}
我分别在freeRTOS
初始化之前调用,以及在freeRTOS
的任务中调用,其输出会是什么呢?
经过验证,在freeRTOS
初始化之前调用,输出的地址范围在0x20002F10 - 0x20003310
之间;而在freeRTOS
的任务中调用,输出的地址范围在0x20002110 - 0x20002D10
之间。
相关文章:

STM32 堆栈空间分布
参考 运行时访问__initial_sp和__heap_base 无RTOS时的情况 在以上配置的情况下,生成工程。在工程的startup.s文件中,由如下代码: Stack_Size EQU 0x400AREA STACK, NOINIT, READWRITE, ALIGN3 __Stack_top ; 自己添加 Stack_Mem…...

小程序制作(超详解!!!)第十五节 自动随机变化的三色旗
1.例题描述 设计一个小程序,开始时界面上显示一个三色旗和一个按钮,当点击按钮时,三色旗的颜色会发生随机变化,即使不点击按钮,三色旗的颜色也会每隔一定时间自动发生变化。 2.index.wxml <view class"box&…...
MySQL_主从复制_环境搭建
MySQL主从复制配置 CentOS 7 配置 阿里云 yum 源 sudo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup sudo wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo sudo yum clean all sudo yum makeca…...

Linux 设置静态IP(Ubuntu 20.04/18.04)
以Ubuntu20.04示例 第一步:查看当前网络信息 ifconfig 本机网卡名为:ens32,IP地址为:192.168.15.133,子网掩码为:255.255.255.0 第二步:查看当前网关信息 route -n 网关地址为:1…...

计网----累积应答,TCP的流量控制--滑动窗口,粘包问题,心跳机制,Nagle算法,拥塞控制,TCP协议总结,UDP和TCP对比,中介者模式
计网----累积应答,TCP的流量控制–滑动窗口,粘包问题,心跳机制,Nagle算法,拥塞控制,TCP协议总结,UDP和TCP对比,中介者模式 一.累积应答 1.什么是累计应答 每次发一些包࿰…...
OpenCV 直方图和归一化
直方图可以反映图片的整体统计信息, 使用函数 CalcHist() 实现. 但CalcHist() 统计出的数量信息和图像大小相关, 如果要剔除图像大小因素, 需要做归一化处理, 归一化处理后的信息, 反映出各个颜色值得占比情况, 这样更方便不同size图像做对比, 归一化的函数为 Normalize(). ///…...

Flink架构
1、Apache Flink集群的核心架构: 1、client(作业客户端):提交任务的地方叫做客户端 2、JobManager(作业管理器):作用是用于管理集群中任务 3、TaskManager(任务管理器)&a…...
Packet Tracer路由器连接终端设备怎么配置?
在Packet Tracer中配置一台路由器和三台终端设备可以帮助你建立一个简单的局域网,以下是配置的基本步骤: 打开Packet Tracer,从左侧设备栏中拖拽一个路由器和三个终端设备到工作区。 连接设备:使用网线将路由器的端口与每台终端设…...

评估APP网页小程序代码UI开发H5估价师怎么评估开发精确研发价格?
作为一名应用程序开发评估师,可能涉及到的主要任务是为特定的应用程序提供估算开发成本和所需时间预测。为了为一个应用程序更准确地评估价格,须遵循以下几个步骤: 问: 如何让一个App更好、更精确地评估出价格? 答: 以下是一个可…...

16 Linux 内核定时器
一、Linux 时间管理和内核定时器简介 1. 内核时间管理简介 Linux 内核中有大量的函数需要时间管理,比如周期性的调度程序、延时程序、定时器等。 硬件定时器提供时钟源,时钟源的频率可以设置,设置好以后就周期性的产生定时中断,系…...
C++11 shared_ptr类型智能指针学习
智能指针和普通指针的用法类似,但是智能指针可以在适当时机自动释放分配的内存。 C++11有三种类型的智能指针,shared_ptr、unique_ptr 以及 weak_ptr; 先学习shared_ptr类型; shared_ptr<T> 的定义位于<memory>头文件,并位于 std 命名空间中; T 表示指针指…...

网络流量分类概述
1. 什么是网络流量? 一条网络流量是指在一段特定的时间间隔之内,通过网络中某一个观测点的所有具有相同五元组(源IP地址、目的IP地址、传输层协议、源端口和目的端口)的分组的集合。 比如(10.134.113.77,47.98.43.47,TLSv1.2&…...
JavaWeb篇_02——服务器简介及Tomcat服务器简介
服务器简介 硬件服务器的构成与一般的PC比较相似,但是服务器在稳定性、安全性、性能等方面都要求更高,因为CPU、芯片组、内存、磁盘系统、网络等硬件和普通PC有所不同。软件服务器(英文名称Server),也称伺服器。指一个…...
2311d游戏引擎适配ios
原文 通过遵循arsd:simpledisplay(v11.0.0之前)上的一些旧代码,Apple的文档和Jacob的这一惊人贡献桥, 我已从金属绑定中删除了所有extern(Objective-C)代码,现在,所有Objective-C桥接代码都是使用D的反射生成的. 因此,给定此例代码: import core.attribute : selector; extern…...

网络唤醒(Wake-on-LAN, WOL)
远程唤醒最简单的方法:DDNSTOOpenwrt网络唤醒,完美实现。 原帖-远程唤醒_超详细windows设置远程唤醒wol远程连接(远程开机) WOL Web# 访问 Wake on Lan Over The Interweb by Depicus 可以无需借助软件很方便的从网页前端唤醒远…...

接口测试框架实战(一) | Requests 与接口请求构造
Requests 是一个优雅而简单的 Python HTTP 库,其实 Python 内置了用于访问网络的资源模块,比如urllib,但是它远不如 Requests 简单优雅,而且缺少了许多实用功能。所以,更推荐掌握 Requests 接口测试实战技能࿰…...

【C++】详解 void*
文章目录 1. void *是什么?2. void*详解3. 和void的区别4. 应用场景4.1 函数传参时不确定类型,或者要支持多类型的传参;4.2 当函数的返回值不考虑类型指关心大小的时候 5. 总结 今天看到一段代码,觉得非常有意思。 void* say_hell…...
Linux家目录变成了-bash-4.2$
Linux家目录变成了-bash-4.2$ Mark a workarround: 使用root用户,执行cp -a /etc/skel/. /home/zookeeper/(不是root用户也可以) 其中/home/zookeeper/目录是对应自己的家目录地址~ 若有帮到你,记得点赞,收藏呀…...
Python和SQLite游标处理多行数据
如果您需要处理多行数据,使用游标或其他适当的方法是更好的选择。以下是一些处理多行数据的方法: 使用游标:游标可以逐行处理查询结果,这对于大量数据或需要逐行处理的场景非常有用。以下是一个使用Python和SQLite的游标示例&…...
安全测试之PHP 漏洞全解
PHP 漏洞全解(一)-PHP的攻击方式 针对 PHP 的网站主要存在下面几种攻击方式: 1、命令注入(Command Injection) 2、eval 注入(Eval Injection) 3、客户端脚本攻击(Script Insertion) 4、跨网站脚本攻击(Cross Site Scripting, XSS) 5、SQL 注入攻击(SQL injection) 6、跨网站…...

uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...

mac:大模型系列测试
0 MAC 前几天经过学生优惠以及国补17K入手了mac studio,然后这两天亲自测试其模型行运用能力如何,是否支持微调、推理速度等能力。下面进入正文。 1 mac 与 unsloth 按照下面的进行安装以及测试,是可以跑通文章里面的代码。训练速度也是很快的。 注意…...
TJCTF 2025
还以为是天津的。这个比较容易,虽然绕了点弯,可还是把CP AK了,不过我会的别人也会,还是没啥名次。记录一下吧。 Crypto bacon-bits with open(flag.txt) as f: flag f.read().strip() with open(text.txt) as t: text t.read…...

Appium下载安装配置保姆教程(图文详解)
目录 一、Appium软件介绍 1.特点 2.工作原理 3.应用场景 二、环境准备 安装 Node.js 安装 Appium 安装 JDK 安装 Android SDK 安装Python及依赖包 三、安装教程 1.Node.js安装 1.1.下载Node 1.2.安装程序 1.3.配置npm仓储和缓存 1.4. 配置环境 1.5.测试Node.j…...