0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Embedded Studio堆栈溢出预防简析

麦克泰技术 来源:麦克泰技术 2023-07-14 11:07 次阅读

为了识别运行的嵌入式系统中的堆栈溢出问题,SEGGER编译器通过为每个函数生成检测代码的方式来检查堆栈溢出。该功能可以使用命令行开关-mstack-overflow-check来使能。对于安全系统,必须在溢出的堆栈破坏内存之前检测到堆栈溢出,因此需要在更改堆栈指针和需大量堆栈空间之前进行检查。

一,Embedded Studio的堆栈溢出预防

在Embedded Studio中启用堆栈溢出预防功能,仅需将工程选项Code->Code Generation->Enable Stack Overflow Prevention设置为“Yes”。

如果工程中没有实现错误回调函数__SEGGER_STOP_X_OnError,它默认保持在一个无限循环中。Embedded Studio安装目录$(StudioDir)/samples下的SEGGER_STOP.c中包含一个错误处理的示例实现。

二,编译器生成的代码

如果在编译器中使能堆栈溢出检查,生成的代码将被改变,如下所示:

1、不使用堆栈的函数不会被更改。

2、使用本地堆栈帧但不使用R3传递参数的函数中:堆栈帧的设置(通常使用sub sp, #size指令)被替换为将所需栈大小加载到寄存器R3中,然后调用函数__SEGGER_STOP_GROW_R3()。

3、使用本地堆栈帧并使用R3传递参数的函数中,操作与2相同,但是使用寄存器R4传值,并调用函数__SEGGER_STOP_GROW_R4()。这意味着,R4必须在进入函数时必须入栈。

4、不使用本地堆栈但需在堆栈中保存寄存器的函数中,在寄存器压栈后将调用不带参数的函数__SEGGER_STOP_GROW_0()。

5、需要动态分配堆栈的函数(如使用alloc()函数或可变大小的数组),编译后代码也将调用__SEGGER_STOP_GROW_R3()。因为分配可能发生在函数执行中,需指示寄存器分配器,确保R3可以使用。

然后,被调用的函数可以使用存储在全局变量中的堆栈上限值检查堆栈是否溢出。检查函数将在需要保存的寄存器被压栈后调用。因此,必须计算堆栈上限,以便始终有栈空间用于:

在函数入口处,入栈所有的通用寄存器(R0 - R11, LR),有一些优化可能导致R0 - R3入栈。

所有被调用者需保存的浮点/矢量寄存器(D8 - D15)

中断入口需保存的寄存器 (8个字)

3个(备用)字用于对齐和紧急溢出缓存

可以使用__attribute__((no_stack_overflow_check))禁止生成单个函数的堆栈检查代码。

三、堆栈检查和错误处理

启用“防止堆栈溢出”功能时,必须实现下列堆栈检查函数。在Embedded Studio中,这些函数已添加到标准库中。

__SEGGER_STOP_GROW_R3

__SEGGER_STOP_GROW_R4

__SEGGER_STOP_GROW_0

堆栈溢出时,堆栈检查函数应该跳转到用户提供的错误处理回调函数__SEGGER_STOP_X_OnError()。

堆栈检查函数

编译器生成的代码调用检查函数检查剩余的堆栈大小,在堆栈溢出的情况下函数不能返回。为了提高效率,这些函数没有遵循标准调用约定。因此,函数不能修改除了R12和包含堆栈大小参数的寄存器之外的任何寄存器,函数在返回之前还必须调整堆栈指针。

错误处理回调

为了确保错误处理回调不使用溢出堆栈,它应该在纯汇编中实现,并且在禁用堆栈溢出检查功能状态下进行编译。

在默认实现中,__SEGGER_STOP_X_OnError定义为:

__attribute__((naked, no_stack_overflow_check)) void __SEGGER_STOP_X_OnError(void);

它在堆栈检查函数尾部调用,不遵循常规调用约定。堆栈上限值、新的堆栈指针值和调用者通过R3、R12和LR传递。

错误处理回调可能会将溢出堆栈重置为安全值。同时,它可能会调用其他函数,比如记录错误和重置系统。

示例:

void __SEGGER_STOP_X_OnError(void) {
  asm(
      "cpsid i
"                       // Disable interrupts
      "mov     r0, r12
"               // Save overflowed SP
      "mov     r1, r3
"                // Save SP limit
      "sub     r2, lr, #5
"            // Save caller
      "mrs     r3, CONTROL
"           // Get currently used stack
      "lsls    r3, #30
"
      "ittee   pl
"                    // Reset this stack
      "ldrpl   r12, =__stack_end__
"
      "msrpl   msp, r12
"
      "ldrmi   r12, =__stack_process_end__
"
      "msrmi   psp, r12
"
      "bl _HandleStackError
"            // Call error handler
      "b .
"                             // Stay here
      );
}

四、堆栈上限

启动代码必须初始化堆栈上限,至少初始化主堆栈上限变量__SEGGER_STOP_Limit_MSP。在默认实现中,该符号由运行时初始化代码自动初始化为默认值。

为了调整上限值,例如改变为保存寄存器保留的空间,以及初始化__SEGGER_STOP_Limit_PSP,应该实现并调用__SEGGER_STOP_X_InitLimits。

使用SEGGER链接器,运行时初始化代码将自动调用__SEGGER_STOP_X_InitLimits:

initialize bycalling __SEGGER_STOP_X_InitLimits { section .data.stop.* };

使用GNU链接器时,应该在main中的开始位置调用__SEGGER_STOP_X_InitLimits

int main(void) {
  int NumItems;
 
 #if !defined (__SEGGER_LINKER)
  //
  // Optionally initialize stack limits if not done by runtime init.
  //
  __SEGGER_STOP_X_InitLimits();
 #endif
 ...
}

在运行初始化之前调用函数

当系统在运行初始化之前调用函数时,Cortex-M上默认在Reset_Handler中调用SystemInit, __SEGGER_STOP_Limit_MSP应设置为0,以禁用堆栈检查。

Reset_Handler:
    .extern __SEGGER_STOP_Limit_MSP
    //
    // Initialize main stack limit to 0 to disable stack checks before runtime init
    //
    movs  R0, #0
    ldr   R1, =__SEGGER_STOP_Limit_MSP
    str   R0, [R1]
    //
    // Call SystemInit
    //
    bl   SystemInit
    ...

使用RTOS

当使用RTOS或其他多任务机制时,任务切换程序必须在切换堆栈时更新堆栈上限变量(通常为__SEGGER_STOP_Limit_PSP)。

ChangeTask:
  ...
  ldr   r0, [r1, #0]  // OS.pCurTask
  ldr   r3, [r0, #8]  // OS.pCurTask->pStackBottom
  add   r3, #100    // Buffer before stack overflow
  ldr   r2, =__SEGGER_STOP_Limit_PSP
  str   r3, [r2]    // Update stack limit
   ...

建议对所有任务启用堆栈检查。RTOS可以通过将limit变量设置为0来禁用某些任务的堆栈检查。

堆栈溢出几乎在每个系统中都可能遇到。Embedded Studio提供了使用示例,展示简单系统和多任务系统的堆栈溢出行为及处理。





审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 寄存器
    +关注

    关注

    30

    文章

    5031

    浏览量

    117736
  • RTOS
    +关注

    关注

    20

    文章

    776

    浏览量

    118796
  • 编译器
    +关注

    关注

    1

    文章

    1577

    浏览量

    48618
  • 缓存器
    +关注

    关注

    0

    文章

    63

    浏览量

    11579
收藏 人收藏

    评论

    相关推荐

    Embedded Studio堆栈溢出预防功能

    为了识别运行的嵌入式系统中的堆栈溢出问题,SEGGER编译器通过为每个函数生成检测代码的方式来检查堆栈溢出。该功能可以使用命令行开关-mstack-overflow-check来使能。
    发表于 07-14 11:08 395次阅读

    什么是堆栈溢出?如何分配堆栈空间大小?

    前些日子bug交流群里的小哥调试了一个堆栈溢出的bug,动不动数据就被篡改了,应该也是搞得焦头烂额,头皮发麻!当时bug菌看了下,于是抛出了自己的一些调试经验,一般这样的问题80%是越界和堆栈
    的头像 发表于 11-08 09:52 1655次阅读
    什么是<b class='flag-5'>堆栈</b><b class='flag-5'>溢出</b>?如何分配<b class='flag-5'>堆栈</b>空间大小?

    TLE9893如何配置堆栈溢出检测?

    我需要了解如何配置堆栈溢出检测。 我从 TLE9893 用户手册中收集到的 需要启用用户堆栈溢出保护 (USOP), 需要通过上限和下限 DSRAM 地址来建立所谓的保护频段。 我
    发表于 01-19 06:11

    freertos与STM32如何分配堆栈空间

    freertos与STM32分栈、堆、全局区、常量区、代码区、RAM、ROM,及如何分配堆栈空间基于STM32分栈、堆、全局区、常量区、代码区、RAM、ROM FreeRTOS任务栈大小确定及其
    发表于 08-03 06:36

    了解堆栈分配避免堆栈溢出环境

    一、通过map文件了解堆栈分配(STM32、MDK5)--避免堆栈溢出环境:STM32F103C8T6,MDK5在最近的一个项目的开发中,每当调用到一个函数,程序就直接跑飞。debug跟进去
    发表于 08-24 07:26

    FreeRTOS中的任务堆栈溢出检测机制

    在FreeRTOS中,每个任务都拥有自己的堆栈,该堆栈的大小由创建任务时xTaskCreate函数的函数参数所决定。但当任务所使用的堆栈空间超出分配给它的空间时,则会发生堆栈
    发表于 10-15 13:51

    如何在Embedded Studio中使用RTT?

    Embedded Studio是SEGGER微控制器的多平台IDE,包含了专业嵌入式C和C++编程和开发所需的所有工具和功能。结合基于Clang、高度优化的C/C++ SEGGER编译器,可以生成
    发表于 02-17 14:25

    SEGGER Embedded Studio下载激活

    先楫半导体非常nice的是,他们和SEGGER达成了合作,可以让开发者免费使用SEGGER Embedded Studio,包括商用哦。 1.SEGGER Embedded Studio
    发表于 05-25 16:23

    在SEGGER Embedded Studio对E203使用NMSIS DSP报错,Embedded Studio应该如何配置?

    模仿embedded_studio_project中dsp_demo中的配置,希望在Embedded Studio中也使用Hbird SDK中的DSP库 但是最后会报这样的错误,好像是因为DSP
    发表于 08-12 06:02

    MSP430 C语言编程的程序堆栈溢出分析

    MSP430 C语言编程的程序堆栈溢出分析
    发表于 05-16 15:04 40次下载

    网络安全中的堆栈溢出技术解析

    网络安全日益为人们所重视,其关键就是缓冲溢出问题,几乎所有的操作系统都避免不了缓冲溢出漏洞的威胁。网络安全中的堆栈溢出技术是一种含量较高的计算机技术。本文用
    发表于 08-26 10:46 14次下载

    cad堆栈溢出的原因及解决方式

    近期有用户反馈在打开AutoCad 2007的时候频繁出现卡死的情况,并提示还提示0x00000FD堆栈溢出,重启电脑和重装软件都无法解决。针对该问题小编整理了一些方法供大家参考。
    发表于 11-28 14:19 2.6w次阅读
    cad<b class='flag-5'>堆栈</b><b class='flag-5'>溢出</b>的原因及解决方式

    关于堆栈溢出技术你知道多少?

    虽然溢出在程序开发过程中不可完全避免,但溢出对系统的威胁是巨大的,由于系统的特殊性,溢出发生时攻击者可以利用其漏洞来获取系统的高级权限root,因此本文将详细介绍堆栈
    的头像 发表于 07-04 16:42 6046次阅读

    CrossCore Embedded Studio集成开发环境的介绍

    这是新的CrossCore® Embedded Studio (CCES)集成开发的简要说明。CrossCore® Embedded Studio是针对ADI公司Blackfin®和S
    的头像 发表于 07-10 06:08 3457次阅读

    STM32 堆栈溢出检测

    释放,存放函数调用,局部变量等数据。堆heap用于动态内存分配。堆栈可以在启动文件或者链接脚本中指定大小,但在实际开发中,尤其工程量较大的项目中难以确定堆栈使用量,容易造成堆栈溢出,造
    发表于 12-27 18:32 22次下载
    STM32 <b class='flag-5'>堆栈</b><b class='flag-5'>溢出</b>检测