文章目录
- 1 生成Map
- 2 map中概念
- 3 文件分析流程
- 3.1 Section Cross References
- 3.2 Removing Unused input sections from the image(移除未使用的段)
- 3.3 Memory Map of the image(映像的内存分布)
- 3.3.1 加载域
- 3.3.2 运行域
- 4 代码运行逻辑
- 5 F103部分
- 5.1 Image component sizes(映像组成大小)
- 5.2 映像文件的总结说明
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 文件分析流程
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
(模块、段的交叉引用关系)各个源文件生成的模块之间相互引用的关系。“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中的LED_Init函数,剩下的基本都是这类的意思。
startup_stm32f40_41xxx.o(.text) refers to __main.o(!!!main) for __main
在启动代码中调用了_main.o模块中的_main函数。
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字节。
3.3 Memory Map of the image(映像的内存分布)
映像文件可以分为加载域(Load Region)和运行域(Execution Region):
3.3.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.3.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)
4 代码运行逻辑
加载域就是程序在Flash中的实际存储,而运行域是芯片上电后的运行状态,因为MCU没上电时RAM中没有数据,所以此时所有的东西(包括代码、变量、初始值等)都是存放在flash中的,当上电后又要把变量等复制到RAM中才能正常运行。
在执行映像之前,必须将已初始化的RW数据从ROM中复制到RAM中的执行地址并创建ZI Section(初始值为0的变量区),这样才算完成了MCU运行的准备。
5 F103部分
5.1 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显示已提取并作为单个对象添加到映像中的库成员占用了多少字节。
5.2 映像文件的总结说明
Grand Totals:显示映像的真实大小。
ELF Image Totals:ELF(Executable and Linking Format)可执行链接格式映像文件大小。
ROM Totals:显示包含映像所需的 ROM的最小大小。这不包括 ZI数据和存储在ROM 中的调试信息。