STM32学习-段的概念_散列文件_重定位

devtools/2024/11/8 14:39:38/

使用keil烧写程序时,程序保存在哪里?这个问题很好想,当掉电时,RAM中的数据会被清除,所以程序数据只能保存在ROM区,对于STM32则是保存在内部的Flash中,那么程序运行是在ROM/Flash还是RAM呢?这个取决于不同的开发平台和使用场景,比如stm32发系列就支持在Flash中运行程序,当然也可以在RAM区运行,但是有的SOC产品只支持在RAM区运行。下图所示STM32的IROM(内部ROM)地址是0x8000000 IRAM(内部RAM)地址是0x2000000,说明程序使用的ROM和RAM地址。

在散列文件中,可以更加清晰的看到链接(运行)地址和加载地址的信息,这里给出官方文档的散列文件的介绍 一个加载域会有很多个执行域,当然也可能有很多加载域 

 加载域是代码保存的地方,可执行域是代码运行的地方,如果加载域地址=可执行域地址,那么就不要额外操作,如果加载域地址!=可执行域地址,那么就需要重定位。

那么图中的RO,RW,ZI是什么,引入段的概念

段的概念
1.2.1 程序直接烧写在ROM上
代码段、只读数据段、可读可写的数据段、BSS段。

char g_Char = 'A';           // 可读可写,不能放在ROM上,应该放在RAM里
const char g_Char2 = 'B';    // 只读变量,可以放在ROM上
int g_A = 0;   // 初始值为0,干嘛浪费空间保存在ROM上?没必要
int g_B;       // 没有初始化,干嘛浪费空间保存在ROM上?没必要

所以,程序分为这几个段: 

  • Code:即代码域,它指的是编译器生成的机器指令,这些内容被存储到ROM区。

  • RO-data:Read Only data,即只读数据域,它指程序中用到的只读数据,这些数据被存储在ROM区,因而程序不能修改其内容。例如C语言中const关键字定义的变量就是典型的RO-data。

  • RW-data:Read Write data,即可读写数据域,它指初始化为“非0值”的可读写数据,程序刚运行时,这些数据具有非0的初始值,且运行的时候它们会常驻在RAM区,因而应用程序可以修改其内容。例如C语言中使用定义的全局变量,且定义时赋予“非0值”给该变量进行初始化。

  • ZI-data:Zero Initialie data,即0初始化数据,它指初始化为“0值”的可读写数据域,它与RW-data的区别是程序刚运行时这些数据初始值全都为0,而后续运行过程与RW-data的性质一样,它们也常驻在RAM区,因而应用程序可以更改其内容。例如C语言中使用定义的全局变量,且定义时赋予“0值”给该变量进行初始化(若定义该变量时没有赋予初始值,编译器会把它当ZI-data来对待,初始化为0);

  • ZI-data的栈空间(Stack)及堆空间(Heap):在C语言中,函数内部定义的局部变量属于栈空间,进入函数的时候从向栈空间申请内存给局部变量,退出时释放局部变量,归还内存空间。而使用malloc动态分配的变量属于堆空间。在程序中的栈空间和堆空间都是属于ZI-data区域的,这些空间都会被初始值化为0值。编译器给出的ZI-data占用的空间值中包含了堆栈的大小(经实际测试,若程序中完全没有使用malloc动态申请堆空间,编译器会优化,不把堆空间计算在内)。

RW-data和ZI-data它们仅仅是初始值不一样而已,为什么编译器非要把它们区分开?这就涉及到程序的存储状态了,应用程序具有静止状态和运行状态。静止态的程序被存储在非易失存储器中,如RT1052的外部FLASH,因而系统掉电后也能正常保存。但是当程序在运行状态的时候,程序常常需要修改一些暂存数据,由于运行速度的要求,这些数据往往存放在内存中(RAM),掉电后这些数据会丢失。因此,程序在静止与运行的时候它在存储器中的表现是不一样的,见图,这河前面的散列文件也对的上

 

图中的左侧是应用程序的存储状态,右侧是运行状态,而上方是RAM存储器区域,下方是ROM存储器区域。

程序在存储状态时,RO节(RO section)及RW节都被保存在ROM区。当程序开始运行时,内核直接从ROM中读取代码,并且在执行主体代码前,会先执行一段加载代码,它把RW节数据从ROM复制到RAM, 并且在RAM加入ZI节,ZI节的数据都被初始化为0。加载完后RAM区准备完毕,正式开始执行主体程序。

编译生成的RW-data的数据属于图中的RW节,ZI-data的数据属于图中的ZI节。是否需要掉电保存,这就是把RW-data与ZI-data区别开来的原因,因为在RAM创建数据的时候,默认值为0,但如果有的数据要求初值非0,那就需要使用ROM记录该初始值,运行时再复制到RAM。

STM32的RO区域不需要加载到SRAM,内核直接从FLASH读取指令运行。计算机系统的应用程序运行过程很类似,不过计算机系统的程序在存储状态时位于硬盘,执行的时候甚至会把上述的RO区域(代码、只读数据)加载到内存,加快运行速度,还有虚拟内存管理单元(MMU)辅助加载数据,使得可以运行比物理内存还大的应用程序。而STM32没有MMU,所以无法支持Linux和Windows系统。

参考文章

嵌入式系统程序运行在FLASH还是RAM - 知乎

39. MDK的编译过程及文件类型全解 — [野火]i.MX RT库开发实战指南——基于i.MXRT1052 文档

ARM架构与编程(基于I.MX6ULL): 代码重定位(八)_i.mx6ull架构-CSDN博客


http://www.ppmy.cn/devtools/132334.html

相关文章

景联文科技专业数据标注公司:高质量数据标注推动AI产业发展

在当今数据驱动的时代,高质量的数据标注对于机器学习、自然语言处理(NLP)和计算机视觉等技术领域的发展起着至关重要的作用。 数据标注是指对原始数据进行处理,标记对象的特征,生成满足机器学习训练要求的可读数据编码…

【算法】(Python)贪心算法

贪心算法: 又称贪婪算法,greedy algorithm。贪心地追求局部最优解,即每一步当前状态下最优选择。试图通过各局部最优解达到最终全局最优解。但不从整体最优上考虑,不一定全局最优解。步骤:从初始状态拆分成一步一步的…

【Spring】更加简单的将对象存入Spring中并使用

前言 本期讲解:通过Controller、Service、Repository、Component、Configurtion类注解、Bean方法注解,来更加简单的在Spring中存与读对象。 目录 1. 类注解 1.1 通过标签 1.2 使用类注解 1.3 什么是类注解 1.4 获取Bean对象命名问题 2. 方法注解 …

Linux驱动开发——零散知识分享

本篇文章记录我学习Linux驱动时的一些零散知识,旨在记录成长,分享心得,希望我的分享能给你带来不一样的收获! 1、C 语言字符串转换为整数二点函数atoi 在 C 语言中,atoi 函数用于将字符串转换为整数。其原型定义在头文…

网络安全从入门到精通(特别篇I):应急响应之APT事件处置流程

应急响应 应急响应之APT处置流程1.现场询问1.1 了解威胁事件表现1.2 了解威胁事件发现时间1.3 了解系统架构,如服务器类型、业务架构、网络拓扑等2 判断安全事件状态3 确认事件对象4 确定事件时间5 问题排查应急响应之APT处置流程 1.现场询问 1.1 了解威胁事件表现 1.C&…

【Python爬虫实战】DrissionPage 与 ChromiumPage:高效网页自动化与数据抓取的双利器

🌈个人主页:易辰君-CSDN博客 🔥 系列专栏:https://blog.csdn.net/2401_86688088/category_12797772.html ​ 目录 前言 一、DrissionPage简介 (一)特点 (二)安装 (三…

【xml转JSON】

Xml转json 先导入需要的依赖包 <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.8</version></dependency><dependency><groupId>com.faster…

idea database连接数据库后看不到表解决方法、格式化sql快捷键

最下面那个勾选上就可以了 或 格式化sql快捷键&#xff1a; 先选中&#xff0c; 使用快捷键格式化 SQL&#xff1a; Windows/Linux: Ctrl Alt L macOS: Cmd Alt L