ARM——分散加载描述文件
- 格式:pdf
- 大小:97.37 KB
- 文档页数:5
一直以来对于ARM体系中所描述的RO,RW和ZI数据存在似是而非的理解,这段时间对其仔细了解了一番,发现了一些规律,理解了一些以前书本上有的但是不理解的东西,我想应该有不少人也有和我同样的困惑,因此将我的一些关于RO,RW和ZI的理解写出来,希望能对大家有所帮助。
要了解RO,RW和ZI需要首先了解以下知识:ARM程序的组成此处所说的“ARM程序”是指在ARM系统中正在执行的程序,而非保存在ROM中的bin映像(image)文件,这一点清注意区别。
一个ARM程序包含3部分:RO,RW和ZIRO是程序中的指令和常量RW是程序中的已初始化变量ZI是程序中的未初始化的变量由以上3点说明可以理解为:RO就是readonly,RW就是read/write,ZI就是zeroARM映像文件的组成所谓ARM映像文件就是指烧录到ROM中的bin文件,也成为image文件。
以下用Image文件来称呼它。
Image文件包含了RO和RW数据。
之所以Image文件不包含ZI数据,是因为ZI数据都是0,没必要包含,只要程序运行之前将ZI数据所在的区域一律清零即可。
包含进去反而浪费存储空间。
Q:为什么Image中必须包含RO和RW?A:因为RO中的指令和常量以及RW中初始化过的变量是不能像ZI那样“无中生有”的。
ARM程序的执行过程从以上两点可以知道,烧录到ROM中的image文件与实际运行时的ARM 程序之间并不是完全一样的。
因此就有必要了解ARM程序是如何从ROM 中的image到达实际运行状态的。
实际上,RO中的指令至少应该有这样的功能:1. 将RW从ROM中搬到RAM中,因为RW是变量,变量不能存在ROM中。
2. 将ZI所在的RAM区域全部清零,因为ZI区域并不在Image中,所以需要程序根据编译器给出的ZI地址及大小来将相应得RAM区域清零。
ZI中也是变量,同理:变量不能存在ROM中在程序运行的最初阶段,RO中的指令完成了这两项工作后C程序才能正常访问变量。
Boot Loader概述简单地说,在操作系统内核运行之前,通过一小程序,可以初始化硬件设备、建立内存空间的映射图等,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核配置好相应的环境,也可以下载文件到系统板上的SDRAM,对Flash进行擦除与编程,这个小程序一般称为Boot Loader。
可以说,一个功能完善的Boot Loader已经相当于一个微型的操作系统了。
Boot Loader作为系统复位或上电后首先运行的代码,一般应写入Flash存储器并从起始物理地址0x0开始。
Boot Loader是非常依赖于硬件而实现的,而且根据实现的功能不同,其复杂程度也各不相同。
一个简单的Boot Loader可以只完成USB口的初始化,而功能完善的Boot Loader可以支持比较复杂的命令集,对系统的软硬件资源进行合理的配置与管理。
因此,建立一个通用的Boot Loader 几乎是不可能的。
系统初始化代码直接对ARM微处理器内核及硬件控制器编程,多采用汇编语言编程,初始化代码一般应包括如下典型任务:1.定义程序入口点;2.设置异常和中断向量表;3.初始化存储设备;4.初始化堆栈指针寄存器;5.初始化用户执行环境;6.呼叫主应用程序。
1.1 定义程序入口初始化代码必须定义整个程序的入口点。
通过伪指令Entry指定编译器保留该段代码,同时配合链接器的设置,确定整个程序的入口点。
1.2 设置异常和中断向量表1.3初始化存储设备1. 存储器类型和时序的配置2.存储器的地址分配与地址重映射一种典型的存储器地址重映射过程描述如下:当系统上电或复位以后,PC指针指向0x0,程序从0x0地址开始执行,因此,为了能正确读取代码,要求此时Flash (或其它类型的ROM)的起始地址为0x0。
但Flash(或其它类型的ROM)的访问速度大大低于RAM,每次产生异常后,都要从Flash(或其它类型的ROM)的异常向量表调转到相应的处理程序,会影响异常的响应速度,因此,系统便提供一种灵活的地址重映射方法,在系统完成必要地初始化以后,将RAM安排到0x0地址处,而将原来位于0x0处的Flash(或其它类型的ROM)安排到其他的地方上去,加快异常的响应速度。
使用分散加载描述文件本章介绍如何将 ARM®链接器armlink与分散加载描述文件配合使用以创建复杂映像。
本章分为以下几节:•第5-2页的关于分散加载•第5-9页的指定区和节地址的示例•第5-31页的简单映像的等效分散加载描述使用分散加载描述文件5.1关于分散加载映像由区和输出节组成。
映像中的每个区可以包含不同的加载和执行地址。
有关详细信息,请参阅第3-2页的指定映像结构。
要构建映像的内存映射,链接器必须具有:•描述如何将输入节划分到输出节和区中的分组信息•描述区位于内存映射中的地址的位置信息通过使用分散加载机制,您可以使用文本文件中的描述为链接器指定映像的内存映射。
分散加载为您提供了对映像组件分组和位置的全面控制。
分散加载可以用于简单映像,但它通常仅用于具有复杂内存映射的映像,即多个区在加载和执行时分散在内存映射中。
5.1.1为分散加载定义的符号当链接器使用分散加载描述文件创建映像时,它会创建一些与区相关的符号。
第4-3页的与区相关的符号对这些符号进行了介绍。
仅当代码引用这些特殊符号时,链接器才会创建它们。
未定义的符号请注意,在使用分散加载描述文件时,不会定义以下符号:•Image$$RW$$Base•Image$$RW$$Limit•Image$$RO$$Base•Image$$RO$$Limit•Image$$ZI$$Base•Image$$ZI$$Limit有关详细信息,请参阅第4-3页的访问链接器定义的符号。
如果使用分散加载描述文件,但没有指定任何特殊区名称,也没有重新实现__user_initial_stackheap(),则库会生成错误消息。
有关详细信息,请参阅:•《库和浮点支持指南》中第2-67页的调整运行时内存模型•《开发指南》中第3-13页的放置堆栈和堆5-2Copyright ©2002-2008 ARM Limited. All rights reserved.ARM DUI 0206IC使用分散加载描述文件5.1.2使用分散加载描述文件指定堆栈和堆ARM C 库提供了__user_initial_stackheap()函数的多个实现,可以根据分散加载描述文件中给出的信息自动选择正确的函数实现。
ARM处理器系统初始化过程1 禁止MMU,关闭中断,禁止cache;2 根据硬件设计配制好处理器时钟、DRAM时钟、定时器时钟;3 根据系统中所用的flash和DRAM芯片容量和电气参数设置它们的起始地址、容量、刷新频率等;4 将固化在flash芯片中的程序搬移到DRAM内存中;5 使能cache,使能MMU,跳转到DRAM内存中运行继续初始化,包括根据具体应用以及系统中的硬件配置初始化各个功能模块、安装好异常中断处理程序、使能中断等;6 进行操作系统相关初始化;禁止MMU,关闭中断,禁止cache通过写系统控制协处理器的寄存器1 的第0 位可以允许和禁止MMU。
在复位后这位是0,MMU 被禁止。
关闭中断与打开中断中断是一种高效的对话机制,但有时并不想程序运行的过程中中断运行,比如正在打印东西,但程序突然中断了,又让另外一个程序输出打印内容,这样在打印机上就会乱得不得了,同时有两份以上的文件交错地打印在一张纸上。
像不可剥夺的资源,就一定要关闭中断,让它占有这个资源。
在ARM里,没有像x86那样有清除中断指令CLI。
那么在ARM里是怎么样实现关中断和开中断的呢?下面就来看看ARM的关中断和开中断实现。
void Lock(void){stmdb sp!, {r0}mrs r0, cpsrorr r0,r0,#0xC0msr cpsr_cxsf,r0ldmia sp!,{r0}}上面这段程序是通过设置CPSR的第6,7位来实现的,因为第6,7位是设置为1时,就不再响应中断。
void UnLock(void){stmdb sp!, {r0}mrs r0, cpsrbic r0,r0,#0xC0msr cpsr_cxsf,r0ldmia sp!,{r0}}上面是重新开中断的命令,同样是设置CPSR的第6,7位,但它的值是0,就可接收中断了。
如果在多个任务之间进行共享数据,一般是需要使用关中断和开中断实现数据同步的,其实中这种关中断和开中断,就是进入临界区和退出临界区。
ARM分散加载文件(一)原理ARM 的连接器提供了一种分散加载机制,在连接时可以根据分散加载文件(.scf 文件)中指定的存储器分配方案,将可执行镜像文件分成指定的分区并定位于指定的存储器物理地址。
这样,当嵌入式系统在复位或重新上电时,在对CPU 相应寄存器进行初始化后,首先执行ROM 存储器的Bootloader 代码,根据连接时的存储器分配方案,将相应代码和数据由加载地址拷贝到运行地址,这样,定位在RAM 存储器的代码和数据就在RAM 存储器中运行,而不再从ROM 存储器中取数据或取指令,从而大大提高了CPU 的运行速率和效率。
(二)结构Scatlertoading 的存储区块可以分成二种类型:装载区:当系统启动或加载时应用程序的存放区。
执行区:系统启动后,应用程序进行执行和数据访问的存储器区域,系统在实时运行时可以有一个或多个执行块。
(三)分散加载时连接器生成的预定义符号在编译连接时如果指定了分散加载文件(.scf 文件),在连接后会自动生成如下变量:(四)具体例子说明;ROM_LOAD 为加载区的名称,其后面的0x00000000 表示加载区的起始地址(存放程序代码的起始地址)ROM_LOAD 0x0{;ROM_EXEC 描述了执行区的地址,放在第一块位置定义ROM_EXEC 0x00000000 {;从起始地址开始放置向量表(即Startup.o(vectors, +First),其中Startup.o 为Startup.s 的目标文件) ;+First 表示Vector 段放在最前面;AREAvectors, CODE, READONLY Startup.o (vectors, +First);接着放置其。
LPC2294-.SCF文件[ 2007-4-14 3:33:00 | By: CANopen ]分散加载描述文件供ARM-ADS链接器使用,用来决定各个代码段和数据段的存储位置,下面为一个添加注释后的.scf文件例子:;YL-LPC2294片内FLASH分散加载文件;Internal Flash 256kBytes, Address range:0x00000000~0x0003ffff;Internal SRAM 16KBytes, Address range:0x40000000~0x40003fff;External Flash 2MBytes,SST39VF1601, Address range:0x80000000~0x401fffff;External SRAM 512KBytes,IS61LV25616,Address range:0x81000000~0x81080000ROM_LOAD 0x0 ;ROM_LOAD:Name of the load region.;0x0:Start address for ROM_LOAD region.{ROM_EXEC 0x00000000 ;ROM_EXEC:Name for the first execute region.;0x00000000:Start address for the execture region.{Startup.o (vectors, +First)* (+RO) ;Place all code and RO data into this exec region,;and make sure the "vectors" section from "Startup.o";be placed first.}IRAM 0x40000000 ;The second execute region;start address is 0x40000000. {Startup.o (+RW,+ZI) ;Place all RW and ZI data from Startup.o here.}ERAM 0x81068000 ;The third execute region;Start address:0x81068000.{* (+RW,+ZI) ;All reset RW/ZI data to be placed here.}HEAP +0 UNINIT ;The fourth execute region;Start address:Follow the;end of ERAM region.{heap.o (+ZI) ;All ZI data from heap.o to be placed here.}STACKS 0x40004000 UNINIT ;The fifth execute region.{stack.o (+ZI) ;All ZI data from stack.o to be placed here.}}一般一个简单的分散加载描述文件包含三部分:Loader region、Execute region、Input section。
KEIL下分散加载文件的使用在KEIL下进行分散加载文件的使用可以通过在工程设置中进行配置来实现。
KEIL是一种嵌入式开发工具,可用于开发各种微控制器架构的应用程序。
分散加载(Scatter Loading)是一种在嵌入式系统中进行内存映射的技术,它通过将不同的代码段和数据段分散加载到不同的物理地址上,实现有效的内存管理和资源分配。
要在KEIL下使用分散加载文件,可以按照以下步骤进行配置:1. 打开KEIL软件,选择要进行配置的项目工程,在菜单栏中选择Project -> Options for Target。
2. 在弹出的对话框中,选择"Output"选项卡,然后点击"Manage"按钮。
3. 在下方的列表中,点击"Add"按钮,然后选择要进行分散加载的文件。
4.在弹出的对话框中,选择要添加的文件,并设置加载地址和加载大小,然后点击"OK"。
5.重复步骤3和4,将所有要进行分散加载的文件都添加到列表中。
6.设置每个分散加载文件的加载地址和加载大小,以确保它们不会重叠或冲突。
7.在列表中选择每个分散加载文件,并使用上下箭头按钮来调整它们的加载顺序。
8.最后,点击"OK"保存配置信息。
通过上述步骤,我们可以实现对不同代码段和数据段的分散加载,从而实现对内存资源的有效管理和分配。
在KEIL中,配置完成后,编译和生成可执行文件时将按照配置的分散加载文件进行内存映射和分配。
使用分散加载文件可以帮助我们更好地管理内存资源,提高系统性能和效率。
需要注意的是,在进行分散加载文件配置时,需要确保分散加载文件之间不会出现重叠或冲突。
同时,还需要根据硬件平台和应用程序的需求,合理设定加载地址和加载大小。
KEIL作为一款功能强大的嵌入式开发工具,支持分散加载文件的配置,可以帮助开发人员更好地进行内存管理和资源分配,使嵌入式应用程序更加高效和可靠。
MTK Scatter文件学习概述:分散加载(scatter loading)是ARM 连接接器提供的一个机制,该机制可以把一个可执行映像文件(即Bin文件)分割放置到内存中不同的独立段。
映像(Image)文件有两个视图:加载视图(Load view) 和执行视图(execution view)。
在下载的时候Image regions被放置在memory map当中,而在执行Image前,或许你需要将一些regions放置在它们执行时的地址上,并建立起ZI regions。
例如,你初始化的RW数据需要从它在下载时的在ROM中的地址处移动到执行时RAM的地址处。
在scatter 文件中可以为每一个代码或数据段在装载和执行时指定不同的存储区域地址,Scatlertoading的存储区块可以分成二种类型:装载区:当系统启动或加载时应用程序的存放区。
执行区:系统启动后,应用程序进行执行和数据访问的存储器区域,系统在实时运行时可以有一个或多个执行区。
映像中所有的代码和数据都有一个装载地址和运行地址(二者可能相同也可能不同,视具体情况而定)。
在系统启动时,C函数库中的__main初始化代码会执行必要的复制及清零操作,使应用程序的相应代码和数据段从装载状态转入执行状态。
为什么需要Scatter文件:制定存储器映射(memory map)的方法基本上有二种,一是在link时使用命令行选项,并在程序执行前利用linker pre-define symbol使用汇编语言制定section的段初始化,二是使用scatter file,即采用“分散加载机制”。
以上二种方法依应用程序的复杂度而定,一针对简单的情况,二针对复杂的情况。
手机属于复杂的情况,必须使用scatter file。
Scatter文件语法:scatter文件是一个简单的文本文件,包含一些简单的语法(分号后面的内容是注释):My_Region 0x0000 0x1000 ;区域名称区起始地址区长度{the context of region ;区内容}每个区由一个头标题开始定义,头中至少包含区的名字和起始地址,另外还有最大长度和其他一些属性选项。
ARM--分散加载描述文件.scf的设置ARM--分散加载描述文件.scf的设置[转]2010-04-20 20:13:12| 分类: uc/os-ii |字号订阅简单应用时可以不写.scf文件。
而在"Output"页中选择"Simple".然后填写"RO Base"和"RW Base"的起始地址。
在"Lay Out"页中,填写Object/Symble: Startup.o, Section: Start.编写启动文件:Startup.s.在"Option"页里的"Image Entry Point"填入起始地址。
--------------------------------------------------------------------------------Scatter-Load Description File的结构:".scf"文件中的"+RW"对应".s"源文件中的"READWRITE".".scf"文件中的"+ZI"对应".s"源文件中的"NOINIT".".scf"文件中的"+RO"对应".s"源文件中的"READONLY".在".s"源文件中有:AREA area_name CODE/DATA,READONLY/NOINIT/READWRITEEND".scf"的例子下面是在scf文件中引用过的源文件示意:在Scatter文件中最好每一个Region都加一个Maximum参数,这样当编译时如果实际使用的空间大于Maximum Size,会有Error:16220E: Excution region xxx size (xxx bytes) exceeds limit (xx bytes)。
试图搞懂MDK程序下载到flash(二)--分散加载文件scatter分散加载文件概念对于分散加载文件的概念,在《ARM体系结构与编程》书第11章有明确介绍。
分散加载文件(即scatter file,后缀为 .scf)是一个文本文件,通过编写一个分散加载文件来指定ARM连接器在生成映像文件时如何分配RO、RW、ZI等数据的存放地址。
如果不用SCATTER文件指定,那么ARM连接器会按照默认的方式来生成映像文件,一般情况下我们是不需要使用分散加载文件的。
但在某些场合,我们希望把某些数据放在知道那个的地址处,那么这时候SCATTER文件就发挥了非常大的作用,而且SCATTER文件用起来非常简单好用。
我越看这个分散加载文件越感觉它的作用和uboot的连接脚本lds 一样。
分散加载文件的格式分散加载描述文件是一个文本文件,它向链接器描述目标系统的存储器映射。
如果通过命令行使用链接器,则描述文件的扩展名并不重要。
分散加载文件指定:①每个加载区的加载地址和最大尺寸;②每个加载区的属性;③从每个加载区派生的执行区;④每个执行区的执行地址和最大尺寸;⑤每个执行区的输入节。
从描述文件的格式就可以看出加载区、执行区和输入节的层次关系。
分散加载文件基本点①编译后输出的映像文件中各段是首尾相连的,中间没有空闲的区域,他们的先后关系是根据链接时参数的先后次序决定的armlinker -file1.o file2.o ...② scatter用于将编译后的映像文件中的特定段加载到多个分散的指定内存区域③有两类域(region):执行域(execution region,一般是ram区域)和加载域(load region,一般是rom区域)④加载域:就是编译之后得到的二进制文件烧写到rom中的这一段区域,所有的代码R0、预定义变量RW、堆栈之类和清不清空无关紧要的大片内存区域ZI,都包括在其中。
⑤执行域:就是把加载域进行“解压缩”后的样子。
分散加载描述文件7.5 分散加载描述文件在7.3节中已经简单介绍了映像的组成,也介绍了如何用命令选项来构建简单结构的映像。
要构建映像的存储器映射,链接器必须有:描述节如何分组成区的分组信息、描述映像区在存储器映射中的放置地址的放置信息。
分散加载机制允许为链接器指定映像的存储器映射信息,可实现对映像组件分组和布局的全面控制。
分散加载通常仅用于具有复杂存储器映射的映像(尽管也可用于简单映像),也就是适合加载和执行时内存映射中的多个区是分散的情况。
本节将对armlink所使用的分散加载描述文件作详细介绍。
7.5.1 分散加载机制7.5.1.1 何时使用分散加载机制链接命令行选项提供了一些对数据和代码布局的控制,但如果要对布局进行全面控制则需要比命令行选项更详细的指令。
对于以下一些情况,就需要或最好使用分散加载描述文件:复杂存储器映射:代码和数据需要放在多个不同存储器区域,必须详细指明哪个节放在哪个存储器空间。
不同存储器类型:许多系统包含FLASH、ROM、SDRAM和快速SRAM。
利用分散加载可将代码和数据放置在最适合的存储器类型中。
例如,中断代码可能放在快速SRAM中,以改进中断响应时间,而将不频繁使用的配置信息可能放在较慢的FLASH中。
存储器映射I/O:分散加载机制可将数据节精确放在存储器的某个地址,便于访问外设映射内存。
固定位置的函数:可以将函数放在存储器中的一个固定位置,即使周围的应用程序已经被修改并重新编译。
使用符号识别堆和栈:链接程序时,分散加载机制可为堆和栈的位置定义符号。
在实现嵌入式系统时,通常会需要使用分散加载机制,因为这些系统一般都会使用ROM、RAM和存储器映射I/O。
注意,如果为Cortex-M3结构的处理器编译程序,此处理器结构有着一个固定的内存映射,可以使用分散加载文件来定义栈和堆。
链接时如要使用分散加载文件,则需使用链接命令选项--scatter description_file,详细内容参考7.2节。
ARMCortex-M底层技术(十三)手把手教你写分散加载ARM Cortex-M底层技术(十三)手把手教你写分散加载还记得之前教大家写的启动代码吗?木看过滴,出门左转,第四篇【编写自己的启动代码】,当然仅仅能编写自己的启动代码怎么够,说了辣么多分散加载的东东,是时候检验一下我们的水平了,合上书,来出题考试了~【自己编写分散加载】。
来司机们,将装B进行到底~首先,看看我们之前第四篇文章里面的简易版分散加载:如下,之前按着没讲,前面罗里吧嗦的扯了辣么多分散加载,大家现在再回头看下这个分散加载,估计都看的明白了吧~load_rom 0x00000000 0x00080000{vector_rom 0x00000000 0x400{*( vector_table, +first)}execute_rom 0x400 FIXED 0x0007F C00{*( InRoot$$Sections ).any( +ro )}execute_data 0x20000000 0x00010000 {.any ( +rw +zi )}ARM_LIB_HEAP +0 empty 0x400 {} ARM_LIB_STACK 0x20020000 empty -400 {}}这里还是简单扯几点:•没有使用预处理器,比较Low逼;•就一个加载域、两个RO运行域(一个项链表运行域,一个根域)、一个RW+ZI运行域以及堆+栈的分配;•第三,参考以上两点~~~~深入理解“FIXED”关键字但是其实这里还是有一些技能点的~比如:根域的FIXED属性,你若把这个FIXED属性去掉,试试会发生什么没错,链接器罢工了,16个错,看一下,主要是加载域和运行域的地址不匹配导致的错误;原因是这样的:1.任何MCU的分散加载必须有一个根区,这点我们在之前讲过;2.根区是指加载域和运行域相同的地址的区(因为根区里面要放置C Library&分散加载相关代码,而分散加载本身不能被分散加载,所以根区的加载域与运行域必须相同);3.程序的入口地址必须在根区中,因为程序的入口显然不能被分散加载,所以必须在根区中;4.如果运行域基址与加载域基址相同则默认可以看做根区(这点很好理解,参考第二点,根区就是运行域与加载域相同的区);5.加载域后续的执行域指定“+0”偏移,则这些执行域默认都为根区(因为地址上是连续的,基址又与加载域基址相同);6.如果基址不相同,则需要使用FIXED关键字指定根区;7.FIXED关键字只能用于指定执行域,作用是确保执行域与加载域地址相同。