2012-05-07 22:56:38
最近了解了RTOS的核心就是用户自己设置栈空间。那么为什么要用户自己设置栈空间呢?自己思考了下,自认为答案是自己设置栈空间存在优点。优点之一应该就是能防止栈溢出导致的程序跑飞吧!一般RTOS创建一个task时候都会要求输入栈空间大小。如何计算栈空间要分配多少,一个调用函数及函数中的参数,局部变量都是放在栈空间的中,基本就是这么评估的。今天主要研究一下栈溢出的现象及如何在调试中发现栈溢出。
一,名词解释
1, 栈溢出。
栈的size为0x100=256字节。栈地址的bottom为0x2100,而首地址为0x2000。
根据默认的CW5.1生成的工程就是如此的默认设置。可以参考prm文件。
栈溢出:就是指SP(堆栈指针)指向的地址超出了此范围就做栈溢出。
栈溢出分类:top溢出。
Bottom溢出。
二,情况分析
1, 顶端溢出1,代码运行前局部变量空间已经溢出。
代码如下
#define NUM 255 //253,252
unsigned char g_testa,g_testb;
unsigned char g_result;
void main(void) {
unsigned int i;
unsigned char l_testa[NUM];
for (i=0;i<NUM;i++)
l_testa[i]=i;
g_result=l_testa[NUM-1];
}
溢出分析:局部变量为257字节大于256字节。SP地址值小于0x2000, g_top,g_bot读数都不正确。
2, 顶端溢出2,代码运行前局部变量空间没有溢出。
代码如下:
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
//Data type
typedef unsigned char uint8;
//Macro
//#define TopOverFlow //OverFlow type.
//#define BotOverFlow
#if defined(TopOverFlow)
typedef unsigned int type_i;
#define NUM 255 //Array Lenth
#else
typedef unsigned char type_i;
#define NUM 255
#endif
//Global var
uint8 g_result; //not need it
uint8 g_top,g_bot; //Save value of Array[top] and Arry[Bottom],located Address:FE2100.FE2101
//Function
void main(void)
{
//Local
type_i i; //Local var,save in stack temporary
uint8 l_testa[NUM]; //Local var,save in stack temporary
//Test
for ( i=0; i<NUM; i++ )
{
l_testa[i] = (uint8)i;
}
g_top = l_testa[0];
g_bot = l_testa[NUM-1];
}
溢出分析:局部变量为256字节等于栈空间的大小,但是由于调用main函数,所以会占用3个字节0xFE C0 0F,所以,SP地址值小于0x2000,栈顶溢出。Top值预期为0,但是读数为90。
3, 顶底溢出。由于栈是从底到顶增长的。所以要向下溢出,只能通过数组溢出。
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
//Data type
typedef unsigned char uint8;
//Macro
//#define TopOverFlow //OverFlow type.
#define BotOverFlow
#if defined(TopOverFlow)
typedef unsigned int type_i;
#define NUM 255 //Array Lenth
#elif defined(BotOverFlow)
typedef unsigned char type_i;
#define NUM 10
#else
typedef unsigned char type_i;
#define NUM 255
#endif
//Global var
uint8 g_result; //not need it
uint8 g_top,g_bot; //Save value of Array[top] and Arry[Bottom],located Address:FE2100.FE2101
//Function
void main(void)
{
//Local
type_i i; //Local var,save in stack temporary
uint8 l_testa[NUM]; //Local var,save in stack temporary
//Test
#if defined(BotOverFlow)
for ( i=1; i<NUM+5; i++ )
{
l_testa[i] = (uint8)i-1;
}
#else
for ( i=0; i<NUM; i++ )
{
l_testa[i] = (uint8)i;
}
#endif
g_top = l_testa[0];
g_bot = l_testa[NUM-1];
}
溢出分析:代码运行前栈是没有溢出的,数组分配空间期望值为10个字节+1个字节的局部变量i。然后代码运行后,for循环数组赋值超出了数组的上限,则赋值继续进行,把数组栈地址下面的局部变量(main的入栈函数地址)及g_top,g_bot的全局变量给覆盖了。
兼容三种情况,最终代码改成如下
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
//Data type
typedef unsigned char uint8;
//Macro
//Select one of next list to test OverFlow
#define TopOverFlow1 //OverFlow type1.
//#define TopOverFlow2 //OverFlow type2.
//#define BotOverFlow //OverFlow type3.
#if defined(TopOverFlow1)
typedef unsigned int type_i;
#define NUM 255 //Array Lenth
#elif defined(BotOverFlow)
typedef unsigned char type_i;
#define NUM 10
#else
typedef unsigned char type_i;
#define NUM 255
#endif
//Global var
uint8 g_result; //not need it
uint8 g_top,g_bot; //Save value of Array[top] and Arry[Bottom],located Address:FE2100.FE2101
//Function
void main(void)
{
//Local
type_i i; //Local var,save in stack temporary
uint8 l_testa[NUM]; //Local var,save in stack temporary
//Test
#if defined(BotOverFlow)
for ( i=1; i<NUM+5; i++ )
{
l_testa[i] = (uint8)i-1;
}
#else
for ( i=0; i<NUM; i++ )
{
l_testa[i] = (uint8)i;
}
#endif
g_top = l_testa[0];
g_bot = l_testa[NUM-1];
}
但是发现一个问题。#define TopOverFlow1情况和我之前一开始的代码运行情况不同了。最终g_top为0,g_bot为1,并且进入一次for循环。不过g_bot为什么为1?没找到来源。