STM32堆棧溢出問題


通過map文件了解堆棧分配(STM32、MDK5)--避免堆棧溢出

環境:STM32F103C8T6,MDK5

在最近的一個項目的開發中,每當調用到一個函數,程序就直接跑飛。debug跟進去看不出什么邏輯錯誤,但發現函數內局部變量聲明之后,全局變量的值被清零,后來查看局部變量地址已經超出棧的范圍,於是確定是棧溢出。如果不稍微了解一下堆棧,在開發過程中可能碰到各種奇怪的錯誤。

.map和startup.s文件

MAP 文件是程序的全局符號、源文件和代碼行號信息的唯一的文本表示方法,它可以在任何地方、任何時候使用,不需要有額外的程序進行支持。

在MDK5中,在項目中雙擊Target就能自動打開.map文件。

Startup.s文件是系統的啟動文件,主要包括堆和棧的初始化配置、中斷向量表的配置以及將程序引導到main( )函數等。

Startup.s主要完成三個工作:棧和堆的初始化、定位中斷向量表、調用Reset Handler。

 堆棧作用

棧(stack)空間,用亍局部變量,函數調時現場保護和返回地址,函數的形參等。

堆(heap)空間,主要用亍勱態內存分配,也就是說用 malloc,calloc, realloc 等函數分配的變量空間是在堆上。

堆棧在內存分布

在map文件中搜索STACK或者HEAP,在接近文件底部的位置可以看到SRAM的分配,如下圖。

 

 從上圖中可以看出SRAM空間用來存放:1、各個文件中聲明和定義的全局變量、靜態數據和常量;2、HEAP區;3、STACK區。

STM32的堆棧是存放在SRAM中的,分配堆棧大小需要考慮SRAM容量。

在.map文件中的Image Symbol Table底下可以找到如下圖所示堆棧分布信息。

堆在使用時會從低地址往上加,而棧是從__initial_sp開始往下減。以上圖中的堆棧地址為例,malloc會從0x20002248開始往上加,局部變量的分配會從0x20004448開始往下減。如果入棧元素過大,使得入棧元素的地址訪問到了0x20002448之后的內容,就發生了棧溢出,首先會改變堆中的元素值,如果入棧元素夠大,可能會直接改變HEAP后面的全局變量。同理,當動態申請的內存過大時,堆中變量越界到棧中,此時就發送堆溢出。

避免產生這類錯誤的產生,程序設計時就應該考慮變量大小和堆棧大小是否合適。一個是減少過大的臨時變量和動態申請內存,另一個是在SRAM空間允許的情況下增大堆棧大小,如上圖中棧大小是8192字節,堆大小是512。

 堆棧大小設置

MDK5中可以通過修改startup.s文件來設置堆棧大小,只需要修改startup.s文件中的Stack_Size和Heap_Size即可,如下圖所示。

 

KEIL Uvison5中默認生成的startup.s文件是只讀的,無法修改,只需要設置一下該文件的屬性,把只讀取消即可。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM