简单来说,Map文件是编译器编译工程后生成的一个文件,这个文件反映了各个源文件生成的模块间的交叉引用、移除的未使用模块、符合映射表、内存映射以及各个模块的大小和汇总数据等。
所以说,当你在遇到或怀疑存在内存越界或溢出的情况时,首先想到的应该就是分析Map文件,确认嫌疑分子、构建RAM的分布图,还原问题发生的过程,才能从根本上解决问题。
那,我们就一起来看下怎么看Map文件这个问题吧~
二、如何生成Map文件根据设置的不同,生成的Map文件包含的内容也不同。如图1所示,在“Options for Target ‘XXX’”窗口的Listing页面,通过勾选不同的项目可以定制Map文件中的记录的内容。
图1
PS:点击快捷工具栏的魔法棒按钮 或 菜单Project->“Options for Target ‘XXX’...”可以打开“Options for Target ‘XXX’”窗口。
设置完,代码编译成功后,在指定目录就可以找到生成的Map文件。
三、Map文件解析Map文件已经生成了,那么接下来我们一起看下Map是何方神圣。既然要看,就需要先打开Map文件,那么Map文件怎么打开呢?
很简单,打开Map文件的方式有多种,在KEIL的左侧的Project窗口中目标工程上双击即可打开;或者,直接找到Map文件,用文本编辑器等方式都可以打开查看这里就不再赘述。
按照最全的配置,Map文件包括以下几个部分:
1. Section Cross References主要是指各源文件生成的模块间的相互引用关系。
比如,下面这句表示:
spi.c文件编译生成的模块spi.o中调用了stm32f4xx_rcc.c文件编译生成的模块stm32f4xx_rcc.o z中的函数RCC_AHB1PeriphClockCmd。 剩下的也差不多都是这个意思。
Section Cross References……spi.o(.text) refers to stm32f4xx_rcc.o(.text) for RCC_AHB1PeriphClockCmd……2. Removing Unused input sections from the image将未使用的函数之类的删除,以减少image映像的大小。
Removing Unused input sections from the image.……Removing data_quk.o(.rev16_text), (4 bytes).……这个从我个人目前接触的内容看,没用到过,如果XDJM在调试程序的过程中有用到这些信息的场景也希望不吝赐教,我也开阔下视野,多谢~
3. Image Symbol Table映像中涉及的符号表,包括局部符号(Local Symbols)和全局符号(Global Symbols)。
Image Symbol Table // 局部符号 Local Symbols // 符号名 // 地址 // 类型 // 大小 Symbol Name Value Ov Type Size Object(Section) ../clib/angel/boardlib.s 0x00000000 Number 0 boardinit1.o ABSOLUTE ..TASKSalm_task.c 0x00000000 Number 0 alm_task.o ABSOLUTE ...... HEAP 0x20006248 Section 512 startup_stm32f40_41xxx.o(HEAP) Heap_Mem 0x20006248 Data 512 startup_stm32f40_41xxx.o(HEAP) STACK 0x20006448 Section 2048 startup_stm32f40_41xxx.o(STACK) Stack_Mem 0x20006448 Data 2048 startup_stm32f40_41xxx.o(STACK) __initial_sp 0x20006c48 Data 0 startup_stm32f40_41xxx.o(STACK) // 全局符号 Global Symbols // 符号名 // 地址 // 类型 // 大小 Symbol Name Value Ov Type Size Object(Section) ...... limit_check 0x0800d27d Thumb Code 566 alm_task.o(.text) aaaaa_err 0x20000089 Data 1 global.o(.data) play_cnt 0x2000008a Data 1 global.o(.data) lock_cnt 0x2000008b Data 1 global.o(.data) ...... Region$$Table$$Base 0x0801bf24 Number 0 anon$$obj.o(Region$$Table) Region$$Table$$Limit 0x0801bf44 Number 0 anon$$obj.o(Region$$Table) ......注意,这里的符号包括函数名,变量名。局部的static变量和全局变量在这里都可以找到,如果疑似存在内存越界的变量属于这两种类型,那么可以从这里找到他们的地址,看看他上下左右的小伙伴儿都是谁,就能确定嫌疑分子了。
另外,类型包括Number、Section、Thumb Code、Data。其中,Number是指它并不占据程序空间,而只是具有一定数值的符号,类似于程序中用宏定义define和EQU。
4. Memory Map of the image映像的内存分布,顾名思义,这部分内容主要记录了映像的加载域和运行域的起始地址、大小和最大Size以及各个段的起始地址。
在说介绍之前,我们先了解下这几个段的意义,方便理解:
段名说明.constdata只读常量数据段,属于RO-data。.text代码段。
用来存放程序执行代码的内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读(当然也有些架构允许代码段为可写,即允许修改程序)。也有可能包含一些只读的常数变量,例如字符串常量等。
.data数据段。
data 段用于存储已经赋初值(非零)的全局变量,且变量占有实际的内存空间。本段的内容由程序初始化,因此会占用exe文件空间。
.bss数据段,Block Started by Symbol。
bss段用于存储未赋初值的全局变量和静态局部变量,这些变量在程序运行前会被初始化为0或NULL。
另外,初始化为零的全局变量和静态局部变量也会存储在bss中的数据不分配实际的空间,只体现为一个占位符,只记录数据所需空间的大小,因此不会占用exe文件空间。
bss段的大小从可执行文件中得到 ,然后