IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> STM32 堆栈溢出检测 -> 正文阅读

[嵌入式]STM32 堆栈溢出检测

前言

在单片机中,栈stack由编译器自动分配释放,用于存放函数调用,局部变量等数据。堆heap用于动态内存分配。堆栈可以在启动文件或者链接脚本中指定大小,但在实际开发中,尤其工程量较大的项目中难以确定堆栈使用量,容易造成堆栈溢出,造成程序崩溃或数据错误。

参考网上的检测方法需要手动告诉检测程序堆栈地址和大小,使用起来不方便,每次堆栈地址或大小改变时都需要修改检测程序。用调试的方式一步一步查看msp寄存器是否溢出需要花费大量时间,而且难以找到堆栈的最高水位。

本文通过C语言使用汇编变量获取堆栈地址和大小,更方便使用。

一、堆栈大小设置

以MDK开发环境为例,堆栈在startup_stm32h743xx.s中设置,Stack_Size和Heap_Size分别表示栈和堆的大小。

Stack_Size		EQU     0x1000

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem       SPACE   Stack_Size
__initial_sp


; <h> Heap Configuration
;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Heap_Size      EQU     0x1000

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit

二、修改汇编文件

在.map文件中搜索heap和stack可以找到堆栈的起始地址和大小。

还可以搜出来其他几个与堆栈有关的变量,这几个变量其实就是在startup_stm32h743xx.s汇编文件中定义的。这些汇编变量的值就是堆栈的起始地址,只要程序可以获取这些值就可以自动获取到堆栈地址。

正常情况下堆栈是连续存放在一起的,因此只需要这三个变量就可以确定堆和栈的起始位置和大小,但对于有多段不连续的内存的单片机来说这三个值无法确定堆的大小,因此还需要修改.s启动文件,增加一个__stack_base变量,并导出变量由C语言调用,修改后的.s启动文件如下。

Stack_Size		EQU     0x1000

                AREA    STACK, NOINIT, READWRITE, ALIGN=3
__stack_base
Stack_Mem       SPACE   Stack_Size
__initial_sp


; <h> Heap Configuration
;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Heap_Size      EQU     0x1000

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit

...

EXPORT  __stack_base
EXPORT  __initial_sp
EXPORT  __heap_base
EXPORT  __heap_limit

...

三、设置和检测堆栈函数

?在C语言中使用汇编变量首先需要声明变量,获取汇编变量的值需要使用取址符。

extern int __initial_sp;
extern int __stack_base;
extern int __heap_base;
extern int __heap_limit;

在单片机启动时在堆栈剩余空间内填充幻数,需要检测堆栈时再检测这些幻数即可得到堆栈使用情况。栈填充幻数和检测幻数的代码如下,其中调用__get_MSP()获取当前msp寄存器的值。下面代码以检测栈为例,检测堆的代码类似。

const int s_magic = 0x43218765;
const int h_magic = 0x56781234;

int stack_set_guard(void)
{
		__disable_irq();
	
		int* msp = (int *)__get_MSP();
		int* base = &__stack_base;

		if(msp < base) {
				__enable_irq();
				return -1;
		}
				
	
		for( ; base != msp; base++)
				*base = s_magic;
		
		__enable_irq();
		
		return (uint32_t)msp - (uint32_t)&__stack_base;
}

int stack_detect_guard(void)
{
		__disable_irq();
	
		int* msp = (int *)__get_MSP();
		int* base = &__stack_base;

		if(msp < base || *base != s_magic) {
				__enable_irq();
				return -1;
		}
	
		for( ; base != msp; base++) {
				if(*base != s_magic)
						break;
		}
		
		__enable_irq();
		
		return (uint32_t)base - (uint32_t)&__stack_base;
}


四、使用范例

首先在主函数开始时调用堆设置幻数函数,将堆中目前未使用部分进行标记,接着在合适的位置调用堆检测函数检测幻数,返回栈历史高水位时堆剩余大小,若返回值为-1则说明发生栈溢出。也可在单个函数前后分别调用设置和检测函数,检测单个函数(包括其中的函数调用)的堆使用量。完整示例可以下载

int main(void)
{
	int ret = stack_set_guard();
	
    /* 初始化 */
    ...

    /* 调用一些函数 */
    ...

    /* 检测单个函数栈使用量 */
    ret = stack_set_guard();
    xxx_func();
    ret = stack_detect_guard() - ret;

    while (1)
    {
        /* 调用一些函数 */
        ...
    	ret = stack_detect_guard();
	    printf("stack_detect_guard %d\r\n", ret);
    }

}

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-22 14:21:29  更:2021-07-22 14:21:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/7 23:54:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码