ARM——分散加载描述文件
scatter file--ARM中的RO、RW和ZI DATA说明

一直以来对于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程序才能正常访问变量。
ARM7的Bootloader和分散加载文件笔记

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)安排到其他的地方上去,加快异常的响应速度。
09327@52RD_使用分散加载文件

使用分散加载描述文件本章介绍如何将 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()函数的多个实现,可以根据分散加载描述文件中给出的信息自动选择正确的函数实现。
Scatter file详述

一直以来对于 ARM 体系中所描述的 RO,RW 和 ZI 数据存在似是而非的理解,这段时间对其仔 细了解了一番,发现了一些规律,理解了一些以前书本上有的但是不理解的东西。我想应该有不少 人也有和我同样的困惑,因此,将我的一些关于 RO,RW 和 ZI 的理解写出来,希望能对大家有所帮 助。要了解 RO,RW 和 ZI 需要首先了解以下知识:
附: 程序的编译命令(假定 C 程序名为 tst.c): armcc -c -o tst.o tst.c armlink -noremove -elf -nodebug -info totals -info sizes -map -list aa.map -o tst.elf tst.o 编译后的信息就在 aa.map 文件中。 ROM 主要指:NAND Flash,Nor Flash RAM 主要指:PSRAM,SDRAM,SRAM,DDRAM
0 Grand Totals
==============================================================
Total RO Size(Code + RO Data) 1008 ( 0.98kB)
Total RW Size(RW Data + ZI Data) 96 ( 0.09kB)
型变量“a”所引起的。 注意:如果一个变量被初始化为 0,则该变量的处理方法与未初始化华变量一样放在 ZI 区域。
即:ARM C 程序中,所有的未初始化变量都会被自动初始化为 0。
7.总结
1.C 中的指令以及常量被编译后是 RO 类型数据。 2.C 中的未被初始化或初始化为 0 的变量编译后是 ZI 类型数据。 3.C 中的被初始化成非 0 值的变量编译后是 RW 类型数据。
ARM处理器系统初始化过程

MEMMAP有两个控制位 MEMMAP[1:0]
00BOOT装载程序模式
01User FLASH模式
10用户RAM模式
11用户外部存储器模式
10模式也就是RAM模式 我们访问地址0X00是跟访问RAM地址0X40000000中的数据是完全一样的 向RAM中写进数据 然后通过数据窗口观察0X0地址的变化 应该是同步变化的
同时有两份以上的文件交错地打印在一张纸上。像不可剥夺的资源,就一定要关闭中断,让
它占有这个资源。在ARM里,没有像x86那样有清除中断指令CLI。那么在ARM里是怎么样实现
关中断和开中断的呢?下面就来看看ARM的关中断和开中断实现。
void Lock(void)
{
stmdb sp!, {r0}
mrs r0, cpsr
(3)总线宽度
ARM微处理器架构支持8/16/32位的数据总线宽度访问存储器和外设,对于特定的存储器来说,需要设定数据总线的宽度。
(4)存储器地址的配置
ARM微处理器架构理论上可以支持4GB的地址空间,而对于一个实际的系统来说,配置的物理地址远没有这么多,因此,如何配置存储器的地址,也是一个重要的问题。
因 为ARM有7种执行状态,每一种状态的堆栈指针寄存器(SP)都是独立的。因此,对程序中需要用到的每一种模式都要给SP定义一个堆栈地址。方法是改变状 态寄存器内的状态位,使处理器切换到不同的状态,让后给SP赋值。注意:不要切换到User模式进行User模式的堆栈设置,因为进入User模式后就不 能再操作CPSR回到别的模式了,可能会对接下去的程序执行造成影响。
IMPORT main
B main
直接从启动代码跳转到应用程序的主函数入口,当然主函数名字可以由用户随便定义。
ARM处理器系统初始化过程程序

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分散加载文件(一)原理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);接着放置其。
分散加载简介

1
什么是分散加载
分散加载是指定ARM连接器在生成映像文 件时如何分配RO,RW,ZI等数据的存放地址。 如果不分散加载,ARM连接器会按照默认的方 式来生成映像,一般情况下不用编写分散加载。 但是某些场合我希望把某些数据存放在指 定的地址处,那么分散加载就发挥了非常大的作 用。
2
如何分散加载
想要实现分散加载就需要编写分散加载文件 在keil中分散加载文件时.sct . 在IAR中是.icf文件 在ads中是.scf Scatter file实际是一个具有简单语法规则的文本文件,可以用来描述ARM连接器生成映像文件时 所需要的信息。 各个加载时域的加载地址、最大尺寸和属性; 从每个加载时域中分割出的运行时域; 各个运行时域的起始地址、最大尺寸和属性; 各个运行时域存储访问特性; 各个运行时域中包含的输入段;
3
分散加载文件语法
• LR_IROM1 0x08000000 0x00002000 第一个加载域,名字为LR_IROM1,起始地址为0x0,大小为0x80000 { ER_IROM1 0x08000000 0x00002000 加载域中的运行时域,名字为ER_IROM1,起始地址为0x08000000 ,大小为0x00002000 { *.o (RESET, +First) 将编译后生成的文件.o中的代码放在第一个起始地址。 *(InRoot$$Sections) .ANY (+RO) 以及所有编译生成的RO属性的代码全部存放在
ARM9异常处理过程+软中断

/...art_pagedir=Next&_c11_BlogPart_handle=cns!E1CB6F8A752E6B22!125&_c11_BlogPart_BlogPart=blogview&_c=BlogPart[2009-10-3 10:18:06]
2.6 异常(Exceptions )
当正常的程序执行流程发生暂时的停止时,称之为异常,例如处理一个外部的中断请求。在处理异常之前,当前处理器的状态必须保留,这样当 异常处理完成之后,当前程序可以继续执行。处理器允许多个异常同时发生,它们将会按固定的优先级进行处理。 ARM体系结构中的异常,与8 位/16 位体系结构的中断有很大的相似之处,但异常与中断的概念并不完全等同。
2.6.4 各类异常的具体描述
FIQ (Fast Interrupt Request) FIQ 异常是为了支持数据传输或者通道处理而设计的。在ARM状态下,系统有足够的私有寄存器,从而可以避免对寄存器保存的需求,并减小了 系统上下文切换的开销。 若将CPSR的F 位置为1 ,则会禁止FIQ 中断,若将CPSR的F 位清零,处理器会在指令执行时检查FIQ 的输入。注意只有在特权模式下才能改 变F 位的状态。 可由外部通过对处理器上的nFIQ 引脚输入低电平产生FIQ 。不管是在ARM状态还是在Thumb 状态下进入FIQ 模式,FIQ 处理程序均会执行以下 指令从FIQ 模式返回: SUBS PC,R14_fiq ,#4
2009 年 10 月 2009 年 9 月 2009 年 8 月 2009 年 7 月
2.6.1 ARM 体系结构所支持的异常类型
ARM体系结构所支持的异常及具体含义如表2-3 所示。 表2-3 ARM体系结构所支持的异常
scf(分散加载描述文件)程序说明

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下进行分散加载文件的使用可以通过在工程设置中进行配置来实现。
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文件学习

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的设置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

试图搞懂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节。
周立功单片机:分散加载文件浅释

_main():完成代码和数据的拷贝,并把 ZI 数据区清零。代码拷贝可将代码拷贝到 另外一个映射空间并执行,如将代码拷贝到 RAM 执行;数据拷贝完成 RW 段数据 赋值;数据区清零完成 ZI 段数据赋值。以上的代码和分散加载文件密切相关。
_rt_entry():进行 STACK 和 HEAP 等的初始化。最后_rt_entry 跳进 main()函数入口。 当 main()函数执行完后,_rt_entry 又将控制权交还给调试器。
2060 ( 2.01kB)
Total ROM Size (Code + RO-Data + RW-Data)
780 ( 0.76kB)
==============================================================================
由程序清单 2.2 所示的 map 文件可看出:
1. 何时使用分散加载 链接器的命令行选项提供了一些对数据和代码位置的控制,但要对位置进行全面控制, 则需要使用比命令行中的输入内容更详细的指令。需要或最好使用分散加载描述的情况包括: 2. 复杂内存映射 如果必须将代码和数据放在多个不同的内存区域中,则需要使用详细指令指定将哪些数 据放在哪个内存空间中。 3. 不同类型的内存 许多系统都包含多种不同的物理内存设备,如闪存、ROM、SDRAM 和快速 SRAM。 分散加载描述可以将代码和数据与最适合的内存类型相匹配。例如,可以将中断代码放在快 速 SRAM 中以缩短中断等待时间,而将不经常使用的配置信息放在较慢的闪存中。 4. 内存映射的 I/O 分散加载描述可以将数据节准确放在内存映射中的某个地址,以便能够访问内存映射的 外围设备。 5. 位于固定位置的函数 可以将函数放在内存中的固定位置,即使已修改并重新编译周围的应用程序。 6. 使用符号标识堆和堆栈 链接应用程序时,可以为堆和堆栈位置定义一些符号。
ARMCortex-M底层技术(十三)手把手教你写分散加载

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关键字只能用于指定执行域,作用是确保执行域与加载域地址相同。
嵌入式开发教程之ARM处理器的分散加载及特殊应用研究3(与“加载”有关文档共15张)

5 重 新 实 现 _user_initial_stEickheap() 函数 使用两个存储区 6 特殊应用 6. 1 定位目标外设 6.2 定义超大型结构体数组 结语
第1页,共15页。
5 重新实现_user_initial_stEickheap()函数
第9页,共15页。
ห้องสมุดไป่ตู้
嵌入式开发教程
例如,一个带有两个32位寄存器的定时器外设,在系统中的物理地址为
Ox04000000,其C语言结构描述如下:
第10页,共15页。
嵌入式开发教程
例如,一个带有两要个使32位用寄分存散器的加定载时将器外上设述,在结系构统体中的定物位理地到址O为xO0x044000000000,0其0C0语的言物结构理描地述如址下,:可以将上述结 本文详细阐述构了体基于放ar在m处一理个器的文分件散名加载为方t法im及e其r特_殊re应g用s,.并c以中实际,工并程在为例分来散说明加载文件中指定即可,如下:
使用分散加载时,必须重新放置堆栈和堆。 r2—堆长度限制值(需要的话); (1)共用一个存储区
汇编语言如下: 它的大小直接影响最终要烧写的文件的大小,且零初始化段的大小还取决于内存的大小,它不能大到超过内存的大小; 但不采用分散加载机制,零初始化段在编译连接后是直接生成到镜像文件中的。 当用户使用分散加载功能的时候,必须重新实现一user_initial_staacklaeap(),否则连接器会报错:
第4页,共15页。
嵌入式开发教程
__user_initial_stackheap()函数的实现有两种方法。 (1)共用一个存储区 汇编语言如下:
第5页,共15页。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一样咯。输入段的排放规律就是:最先排放 RO 属性的输入段,然后是 RW 属性 段,最后是 ZI 或 NOINIT 段。
域:
为什么还要加一层域,我的理解是由于代码的功能不同,那么我们有必要把
不同功能的代码分类放。我们可以把需要高速执行的代码放在一起、把对速度要
求不高的放在一起、把执行频率高的放在一起,把执行频率低的放在一起...那么 按照这种方式放的代码就可以根据其具体需要放在不同的存储器中了。这样可以
程序总有两种状态:运行态和静止态。当系统掉电的时候程序需要被保存在 非易失性的存储器中,且这个时候程序的排放是按照地址依次放的,换句话说: 我才懒得管它怎么放,只要不掉就行。当系统上电后,CPU 就要跑起来了,CPU 属于高速器件,存储器总是不怎么能跟得上,既然跟不上那么我们就尽量缩短它 们之间的差距,那留下一条路,那就是尽量提高存储器的读取速度,存储器类型 决定其速度的水平,那么尽量放在速度高的存储器就成为首选解决方案。那么我 们就把要执行的程序暂时拿到速度较快的 RAM 中。那么拿的过程就牵涉到程序 的加载了。这就是要解决的问题。
AREA RESET, CODE, READONLY AREA DSEG1, DATA, READWRITE AREA HEAP, NOINIT, READWRITE 看出其属性没? 输出段: 为了简化编译过程和更容易取得各种段的地址,那么把多个同属性的输入段 按照一定的规律组合在一起,当然这个输出段的属性就和它包含的输入段的属性
看看这个加深理解:
LOAD_ROM1 0X00000000 ; 从火车上取出来时的地址(如:成都站)
{
EXEC_ROM1 0x40000000
{ PROGRAM.O(+RO) ;把品牌 RO 的货物发给 0x400000
{ PROGRAM.O(+RW,+ZI);把品牌 RW,ZI 的货物依次发给
"Startup.s" code 32 area Vectors,CODE,READONLY entry ... end
注 1:在"Startup.o"里面会生成名为"Vectors"的段,段的 属性为"READONLY"
"Stack.s" area Stacks, DATA, NOINIT export StackUsr StackUsr SPACE 1 end
映像文件就是有 N 节车厢的火车,车厢(域)里装着要送到不同站(不同 类型的存储器)的货物。到相应的站了,那么就把相应的车厢拿下来。指挥拿这
个的就是 scatter 文件。拿下货物车厢后,我们就解开它,把里面的品牌为 RO 的 货物提取出来,按照 scatter 的指示发给某个地址,然后再先后把品牌为 RW 和 ZI 的货物发到 scatter 指定的地址。
在"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"的例子
片内 RAM 区,从 0x40000000 开始,最多 0x4000 字节
指定 Startup.o 中 MyStacks 放在最前面。
Startup.o(+RW,+ZI)
Startup.o 中的其他+RW/+ZI 段。注 1
os_cpu_a.o(+RW,+ZI)
}
STACKS 0x40004000\ UNINIT {
内容
注解
ROM_LOAD\ 0x80000000 {
Name of Load Region, Start Address for Load Region and Maximum size of Load Region(省略了)
ROM_EXEC 0x80000000\ 0x20000 {
Startup.o(Vector,+First)
ARM--分散加载描述文件.scf 的设置
简单应用时可以不写.scf 文件。而在"Output"页中选择"Simple",然后填写"RO Base"和"RW Base"的起始地址。在"Lay Out"页中,填写 Object/Symble:Startup.o, Section: Start,编写启动文件:Startup.s。
注 2: 在"Stack.o"里面会生成名为"Stacks"的段,段的属性 为"NOINIT",该属性对应 scf 文件中的"+ZI". 该段不需要 初始化或者可以被初始化为"0".
"Heap.s" area Heap,DATA,NOINIT export bottom_of_heap bottom_of_heap SPACE 1 end
如果只有一个汇编文件如 startup.s,也可以这样: IRAM 0x40002000 0x1000 { startup.o (Mystack,+first) *(+RW,+ZI) } 用一个"+first"强行将 startup.s 中的 Mystack 放在 0x40002000 位置。 在"Edit -> DebugRel Settings...->ARM Linker"中选中"Image map"。编译后在 Error & Warnings 窗口会 显示出详细的内存分配情况。如果在"List file name"中指定一个输出文件名,该祥单会直接存在制定 文件中以供多次研究。
*(+RO)
片外存储区,从 0x80000000 开始,最多 0x20000 字节。
Startup 模块的 Vector 段放 在最前面。注 1 其他所有模块中的所有代 码和只读的数据放在这里。
} IRAM 0x40000000\ 0x00004000 {
Startup.o(MyStacks,+first)
Stack.o(+ZI)
片内 16K RAM 的顶端,存 放不需要被"C library"初始 化的段。
注2
}
ERAM 0x80040000 {
*(+RW,+ZI)
}
HEAP +0 UNINIT {
"+0"表示接着上一段 "ERAM"的结尾,继续安排
存储区。
Heap.o(+ZI)
注3
}
}
下面是在 scf 文件中引用过的源文件示意:
一个映像文件由域(region)、输出段(output sections)和输入段(input sections) 组成。不要想得太复杂,其实他们之间就是包含与被包好的关系。具体关系是这 样的:
映像文件>域>输出段>输入段 输入段: 输入段就是我们写的代码+初始化的数据+应该被初始化为 0 的数据+没有初 始化的数据,用英文表示一下就是:RO(ReadOnly),RW (ReadWrite),ZI (ZeroInitialized),NOINIT(Not Initialized)。ARM 连接器根据各个输入段不同 的属性把相同的拿再一起组合一下就成为了输出段。 请看看平时写的东东:
Region 的"UNINIT"之类的参数要放在"Maximum size"参数之前。 在一个 Region 中,RAM 的分配不是按照罗列的顺序来的。要想让汇编中使用的变量有固定的位置, 可以把所有汇编文件产生的".o"放在同一个 Region 中。如: IRAM1 0x40000000 { startup.o(+RW,+ZI) ASMSourceCode1.o(+RW,+ZI) ASMSourceCode2.o(+RW,+ZI) } IRAM2 +0 { CSourceCode1.o(+RW,+ZI) CSourceCode2.o(+RW,+ZI) } 这样,所有汇编中定义的变量地址就相对集中了。
提高程序执行速度。一个域中包含 1~3 个输出段。 映像文件:
我暂时把映像文件理解成烧到存储器中的文件,由 N 个域组成。这些域其 实可以看做是独立的模块,只是他们按照一定的顺序(这个顺序还是:
RO+RW+ZI)被捆绑在一起,这样才方便烧写到非易失存储器中去。 好了,了解了映像文件的组成,那么来看看映像文件是怎么跑起来的。
注 3: "Heap.o"里面名为"Heap"的段。
在 Scatter 文件中最好每一个 Region 都加一个 Maximum 参数,这样当编译时如果实际使用的空 间大于 Maximum Size,会有 Error:16220E: Excution region xxx size (xxx bytes) exceeds limit (xx bytes)。 如果地址有重复,会有 Error: 16221E: Excution region xxx overlaps with excution region xxx。前一个 Region 的首地址 + Maximum > 后一个 Region 的首地址时不一定有 Error。只有当一分配的内存出 现覆盖时才会有 Error。