MDK编译过程和文件类型
1 编译过程
(1)编译:MDK 软件使用的编译器是 armcc 和 armasm,它们根据每个 c / c++和汇编源文件编译成对应的以“.o”为后缀名的对
象文件(Object Code,也称目标文件),其内容主要是从源文件编译得到的机器码,包含了代码、数据以及调试使用的信息;
编译器:
.o文件(每个.c文件,编译完都会生成.o目标文件):
(2)链接:链接器 armlink 把各个.o 文件及库文件链接成一个映像文件 “.axf” (MDK)或 “.elf”(IAR) ;
(3)对链接器生成的 elf 映像文件利用格式转换器fromelf 转换成“.bin”或“.hex”文件,交给下载器下载到芯片的FLASH中;
MDK 软件的编译过程:
2 程序的组成、存储和运行
MDK的编译信息:
在工程的编译提示输出信息中有一个语句“ Program Size: Code=xx RO-data=xx RWdata=xx ZI-data=xx”,它说明了程序各个域的大小,编译后,应用程序中所有具有同一性质的数据(包括代码)被归到一个域,程序在存储或运行的时候,不同的域会呈现不同的状态,这些域的意义如下:
接下来,看一下const关键词和编译器优化,对代码大小的影响(均在优化等级 Level 0 下进行测试):
代码如下,很简单的电灯程序,编译完的大小为:
可以看到,RO_data只读数据域的大小为 320字节。接下来,进行测试,使用const关键词,定义一个大的全局数组,观察RO_data的大小变化:
可以看到,无论是代码域,还是只读数据域,所有的大小都没有发生改变。为什么?实际上是因为,我们虽然定义了这个数组,但并没有在程序中有效使用,所以这个数组会直接被编译器优化掉。再看一个例子:
我们虽然在程序中使用到了数组,但实际上,这个语句并没有起到任何作用,所以一样会被编译器优化。
如果我们真正的使用了这个数组,再看一下编译大小:
这次,编译的结果就明显不同。首先,代码域增大,这个很明显时因为我们增加了一些有效代码;比较重要的时,RO-data最开始为320字节,现在为1344字节,1344 - 320 = 1024,正好就是我们定义的const数组。
接下来,再看一下编译器优化等级对编译效果的影响(开到最高等级Level 3):
可以看到,代码域明显变小,其他的空间域无变化。
RW-data,正常时会存储到 Flash 空间,在程序运行时,会被加载到 RAM 区,此时这些数据就可以被修改,进行测试:
未定义前:
接下来,去掉前面定义的大数组的 const,看看编译结果:
可以看到,RW-data增加了1024字节。
ZI-data与RW-data不同,它不需要先存储在Flash中,而是在程序运行时,直接在RAM空间划分一个区域,把这些数据全部初始化为0,后续的运行就和RW-data一致。如果在定义变量时没有初始化,MDK 编译器会默认初始化为0。也就是说,ZI-data的数据不占用Flash空间,如果我们定义ZI-data,就可以节省空间。
实际测试一下:
#define SOFT_DELAY Delay(0x0FFFFF);
uint8_t largeArray[1024] = {0, 1, 2};
编译结果如下,初始时ZI-data = 1024字节
然后我们将变量的初始值设置为0,再编译:
#define SOFT_DELAY Delay(0x0FFFFF);
uint8_t largeArray[1024] = {0};
可以看到,ZI-data增加了1024字节。
总结一下,我们要存储到 Flash 中的数据大小总共为:Code + RO-data + RW-data(字节)
ZI-data 堆栈空间
stm32中,使用的堆栈空间,其实是输入ZI-data。为什么要使用栈和堆?首先是栈,在进行函数调用时,会使用到函数内部定义的局部变量,当然了,这些局部变量也需要临时存储,而且有一个特点,进入函数时申请,退出函数时释放,整一个的生命周期很短,使用栈可以自动申请和释放局部变量以节省内存空间。试想一下,我们定义的一个普通变量,如int a = 8; 它就会一直存在于内存中占用几个字节,没办法释放掉。而使用栈空间,就能够自动的存储和释放局部变量。堆空间的原理类似,主要用于动态内存分配。
注意,如果不使用malloc申请堆空间,则编译器会优化,不把堆空间计算到ZI-data中。我们来看一下,为什么ZI-data为1024?
这是启动文件中,默认定义的栈空间和堆空间的大小,可以看到,栈空间为1024字节,堆空间为512字节。而在我们的函数中,如果不使用malloc函数申请内存,堆空间会直接被编译器优化掉。
可以看到,ZI-data的大小就是分配的栈空间大小。我们尝试一下修改掉启动文件,增加栈的大小,看ZI-data会有什么变化?
如图所示,我们设置的栈大小为2048,将启动文件中的栈设置为0X800,再重新编译:
编译结果如下,与我们预期的结果相同。
接下来,我们在函数中添加动态内存相关的程序,看对编译结果的影响(栈设置为1024字节):
可以看到,当我们使用动态内存分配时,编译器的ZI-data就不再优化堆空间,此时ZI-data = 初始值为0的全局变量 + 栈空间 + 堆空间,如下所示:
编译结果如下所示,ZI-data = 1024(栈)+ 512(堆)+ 1000(0初始值全局变量)= 2536
程序的存储与运行:
stm32的程序运行描述:
总结一下:
在 MDK 编译器中,只要选择好了芯片型号,就会自动对应的给出Falsh起始地址+大小,内存起始地址+大小,下面以stm32vet6(64 + 512)为例说明:
首先是Flash,我们看一下中文参考手册中的描述:
类似的,关于SRAM:
编译工具链
1 Windows cmd路径命令(与Linux系统不太一样)
通常情况下,我们要进入其他盘符下的任意目录,需要在CMD窗口运行两次命令:第一次,进入盘符,第二次进入指定目录
#进入D盘
d:
#进入D盘下的Keil5文件夹
cd test
cls 清除命令行
如下所示:
2 之前有提高编译器的文件夹,里面包含了好几个编译和链接工具,现在使用Windows PowerShell来查看:
可以看到,该文件夹下有5个编译和链接工具,我们尝试来运行一下 fromelf.exe,直接在命令行输入 .fromelf.exe,然后会打印出许多提示信息(包括MDK版本,编译器版本、功能选项等):
3 配置环境变量:
为什么要配置环境变量?刚才,我们是进入到/ARM/ARMCC/bin/路径下,打开的fromelf工具。那么,我们能不能任意路径下都直接打开fromelf呢?可以尝试一下
结果显示,我们直接在c盘下输入fromelf,并不能运行,因为系统在该目录下没找到对应的文件,所以提示错误。当我们输入正确的路径后,fromelf可以运行。那么,每次都要输入这么长的路径吗?看一下windows系统对于环境变量的说明:
很明显,我们可以通过将/ARM/ARMCC/bin/这个路径添加到系统的环境变量,这样就更方便我们程序的执行:
环境变量添加完成后(win10需要重启),直接就能任意路径下运行:
4 工具链的作用(armcc armasm armlink):
4.1 armcc
用于把 c/c++文件编译成 ARM 指令代码,编译后会输出 ELF 格式的 O 文件(对象、目标文件)。
首先来看armcc(MDK推荐使用Level 1 一级优化):
命令说明:
使用 armcc --cpu list,打印当前所有的cpu列表.可以看到,其中包含了Cortex-M0 M3 M4等内核的CPU。
接下来看MDK对armcc编译器的控制命令:
当我们在 MDK 中进行勾选时,实际上就是对armcc编译器进行对应的配置:
4.2 armasm
armasm 是汇编器,它把汇编文件编译成 O 文件。
然后看一下 armasm,其实和 armcc 非常类似:
这里,我们也是通过 MDK 进行勾选来配置:
4.3 armlink
armlink 是链接器,它把各个 O 文件链接组合在一起生成 ELF 格式的 AXF 文件,AXF文件是可执行的,下载器把该文件中的指令代码下载到芯片后,该芯片就能运行程序了;利用 armlink 还可以控制程序存储到指定的 ROM 或 RAM 地址。
armlink 链接器:
同样的,在 MDK 软件中进行勾选配置(注意,这里可以用来配置ROM和RAM的基地址):
链接器默认是根据芯片类型的存储器分布来生成程序的,该存储器分布被记录在工程里的 sct 后缀的文件中,有特殊需要的话可自行编辑该文件,改变链接器的链接方式。
4.4 armar
armar 工具用于把工程打包成静态链接库 .lib文件,.lib文件可以提供给别人使用(别人能够使用,但不能查看源代码),从而保护源代码,勾选可以生成 .lib文件。
4.5 fromelf
fromelf 可根据 axf 文件生成 hex、bin文件, hex 和 bin 文件是大多数下载器支持的下载文件格式。可以在下图加入一些指令:
关于User配置的描述:
接下来,我们尝试利用fromelf 手动生成 bin文件和hex文件:
1 我们复制生成的 .axf到文件夹,如图所示,并在此路径下打开windows powershell:
可以看到,在此路径下,此时只有一个 流水灯.axf 文件,接下来,查看一下 fromelf 的说明:
根据说明提示,来生成bin文件,使用的命令如下:
fromelf --bin --output 流水灯.bin 流水灯.axf
结果如下,bin文件生成成功。
同理,再生成 Intel 格式的hex文件:
fromelf --i32 --output 流水灯.hex 流水灯.axf
hex文件已经生成了,我们还需要看一下,利用fromelf和MDK生成的hex,是不是完全一致,结果如下:
这里还有一个地方值得注意,那就是 .axf 的路径一定要正确。实际上,MDK的相对路径,是从uvprojx工程开始的,如下所示:
上一篇:stm32专题三十五:DAC
下一篇:stm32专题三十六:MDK编译过程和文件类型(二)
推荐阅读
史海拾趣
在1936年至1962年期间,Cornell Dubilier公司在汉密尔顿工业园运营,专门制造电子零件和组件。然而,在这一时期,公司在生产过程中使用了含有多氯联苯(PCB)和其他有害物质的材料,并将其直接倾倒在现场土壤中。这一行为导致了严重的环境污染问题,使得该场地在后续被众多商业企业占据后,仍面临着环境保护的挑战。
1937年,在美国的科罗拉多州,BAND-IT公司应运而生。当时,电子行业正处于快速发展的初期,对高质量紧固件的需求日益增长。BAND-IT创始人敏锐地捕捉到了这一机遇,开始设计和制造不锈钢带和扎扣,以及C00169标准绑带机。这些产品迅速在电子行业中获得了认可,成为电缆、电线束等部件紧固的理想选择。初创时期的BAND-IT面临着资金短缺、市场竞争激烈等挑战,但凭借其创新的产品和卓越的品质,逐渐在电子行业中站稳了脚跟。
除了上述重要事件外,Contrinex还一直致力于产品创新和技术研发。多年来,公司不断推出新型传感器产品,如防磁防焊型电感式传感器、扩展型纤细型安全光幕等,以满足不同客户的需求。同时,Contrinex还积极与OEM和系统集成商合作,共同开发定制化解决方案,为客户提供更加全面和专业的服务。
这些故事只是Contrinex在电子行业发展历程中的一部分。作为一个不断追求卓越和创新的企业,Contrinex将继续致力于为客户提供高品质、高精度的传感器产品和解决方案,推动电子行业的持续发展。
在国内市场取得一定成绩后,Dawning开始将目光投向国际市场。公司积极参加国际电子展会,与全球知名企业进行交流合作。同时,Dawning还根据不同国家和地区的市场需求,调整产品策略,推出符合当地消费者喜好的产品。经过几年的努力,Dawning的产品已经成功打入欧美、东南亚等多个国家和地区的市场,公司的国际化进程取得了显著进展。
在快速发展的过程中,Dawning意识到企业文化的重要性。公司注重培养员工的团队合作精神和创新能力,定期组织各种团建活动和文化交流活动。同时,Dawning还倡导“以人为本”的管理理念,关注员工的成长和发展,为员工提供良好的职业发展平台。这些举措的实施,使得Dawning的员工队伍更加团结、稳定和有活力,为公司的长远发展奠定了坚实的基础。
进入1940年代后期,ET Enterprises Ltd公司将业务重心转向光电倍增管的开发和制造。通过不断的技术创新和市场拓展,公司逐渐在光电倍增管领域建立起领先地位,成为国际知名的光电倍增管供应商。
车型:丰田ES300轿车,A540E型自动变速器。 故障症状:该车D档位前进时,车速不能随油门加大而随之增速,而且逐渐下降,有打滑现象。 诊断与排除:经拆检发现一组摩擦片烧坏,变速器有焦味,更换摩擦片后试车正常。但经高速行驶1500公里后又 ...… 查看全部问答∨ |
摘要:红外微电脑自动泵液晶是21世纪一个实用的全新的小家电产品。它采用红外技术感应人手,由单片机控制出液量,具有抗干扰能力强、无误操作、省电节能等特点。 关键词:红外 泵液晶 单片机 随 ...… 查看全部问答∨ |
前一段时间在论坛看到有人问如何看元器件的时序图,我也曾经发了一个讨论帖 今天在网上看到这个帖子,不敢专享,共享出来,希望对大家有用 1、如何读单片机的时序图,国外的一个培训文档,讲解得很精细,有兴趣有朋友好好读读。 2、MCU ...… 查看全部问答∨ |
|
系统:CE5,开发工具:EVC4 用DirectShow开发MP3播放器,功能已经实现。但昨天测试发现一个问题,先描述一下: 播放MP3,触笔点击播放进度条调整播放进度,然后正常播放。此时一切正常! 但是当这首歌播放完毕,自动转到下一首时,出现异常:不是 ...… 查看全部问答∨ |
|
本人欲移植一个com的test程序(从ARM平台到x86平台),所用的编译平台是pb4.2和evc4.0,源代码(MFC程序)给编译完后可以在arm机器上正常运行,本人在evc中重选了wince x86编译器并且使用的是STANDARSDK_500(4.2有STANDSDK吗?网上没找到),用PB ...… 查看全部问答∨ |
CSR0B = 0x00; UCSR0A = 0x02 ; UCSR0C = 0x26 ; //偶校验 请问是不是UCSR0C的bit5 bit4这两位 设置成 1 0 完成了偶校验的饿设置之后,UCSROC= 0x26 单片机的硬件部分就能自动把软件代码部分自动执行偶校验? ...… 查看全部问答∨ |