IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> C程序载入内存的过程 -> 正文阅读

[嵌入式]C程序载入内存的过程

这篇文章是搜集了许多的帖子和资料,按照本人的理解写出来的。在文章末尾会将参考的帖子和资料标明,如果有什么错误和表达不当,希望读者能够指出。

简介:从内存角度,搞清楚C代码是怎样作用于单片机的。

问题:

  • 了解单片机的内存,众所周知单片机是取指执行,那么单片机从哪里取指的?所执行的数据又放在在哪里?
  • C代码是以什么样的形式进入到单片机内存中的?进入到了单片机内存的哪个位置?
  • 从C编译器到单片机的执行,程序经历了怎样的变化。
  • 在执行的过程中,内存中有怎样的变化?

目录

单片机内的存储区域

C程序 -> 可执行文件

单片机下载程序,保存到内存中

单片机运行过程中FLASH和SRAM的变化


单片机内的存储区域

不同的MCU的内核不同,所对应的RAM和ROM区域也不相同,存放代码和数据的方式也有所区别。在这里仅以Cortex-M4的参考手册为例,简单介绍一下单片机内部的存储机制。

下图是Cortex-M4内核的地址映射,注意到图中标红的Code和SRAM两个区域。这两个区域是单片机下载代码和数据后存放的位置。

Code以0x00000000开始的一片ROM(FLASH)区域,SRAM是以0x20000000开始的一片RAM区域,SRAM的读取速度相比于Code更快,用来保留堆栈和数据,保证CPU的执行效率。

这里要注意,Code是从0x00000000开始,但是我们的代码是从0x08000000开始,因为前面由厂家配置,boot程序之类的东西。

C程序 -> 可执行文件

单片机能够直接执行机器码,也就是可执行文件。C程序经过编译链接之后获得可执行文件。

C代码经过编译、链接之后成为可执行文件。之后装入单片机的FLASH中,由单片机执行可执行文件。

这里的FLASH指的就是Code区域,FLASH是ROM的最新技术,结构简单功耗低,很适合保存程序。

?

编译过程包括预处理、解析、优化,生成目标文件,

  1. 预处理阶段删除注释插入被#include指令包含的文件内容定义和替换由#define指令定义的符号,以及确定代码的部分内容是否应该根据一些条件编译指令进行编译。
  2. 解析阶段检查语法,判断语义,生成汇编语言。
  3. 优化是为了让程序能够更加高效的运行,对目标代码进行进一步处理。

链接过程是将编译所生成的各个目标文件同C函数库捆绑,形成一个可执行程序。

执行的第一步是将程序下载到单片机的FLASH中,第二步是正式执行。

单片机下载程序,保存到内存中

上面提到过,单片机下载代码保存在FLASH里面,那么在FLASH中又是以什么样的结构存在的呢?这时我们可以参考工程中的.map文件。

编译后keil会自动生成map文件保存于工程中。看map文件之前,我们需要了解一些概念。

下载到单片机的文件,包含以下内容:

Code:代码占用的空间

RO-data:Read Only 只读常量

RW-data:Read Write 初始化后的全局/静态变量

ZI-data:Zero Initialize 没有初始化的静态/全局变量

单片机的数据和代码被分成段,保存在内存中:

栈:存放程序的活动记录,随用随丢,用完就释放掉。

????????函数参数;局部变量;函数调用上下文

堆:存放动态分配的内存,由开发者负责申请和释放,关键字为malloc,free

.bss段:存放未初始化的静态或者全局变量所需空间大小
?? ?未初始化的全局或静态不分配数据空间,只记录所需空间大小

.data段:存放已经初始化的静态或者全局变量以及它们的值
?? ?分配数据空间,数据保存在目标文件中;data段包含经过初始化的全局变量以及它们的值

.rodata段:存放只读变量,如字符串

.text段:存放代码程序段

之前把RO、RW和.bss、.text之间的关系理解成了程序静态存储时的状态和动态运行时的状态,但是map文件中明确标明了bss这些段保存在FLASH中,说明静态的时候bss这些概念已经有了,于是推翻了这个想法。后来也有想过操作系统和裸机之间的区别,但是我这程序就是裸机程序,map文件中也分了段,也被推翻了。

现在对于这两类说法,我的理解(不一定正确):从不同的角度去给划分代码数据,这两方的范围有重合,但是没有逻辑关系。将代码和数据分成段保存在单片机对应的区域内,最后按照RW、RO这种计算出来数据大小打印在map文件的末尾。

回到map文件这边, .map文件中包含工程的内存映射和对应段的大小。在keil配置中勾选了对应项,编译之后map文件中才会包含。

?设定的RAM和ROM空间大小,注意ROM从0x08000000开始,RAM从0x20000000开始。

?这个表格是截了一位博主的,他写的很详细。帖子链接在这里👉链接[4]

接下来从map文件找相关的说一下。

?Image Symbol Table:映射符号表

keil勾选项:Symbols

Local Symbols:局部变量

从上到下依次的顺序为:

常量.constdata

????????常量所保存的地址是从0x0800开始,常量之前是代码段,也就是保存boot和用户代码的地方。这部分内容保存在FLASH中,不会被改变,在运行的时候也不发生变化。

数据.data

??????? 里面存放已经初始化的全局变量和静态变量,在单片机上电了之后这部分被拷贝到SRAM中。

.bss

????????未初始化的全局或静态不分配数据空间。因为没有被初始化,所以只记录这些全局变量所占据的大小,单片机上电之后,拷贝到SRAM中,全部分配0值即可。

栈STACK

??????? 申请的栈的大小

.bss

??????? 在这段.bss请看下面的全局变量,就是用户申请mem1base的空间的大小。

Global Symbols:全局变量

mem1base是使用melloc函数申请的空间,保存在堆内,也就是SRAM中,那么地址就是0x20000000开始。

?Memory Map:内存映射

keil勾选项:Memory Map

这部分就是内存映射,程序入口,以及从keil中配置的ROM大小。

Image component sizes:存储组成大小

最后map文件结尾,会将所有的数据统计起来,给一个总表。

根据map文件中的内容,不难得出,我们的程序和数据都保存在FLASH中。

也就是说单片机将程序下载到FLASH里面,按照【代码-常量-有初值的变量-无初值的变量】的顺序保存起来。对于未初始化的变量保存其大小,之后统一给0值。

map中的内存映射部分标明了文件映射到的物理地址,这部分是按照keil中配置的ROM和RAM来的。


单片机运行过程中FLASH和SRAM的变化

现在我们已经了解了单片机下载程序保存在哪里,代码和数据对应哪些区域,这些区域映射到内存中哪些位置。关于静态的部分已经足够了解,那么在程序运行之后,内存中又会发生哪些变化呢?

FLASH是ROM存储器,在工作的情况下只能用来读,不能立刻写出或者修改内容,因此我们在程序运行之前需要把数据移到SRAM中,这是一种读写速度块,掉电不保存的存储器。

上电之后拷贝FLASH里面的数据到SRAM中,在SRAM创建堆栈运行程序,程序运行过程在SRAM,而不再对FLASH中的RW-data进行改动。

等程序下一次上电时,再次将FLASH中的数据拷贝到SRAM中,保证FLASH数据的原始状态。

???????

????????总的来说,对于以Cortex-M4为内核的芯片,C程序在Keil中经过编译运行获得可执行文件,由单片机下载保存到内存中,此时代码和数据按照其属性(全局、静态)被划分成段保存于FLASH对应的空间内,数据和代码保存到同一空间内,对应CPU的哈佛结构。

??????? 单片机复位上电之后,FLASH中的读写数据会被拷贝到SRAM中,并在SRAM中建立堆栈运行程序。断电之后,SRAM中的数据掉电丢失,而FLASH中的数据等到下一次上电再次拷贝到SRAM中。

参考来源:

《C与指针》

《ARM Cortex-M4权威指南》

《ARM Cortex-M4内核参考手册》

[1] https://www.cnblogs.com/LittleTiger/p/4812523.html

[2] https://www.cnblogs.com/shirishiqi/p/5545085.html

[3] https://docs.microsoft.com/zh-cn/cpp/c-language/c-language-syntax-summary?view=msvc-160

[4] https://blog.csdn.net/shazip/article/details/97650139

[5] https://www.cnblogs.com/39950436-myqq/p/11387179.htm

[6] https://blog.csdn.net/qq_28877125/article/details/108662427

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-15 15:45:24  更:2021-08-15 15:45:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 20:36:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码