CM3/4 map文件分析

1. map 文件的MDK设置

  1. 要生成 map 文件,我们需要在 MDK 的魔术棒→Listing 选项卡里面,进行相关设置。
    默认情况下,MDK 这部分设置是全勾选的,如果想取消掉一些信息的输出,则取消相关勾选即可(一般不建议)如图所示:
    在这里插入图片描述
  2. 设置好 MDK 以后,全编译当前工程,当编译完成后(无错误),就会生成.map 文件。如图所示:
    在这里插入图片描述

2. MDK 编译生成文件简介

  MDK 编译工程,会生成一些中间文件(如.o、.axf、.map 等),最终生成 hex 文件,以便下载到 MCU 上面执行,编译过程产生的所有文件,都存放在 OBJ 文件夹下,如下图所示:
在这里插入图片描述
  这里总共生成了 66 个文件,共 11 个类型,分别是:.axf、.crf、.d、.dep、.hex、.lnp、.lst、.o、.htm、
bulild_log.htm 和.map。66 个文件看着不是很多,但是随着工程的增大,这些文件也会越来越多,大项目编译一次,可以生成几百甚至上千个这种文件,不过文件类型基本就是上面这些。
  对于 MDK 工程来说,基本上任何工程在编译过程中都会有这 11 类文件,常见的 MDK 编译过程生产文件类型如表所示:

文件类型 说明
.o 可重定向对象文件,每个源文件(.c/.s 等)编译都会生成一个.o 文件
.axf 由 ARMCC 编译生产的可执行对象文件,不可重定向(绝对地址),它是由 armlink 链接器,将整个工程参与编译的多个.o 文件链接生成.axf 文件,我们在仿真的时候,需要用到该文件
.hex Hex 格式文件,可用于下载到 MCU,可执行对象文件 .hex 由.axf 文件转换而来。.hex 文件和.bin 文件的区别是:.bin 文件不含地址信息,全部都是可执行代码;而.hex 文件则是包含地址信息的可自行代码。同样的.bin 文件也是由.axf 文件转换而来的。我们在使用 ISP 软件进行程序下载的时候,一般使用的是.hex 文件,由 ISP 软件解析.hex 文件包含的地址信息来实现程序下载。而我们在进行 BootLoader 升级的时候,一般使用.bin 文件,地址由 Bootloader 程序指定。
.crf 交叉引用文件,包含浏览信息(定义、标识符、引用)
.d 由 ARMCC/GCC 编译生产的依赖文件(.o 文件所对应的依赖文件)每个.o 文件,都有一个对应的.d 文件
.dep 整个工程的依赖文件
.lnp MDK 生成的链接输入文件,用于命令输入
.lst C 语言或汇编编译器生成的列表文件
.htm 它是编译器在编译代码的时候生成的一个列表文件,包含了整个工程的静态调用图,最大的用处就是可以查看栈深度(最小深度),方便设置栈大小。.htm 文件可以直接由浏览器打开(双击打开)
.build_log.htm 最近一次编译工程时的日志记录文件
.map 连接器生成的列表文件/MAP 文件, 该文件对我们非常有用

注1:可重定向是指该文件包含数据/代码,但是并没有指定地址,它的地址可由后续链接的时候进行指定。
注2:不可重定向是指该文件所包含的数据/代码都已经指定地址了,不能再改变。


其他文件类型及说明,请大家参考:MDK→help→uVision Help→B. File Types,如图所示:
在这里插入图片描述


注意:.htm 文件包含两部分内容:

  1. 整个工程最大栈(Stack)深度及其调用关系
    我们打开:新建工程例程→Output→XXX.htm 文件(双击,注意:必须整个工程编译一遍,才会生成 XXX.htm 文件,否则是找不到这个文件的!),可以看到如图所示:
    在这里插入图片描述
    例程的最大栈深度是 416 字节,最大栈深时的调用关系为:__rt_entry_main ⇒ main ⇒ sys_stm32_clock_init ⇒ HAL_RCC_ClockConfig ⇒ HAL_InitTick ⇒HAL_NVIC_SetPriority ⇒ __NVIC_SetPriority。
    不过需要注意的是,这里的最大栈深度仅仅是最低要求(静态栈),因为它并没有统计无栈深的函数(用内存管理)、递归函数、以及无法追踪的函数(函数指针)等所包含的栈(Stack)。
    不过它给我们指明了最低需求,我们在分配栈深度的时候,就可以参考这个值来做设置,一般不低于静态栈的2倍。默认设置的栈深(Stack_Size)通过 startup_stm32f***.s文件设置。
  2. 各个函数的栈深及其调用关系
    .htm 文件还给出了每个函数所使用的栈深度以及其调用关系,如图所示:
    在这里插入图片描述

3. map 文件的基本概念

  • Section:描述映像文件的代码或数据块,我们简称程序段
  • RO:包括只读数据(RO data)和代码(RO code)两部分内容,占用 FLASH 空间
  • RW:包含可读写数据(RW data,有初值,且不为 0),占用FLASH(存储初值)和 RAM(读写操作)
  • ZI:Zero initialized 的缩写,包含初始化为 0 的数据(ZI data),占用 RAM 空间
  • .constdata:相当于 RO data
  • .text:相当于 RO code
  • .data:相当于 RW data
  • .bss:相当于 ZI data

4. map 文件分析

.map 文件是编译器链接时生成的一个文件,它主要包含了交叉链接信息。通过.map 文件,我们可以知道整个工程的函数调用关系、FLASH 和 RAM 占用情况及其详细汇总信息,能具体到单个源文件(.c/.s)的占用情况,根据这些信息,我们可以对代码进行优化。
.map 文件可以分为以下 5 个组成部分:

  1. 程序段交叉引用关系(Section Cross References)
  2. 删除映像未使用的程序段(Removing Unused input sections from the image)
  3. 映像符号表(Image Symbol Table)
  4. 映像内存分布图(Memory Map of the image)
  5. 映像组件大小(Image component sizes)

4.1 程序段交叉引用关系(Section Cross References)

  在这部分中,详细列出了各个 *.o 文件之间的符号引用。由于 *.o 文件是由 asm 或 c/c++ 源文件(.c/.s 等)编译后生成的,各个文件及文件内的节区间互相独立,链接器根据它们之间的互相引用链接起来,链接的详细信息在 Section Cross References 下面一一列出。
  即这部分内容描述了各个文件(.c/.s 等)之间函数(程序段)的调用关系,如图所示:
在这里插入图片描述

例如:上图框出部分main.o(i.main) refers to os_core.o(i.OSInit) for OSInit表示:
main.c 文件中的 main 函数,调用了 os_core.c 中的 OSInit 函数。

  • i.main 表示 main 函数的入口地址;
  • i.OSInit 表示 OSInit 函数的入口地址。


这些跨文件引用的符号其实就是源文件中的函数名、变量名。有时在构建工程的时候,编译器会输出Undefined symbol xxx (referred from xxx.o)这样的提示,该提示的原因就是在链接过程中,某个文件无法在外部找到它引用的标号,因

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值