临近放假得空研究了一下MCU编译生成的map文件之前主要是通过这个文件查看RAM和Flash的使用情况其他的内容倒是没怎么仔细去关注最近研究了一下与大家分享。以Keil编译为例在工程指定的文件夹下面一般是listings文件夹会生成一个map文件这里的map其实是映像的意思所以一般称之为映像文件即可我们先来总结一下映像文件的作用概括一下主要涉及以下这个方面1. 内存使用分析查看各段Section大小代码段.text、数据段.data、未初始化数据段.bss、堆栈等检查内存溢出确认是否超出芯片RAM/Flash容量优化内存布局调整关键代码/数据位置。2. 调试和定位问题查找函数/变量地址将运行时地址映射回源代码分析链接错误如符号重复定义、未解析引用定位崩溃位置通过崩溃地址找到对应函数。3. 优化代码识别占用大的模块找出消耗Flash/RAM最多的文件/函数评估优化效果比较优化前后的内存变化管理库依赖查看链接了哪些库及其大小。4. 可以查看关键信息映像文件通常包含以下内容- Memory Configuration内存区域定义- Linker script info链接脚本配置- Section Placement各段分配地址和大小- Symbol Table所有符号函数/变量地址- Cross Reference模块间引用关系- Size Breakdown各模块/文件大小统计接下来我们以一个实际的映像文件来说明一下相关内容。打开映像文件后第一行有下面这样一句话其实这句话包含两个信息编译器版本ARM Compiler 5.06 update 7 (build960)链接器工具armlink [4d3601]这里的armlink是ARM Compiler工具链中的一部分负责将编译后的对象文件或者目标文件.o 或 .obj 文件和其他必要的库文件链接成最终的可执行文件或库文件。然后便是“Section Cross References”即前文所述的段模块之间的引用关系最开始的内容就是说明了main引用了哪些模块或文件的哪些接口比如main文件引用了app_di文件的di_thread接口比如main文件引用了app_do文件的do_thread接口等等。而main.o(i.cpu_thread)的括号里面的指的是main里面的哪个接口进行了引用。在这个里面你可以找到函数之间的调用关系是不是很Nice这部分内容的篇幅大小取决于代码的复杂程度一般会比较多的像我这个的话占了800多行吧。然后便是“Removing Unused input sections fromthe image”这部分主要是编译器移除你的工程中没有使用到的文件每行的开始都带着“Removing”字样在该部分的结尾的地方也可以看到下面这样一条内容以说明有多少个段区及总共有多少字节的数据量被移除这里表示链接器移除了未使用的段区共489个总计18906字节其实这有助于减少最终映像的大小。再往下就是“Image Symbol Table”可以翻译为“映像符号表”映像符号表其实是 Keil MDK 等嵌入式开发工具生成的 .map 文件中的核心部分它详细列出了程序中所有符号如变量、函数、代码段等在内存中的地址、类型和大小信息是分析程序内存布局、进行调试和优化的关键依据另外映像符号表主要分为Local Symbols局部符号 和Global Symbols全局符号 两类它们在作用域、内容和用途上存在明显区别。其中Local Symbols局部符号大概包括下面几种内容a、源文件路径和编译信息从左到右依次为符号名称地址符号类型大小和所属的目标文件。这里的符号类型要说明一下常见的主要有四种分别是Number、Section、Thumb Code 和 DataNumber表示一个具有特定数值的标签或地址标识通常用于定义常量或绝对地址不占用实际的存储空间。其大小字段通常为0。Section标识一个代码段或数据段的起始地址通常用于标记函数或变量的入口点。Thumb Code表示使用ARM Thumb指令集编译的机器代码通常是程序中的函数体。Data表示程序中的数据符号如全局变量或静态变量。其大小 字段表示该变量占用的字节数。b、编译器生成的段区地址和大小列出了各个段区的地址、大小和所属的目标文件。例如startup_at32f403a_407 .o(RESET)位于0x08000000大小为388字节以点号.开头如.text、.data、.bss表示各个段区的起始地址和大小这些信息对于链接器布局内存至关重要。c、Thumb Coded、局部变量或静态变量信息其中Global Symbols全局符号的各个参数说明与局部符号一样全局符号其实是链接器可见的、可以在不同模块间相互引用的符号构成了程序的公共接口主要包括全局函数全局变量外部可见的符号中断向量表中的符号。a、代码类符号主要就是函数类型为Thumb Code地址在flash区域大小则表示函数编译后的机器码字节数b、数据类符号主要就是变量接下来就是“Memory Map of the image”部分也就是映像内存分布是映像文件中最核心的内存布局描述内容是分析程序内存占用的关键依据有助于开发者明确程序各段在存储器中的物理位置加载时与运行时的内存映射关系以及RAM中动态分配区域的边界辅助排查内存溢出问题。在这部分的开始可以看到下面的内容Image Entry point指的是映射的入口地址是0x08020185Load Region LR_IROM1 (Base: 0x08020000,Size: 0x000092c4, Max: 0x00020000, ABSOLUTE, COMPRESSED[0x00008e84])表示Flash的起始地址基地址是0x08020000其实如果没有Bootloader程序这里的其实地址应该是0x08000000因为配置了偏移地址为0x20000即APP程序从0x08020000开始Size为0x000092c4即表示已使用0x000092c4/102436.6KBMax为0x00020000即表示最大容量为0x00020000/1024128KB。Execution Region ER_IROM1表示Flash中的执行区域其实这是实际在Flash中运行的部分各个参数的含义如下Execution Region RW_IRAM1表示RAM区域Exec baseRAM执行地址Load base初始值在Flash中的位置Size已使用的大小0x00001620即0x00001620/1024 5.53KBMax最大容量0x00038000即0x00038000/1024 224KB也就是此款MCU的RAM容量COMPRESSED 压缩的意思即这些数据的初始值在Flash中被压缩存储启动时解压到RAM。到了最后一部分了即“Image component sizes”映像组件大小其实这块是映像文件比较实用的一部分它告诉我们程序的每个部分占了多少的RAM或者Flash空间特别是MCU内存资源有限的时候有助于我们查看和优化代码各个参数的含义参考如下在下面你可以看到总计信息还可以看到RAM和Flash的总计信息这个里面细分了很多数据类型有兴趣的可以继续了解一下有助于代码优化。以上这些内容基本上就是整个映像文件的所有内容信息里面包含了各个函数和各个变量的地址信息如果真要继续展开来讲那简直是太多了。当遇到程序崩溃或者宕机的时候可以根据崩溃的地址信息到映像文件里查看地址对应的函数以尽量定位出现程序问题的接口位置有助于我们更快更精准的解决Bug。或者当你需要优化代码以节约内存空间的时候也可以来翻阅映像文件。另外其实在Keil仿真的时候我们也可以查看函数的地址信息将鼠标放在函数调用的地方就可以显示看到然后到映像文件里面看下这个函数的地址是不是这个地址确实是一样的。不仅如此在Keil里的MemoryWindow里面也可以直接输入地址进行查看总之很多时候你可以结合Keil的很多窗口信息和映像同步进行查看和问题排查。反正映像文件的内容实在是太多了我都快解读到晕了~~网上也有很多好的资料可以学习。。---------------------作者dffzh链接https://bbs.21ic.com/icview-3505686-1-1.html来源21ic.com此文章已获得原创/原创奖标签著作权归21ic所有任何人未经允许禁止转载。