0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Embedded Studio堆棧溢出預(yù)防簡析

麥克泰技術(shù) ? 來源:麥克泰技術(shù) ? 2023-07-14 11:07 ? 次閱讀

為了識(shí)別運(yùn)行的嵌入式系統(tǒng)中的堆棧溢出問題,SEGGER編譯器通過為每個(gè)函數(shù)生成檢測(cè)代碼的方式來檢查堆棧溢出。該功能可以使用命令行開關(guān)-mstack-overflow-check來使能。對(duì)于安全系統(tǒng),必須在溢出的堆棧破壞內(nèi)存之前檢測(cè)到堆棧溢出,因此需要在更改堆棧指針和需大量堆??臻g之前進(jìn)行檢查。

一,Embedded Studio的堆棧溢出預(yù)防

在Embedded Studio中啟用堆棧溢出預(yù)防功能,僅需將工程選項(xiàng)Code->Code Generation->Enable Stack Overflow Prevention設(shè)置為“Yes”。

如果工程中沒有實(shí)現(xiàn)錯(cuò)誤回調(diào)函數(shù)__SEGGER_STOP_X_OnError,它默認(rèn)保持在一個(gè)無限循環(huán)中。Embedded Studio安裝目錄$(StudioDir)/samples下的SEGGER_STOP.c中包含一個(gè)錯(cuò)誤處理的示例實(shí)現(xiàn)。

二,編譯器生成的代碼

如果在編譯器中使能堆棧溢出檢查,生成的代碼將被改變,如下所示:

1、不使用堆棧的函數(shù)不會(huì)被更改。

2、使用本地堆棧幀但不使用R3傳遞參數(shù)的函數(shù)中:堆棧幀的設(shè)置(通常使用sub sp, #size指令)被替換為將所需棧大小加載到寄存器R3中,然后調(diào)用函數(shù)__SEGGER_STOP_GROW_R3()。

3、使用本地堆棧幀并使用R3傳遞參數(shù)的函數(shù)中,操作與2相同,但是使用寄存器R4傳值,并調(diào)用函數(shù)__SEGGER_STOP_GROW_R4()。這意味著,R4必須在進(jìn)入函數(shù)時(shí)必須入棧。

4、不使用本地堆棧但需在堆棧中保存寄存器的函數(shù)中,在寄存器壓棧后將調(diào)用不帶參數(shù)的函數(shù)__SEGGER_STOP_GROW_0()。

5、需要?jiǎng)討B(tài)分配堆棧的函數(shù)(如使用alloc()函數(shù)或可變大小的數(shù)組),編譯后代碼也將調(diào)用__SEGGER_STOP_GROW_R3()。因?yàn)榉峙淇赡馨l(fā)生在函數(shù)執(zhí)行中,需指示寄存器分配器,確保R3可以使用。

然后,被調(diào)用的函數(shù)可以使用存儲(chǔ)在全局變量中的堆棧上限值檢查堆棧是否溢出。檢查函數(shù)將在需要保存的寄存器被壓棧后調(diào)用。因此,必須計(jì)算堆棧上限,以便始終有??臻g用于:

在函數(shù)入口處,入棧所有的通用寄存器(R0 - R11, LR),有一些優(yōu)化可能導(dǎo)致R0 - R3入棧。

所有被調(diào)用者需保存的浮點(diǎn)/矢量寄存器(D8 - D15)

中斷入口需保存的寄存器 (8個(gè)字)

3個(gè)(備用)字用于對(duì)齊和緊急溢出緩存

可以使用__attribute__((no_stack_overflow_check))禁止生成單個(gè)函數(shù)的堆棧檢查代碼。

三、堆棧檢查和錯(cuò)誤處理

啟用“防止堆棧溢出”功能時(shí),必須實(shí)現(xiàn)下列堆棧檢查函數(shù)。在Embedded Studio中,這些函數(shù)已添加到標(biāo)準(zhǔn)庫中。

__SEGGER_STOP_GROW_R3

__SEGGER_STOP_GROW_R4

__SEGGER_STOP_GROW_0

堆棧溢出時(shí),堆棧檢查函數(shù)應(yīng)該跳轉(zhuǎn)到用戶提供的錯(cuò)誤處理回調(diào)函數(shù)__SEGGER_STOP_X_OnError()。

堆棧檢查函數(shù)

編譯器生成的代碼調(diào)用檢查函數(shù)檢查剩余的堆棧大小,在堆棧溢出的情況下函數(shù)不能返回。為了提高效率,這些函數(shù)沒有遵循標(biāo)準(zhǔn)調(diào)用約定。因此,函數(shù)不能修改除了R12和包含堆棧大小參數(shù)的寄存器之外的任何寄存器,函數(shù)在返回之前還必須調(diào)整堆棧指針。

錯(cuò)誤處理回調(diào)

為了確保錯(cuò)誤處理回調(diào)不使用溢出堆棧,它應(yīng)該在純匯編中實(shí)現(xiàn),并且在禁用堆棧溢出檢查功能狀態(tài)下進(jìn)行編譯。

在默認(rèn)實(shí)現(xiàn)中,__SEGGER_STOP_X_OnError定義為:

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

它在堆棧檢查函數(shù)尾部調(diào)用,不遵循常規(guī)調(diào)用約定。堆棧上限值、新的堆棧指針值和調(diào)用者通過R3、R12和LR傳遞。

錯(cuò)誤處理回調(diào)可能會(huì)將溢出堆棧重置為安全值。同時(shí),它可能會(huì)調(diào)用其他函數(shù),比如記錄錯(cuò)誤和重置系統(tǒng)。

示例:

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
      );
}

四、堆棧上限

啟動(dòng)代碼必須初始化堆棧上限,至少初始化主堆棧上限變量__SEGGER_STOP_Limit_MSP。在默認(rèn)實(shí)現(xiàn)中,該符號(hào)由運(yùn)行時(shí)初始化代碼自動(dòng)初始化為默認(rèn)值。

為了調(diào)整上限值,例如改變?yōu)楸4婕拇嫫鞅A舻目臻g,以及初始化__SEGGER_STOP_Limit_PSP,應(yīng)該實(shí)現(xiàn)并調(diào)用__SEGGER_STOP_X_InitLimits。

使用SEGGER鏈接器,運(yùn)行時(shí)初始化代碼將自動(dòng)調(diào)用__SEGGER_STOP_X_InitLimits:

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

使用GNU鏈接器時(shí),應(yīng)該在main中的開始位置調(diào)用__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
 ...
}

在運(yùn)行初始化之前調(diào)用函數(shù)

當(dāng)系統(tǒng)在運(yùn)行初始化之前調(diào)用函數(shù)時(shí),Cortex-M上默認(rèn)在Reset_Handler中調(diào)用SystemInit, __SEGGER_STOP_Limit_MSP應(yīng)設(shè)置為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

當(dāng)使用RTOS或其他多任務(wù)機(jī)制時(shí),任務(wù)切換程序必須在切換堆棧時(shí)更新堆棧上限變量(通常為__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
   ...

建議對(duì)所有任務(wù)啟用堆棧檢查。RTOS可以通過將limit變量設(shè)置為0來禁用某些任務(wù)的堆棧檢查。

堆棧溢出幾乎在每個(gè)系統(tǒng)中都可能遇到。Embedded Studio提供了使用示例,展示簡單系統(tǒng)和多任務(wù)系統(tǒng)的堆棧溢出行為及處理。





審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5253

    瀏覽量

    119206
  • RTOS
    +關(guān)注

    關(guān)注

    20

    文章

    804

    瀏覽量

    119117
  • 編譯器
    +關(guān)注

    關(guān)注

    1

    文章

    1602

    瀏覽量

    48896
  • 緩存器
    +關(guān)注

    關(guān)注

    0

    文章

    63

    瀏覽量

    11624
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Embedded Studio堆棧溢出預(yù)防功能

    為了識(shí)別運(yùn)行的嵌入式系統(tǒng)中的堆棧溢出問題,SEGGER編譯器通過為每個(gè)函數(shù)生成檢測(cè)代碼的方式來檢查堆棧溢出。該功能可以使用命令行開關(guān)-mstack-overflow-check來使能。
    發(fā)表于 07-14 11:08 ?501次閱讀

    什么是堆棧溢出?如何分配堆棧空間大小?

    前些日子bug交流群里的小哥調(diào)試了一個(gè)堆棧溢出的bug,動(dòng)不動(dòng)數(shù)據(jù)就被篡改了,應(yīng)該也是搞得焦頭爛額,頭皮發(fā)麻!當(dāng)時(shí)bug菌看了下,于是拋出了自己的一些調(diào)試經(jīng)驗(yàn),一般這樣的問題80%是越界和堆棧
    的頭像 發(fā)表于 11-08 09:52 ?3569次閱讀
    什么是<b class='flag-5'>堆棧</b><b class='flag-5'>溢出</b>?如何分配<b class='flag-5'>堆棧</b>空間大???

    freertos與STM32如何分配堆棧空間

    freertos與STM32分棧、堆、全局區(qū)、常量區(qū)、代碼區(qū)、RAM、ROM,及如何分配堆棧空間基于STM32分棧、堆、全局區(qū)、常量區(qū)、代碼區(qū)、RAM、ROM FreeRTOS任務(wù)棧大小確定及其
    發(fā)表于 08-03 06:36

    FreeRTOS中的任務(wù)堆棧溢出檢測(cè)機(jī)制

    在FreeRTOS中,每個(gè)任務(wù)都擁有自己的堆棧,該堆棧的大小由創(chuàng)建任務(wù)時(shí)xTaskCreate函數(shù)的函數(shù)參數(shù)所決定。但當(dāng)任務(wù)所使用的堆棧空間超出分配給它的空間時(shí),則會(huì)發(fā)生堆棧
    發(fā)表于 10-15 13:51

    如何在Embedded Studio中使用RTT?

    Embedded Studio是SEGGER微控制器的多平臺(tái)IDE,包含了專業(yè)嵌入式C和C++編程和開發(fā)所需的所有工具和功能。結(jié)合基于Clang、高度優(yōu)化的C/C++ SEGGER編譯器,可以生成
    發(fā)表于 02-17 14:25

    SEGGER Embedded Studio下載激活

    先楫半導(dǎo)體非常nice的是,他們和SEGGER達(dá)成了合作,可以讓開發(fā)者免費(fèi)使用SEGGER Embedded Studio,包括商用哦。 1.SEGGER Embedded Studio
    發(fā)表于 05-25 16:23

    在SEGGER Embedded Studio對(duì)E203使用NMSIS DSP報(bào)錯(cuò),Embedded Studio應(yīng)該如何配置?

    模仿embedded_studio_project中dsp_demo中的配置,希望在Embedded Studio中也使用Hbird SDK中的DSP庫 但是最后會(huì)報(bào)這樣的錯(cuò)誤,好像是因?yàn)镈SP
    發(fā)表于 08-12 06:02

    MSP430 C語言編程的程序堆棧溢出分析

    MSP430 C語言編程的程序堆棧溢出分析
    發(fā)表于 05-16 15:04 ?40次下載

    網(wǎng)絡(luò)安全中的堆棧溢出技術(shù)解析

    網(wǎng)絡(luò)安全日益為人們所重視,其關(guān)鍵就是緩沖溢出問題,幾乎所有的操作系統(tǒng)都避免不了緩沖溢出漏洞的威脅。網(wǎng)絡(luò)安全中的堆棧溢出技術(shù)是一種含量較高的計(jì)算機(jī)技術(shù)。本文用
    發(fā)表于 08-26 10:46 ?14次下載

    鼠標(biāo)HID例程(中)

    鼠標(biāo) HID 例程 緊接《鼠標(biāo) HID 例程(上)》一文,繼續(xù)向大家介紹鼠 標(biāo) HID 例程的未完的內(nèi)容。
    發(fā)表于 07-26 15:18 ?0次下載

    cad堆棧溢出的原因及解決方式

    近期有用戶反饋在打開AutoCad 2007的時(shí)候頻繁出現(xiàn)卡死的情況,并提示還提示0x00000FD堆棧溢出,重啟電腦和重裝軟件都無法解決。針對(duì)該問題小編整理了一些方法供大家參考。
    發(fā)表于 11-28 14:19 ?2.7w次閱讀
    cad<b class='flag-5'>堆棧</b><b class='flag-5'>溢出</b>的原因及解決方式

    關(guān)于堆棧溢出技術(shù)你知道多少?

    雖然溢出在程序開發(fā)過程中不可完全避免,但溢出對(duì)系統(tǒng)的威脅是巨大的,由于系統(tǒng)的特殊性,溢出發(fā)生時(shí)攻擊者可以利用其漏洞來獲取系統(tǒng)的高級(jí)權(quán)限r(nóng)oot,因此本文將詳細(xì)介紹堆棧
    的頭像 發(fā)表于 07-04 16:42 ?6261次閱讀

    CrossCore Embedded Studio集成開發(fā)環(huán)境的介紹

    這是新的CrossCore? Embedded Studio (CCES)集成開發(fā)的簡要說明。CrossCore? Embedded Studio是針對(duì)ADI公司Blackfin?和S
    的頭像 發(fā)表于 07-10 06:08 ?3762次閱讀

    EE-372:CrossCore?Embedded Studio 1.1.x入門

    EE-372:CrossCore?Embedded Studio 1.1.x入門
    發(fā)表于 05-15 18:43 ?10次下載
    EE-372:CrossCore?<b class='flag-5'>Embedded</b> <b class='flag-5'>Studio</b> 1.1.x入門

    STM32 堆棧溢出檢測(cè)

    釋放,存放函數(shù)調(diào)用,局部變量等數(shù)據(jù)。堆heap用于動(dòng)態(tài)內(nèi)存分配。堆棧可以在啟動(dòng)文件或者鏈接腳本中指定大小,但在實(shí)際開發(fā)中,尤其工程量較大的項(xiàng)目中難以確定堆棧使用量,容易造成堆棧溢出,造
    發(fā)表于 12-27 18:32 ?22次下載
    STM32 <b class='flag-5'>堆棧</b><b class='flag-5'>溢出</b>檢測(cè)