map文件简介


内容

首先我们需要了解map文件是什么,map文件是通过编译器编译之后,集程序、数据及IO空间的一种映射文件;一般出现内存越界或溢出,又或者是代码优化的情况,首先想到的就是分析map文件,通过map文件可以知道函数大小,入口地址等一些重要信息,总共分为五大类

  • Section Cross References:模块、段(入口)交叉引用
  • Removing Unused input sections from the image:移除未调用模块
  • Image Symbol Table:映射符号表
  • Memory Map of the image:内存(映射)分布
  • Image component sizes:存储组成大小

配置

其次就是配置,由于笔者这里大多数是使用keil,所有就展示的keil的配置(虽然大概率就是已经配置好的);路径是先点击魔法棒,然后Listing选项卡中,最后在Linker Listing:map.map勾选即可

  • Memory Map:内存映射
  • Callgraph:图像映射
  • Symbols:符号
  • Cross Reference:交叉引用
  • Size Info:大小信息
  • Totals Info:统计信息
  • Unused Section Info:未调用模块信息
  • Veneers Info:装饰信息

最后的map文件可以在~\xxx\MDK-ARM\xxx中找到

概念

最后是关于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同义

map文件内容详解


Section Cross References—模块、段(入口)交叉引用

当我们打开map文件的时候,第一大块就是Section Cross References,主要内容是是各个源文件生成的模块、段(定义的入口)之间相互引用的关系

例如: main.o(i.SystemClock_Config) refers to stm32f1xx_hal_rcc.o(i.HAL_RCC_OscConfig) for HAL_RCC_OscConfig,意思是main模块中SystemClock_Config引用了 stm32f1xx_hal_rcc模块中HAL_RCC_OscConfig函数

需要注意的是,在map文件中i指的是独立函数,是一种编译器优化编译的一种方式,可以精确地控制每个函数的位置,或者删除没用的函数,通俗来讲也就是可以在map文件看到更多信息以及更精准的定位

Removing Unused input sections from the image—移除未调用模块

在代码中没有被调用的模块会在map文件生成列表,最后会在这部分显现出来

例如:Removing stm32f1xx_hal_rcc_ex.o(i.HAL_RCCEx_GetPeriphCLKConfig), (44 bytes).,意思是删除了stm32f1xx_hal_rcc_ex模块的HAL_RCCEx_GetPeriphCLKConfig函数,大小是44字节

除此以外,最后会有一个汇总,删除了180个模块,共计7710字节

Image Symbol Table—映射符号表

这部分分为两块,一块是Local Symbols,主要静态函数,变量以及常量;另外一块是Global Symbols,主要是外部函数和全局变量

  • Symbol Name:符号的名称以及路径
  • Value:地址
  • Type:符号的类型,常见的大概是四种
    • Number
    • Section
    • Thumb Code
    • Data
  • Size:大小,单位是字节
  • Object(Section):表示符号所在的目标文件及其对应的段
    我们从这部分可以看出一些函数或变量的地址

Memory Map of the image—内存(映射)分布

在执行映像之前,必须将已初始化的RW数据从ROM中复制到RAM中的执行地址并创建ZI Section(初始化为0的变量区)

这里引用rtthread文档中的内存分布图

STM32 在上电启动之后默认从 Flash 启动,启动之后会将 RW 段中的 RW-data(初始化的全局变量)搬运到 RAM 中,但不会搬运 RO 段,即 CPU 的执行代码从 Flash 中读取,另外根据编译器给出的 ZI 地址和大小分配出 ZI 段,并将这块 RAM 区域清零

  • Exec Addr:执行地址,即当程序运行时,该段在内存中将被加载到的地址
  • Load Addr:加载地址,即当程序从存储器(如 Flash)加载到内存时,该段最初加载到的地址,由上图可以知道,启动之后RO是不会变的,但RW是会移动到RAM里面,所以在RO中Exec Addr和Load Addr是一致的,但RW会不一样且Load Addr比Exec Addr大
  • Size:段的大小,以字节为单位
  • Type:段的类型
    • Code:表示可执行代码
    • Data:表示数据段,包括已初始化的全局变量等
    • RO Data:只读数据,如常量、字符串字面值等
  • Attr:段的属性,在RO中Attr都是RO,在RW中Attr都是RW
  • Idx:索引号,表示该段在符号表中的索引位置,通常用于区分符号表中的不同段
  • E Section Name:段的名称
  • Object:目标文件

Image component sizes—存储组成大小

  • Code (inc. data):代码部分(即可执行指令)及其包含的任何初始化数据的总大小,包括.text段和任何被标记为只读的初始化数据(如.rodata段)
  • RO Data:只读数据的总大小。这部分通常包括常量字符串、枚举、常量数组等,存储在.rodata段中
  • RW Data:可读可写数据的总大小。这部分包含已初始化的全局变量和静态变量,存储在.data段中
  • ZI Data:零初始化数据的总大小。这部分通常包含未初始化的全局变量和静态变量,存储在.bss段中
  • Debug:表示与调试相关的数据占用空间,包括调试符号、调试信息
  • Object Name:目标文件的名称

RAM=RW=1.62KB

ROM=ROM = 2.44KB