|
越来越多的客户在使用STM32CubeIDE作为集成开发工具。STM32CubeIDE在编译代码的时候,用到了链接脚本。通常情况下,STM32CubeIDE会自动生成默认的链接脚本。但是有些情况下,例如,用户程序需要定义一些特别的段来放置代码或者数据的时候,我们就需要修改链接脚本文件。 5 B+ F& i0 I$ l- j. k" G: @! X 8 W7 V: Z! n' N, q 最近有客户在修改链接脚本后,编译没有出现问题。但是编译之后生成的BIN文件很大,导致无法烧录到Flash中。结合这个问题,本文详细分析一下它的原因以及解决办法。 问题描述/ g1 J; S2 d; x0 }) R $ W( I6 z* F4 p9 T 使用STM32CubeIDE创建工程的时候,在项目工程目录文件夹下生成后缀为ld的链接脚本文件,程序的编译和链接都会依赖链接脚本文件。如下图所示,STM32H743VIT6的RAM空间被包含6块,每块RAM的起始地址是独立的,如果客户需要把指定特定的RAM区域放置数据或者代码的时候,需要手动修改链接脚本文件。
客户在使用STM32H743VIT6进行应用开发的时候,需要在0x24000000 以及0x30000000的RAM空间定义两个未初始化的数组。所以客户修改了ld链接脚本文件,添加两个SECTIONS分别定位在0x24000000和0x30000000位置,同时在代码中使用__attribute__关键字指定数组在对应的SECTIONS中。3 Y, K2 W! g% X, K* r" o% J T/ r7 w( l- U. y7 I+ v; @ 依照客户的问题描述,我们首先修改链接脚本,添加两个SECTIONS分别为ram_at_0x24000000和ram_at_0x30000000,参考如下。: Z }4 C2 B! V. r
. o/ t& K7 P1 f }' D$ H2 x" U9 n) J 同时在源代码中添加两个数组,分别定位在添加的SECTIONS中,参考如下。; D, B1 r# T; E! n( T/ T, S- s& j
$ ~. _! c) R m) W8 c0 Y: M% { , v9 W9 U' @* i8 e 编译修改之后的工程,是可以正常运行的,但是我们发现当把ELF目标文件转为BIN文件之后,产生的BIN文件非常的大。这就导致如果使用BIN文件进行下载的话,是无法下载成功的,因为BIN文件的大小以及超出了Flash的存储空间。由下图BIN文件属性我们可以看到BIN文件的大小为650M。
+ X1 I5 @4 V% } a 那么是什么原因导致产生的BIN文件这么大呢?文件就出在ld链接脚本文件这里。 . w+ F) k3 X& m 问题分析 & [5 N0 k6 ?( i3 H8 x c( |8 E* _ : i/ v. @ }4 l; a BIN文件是最纯粹的二进制机器代码, 或者说是"顺序格式"。按照assembly code顺序翻译成binary machine code,内部没有地址标记。BIN是直接的内存映象表示,二进制文件大小即为文件所包含的数据的实际大小。BIN文件就是直接的二进制文件,一般用编程器烧写时从00开始,而如果下载运行,则下载到编译时的地址即可。" ?3 z+ d/ _: H! x6 B( v STM32CubeIDE依赖链接脚本文件生成目标ELF文件,生成ELF目标文件之后,STM32CubeIDE会依赖GNU Objcopy工具把ELF文件转为BIN文件。这个过程简单一点来说,就是提取ELF文件中的代码段以及可加载数据段按照地址信息顺序生成BIN文件。* e. F5 a1 X$ L% t$ V9 Z9 N & e3 x4 ~* v% C* u! G1 l3 t 所以,如果BIN文件很大,那说明可加载的代码段和数据段很大。在我们的测试项目中,代码段是固定的;现在BIN文件很大,说明是数据段过大导致的。 9 \, p' Z5 ]* r5 k+ [1 R m# _# f 通过查看编译产生的list文件,我们可以清楚的看到每个段的大小。
/ |$ ]# K$ z9 q 从上图的Sections Map中,每个Section会有几个关键的参数和类型。Size为每个Section的大小,VMA是指Section在程序运行时候的地址,LMA是指Section在Flash中的加载地址。通常情况下从Flash执行的程序,Code段VMA和LMA是一样的。Data段的VMA会放在RAM中,LMA会放在Flash中,所以Data段的VMA和LMA通常不一样。在每个段的类型中,还有一个关键的属性是LOAD,如果定义了LOAD属性,那说明这个段是需要写入Flash中的。 GNU Objcopy工具生成BIN文件的过程,实际上就是把ELF文件中各个定义了LOAD属性的SECTION按照LMA的先后顺序提取出来,写入BIN文件中。SECTION的地址如果不是连续的,间隔部分则会填充DUMMY或指定的数据。所以BIN文件的大小为最大LMA加上对应的SECTION的Size。, S7 b' ~8 J7 Q: ? 结合上图,该工程最终生成的BIN文件大小为 0x30000000+0x4000 -0x8000000 = 671105024 和图4的文件属性显示的大小是一致的。7 H1 n. e h) u: e9 F5 D) o 问题已分析' @% Y6 F* [# b' L! O3 ~ 问题解决 0 v3 X. j. o$ w- a e ▼查收解决方法▼ . m' Z3 U. j: a. L) E$ [6 p根据上面章节分析的原因,BIN文件过大是新增加的两个SECTIONS导致的。如图5所示,ram_at_0x24000000 段和ram_at_0x30000000段都具有LOAD属性,所以GNU Objcopy工具认为该段是需要加载到Flash中的。如果修改该段的属性为NOLOAD,则可解决这个问题。' q# q5 W! g' H( m4 l- T) J ) c, @- S8 q0 _9 ` 参考 The GNU Linker 文档第73页,指定SECTION的类型为NOLOAD。最终修改后的链接脚本文件如下所示。0 o; h, l/ D/ b
, v( y: O; |0 _9 l 依赖修改后的链接脚本编译得到的目标ELF文件,查看其段描述,可以知道新添加的段的属性不再为LOAD。GNU Objcopy工具在进行BIN文件生成的时候,也不会加载这两个段。所以,最终得到的BIN文件只包含有效的代码段和数据段,大小为24428字节。# W9 b; R3 r" H9 J5 ]2 ~% a0 ~
% ^& |. Y$ V) J: z 问题总结 ! t* X, q9 M/ C8 Z+ u4 n 5 @: U/ l3 S _) L. x 本文通过一个具体的问题阐述了BIN文件的产生过程,同时对链接脚本的格式做了一个简单的介绍。STM32用户后期如果遇到变量无需加载却导致BIN文件过大的问题,可依照该方法进行处理。/ @" a. ^" ^! B3 Q % s2 l l! L- I# q+ N: w0 ] |
【STM32H5 评测】基础硬件加密与随机数性能 - STM32H5E5实测硬件AES加解密、HASH运算、TRNG真随机数输出速率与稳定性
【STM32H5 评测】NUCLEO-H5E5ZJ 使用 TrustZone 安全分区系统实践测试
【STM32H5 评测】CPU核心性能 - STM32H5E5跑 RTOS,观察任务切换速度、中断响应快慢
【STM32H5 评测】内存读写性能 - STM32H5E5实测Flash,SRAM读写速度,用DMA搬运大块数据
【NUCLEO-C562RE】OLED 显示
保姆级教程:CMake 工程导入 STM32CubeIDE 步骤
STM32CubeCLT 1.22.0新版本发布
【下载问题解决】关于ST官网下载软件问题解决
【STM32H735G-DK测评】lvgl移植
【STM32H735G-DK 测评】STM32H735G-DK External Loder 编译和测试
微信公众号
手机版