打印

开新贴,翻译RVDS的scatter文档

[复制链接]
11141|49
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xinzha|  楼主 | 2009-12-24 21:28 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 xinzha 于 2011-1-6 20:49 编辑

5.1 关于分散加载
     一个镜像通常由多个域和输出段组成。每个域可以有独立的加载和执行地址。
     为了构建镜像的内存表,链接器必须掌握如下信息:
     1、输入段与区域对应的描述信息
     2、域与内存表中的地址一一对应的描述信息

     分散加载机制使链接器通过读取一个描述文档来生成指定的内存表。分散加载可以完全控制镜像内组件的分组和放置。分散加载也可以使用在简单镜像上,但是多数情况下还是使用在复杂内存表的情况下,这种情况下,多个域在加载和运行时可能处于不同的地址(甚至地址会相差很远,这句是我自己加的)。
     本节内容包括:
     1、为分散加载定义的符号
     2、指定栈和堆
     3、什么时候使用分散加载
     4、分散加载的命令行选项
     5、简单内存表镜像
     6、复杂内存表镜像

相关帖子

沙发
xinzha|  楼主 | 2009-12-24 21:40 | 只看该作者
本帖最后由 xinzha 于 2011-1-6 20:50 编辑

arm和rvds那篇根据项目进度随时更新,scatter争取有时间就翻译。然后想再写一些MIPS的,接下来再写ATA/ATAPI(这个东西感觉面太窄,写不写不定),

使用特权

评论回复
板凳
xinzha|  楼主 | 2009-12-25 22:20 | 只看该作者
本帖最后由 xinzha 于 2011-1-6 20:52 编辑

5.1.1 为分散加载定义的符号

  如果链接器使用了一个分散加载描述文件来生成镜像文件,链接器就会产生一些跟域相关的符号。这些符号在4-3(域相关符号)中有详细描述。链接器当且仅当这些符号被你的代码使用才会生成。

未定义符号

  在默认状态下,下面这些符号在使用分散加载描述文件时不会被定义:
1、Image$$RW$$Base
2、Image$$RW$$Limit
3、Image$$RO$$Base
4、Image$$RO$$Limit
5、Image$$ZI$$Base
6、Image$$ZI$$Limit

  默认提供的__user_initial_stackheap()函数会用到Image$$ZI$$Limit这个值,因为在使用分散加载描述文件时这个值在默认情况下不被定义,所以你就必须自己重新生成__user_initial_stackheap()来定义堆顶和栈顶区域的值。实际上,你完全可以使用C库提供的替代函数,而不用你自己去重新写一个__user_initial_stackheap()。
___注意___
如果你自己写了__user_initial_stackheap(),那么所有同名的库函数都会被覆盖。
_________

如果你使用了分散加载,但是并没有指定任何特殊区域的名字,并且没有重新生成__user_initial_stackheap()的话,链接库就会产生如下错误信息:
Error:L6915E: Library reports error:scatter-load file declares no heap or stack regions and __user_initial_stackheap() is not defined.
如想获得更详细信息,请参阅如下章节:
1、在RealView Compilation Tools v3.0 Compiler and Libraries Guide中的C和C++库(库内存模型的详细信息)
2、RealView Compilation Tools v3.0 Developer Guide中的如何开发嵌入式软件。

使用特权

评论回复
地板
xinzha|  楼主 | 2009-12-27 16:56 | 只看该作者
本帖最后由 xinzha 于 2011-1-6 20:55 编辑

5.1.2  指定栈和堆

  ARM的C库提供了可选择的__user_initial_stackheap(),可以根据分散加载描述文件中提供的信息自动地为你选择正确的函数。
  如果想用使用两段内存域模式,就要在你的分散加载描述文件中定义两个特殊的执行区域,分别是ARM_LIB_HEAP和ARM_LIB_STACK,这两个区域都要求是EMPTY属性。这种操作会通知C库选择使用如下符号的__user_initial_stackheap()进行编译链接:
  Image$$ARM_LIB_STACK$$Base
  Image$$ARM_LIB_STACK$$ZI$$Limit
  Image$$ARM_LIB_HEAP$$Base
  Image$$ARM_LIB_HEAP$$ZI$$Limit
  只能指定一个ARM_LIB_STACK或者ARM_LIB_HEAP,而且你必须为它们分配一个大小,例如:
  ARM_LIB_HEAP 0X20100000 EMPTY 0x10000 -0x8000  ;堆从1M偏移开始,并且向上生长
  ARM_LIB_STACK 0X20200000 EMPTY -0x8000 ;栈顶在2M偏移处,向下生长,32K大小
  你也可以强制__user_initial_stackheap()使用一个混合堆栈区,只需定义一个属性为EMPTY,名字叫做ARM_LIB_STACKHEAP的单一执行区域即可。这一操作通知__user_initial_stackheap()使用符号Image$$ARM_LIB_HEAP$$BASE和Image$$ARM_LIB_STACK$$ZI$$LIMIT来生成堆栈区。

注意:如果你自己重新生成__user_initial_stackheap(),会导致所有库函数被重置。

使用特权

评论回复
5
xinzha|  楼主 | 2009-12-27 17:27 | 只看该作者
5.1.3  什么时候使用分散加载

  链接器的命令行选项能够对代码和数据的放置提供一定程度上的控制,但是要想实现完全控制就要求有更复杂更详细的描述指令,而这些是命令行不能胜任的。需要使用分散加载的情况包含以下几种:

复杂内存表
  数据和代码必须被放置到内存的许多不同区域之中,要求有详细的指令说明哪一部分要被放置入哪一内存区域。

不同种类的内存
  许多系统包含多种不同种类的物理存储器,比如flash,ROM,SDRAM和快速的SRAM,分散加载描述能够准确的将代码和数据放入其最适合的种类的存储器中。举例来说,中断处理可能会被放入SRAM以提高中断响应速度,而不常使用的配置信息则可以放在低速的flash中。

映射到内存的I/O
  分散加载描述可以精确地将一段数据结构放置在内存表中的指定地址上,从而被映射的外设能够很方便地访问到。

固定地址上的函数
  一个函数可以链接在内存的固定地址上,即使整个软件环境已经改变并且重新编译过。

使用符号来识别堆和栈
  应用程序被链接的时候,可以定义堆和栈地址的符号。

  综上所诉,基本上嵌入式系统都会要求使用分散加载文件,因为它们都要有ROM,RAM和映射I/O。

下面是一段描述Cortex-M3的分散加载的文字,没做过,看不懂,不翻译。

使用特权

评论回复
6
暮然| | 2009-12-27 18:03 | 只看该作者
众里寻他千百度,“暮然”回首那人却在灯火阑珊处。
我很懒的,都不想去看E文,多谢楼主辛苦翻译。

使用特权

评论回复
7
zyok| | 2009-12-27 18:17 | 只看该作者
mark

使用特权

评论回复
8
xinzha|  楼主 | 2009-12-27 19:22 | 只看该作者
谢楼上二位捧场,我翻这个也是为了强迫自己把每句话都看一遍,要不然就总是跳着看。

使用特权

评论回复
9
xinzha|  楼主 | 2009-12-27 20:29 | 只看该作者
5.1.4  分散加载命令字

  在armlink中使用分散加载的格式如下:
  -scatter description_file
   这个命令字指示链接器用description中所描述的格式来生成镜像文件,描述文件的格式在《分散加载描述文件的正式语法》这一节中描述。
  获取更多分散加载描述文件的信息,参考如下内容:
1、指定区域地址和段地址的例子(5.3)
2、简单镜像的等效分散加载描述(5.4)
3、在Realview Compilation Tools v3.0 Developer Guide中描述如何开发嵌入式软件的章节。

使用特权

评论回复
10
xinzha|  楼主 | 2009-12-28 20:48 | 只看该作者
本帖最后由 xinzha 于 2009-12-29 19:42 编辑

5.1.5 简单内存表镜像

  图5-1中的的分散加载描述将目标文件中的各个段按照如图5-2中所示放置。
  每个区域的指定大小虽然只是一个可选参数,不过如果指定这些参数,链接器就会帮助你检查链接结果是否超过该区域的指定范围。
  这个例子利用链接器的简单命令字来替代,只需在链接命令行中指定--ro-base 0x0和--rw-base 0x10000即可达到同样效果。

使用特权

评论回复
11
xinzha|  楼主 | 2009-12-28 21:04 | 只看该作者
下面这段是对图5-1中的scatter描述的一些说明。
图5-1中,加载区域的命名为LOAD_ROM,它的起始地址为0x0000,最大尺寸为0x8000。
此加载区域中有两个执行区域,第一个执行区域命名为EXEC_ROM,起始地址为0x0000,最大尺寸0x8000,此区域中放置所有属性为RO的段,包含代码和只读数据段。
第二个执行区域命名为RAM,起始地址为0x10000,最大尺寸为0x6000,该区域存放所有属性为RW和ZI的段,所谓的ZI也就是zero init,包括bss段,stack和heap等。

使用特权

评论回复
12
xinzha|  楼主 | 2009-12-29 20:10 | 只看该作者
5.1.6 复杂内存表镜像


图5-3中的分散加载描述将program1.o和program2.o这两个文件中的各个段按照如图5-4所示加载到系统内存中。
和图5-1中的例子不同,这种复杂的应用不同通过简单的命令行中的命令字来实现。

注意事项:图5-3中的分散加载描述只描述了program1.o和program2.o的代码和数据段加载。而如果你链接了另外一个文件,比如说program3.o,而却还是使用图5-3中的分散加载描述,那么program3.o中的代码和数据段就无处存放。
除非你是对代码和数据的位置有非常特殊的要求,我们建议使用*或者.ANY描述符来放置余下的代码和数据。(参考《在固定位置存放多个区域》这一节)

使用特权

评论回复
13
xinzha|  楼主 | 2009-12-29 21:04 | 只看该作者
本帖最后由 xinzha 于 2011-1-6 21:00 编辑

5.2 分散加载描述文件的正规语法

  分散加载文件是一个向链接器描述目标嵌入式产品的内存表的文本文件。如果你正在使用链接器的命令行形式,描述文件的扩展名并不是很重要。描述文件使你能够指定以下内容:
1、每个加载区域的加载地址和最大尺寸
2、每个加载区域的属性
3、从每个加载区域导出的执行区域
4、每个执行区域的执行地址和最大尺寸
5、生成每个执行区域的输入段。
描述文件的格式反映了加载区域,执行区域和输入段之间的层次关系。

注意事项:
输入段到底是分配给哪个区域,跟分散加载描述文件中选择模式的书写顺序没有任何关系。选择模式同文件/段名字或者段属性之间的最佳配对赢得这种分配关系。参考《解决多重配对》小节。

这一节中描述如下内容:
1、BNF符号及语法
2、分散加载描述文件语法概述
3、加载区域描述
4、输入段描述
5、解决多重配对
6、解决路径名

使用特权

评论回复
14
精益求精| | 2009-12-30 11:23 | 只看该作者
好。顶。辛苦。谢。
顺便把帮助都翻译了吧。呵呵。

使用特权

评论回复
15
一朝成名| | 2009-12-30 12:49 | 只看该作者
研究太细,小心无法自拔阿~~

使用特权

评论回复
16
xinzha|  楼主 | 2009-12-30 21:07 | 只看该作者
研究太细,小心无法自拔阿~~
一朝成名 发表于 2009-12-30 12:49


还不至于,只是晚上回家无聊玩的,顺便学学英语。

使用特权

评论回复
17
xinzha|  楼主 | 2009-12-30 21:09 | 只看该作者
好。顶。辛苦。谢。
顺便把帮助都翻译了吧。呵呵。
精益求精 发表于 2009-12-30 11:23

你是指RVDS的帮助文档...,那个稍微有点长...

使用特权

评论回复
18
xinzha|  楼主 | 2009-12-30 21:46 | 只看该作者
本帖最后由 xinzha 于 2011-1-6 21:06 编辑

5.2.1 BNF符号和语法
BNF(backus naur format)就是scatter文件所用的形式语言,这里概括了它所用的语法和符号规则。
"        : 引号用来表示所引用的符号作为通常意义的字符。(个人理解就类似于c语言中的n和\n的关系),比如 B"+"C只能用B+C形式来替代,而B+C可以用BC,BBC或者BBBC来替代都可以。

A::=B : 定义A与B等价,比如A::=B"+" | C 代表A = B+ 或者 A=C。::=表示法还可以进行复杂结构的定义,表达式中的每个成员都可以用更简单的成员来表达,例如 A::=B和 B::C|D表示A=C或者A=D。

[A]     :可选元素A,例如,A::=B[C]D表示A=BD或者A=BCD。

A+     :元素A可能会出现多次(一次以上)。例如 A::=B+表示A可以被表示为B或者BB或者BBB。

A*     :元素A可能会出现多次(零次以上)。

A|B    :元素A或者B可能会出现,但是不会同时都出现。

(AB)   :元素A和B被打包在一起。这一表示方式在使用 | 运算符或者重复一个复杂模板的时候很有用,例如A::=(BC)+(D|E)表示A的值可能是BCD,BCE, BCBCD,BCBCE,BCBCBCD,BCBCBCE中的一个。

时间过去了一年多,此时重新看了下这部分文档,由于这一年中学习了一些正则表达式的知识,立即感觉到了不一样的内容,看来多学点“没用”的东西还是有用的。

使用特权

评论回复
19
xinzha|  楼主 | 2009-12-30 21:50 | 只看该作者
刚才在网上搜到了一份别人已经翻译好的资料,是某个培训机构的,看过这个培训机构的一些资料,确实是相当不错,至少写资料的人肯定是做过很多很底层的工作的,某公的那些ppt,培训文档什么的就是明目张胆的直接指向他们的培训资料。
所以我这个的目的就纯粹是逼自己学习并练习英语了。

使用特权

评论回复
20
xinzha|  楼主 | 2009-12-31 20:22 | 只看该作者
5.2.2 分散加载描述文件语法概述

注意事项:本节中的BNF定义,添加的回车和空格只是为了增加可读性,分散加载定义对此并不做要求,并且它们如果出现会被忽略。

一个scatter_description(分散加载描述)表达一个或者多个load_region_description(加载区域描述):Scatter_description ::= load_region_description+

每个load_region_description由以下成员表示,一个加载区域名,属性或者大小声明是可选项,还需要有一个或者多个执行区域描述:
load_region_name (base_address | ("+" offset)) [attributes] [max_size]
"{"
        execution_region_description+
"}"

每个execution_region_description由以下成员表示,执行区域名,基地址说明,一个或者多个输入段描述,属性或者大小作为可选项:
execution_region_description ::=
    exec_region_name (base_address | "+" offset) [attribute_list] [max_size | "-" length]
        "{"
              input_section_description*
        "}"

每个input_section_description由以下成员组成,一个源模块选择程序模板,后面可能跟随输入段选择程序:
input_section_selector ::=
           ("+" input_section_attr | input_section_pattern | input_symbol_pattern)

input_section_description ::=
    module_select_pattern
      ["("
         ("+"input_section_attr | input_section_pattern | input_symbol_pattern)
         ("," "+" input_section_attr | "," input_section_pattern | "," input_symbol_pattern)*
        ")"]

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

10

主题

949

帖子

7

粉丝