环境:STM32F103C8T6,MDK5函数
在最近的一个项目的开发中,每当调用到一个函数,程序就直接跑飞。debug跟进去看不出什么逻辑错误,但发现函数内局部变量声明以后,全局变量的值被清零,后来查看局部变量地址已经超出栈的范围,因而肯定是栈溢出。若是不稍微了解一下堆栈,在开发过程当中可能碰到各类奇怪的错误。debug
MAP 文件是程序的全局符号、源文件和代码行号信息的惟一的文本表示方法,它能够在任何地方、任什么时候候使用,不须要有额外的程序进行支持。设计
在MDK5中,在项目中双击Target就能自动打开.map文件。blog
Startup.s文件是系统的启动文件,主要包括堆和栈的初始化配置、中断向量表的配置以及将程序引导到main( )函数等。内存
Startup.s主要完成三个工做:栈和堆的初始化、定位中断向量表、调用Reset Handler。开发
栈(stack)空间,用亍局部变量,函数调时现场保护和返回地址,函数的形参等。get
堆(heap)空间,主要用亍劢态内存分配,也就是说用 malloc,calloc, realloc 等函数分配的变量空间是在堆上。it
在map文件中搜索STACK或者HEAP,在接近文件底部的位置能够看到SRAM的分配,以下图。程序设计
从上图中能够看出SRAM空间用来存放:一、各个文件中声明和定义的全局变量、静态数据和常量;二、HEAP区;三、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文件是只读的,没法修改,只须要设置一下该文件的属性,把只读取消便可。