1.棧指針溢出現(xiàn)象
當在編程的時候,如果沒有棧溢出的意識,某些情況下可能會將局部變量的大小設(shè)置的非常大赃梧,如下代碼:
void fun()
{
//....
}
int main(void)
{
char a[1024];
char b[1024];
int c;
fun();
//...
}
局部變量 a、b數(shù)組總共的有2k內(nèi)存大小豌熄,如果設(shè)置芯片的棧大小為2k時授嘀,當運行fun函數(shù)時,程序直接進入hardware出現(xiàn)死機的問題锣险。
2.理論分析
keil工程下內(nèi)存分布
我們先來看一下在keil工程的內(nèi)存分布:
使用MDK編譯代碼時蹄皱,在編譯輸出窗口會輸出以下內(nèi)容:
Program Size: Code=5756 RO-data=336 RW-data=56 ZI-data=1832
MDK將代碼分成了Code,RO-data,RW-data,ZI-data這幾個段:
- Code :是存儲程序代碼(指令)的。
- RO-data:是存儲const常量芯肤,如一些字符串巷折。
- RW-data :是存儲初始化值不為0的全局變量。
- ZI-data :是存儲未初始化的全局變量或初始化值為0的全局變量崖咨。
Flash = Code + RO Data + RW Data;
RAM= RW-data + ZI-data;
MSP指針
我們現(xiàn)在主要來看一下 RAM 的分配锻拘, RAM 不僅存放了初始化和未初始化的全局變量, 我們還將RAM劃分成兩個段來存放堆和棧击蹲, 堆和棧的區(qū)分如下:
- 堆:這部分內(nèi)存一般用于程序員分配和釋放署拟,如使用malloc函數(shù)申請的內(nèi)存
- 棧:這部分由程序自動完成, 如入棧的時候?qū)⒕植孔兞看娣胚@個區(qū)域
在cortex-M3中歌豺, 0地址存放的就是SP的指針值推穷,使用的是“向下生長的滿棧”模型, 即SP指向的是棧內(nèi)存的最高地址类咧,入棧時馒铃,SP指針值遞減,如下圖所示:
在stm32 keil工程中設(shè)置棧的大小在 starup_stm32f10x_hd.s文件中:
Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
意思講棧的大小設(shè)置為了0x00000400 = 1k(我們自己也可以改)痕惋。
如上代碼中区宇, 局部變量有2k大小,當調(diào)用fun函數(shù)時血巍,程序會將這些局部變量入到棧內(nèi)存中萧锉,這時,MSP指向的位置早已超出了棧內(nèi)存的位置述寡,如果MSP指向的RAM內(nèi)存暫時沒用到柿隙,可能會比較幸運的不出現(xiàn)問題,如果MSP 指向的位置已不在RAM 的范圍之內(nèi)鲫凶,程序?qū)⒅苯铀罊C禀崖。
- 在eclipse工程(GCC編譯)中,內(nèi)存是通過鏈接腳本來分布設(shè)置的螟炫,棧一般設(shè)置在RAM的最高地址的那塊區(qū)域波附。
- 在keil工程(ARMCC編譯)中是通過分散加載文件設(shè)置的,一般是采用keil工程自帶的〉牛可以用j-flash 查看編譯出來的hex文件封寞,其中前四個字節(jié)就是SP指針指向的地址,棧一般設(shè)置為RAM 的低地址那塊區(qū)域仅财。
所以狈究,有時候同樣的代碼在eclipse工程中能跑過,在keil工程中跑不過盏求,這就是其中的原因抖锥。
3. 結(jié)論
我們要合理的設(shè)置棧的大小和 局部變量的大小,合理的分配內(nèi)存分布碎罚。