ARM——分散加载描述文件
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
0x80000000
}
}
......
} 其他的段也可以这样依葫芦画瓢。
scatter 的原理就介绍这样,其中的语法和规则要多写多把代码的地址拖出来 看才能体会。不过都是很简单的,生活中的小常识就能解决这些问题。为什么?
因为设计这些规则的工程师的灵感就是源自生活。嘿嘿...享受把代码随处放的乐 趣吧,...enjoy...
一样咯。输入段的排放规律就是:最先排放 RO 属性的输入段,然后是 RW 属性 段,最后是 ZI 或 NOINIT 段。
域:
为什么还要加一层域,我的理解是由于代码的功能不同,那么我们有必要把
不同功能的代码分类放。我们可以把需要高速执行的代码放在一起、把对速度要
求不高的放在一起、把执行频率高的放在一起,把执行频率低的放在一起...那么 按照这种方式放的代码就可以根据其具体需要放在不同的存储器中了。这样可以
在"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"的例子
AREA RESET, CODE, READONLY AREA DSEG1, DATA, READWRITE AREA HEAP, NOINIT, READWRITE 看出其属性没? 输出段: 为了简化编译过程和更容易取得各种段的地址,那么把多个同属性的输入段 按照一定的规律组合在一起,当然这个输出段的属性就和它包含的输入段的属性
注 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" 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
程序总有两种状态:运行态和静止态。当系统掉电的时候程序需要被保存在 非易失性的存储器中,且这个时候程序的排放是按照地址依次放的,换句话说: 我才懒得管它怎么放,只要不掉就行。当系统上电后,CPU 就要跑起来了,CPU 属于高速器件,存储器总是不怎么能跟得上,既然跟不上那么我们就尽量缩短它 们之间的差距,那留下一条路,那就是尽量提高存储器的读取速度,存储器类型 决定其速度的水平,那么尽量放在速度高的存储器就成为首选解决方案。那么我 们就把要执行的程序暂时拿到速度较快的 RAM 中。那么拿的过程就牵涉到程序 的加载了。这就是要解决的问题。
注 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。
内容
注解
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)
如果只有一个汇编文件如 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"中指定一个输出文件名,该祥单会直接存在制定 文件中以供多次研究。
看看这个加深理解:
LOAD_ROM1 0X00000000 ; 从火车上取出来时的地址(如:成都站)
{
EXEC_ROM1 0x40000000
{ PROGRAM.O(+RO) ;把品牌 RO 的货物发给 0x40000000 去
RAM1
0x80000000
{ PROGRAM.O(+RW,+ZI);把品牌 RW,ZI 的货物依次发给
*(+RO)
片外存储区,从 0x80000000 开始,最多 0x20000 字节。
Startup 模块的 Vector 段放 在最前面。注 1 其他所有模块中的所有代 码和只读的数据放在这里。
} IRAM 0x40000000\ 0x00004000 {
Startup.o(MyStacks,+first)
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) } 这样,所有汇编中定义的变量地址就相对集中了。
ARM--分散加载描述文件.scf 的设置
简单应用时可以不写.scf 文件。而在"Output"页中选择"Simple",然后填写"RO Base"和"RW Base"的起始地址。在"Lay Out"页中,填写 Object/Symble:Startup.o, Section: Start,编写启动文件:Startup.s。
ARM——分散加载描述文件
分散加载的实现(scatter)
很多朋友对分散加载不是很理解,其实它的原来很简单,这些加载的原理都 源自生活。
由于现在的嵌入式技术发展比较快,各类存储器也层出不穷,但是它们在容 量、成本和速度上有所差异,嵌入式系统又对成本比较敏感,那么合理的选择存 储器和充分的利用存储器资源成为一个必要解决的问题。咋们工程师最喜欢的就 是发掘问题,然后解决问题,基于嵌入式系统对存储器的敏感,那么要合理的利 用存储器资源,就必须找到一种合理的方式。工程师们发现,可以把运行的程序 放在不同成本的存储器中来寻找这个成本的支点,比如把没有运行的但是较为庞 大的程序放在容量大、成本低、速度也较低的 FLASH 存储器中,要用的时候再 去拿。但是,这里面又有一个问题,嵌入式本身就对信号的处理速度有较高的要 求,这点在实时操作系统的定义上上有所体现。所以那些经常要用的程序段如果 要保证其高速的运行那么就得放在一个在高速的存储器中,不过这是有代价的: 较高成本,小容量。但是,相信由于技术的发展这个问题终将被解决,到时候寻 找平衡点的问题也就不存在了。好了,说了多了点。切入正题。
Stack.o(+ZI)
片内 16K RAM 的顶端,存 放不需要被"C library"初始 化的段。
注2
}
ERAM 0x80040000 {
*(+RW,+ZI)
}
HEAP +0 UNINIT {
"+0"表示接着上一段 "ERAM"的结尾,继续安排
存储区。
Heap.o(+ZI)
注3
}
}
下面是在 scf 文件中引用过的源文件示意:
映像文件就是有 N 节车厢的火车,车厢(域)里装着要送到不同站(不同 类型的存储器)的货物。到相应的站了,那么就把相应的车厢拿下来。指挥拿这
个的就是 scatter 文件。拿下货物车厢后,我们就解开它,把里面的品牌为 RO 的 货物提取出来,按照 scatter 的指示发给某个地址,然后再先后把品牌为 RW 和 ZI 的货物发到 scatter 指定的地址。
片内 RAM 区,从 0x40000000 开始,最多 0x4000 字节
指定 Startup.o 中 MyStacks 放在最前面。
Startup.o(+RW,+ZI)
Startup.o 中的其他+RW/+ZI 段。注 1
os_cpu_a.o(+RW,+ZI)
}
STACKS 0x40004000\ UNINIT {
提高程序执行速度。一个域中包含 1~3 个输出段。 映像文件:
我暂时把映像文件理解成烧到存储器中的文件,由 N 个域组成。这些域其 实可以看做是独立的模块,只是他们按照一定的顺序(这个顺序还是:
RO+RW+ZI)被捆绑在一起,这样才方便烧写到非易失存储器中去。 好了,了解了映像文件的组成,那么来看看映像文件是怎么跑起来的。
一个映像文件由域(region)、输出段(output sections)和输入段(input sections) 组成。不要想得太复杂,其实他们之间就是包含与被包好的关系。具体关系是这 样的:
映像文件>域>输出段>输入段 输入段: 输入段就是我们写的代码+初始化的数据+应该被初始化为 0 的数据+没有初 始化的数据,用英文表示一下就是:RO(ReadOnly),RW (ReadWrite),ZI (ZeroInitialized),NOINIT(Not Initialized)。ARM 连接器根据各个输入段不同 的属性把相同的拿再一起组合一下就成为了输出段。 请看看平时写的东东: