STM32 MAP文件

1 生成Map

Keil生成map文件,要设置:
在这里插入图片描述

2 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同义

3 文件分析流程

.map文件可以分为五个部分:
①程序段交叉引用关系(Section Cross References)
②删除映像未使用的程序段(Removing Unused input sections from the image)
③映像符号表(Image Symbol Table )
④映像内存分布图(Memory Map of the image)
⑤映像组件大小(Image component sizes)

3.1 Section Cross References

Section Cross References

    main.o(i.main) refers to misc.o(i.NVIC_PriorityGroupConfig) for NVIC_PriorityGroupConfig
    main.o(i.main) refers to delay.o(i.delay_init) for delay_init
    main.o(i.main) refers to usart.o(i.uart1_init) for uart1_init
    main.o(i.main) refers to led.o(i.LED_Init) for LED_Init
    main.o(i.main) refers to lcd.o(i.LCD_Init) for LCD_Init
    main.o(i.main) refers to key.o(i.KEY_Init) for KEY_Init

链接器根据.o之间的互相引用链接起来,在这部分中,详细列出了各个 *.o 文件之间的符号引用。“refer to”是引用的意思,比如:

  • 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中的i.LED_Init节区的LED_Init函数,剩下的基本都是这类的意思。

startup_stm32f40_41xxx.o(.text) refers to __main.o(!!!main) for __main

在启动代码中调用了_main.o模块中的_main函数。

有时在构建工程的时候,编译器会输出“Undefined symbol xxx (referred from xxx.o)”这样的提示

  • 原因就是在链接过程中,某个文件无法在外部找到它引用的标号,因而产生链接错误。
    在这里插入图片描述
    定义的函数 LED_GPIO_Config 改名为 LED_GPIO_ConfigABCD

3.2 Removing Unused input sections from the image(移除未使用的段)

将库中没有用到的函数从可执行映像中删除掉,减小程序的体积。

Removing Unused input sections from the image.

    Removing main.o(.rev16_text), (4 bytes).
    Removing main.o(.revsh_text), (4 bytes).
    Removing stm32f4xx_it.o(.rev16_text), (4 bytes).
    Removing stm32f4xx_it.o(.revsh_text), (4 bytes).
    Removing system_stm32f4xx.o(.rev16_text), (4 bytes).
    Removing system_stm32f4xx.o(.revsh_text), (4 bytes).
    Removing system_stm32f4xx.o(i.SystemCoreClockUpdate), (192 bytes).
    Removing system_stm32f4xx.o(.data), (20 bytes).

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

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

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

  • 删除 指不加入到 *.axf 文件,不是指在 *.o 文件删除

由此也可以知道,虽然我们把RT1052 标准库的各个外设对应的 c 库文件都添加到了工程,但不必担心这会使工程变得臃肿,因为未被引用的节区内容不会被加入到最终的机器码文件中。

3.3 Image Symbol Table 映像符号表

映像符号表描述了被引用的各个符号(程序段/数据)在存储器中的存储地址、类型、大小等信息。

  • 映像符号表分为两类:本地符号(Local Symbols)和全局符号(Global Symbols)

1、本地符号
本地符号记录了用static声明的全局变量地址和大小,c文件中函数的地址和用 static 声明的函数代码大小,汇编文件中的标号地址(作用域:限文本文件),本地符号如图:
本地符号

图中,图中红框框处部分,表示 sys.c 文件中的 sys_stm32_clock_init 函数的入口地址为:0x08002bc8,类型为:Section(程序段),大小为 0。因为:i. sys_stm32_clock_init 仅仅表示sys_stm32_clock_init 函数入口地址,并不是指令,所以没有大小。在全局符号段,会列出sys_stm32_clock_init 函数的大小。

2、全局符号
全局符号,记录了全局变量的地址和大小,C文件中函数的地址及其代码大小,汇编文件中的标号地址(作用域:全工程),全局符号如图:
在这里插入图片描述图中红框框处部分,表示 sys.c 文件中的 sys_stm32_clock_init 函数的入口地址为:
0x08002bc9,类型为:Thumb Code(程序段),大小为 344 字节。

注意,此处的地址用的 0x08002bc9,和 2.1.3.1 节的0x08002bc8 地址不符,这是因为ARM 规定 Thumb 指令集的所有指令,其最低位必须为 1,0x08002bc9 = 0x08002bc8 + 1,所以才会有 2 个不同的地址,且总是差 1,实际上就是同一个函数。

3.4 Memory Map of the image(存储器映像索引)

映像文件可以分为加载域(Load Region)和运行域(Execution Region):

3.4.1 加载域

加载域反映了ARM可执行映像文件的各个段存放在存储器中的位置关系。

Memory Map of the image

  Image Entry point : 0x00000000

  Load Region LR_IROM1 (Base: 0x08000000, Size: 0x00008dac, Max: 0x00100000, ABSOLUTE)

    Execution Region ER_IROM1 (Base: 0x08000000, Size: 0x00008bd8, Max: 0x00100000, ABSOLUTE)

    Base Addr    Size         Type   Attr      Idx    E Section Name        Object

    0x08000000   0x00000188   Data   RO          302    RESET               startup_stm32f40_41xxx.o
    0x08000188   0x00000008   Code   RO         5804  * !!!main             c_w.l(__main.o)
    0x08000190   0x00000000   Code   RO         5799    .ARM.Collect$$_printf_percent$$00000000  c_w.l(_printf_percent.o)
    0x08000190   0x00000006   Code   RO         5798    .ARM.Collect$$_printf_percent$$00000009  c_w.l(_printf_d.o)
    0x08000196   0x00000006   Code   RO         5797    .ARM.Collect$$_printf_percent$$0000000C  c_w.l(_printf_x.o)
    0x0800019c   0x00000006   Code   RO         5796    .ARM.Collect$$_printf_percent$$00000014  c_w.l(_printf_s.o)
    0x080001a2   0x00000004   Code   RO         5832    .ARM.Collect$$_printf_percent$$00000017  c_w.l(_printf_percent_end.o)
    0x080001a6   0x00000002   Code   RO         5923    .ARM.Collect$$libinit$$00000000  c_w.l(libinit.o)

1、Exec Addr:运行域地址
2、Load Addr:加载域地址
3、Size:存储大小
4、Type:类型
Data:数据类型
Code:代码类型
Zero:未初始化变量类型
PAD:这个类型在map文件中放在这个位置,其实它不能算这里的类型。要翻译的话,只能说的“补充类型”。

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

3.4.2 运行域

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

Execution Region RW_IRAM1 (Base: 0x20000000, Size: 0x00002920, Max: 0x00020000, ABSOLUTE)

    Base Addr    Size         Type   Attr      Idx    E Section Name        Object

    0x20000000   0x00000028   Data   RW            7    .data               main.o
    0x20000028   0x00000180   Data   RW          347    .data               usart.o
    0x200001a8   0x00000008   Data   RW          501    .data               timer.o
    0x200001b0   0x00000004   Data   RW          565    .data               delay.o
    0x200001b4   0x00000001   Data   RW          694    .data               key.o
    0x200001b5   0x00000001   PAD
    0x200001b6   0x00000004   Data   RW          790    .data               lcd.o
    0x200001ba   0x00000002   PAD
    0x200001bc   0x00000008   Data   RW          979    .data               pwm.o
    0x200001c4   0x00000010   Data   RW         3651    .data               stm32f4xx_rcc.o
    0x200001d4   0x00002008   Zero   RW            5    .bss                main.o
    0x200021dc   0x000000c8   Zero   RW          346    .bss                usart.o
    0x200022a4   0x0000000e   Zero   RW          788    .bss                lcd.o
    0x200022b2   0x0000000a   Zero   RW          978    .bss                pwm.o
    0x200022bc   0x00000060   Zero   RW         5842    .bss                c_w.l(libspace.o)
    0x2000231c   0x00000004   PAD
    0x20002320   0x00000200   Zero   RW          301    HEAP                startup_stm32f40_41xxx.o
    0x20002520   0x00000400   Zero   RW          300    STACK               startup_stm32f40_41xxx.o
  Load Region LR$$.ARM.__AT_0x68000000 (Base: 0x68000000, Size: 0x00000000, Max: 0x000f4240, ABSOLUTE)

    Execution Region ER$$.ARM.__AT_0x68000000 (Base: 0x68000000, Size: 0x00000000, Max: 0x000f4240, ABSOLUTE, UNINIT)

3.5 Image component sizes(映像组件大小)

map 文件的最后一部分是包含映像组件大小的信息 (Image component sizes),这也是最常查询的内容
在这里插入图片描述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显示已提取并作为单个对象添加到映像中的库成员占用了多少字节。

在这里插入图片描述

映像文件的总结说明

在这里插入图片描述Grand Totals:显示映像的真实大小。表示整个代码占据的所有空间信息

  • Code 20880已经包含inc.data
  • inc.data 1902 字节
  • RO Data 1016 字节

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

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

第二部分列出了只读数据 (RO)、可读写数据 (RW) 及占据的 ROM 大小。(与图不对应 凑活看)

  • 其中只读数据大小为14376 字节,它包含 Code 段及 RO-data 段;
  • 可读写数据大小为 2112 字节,它包含 RW-data 及 ZI-data 段;
  • 占据的 ROM 大小为 14404 字节,它除了 Code 段和 RO-data 段,还包含了运行时需要从ROM 加载到 RAM 的 RW-data 数据。

4 代码运行逻辑

加载域就是程序在Flash中的实际存储,而运行域是芯片上电后的运行状态,因为MCU没上电时RAM中没有数据,所以此时所有的东西(包括代码、变量、初始值等)都是存放在flash中的,当上电后又要把变量等复制到RAM中才能正常运行。
在这里插入图片描述在执行映像之前,必须将已初始化的RW数据从ROM中复制到RAM中的执行地址并创建ZI Section(初始值为0的变量区),这样才算完成了MCU运行的准备。

当程序下载到 外部 FLASH 时

  • 需要使用的内部 FLASH 是从 0x6000 0000 地址开始的大小为 14376 字节的空间;
  • 当程序运行时,需要使用的内部 SRAM 是从 0x20000000 地址开始的大小为 2112 字节的空间。
    • 仔细分析 map 文件后,可了解到这 2112 字节中包含堆空间和栈空间。
    • 栈空间大小是在分散加载文件中定义的,这1024 字节是默认值 (0x00000400),是提供给 C 语言程序局部变量申请使用的空间
    • 不需要这么大的栈,完全可以修改分散加载文件,把它改小一点
    • htm 静态调用图文件可了解静态的栈调用情况
  • 22
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万码无虫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值