生成 bin 和 hex文件
若编译过程无误,即可把工程生成前面对应的*.axf 文件,而在 MDK 中使用下载器(DAP/JLINK/ULINK 等)下载程序或仿真的时候, MDK 调用的就是*.axf 文件,它解释该文件,然后控制下载器把*.axf 中的代码内容下载到 STM32 芯片对应的存储空间,然后复位后芯片就开始执行代码了。
然而,脱离了 MDK 或 IAR 等工具,下载器就无法直接使用*.axf 文件下载代码了,它们一般仅支持 hex 和 bin 格式的代码数据文件。默认情况下 MDK 都不会生成 hex 及 bin 文件,需要配置工程选项或使用 fromelf 命令。
fromelf的命令描述:
bin 和 hex 文件详解
bin文件就是纯二进制数据,无特殊格式。
hex 是 Intel 公司制定的一种使用 ASCII 文本记录机器码或常量数据的文件格式,这种文件常常用来记录将要存储到 ROM 中的数据,绝大多数下载器支持该格式。
hex格式的具体描述如下所示,非常重要。
5个记录,每部分的具体意义:
接下来,我们分析一下这几条hex文件的内容和意义:
用vscode打开我们生成的hex文件如下,可以看到,与上述hex格式编码要求一致。
为了更清楚地对比 bin、 hex 及 axf 文件的差异,我们来查看这些文件内部记录的信息来进行对比:
注意,bin文件直接用记事本打开会乱码,因为windows记事本默认是ASCII编码格式,而bin文件不是ASCII格式存储,所以记事本打开会是乱七八糟的乱码。
接下来,我们对比看一下bin hex文件的大小:
bin文件:
可以看到,bin文件大小为1440字节,而占用的空间是4096字节。为什么会有这个区别?
因为博主使用的windows系统,一个文件最小是4096字节,文件占用的空间都必须是4096的倍数。再进一步分析,为什么bin文件是1440字节?
实际上,1440 = 1096 + 336 + 8,bin文件的大小,就是实际上要存储在flash的数据大小。所以,bin文件是一种很纯粹的数据格式。
hex文件:
可以看到,hex的实际大小为4101字节(>4096),只比4096字节超出一点点。但windows使用的文件系统,就是会占用到
8192 = 2 * 4096字节的存储空间。
axf文件:
axf文件,可以看到,要比bin文件和hex文件大很多,因为其中还存储了各种MDK文件类型信息。我们可以直接使用fromelf工具,来对axf文件进行反汇编,来得到汇编代码,进而破解别人的程序。
下面是bin hex elf反汇编的比较:
htm静态调用图文件
我们打开对应的流水灯.htm文件,如下所示:
该文件说明了本工程的静态栈空间最大占用 40 字节(Maximum Stack Usage:40bytes),这个占用最深的静态调用为“ main->LED_GPIO_Config->GPIO_Init”。注意这里给出的空间只是静态的栈使用统计,链接器无法统计动态使用情况,例如链接器无法知道递归函数的递归深度。在本文件的后面还可查询到其它函数的调用情况及其它细节。利用这些信息,我们可以大致了解工程中应该分配多少空间给栈,有空间余量的情况下,一般会设置比这个静态最深栈使用量大一倍,在 STM32 中可修改启动文件改变堆栈的大小;如果空间不足,可从该文件中了解到调用深度的信息,然后优化该代码。
map文件
如何打开 map 文件?1 直接在Listing目录下打开;2 在 MDK 中双击目标选项,即可打开 map 文件;
注意,在查看 map 文件时,要勾选 MDK 的如下选项配置:
选项One ELF Section per Function的主要功能是对冗余函数的优化。通过这个选项,可以在最后生成的二进制文件中将冗余函数排除掉(虽然其所在的文件已经参与了编译链接),以便最大程度地优化最后生成的二进制代码。
而该选项实现的机制是将每一个函数作为一个优化的单元,而并非整个文件作为参与优化的单元。
选项One ELF Section per Function所具有的这种优化功能特别重要,尤其是在对于生成的二进制文件大小有严格要求的场合。人们习惯将一系列接口函数放在一个文件里,然后将其整个包含在工程中,即使这个文件将只有一个函数被用到。这样,最后生成的二进制文件中就有可能包含众多的冗余函数,造成了宝贵存储空间的浪费。
选项One ELF Section per Function对于一个大工程的优化效果尤其突出,有时候甚至可以达到减半的效果。当然,对于小工程或是少有冗余函数的工程来说,其优化效果就没有那么明显了。
打开“流水灯.map”文件,可看到它的第一部分——节区的跨文件引用(Section Cross References):
我们来看一下 map 文件:
在这部分中,详细列出了各个*.o 文件之间的符号引用。由于*.o 文件是由 asm 或 c/c++源文件编译后生成的,各个文件及文件内的节区间互相独立,链接器根据它们之间的互相引用链接起来,链接的详细信息在这个“Section Cross References”一一列出。例如,开头部分说明的是 startup_stm32f10x.o 文件中的“RESET”节区分为它使用的“__initial_sp” 符号引用了同文件“STACK”节区。
也许我们对启动文件不熟悉,不清楚这究竟是什么,那我们继续浏览,可看到 main.o文件的引用说明,如说明 main.o 文件的 i.main 节区为它使用的 LED_GPIO_Config 符号引用了 bsp_led.o 文件的 i.LED_GPIO_Config 节区。
可以了解到,这些跨文件引用的符号其实就是源文件中的函数名、变量名。
常见的调试错误:
比如,我们现在改一下函数名(改成LED_GPIO_Config0),如下:
直接编译文件,没有问题,结果如下:
而当点击build(编译链接)时,就会出现错误如下:
其实,我在写代码时,有时会经常遇到这个错误。它提示的是,在main.o中,没有找到引用的函数(符号)LED_GPIO_Config,实际上,main.o是main.c编译后生成的目标文件,这个目标文件引用的LED_GPIO_Config在所有的目标文件中都没有找到,因为我们把函数名修改成了LED_GPIO_Config0。找不到,那么自然就提示错误了。
删除无用节区
map 文件的第二部分是删除无用节区的说明(Removing Unused input sections from the image)
这部分列出了在链接过程它发现工程中未被引用的节区,这些未被引用的节区将会被删除(指不加入到*.axf 文件,不是指在*.o 文件删除),这样可以防止这些无用数据占用程序空间。
再看一下gpio,因为我们之前使用了gpio_init的初始化函数,进行对比一下:
对比左右两边可以发现,我们在程序中调用过的GPIO_Init函数,没有出现在删除无用节区的列表中。而没有调用到的函数,被直接被删除掉以节省存储空间。
符号映像表
map 文件的第三部分是符号映像表
这个表列出了被引用的各个符号在存储器中的具体地址、占据的空间大小等信息。如我们可以查到 LED_GPIO_Config 符号存储在 0x08000251 地址,它属于 Thumb Code 类型,大小为 92 字节,它所在的节区为 bsp_led.o 文件的 i.LED_GPIO_Config 节区。
存储器映像索引
本工程的存储器映像索引分为 ER_IROM1 及 RW_IRAM1 部分,它们分别对应 STM32内部 FLASH 及 SRAM 的空间。相对于符号映像表,这个索引表描述的单位是节区,而且它描述的主要信息中包含了节区的类型及属性,由此可以区分 Code、 RO-data、 RW-data及 ZI-data。
例如,从上面的表中我们可以看到 i.LED_GPIO_Config 节区存储在内部 FLASH 的0x08000250 地址,大小为 0x00000060,类型为 Code,属性为 RO。而程序的 STACK 节区(栈空间)存储在 SRAM 的 0x20000208 地址,大小为 0x00000400,类型为 Zero,属性为RW(即 RW-data) 。
映像组件大小
map 文件的最后一部分是包含映像组件大小的信息(Image component sizes),这也是最常查询的内容。
首先是前面的表格数据,可以明显的看到中断向量表和启动文件栈空间:
这部分包含了各个使用到的*.o 文件的空间汇总信息、整个工程的空间汇总信息以及占用不同类型存储器的空间汇总信息,它们分类描述了具体占据的 Code、 RO-data、 RW-data及 ZI-data 的大小,并根据这些大小统计出占据的 ROM 总空间。
数据分析:
上一篇:stm32专题三十六:MDK编译过程和文件类型(二)
下一篇:stm32专题三十六:MDK编译过程和文件类型(四)
推荐阅读
史海拾趣
作为一家电子产品制造企业,Epistar始终关注环保和可持续发展问题。公司积极采用环保材料和生产工艺减少污染排放和能源消耗;同时,Epistar还加强了对废旧产品的回收和处理工作以减少对环境的负面影响。这些努力不仅提升了公司的社会形象也增强了公司的市场竞争力。
Big-Sun Electronics Co Ltd公司在追求经济效益的同时,也积极履行社会责任。公司注重环保和节能减排,采用先进的生产工艺和设备,减少生产过程中的环境污染。此外,Big-Sun还积极参与社会公益事业,为当地社区的发展和教育事业做出了积极贡献。
这些故事旨在展示Big-Sun Electronics Co Ltd公司可能的发展历程,但请注意,这些并非基于实际发生的事件。如果需要了解Big-Sun Electronics Co Ltd公司的真实历史和发展故事,建议查阅相关官方资料或新闻报道。
在电子行业竞争日益激烈的背景下,EOREX公司敏锐地洞察到智能家居市场的巨大潜力。他们及时调整战略方向,将研发重心转向智能家居领域,推出了一系列具有创新性和实用性的智能家居产品。同时,EOREX还积极布局全球市场,通过与海外企业的合作与交流,不断引进先进的技术和设计理念,提升自身的竞争力。这些举措使得EOREX在智能家居领域迅速崛起,成为行业内的佼佼者。
在电子行业竞争日益激烈的背景下,EOREX公司敏锐地洞察到智能家居市场的巨大潜力。他们及时调整战略方向,将研发重心转向智能家居领域,推出了一系列具有创新性和实用性的智能家居产品。同时,EOREX还积极布局全球市场,通过与海外企业的合作与交流,不断引进先进的技术和设计理念,提升自身的竞争力。这些举措使得EOREX在智能家居领域迅速崛起,成为行业内的佼佼者。
在国内市场取得成功后,Datalinear公司开始寻求国际化的发展。公司派遣团队前往欧美等发达国家进行市场调研,并根据当地市场需求进行产品定制。通过不懈的努力,Datalinear公司的产品在海外市场取得了良好的销售业绩,并逐步建立了全球化的销售网络。
进入1950年代,随着联邦政府对卡车运输的规范,Günter Bals意识到单一的运输业务已无法满足公司长远发展的需要。于是,他与妻子伊丽莎白共同创立了Bals Elektrotechnik GmbH,开始涉足电气连接器的生产。这一转型对Bals来说既是挑战也是机遇,他们凭借对市场的敏锐洞察和不懈的技术研发,成功推出了第一批铝制连接器,并逐步打开了市场。
引自:http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=1333173&bbs_page_no=1&bbs_id=9999 我本来觉得水果电池驱动LCD只是展示会上的噱头,三片柠檬的电力,应该足够带动LCD的。不过最初当我用 Mega8L做了一个电路却不能用水果电池驱动时, ...… 查看全部问答∨ |
今天弄了一个12864显示图片的程序,网上有不少例程,我找的不够详细,比如取模时的设置那些,我就是在取模的设置费了不少时间,很是郁闷,还以为程序有问题呢。应该说是战略问题,一开始用的图片很复杂,后来才用简单的直线来揣摩出取模的正确设置 ...… 查看全部问答∨ |
想学学wince 怎么入门呢? (1)入门要看什么书啊?推荐些经典的! (2)wince是不是就是嵌入式的意思? ARM是和wince什么关系啊? 问题很菜吧,呵!… 查看全部问答∨ |
|
小弟目前在做一款PCMCIA无线网卡在wince下的驱动程序,但一开始就遇到麻烦,我用下面的代码查找总线上的无线网卡的VenderID,但返回值一直是0x8000FF00,请各位指点一下. for (bus = 0; bus < PCI_MAX_BUS; bus++) { for (device = 0; ...… 查看全部问答∨ |
请问:platform manager 与platform builder有什么区别呀,是不是一个意思呀? platform manager 与platform builder有什么区别呀,是不是一个意思呀… 查看全部问答∨ |
本帖最后由 jameswangsynnex 于 2015-3-3 19:59 编辑 USB充电器套件,又名MP3MP4充电器,输入AC160-240V,50/60Hz,额定输出:DC 5V 250mA(标签贴纸为500mA,如果要长期输出更大电流,请更换Q1为13003)。MP3和MP4在全国范围大量流行,不过作为 ...… 查看全部问答∨ |
|
我准备开个VC和C#教程,大家觉得从什么方面开始,我觉得还是从做个实用的小程序开始,慢慢积累大家的兴趣,大家多提意见啊?我准备了几个方面:1、串口通信方面的,如串口调试助手2、通信控制显示方面的,用串口通信实现上位机显示单片机信息和下发 ...… 查看全部问答∨ |
【信号处理】:DSP+FPGA实时信号处理系统中FPGA设计的关键问题 简要分析了DSP+FPGA系统的特点和优越性,并且结合一个实时信号处理板的开发,提出在此类系统中,FPGA设计的几个关键问题,并且给出了详实的分析和解决方案。 … 查看全部问答∨ |