STM32 KEIL里的MAP文件分析

一、要让Keil生成map文件,要设置:

STM32 KEIL里的MAP文件分析_第1张图片

再重新编译,没有错误后,就会生成map文件了。

二、map文件中相关概念:

段(section) :描述映像文件的代码和数据块。

RO:Read-Only的缩写,包括RO-data(只读数据)和RO-code(代码)。
RW:Read-Write的缩写,主要是RW-data,RW-data由程序初始化初始值。 
ZI:Zero-initialized的缩写,主要是ZI-data,由编译器初始化为0。 
.text:与RO-code同义。
.constdata:与RO-data同义。 
.bss: 与ZI-data同义。
.data:与RW-data同义

三、文件分析流程

第一部分:Section Cross References(模块、段的交叉引用关系)
主要是各个源文件生成的模块之间相互引用的关系。“refer to”是引用的意思,比如:

main.o(i.main) refers to led.o(i.LED_Init) for LED_Init

首先main.c和led.c会被编译成目标文件main.o和led.o。i.main是main.c中main函数的入口(也是main函数编译出的段,函数编译后以段的形式存在,函数之间的引用,也就是段与段之间的引用)。i.LED_Init是led.c中LED_Init函数的入口(也是LED_Init函数编译出的段)。因此上面这句话意思就是main.c中的main函数引用了led.c中的LED_Init函数,剩下的基本都是这类的意思。

main.o(i.main) refers to sys.o(i.Cache_Enable) for Cache_Enable
main.o(i.main) refers to stm32h7xx_hal.o(i.HAL_Init) for HAL_Init
main.o(i.main) refers to sys.o(i.Stm32_Clock_Init) for Stm32_Clock_Init
main.o(i.main) refers to delay.o(i.delay_init) for delay_init
main.o(i.main) refers to usart.o(i.uart_init) for uart_init
main.o(i.main) refers to led.o(i.LED_Init) for LED_Init

其中有关于启动代码的引用说明:

stm32f10x_vector.o(.text) refers to __main.o(!!!main) for __main
__main.o(!!!main) refers to kernel.o(.text) for __rt_entry
kernel.o(.text) refers to usertask.o(.text) for main


上面这几个对于程序意义比较重大用户在启动代码中调用了__main.o模块中的__main函数,__main又调用了kernel.o中的__rt_entry函数,最后kernel.o又调用了用户定义的main主函数。


第二部分:Removing Unused input sections from the image(移除未使用的段)
就是将库中没有用到的函数从可执行映像中删除掉,减小程序的体积。

    Removing os_mbox.o(.text), (1094 bytes).
    Removing os_mutex.o(.text), (1744 bytes).
    Removing os_sem.o(.text), (1016 bytes).

最后一栏有个总的统计结果:

2737 unused section(s) (total 289508 bytes) removed from the image.

总共移除了2737个未使用的段,共289508字节。


第三部分:Image Symbol Table(映射符号表,列出了各个段所存储的对应地址)

分为Local Symbols局部 和 Global Symbols全局。

Local Symbols记录了用static声明的全局变量地址和大小,C文件中函数的地址和用static声明的函数代码大小,汇编文件中的标号地址(作用域限本文件),下面是部分截图:

STM32 KEIL里的MAP文件分析_第2张图片

Global Symbols记录了全局变量的地址和大小,C文件中函数的地址及其代码大小,汇编文件中的标号地址(作用域全工程),下面是部分截图:

STM32 KEIL里的MAP文件分析_第3张图片

1、Symbol Name:符号名称

2、Value:存储对应的地址;

大家会发现有0x0800xxxx、0x2000xxxx这样的地址。

0x0800xxxx指存储在FLASH里面的代码、变量等。

0x2000xxxx指存储在内存RAM中的变量Data等。

3、Ov Type:符号对应的类型

符号类型大概有几种:Number、Section、Thumb Code、Data等;

细心的朋友会发现:全局、静态变量等位于0x2000xxxx的内存RAM中。

4、Size:存储大小

这个容易理解,我们怀疑内存溢出,可以查看代码存储大小来分析。

5、Object(Section):当前符号所在段名

这里一般指所在模块(所在源文件)。

第四部分:Memory Map of the image(映像的内存分布)

映像文件可以分为加载域(Load Region)和运行域(Execution Region):加载域反映了ARM可执行映像文件的各个段存放在存储器中的位置关系。下面是部分截图,另外映像中的入口点就是程序开始执行的位置。

STM32 KEIL里的MAP文件分析_第4张图片

1、Exec Addr:运行域地址

2、Load Addr:加载域地址

3、Size:存储大小

4、Type:类型

Data:数据类型

Code:代码类型

Zero:未初始化变量类型

PAD:这个类型在map文件中放在这个位置,其实它不能算这里的类型。要翻译的话,只能说的“补充类型”。

ARM处理器是32位的,如果定义一个8位或者16位变量就会剩余一部分,这里就是指的“补充”的那部分,会发现后面的其他几个选项都没有对应的值。
 

运行域反映了ARM可执行映像文件各个段真正执行时在存储器中的位置关系:

STM32 KEIL里的MAP文件分析_第5张图片

加载域就是程序在Flash中的实际存储,而运行域是芯片上电后的运行状态,因为MCU没上电时RAM中没有数据,所以此时所有的东西(包括代码、变量、初始值等)都是存放在flash中的,当上电后又要把变量等复制到RAM中才能正常运行。

STM32 KEIL里的MAP文件分析_第6张图片

通过上面的框图可以看出,RW区也是要存储到ROM/Flash里面的。在执行映像之前,必须将已初始化的RW数据从ROM中复制到RAM中的执行地址并创建ZI Section(初始值为0的变量区),这样才算完成了MCU运行的准备。


第五部分:Image component sizes(映像组成大小)

STM32 KEIL里的MAP文件分析_第7张图片
Code (inc. Data) :显示代码占用了多少字节。 在此映像中,有19442字节的代码, 其中包括1832字节的内联数据 (inc. data),例如文字池和短字符串。

RO Data :显示只读数据占用了多少字节(比如const char buf[] = "123456")。这是除 Code (inc. data) 列中包括的内联数据之外的数据。

RW Data :显示读写数据占用了多少字节。

ZI Data :显示零初始化的数据占用了多少字节。

Debug :显示调试数据占用了多少字节,例如,调试输入节以及符号和字符串。

Object Totals :显示链接到一起以生成映像的对象占用了多少字节。

(incl. Generated):链接器会生成的映像内容,例如,交互操作中间代码。 如果 Object Totals 行包含此类型的数据,则会显示在该行中。本例中共有 1016 字节的 RO 数据,其中32字节是链接器生成的 RO 数据。

(incl. Padding) :链接器根据需要插入填充,以强制字节对齐。

下面的Library Totals显示已提取并作为单个对象添加到映像中的库成员占用了多少字节。

STM32 KEIL里的MAP文件分析_第8张图片

下面是整个映像文件的总结说明:

STM32 KEIL里的MAP文件分析_第9张图片

Grand Totals:显示映像的真实大小。

ELF Image Totals:ELF(Executable and Linking Format)可执行链接格式映像文件大小。

ROM Totals:显示包含映像所需的 ROM的最小大小。这不包括 ZI数据和存储在ROM 中的调试信息。

 

你可能感兴趣的:(MCU)