关于STM32堆栈指针获取及溢出检测

1.堆栈的使用:

在MCU中,栈空间由编译器自动分配释放,存放函数的参数值,局部变量的值等。在函数中定义的局变量占用栈空间,当数据较多,栈空间使用完,则会占用堆空间,甚至其他全局变量空间,造成程序崩溃或数据错误。

2.堆栈大小的分配:

STM32F1属于ARM Cortex-M3内核,在Keil(MDK)开发环境中,工程中必须包含一个startup_stm32f10x_hd.s的启动文件,启动文件中最前面一段声明了堆(heap)和栈(stack)的大小。

Stack_Size      EQU     0x00001000 ;声明栈的大小为 4KB

                AREA    STACK, NOINIT, READWRITE, ALIGN=3 
                ;声明一个名为STACK的段,未初始化,可读写,8字节对齐
Stack_Mem       SPACE   Stack_Size
__initial_sp    ;栈顶指针(地址值最大)


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

Heap_Size       EQU     0x00000200;声明栈的大小为 512 Byte
                ;声明一个名为STACK的段,未初始化,可读写,8字节对齐
                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base    ;堆起始地址
Heap_Mem        SPACE   Heap_Size
__heap_limit   ;堆结束地址(值大于起始地址)

3.栈顶地址的获取:

由于程序往往会不断修改,全局变量时多时少,所以编译完的程序的栈顶指针也是在不断变化的。

方法一:对于Cortex-M3核,在内存地址为0x00000000的地址存储着栈顶的地址。

方法二:在程序复位还未运行时,在register窗口看到的 R13(SP) 或 MSP 的内容。(注:在没有使用RTOS的时候,MSP 和 SP值相同,使用一个栈指针MSP,当使用RTOS时,main函数还是用MSP,task使用PSP)

方法三:在map文件中搜索" __initial_sp "同样也可以看到栈顶地址(例" 

 Symbol Name                              Value     Ov Type        Size  Object(Section)

  __initial_sp                             0x20002368   Data           0  startup_stm32f10x_md.o(STACK)"

这里的0x20002368 即为栈顶地址)。

4.运行中栈指针的获取:

方法一:在需要观察栈指针的位置连上仿真器打断点(一般在函数调用的层次最多的地方),然后观察register窗口中MSP的值(register 窗口中的值不会即时刷新,当打断点停止运行时才会更新)。(注:需要注意当前程序打断点是否会造成具有破坏性的后果)

方法二:使用core_m3.c中的函数__ASM uint32_t __get_MSP(void)获取当前的MSP寄存器的栈地址,函数的返回值即为当前栈指针。函数中第一句汇编 mrs r0, msp 表示将msp寄存器值装载进R0寄存器(这里用作保存返回值的寄存器),bx lr 表示函数返回。

/**
 * @brief  Return the Main Stack Pointer
 *
 * @return Main Stack Pointer
 *
 * Return the current value of the MSP (main stack pointer)
 * Cortex processor register
 */
__ASM uint32_t __get_MSP(void)
{
  mrs r0, msp 
  bx lr
}

5. 堆栈溢出判断:

堆栈溢出可能会出现无法解释的莫名其妙的现象。所以一定要防止堆栈溢出。现在可以通过堆栈指针来判断是否溢出。

判断方法:根据第3部分我们得到了堆栈指针,而根据第2部分我们可以获取到我们设置的栈的大小,栈底地址 = 栈顶地址 - 栈大小,当通过第4部分获取到的栈指针小于栈底地址,可以确定为堆栈溢出,这时可以根据程序的情况适当加大栈空间大小。(例,栈顶地址0x20002368,栈大小设置 0x1000,则栈底地址0x20001368,当栈指针小于0x20001368 的时候说明堆栈溢出,你的函数中的局部变量写入堆空间甚至覆盖了全局变量的值)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值