专栏首页嵌入式大杂烩程序的组成、存储与运行

程序的组成、存储与运行

一般 MCU 包含的存储空间有:片内 Flash 与片内 RAM, RAM 相当于内存, Flash 相当于硬盘。编译器会将一个程序分类为好几个部分,分别存储在 MCU 不同的存储区。

一、编译过程

之前分享过C程序的编译过程的笔记:C程序的编译过程是怎样的?

这里先简单看一下MDK的编译过程(它与其它编译器的工作过程是类似的 ):

(1) 编译, MDK 软件使用的编译器是 armccarmasm,它们根据每个 c/c++和汇编源文件编译成对应的以“.o”为后缀名的对象文件(Object Code,也称目标文件),其内容主要是从源文件编译得到的机器码,包含了代码、数据以及调试使用的信息; (2) 链接,链接器 armlink 把各个.o 文件及库文件链接成一个映像文件.axf.elf

(3) 格式转换,一般来说 Windows 或 Linux 系统使用链接器直接生成可执行映像文件 elf后,内核根据该文件的信息加载后,就可以运行程序了,但在单片机平台上,需要把该文件的内容加载到芯片上,所以还需要对链接器生成的 elf 映像文件利用格式转换器fromelf 转换成.bin.hex文件,交给下载器下载到芯片的 FLASH 或 ROM 中。

这些编译工具都存在于我们MDK的安装目录下,如:

二、程序的组成、存储及运行

程序在我们的MDK编译后,Build Output 窗口显示信息如下:

Program Size 包含以下几个部分:

1) Code:代码段,存放程序的代码部分; 2) RO-data:只读数据段,存放程序中定义的常量; 3) RW-data:读写数据段,存放初始化为非 0 值的全局变量; 4) ZI-data: 0 数据段,存放未初始化的全局变量及初始化为 0 的变量;

编译完工程会生成一个. map 的文件,该文件说明了各个函数占用的尺寸和地址,在文件的最后几行也说明了上面几个字段的关系,如:

1) RO Size 包含了 Code 及 RO-data,表示程序占用 Flash 空间的大小; 2) RW Size 包含了 RW-data 及 ZI-data,表示运行时占用的 RAM 的大小; 3) ROM Size 包含了 Code、 RO Data 以及 RW Data,表示烧写程序所占用的 Flash 空间的大小;

程序运行之前,需要有文件实体被烧录到 STM32 的 Flash 中,一般是 bin 或者 hex 文件,该被烧录文件称为可执行映像文件。STM32程序内存分布如:

左图是可执行映像文件烧录到 STM32 后的内存分布,它包含 RO 段和 RW 段两个部分:其中 RO 段中保存了Code、 RO-data 的数据, RW 段保存了 RW-data 的数据,由于 ZI-data 都是 0,所以未包含在映像文件中。

STM32 在上电启动之后默认从 Flash 启动,启动之后会将 RW 段中的 RW-data(初始化的全局变量)搬运到 RAM 中,但不会搬运 RO 段,即 CPU 的执行代码从 Flash 中读取,另外根据编译器给出的 ZI 地址和大小分配出 ZI 段,并将这块 RAM 区域清零。

其中动态内存堆为未使用的 RAM 空间,应用程序申请和释放的内存块都来自该空间。如下面的例子:

代码中的 msg_ptr 指针指向的 128 字节内存空间位于动态内存堆空间中。

而一些全局变量则是存放于 RW 段和 ZI 段中, RW 段存放的是具有初始值的全局变量(而常量形式的全局变量则放置在 RO 段中,是只读属性的), ZI 段存放的系统未初始化的全局变量,如下面的例子:

sensor_value 存放在 ZI 段中,系统启动后会自动初始化成零(由用户程序或编译器提供的一些库函数初始化成零)。 sensor_inited 变量则存放在 RW 段中,而 sensor_enable 存放在 RO 段中。

三、MDK 工程的文件类型

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【STM32笔记】使用STM32内部Flash额外的空间来存储数据

    STM32 芯片内部的 FLASH 存储器,主要用于存储我们代码。如果内部FLASH存储完我们的代码还有剩余的空间,那么这些剩余的空间我们就可以利用起来,存储一...

    正念君
  • 【C语言笔记】枚举

    这个知识点很重要,到处能用得到。其可以与typedef来进行类比进行理解(可查看【C语言笔记】define与typedef的区别?)。除此之外,其还可以与枚举e...

    正念君
  • 【Linux笔记】make工程管理工具(一)

    上一篇笔记写了如何使用gcc的编译命令编译:【Linux笔记】Linux下编译C程序。当源文件较少时,使用gcc编译命令编译就比较方便,在gcc编译命令中依次列...

    正念君
  • python接口自动化27-urlencode编码与解码

    urllib.parse 里面三个方法:urlencode,quote,unquote详解。

    上海-悠悠
  • 《数据科学家访谈录》总结·4

    01 - 05:DJ Patil, Hillary Mason, Pete Skomoroch, Mike Dewar, Riley Newman 06 - ...

    SeanCheney
  • 如何不编程,采集网站评论信息?(视频教程)

    最近的一次组会,我们请来了一位分享嘉宾——15级研究生庞琳同学,给我们科研团队分享网站评论数据的采集。

    用户2930930
  • intellij idea tomcat热部署配置1.设置Debugger-HotSwap2.项目设置3.配置tomcat

    在setting界面,打开Debugger-HotSwap选项,确保勾选了Build project before reloading classes,同时选择...

    JavaEdge
  • LeetCode 37. Sudoku Solver

    ShenduCC
  • 自动微分技术

    几乎所有机器学习算法在训练或预测时都归结为求解最优化问题,如果目标函数可导,在问题变为训练函数的驻点。通常情况下无法得到驻点的解析解,因此只能采用数值优化算法,...

    SIGAI学习与实践平台
  • Unity Application Block 发布

    今天Unity Application Block提前发布了,翻译一下下文纪念一下. 顺便推荐看看我整理的Castle方面的资料开源框架:Castle,这有助于...

    张善友

扫码关注云+社区

领取腾讯云代金券