STM32 MAP文件结合固件文件分析

MAP 文件分析可以参考之前的文章

程序代码在未运行时在存储器空间内称为加载域,在运行时在存储器空间内称为运行域。

加载域的结束地址并不是固件的结束地址?

在这里插入图片描述
在这里我们根据加载域的描述可以知道加载域的空间结束位置应该为0x08020000+0x00010978=0x08030978的位置。从下面的固件我们可以知道固件的实际结束位置应该是0x080305E8。这里的俩个位置并不一致是什么原因呢?我们继续往下逐步分析。

在这里插入图片描述

ROM中执行域的描述

在这里插入图片描述

上图内容的最后一行:结束地址为0x080304e0+0x20=0x08030500,和第一行中的描述一致。
根据类型和属性可以知道这一部分的内容为代码段(Code)只读数据段(RO Data)
起始的第一个段为只读数据段,这个段的内容为中断向量表的数据。

这里我们根据上图计算下:
代码段大小:0x0802f754-0x08020188= 0x000f5cc对应于十进制为62924
只读数据段大小:0x08030500-0x0802f754+0x188=0xf34对应于十进制为3892
在这里插入图片描述
计算结果刚好和MAP文件中固件信息汇总处的结果一致

RAM中执行域的描述

在这里插入图片描述
根据类型和属性信息我们可以知道这一部分内容为RW DataZI Data
这里我们根据上图计算:
RW Data大小:0x478对应于十进制为1144
ZI Data:0x49b0+0x2000-0x478=0x6538对应于十进制为25912
在这里插入图片描述
Grand Totals - 显示映像文件的真实大小
ELF Image Totals - 可执行链接格式映像文件大小(如果使用RW数据压缩来优化ROM大小,则最终镜像的大小会发生变化)
ROM Totals - 显示包含镜像所需的ROM的最小大小
上面的计算结果和真实映像文件的大小是对应的,由于对RW数据进行了压缩,导致实际的RW空间会比上面的计算值小。
知识点:linker默认会将重复的RW数据压缩。

上图中最后一行0x200049b0+0x2000=0x200069b0刚好和栈顶地址一致:
在这里插入图片描述

问题分析

至此我们基本知道了原因,由于链接时会将重复的RW数据进行压缩,所以实际的固件大小会小于加载数据的大小,差值刚好为被压缩掉的RW数据空间的大小

中断向量表在固件中的存储位置

在MAP文件中我们可以知道 ,向量表的起始地址为0x08020000结束地址为0x08020188
在这里插入图片描述
对应于固件中的信息:
在这里插入图片描述
首地址为栈顶地址,
在这里插入图片描述
第二数据为复位函数的入口地址
在这里插入图片描述
后续内容依次为中断向量表中各个中断函数的入口地址。

代码段在固件中的位置

中断向量表的内容结束后便是代码段的内容
从MAP文件中可以看出0x08020188位置开始到0x0802f754位置结束存储的内容便为代码段的程序代码
在这里插入图片描述
如下图红框中的位置开始后续便为程序代码的数据
在这里插入图片描述

在这里插入图片描述
上图为代码段结束部分的位置

只读数据

代码段内容结束后紧跟着就是只读数据段
从下面的map文件可知0x0802f754到0x0803500之间存储的便是只读数据
在这里插入图片描述
这里我们去上图长框位置的CRC32Table的数据进行查看,对应固件位置如下图所示:
在这里插入图片描述
上图红框位置开始后续的数据和下面表中的数据是完全一致的。
在这里插入图片描述

Regin$$Table

之前的文章中有分析这个数据表,往RAM空间加载数据依据的便是这个表提供的信息。
在这里插入图片描述

RW Data段

单纯从MAP文件看RW Data数据需要0x478字节的空间
在这里插入图片描述

在固件文件中从0x0803500一直到程序的结束存储的便是RW Data数据的内容,共占0xE8字节的空间,从上面的分析中可以知道,实际生成固件中的RW Data是压缩过后的数据,其中去掉了重复数据,等程序运行时在RAM中再将数据展开,这样有助于节省ROM空间。
在这里插入图片描述

其中的内部机理

对于没有赋初值或初始化为0的全局变量,会等到程序运行时再在RAM中划分出一块区域并初始化为0,这时你可能会纳闷程序代码中怎么知道变量在RAM中划分区域的位置呢?答案是程序实际就是知道,并且程序中每次需要访问变量的位置在程序代码中变量指向的空间就是RAM中对应的位置。你可能会感觉很神奇,但结合之前的Regin$$Table分析你可能就会感到豁然了,毕竟RAM中的空间分配早就在固件生成时都定义好了,固件中也已经记录了这些信息。
那对于RW Data而言其实道理也是一样的,只不过RW Data对应的数据是有初值的。这里我们只需将全部全局变量的值记录下来并去掉重复数据后存储到固件中,在程序运行时在RAM中创建了对应的全局变量空间后将初值赋值给对应的变量即可。不过这好像还有个疑问:运行时怎么知道将那个值赋值给哪个变量呢?后续再继续探究下。

这里进一步了解了下:在固件中存储的RW Data数据是压缩过的,在执行复制到RAM空间的过程中通过__decompress函数将数据解压缩出来,然后给对应位置的RAM空间赋值。
在这里插入图片描述
在这里插入图片描述

验证固件中的RW Data默认是经过压缩的

为了验证固件中的RW数据是压缩过的数据,这里可以使用链接器命令行选项 --datacompressor off 禁用压缩,然后再查看MAP文件中的RW数据大小:
在这里插入图片描述

在这里插入图片描述
此时使用了禁止压缩的指令后,RW数据部分的大小和之前的分析全都能对应起来了

总结

固件各段在Flash中的存放顺序,以及运行时加载到SRAM中的顺序如下:
在这里插入图片描述

参考链接:

Region-Table-format

  • 27
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值