Chinaunix首页 | 论坛 | 博客
  • 博客访问: 192314
  • 博文数量: 34
  • 博客积分: 746
  • 博客等级: 军士长
  • 技术积分: 202
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-09 21:19
文章分类

全部博文(34)

文章存档

2011年(34)

分类: 嵌入式

2011-05-08 20:13:45

 
(和《ARM嵌入式应用技术基础》186-190页一模一样)
 
Scatter文件编写
 
    一个映像文件中可以包含多个域(region),在加载和运行映像文件时,每个域可以有不同的地址。每个域可以包括多达3个输出段,每个输出段是由若干个具有相同属性的输入段组成。这样在生成映像文件时,ARM链接器就需要知道下述两个信息。
  • 分组信息    决定各域中的输出段是由哪些输入段组织而成;
  • 定位信息    决定各域在存储空间中的起始地址。
    根据映像文件中地址映射的复杂程度,有两种方法来告诉ARM链接器这些相关的信息。对于映像文件中地址映射关系比较简单的情况,可以使用命令行选项;对于映像文件中地址映射关系比较复杂的情况,可以使用一个scatter配置文件。Scatter文件又称为分散加载文件,将重点讲解如何编写scatter文件。
1、Scatter文件结构
    Scatter文件是一个文本文件,使用BNF语法来描述ARM链接器生成映像文件时所需要的信息。具体来说,在scatter文件中可以指定下列信息:
  • 各个加载时域的加载时起始地址、最大尺寸和属性;
  • 每个加载时域包含的输出段;
  • 各个输出段的运行时起始地址、最大尺寸、存储访问特性和属性;
  • 各个输出段中包含的输入段。
    一个Scatter文件包含若干个加载域,一个加载域包含若干个输出段,一个输出段由若干个具有相同属性的输入段组成,其结构如图1所示。
               
                                   图1 Scatter文件结构示意图
    ① 加载时域的描述
    加载时域包括名称、起始地址、属性、最大尺寸和一个运行时域的列表。使用BNF语法描述,加载时域的格式如下所示:

Load_name      base_designator         attribute      max_size
{
……
}

  • Load_name   运行时域名称,它除了唯一地标识一个运行时域外,还用来构成链接器生成的链接符号;
  • base_designator 用来表示本加载时域的起始地址,它可以有两种格式表示:起始地址或偏移量; 
  • attribute   本加载时域的属性,其可能的取值为下面之一,默认的取值为ABSOLUTE:
  •     PI          位置无关属性;
  •     RELOC       重定位;
  •     ABSOLUTE    绝对地址; 
  • max_size 最大尺寸,如果本加载时域的实际尺寸超过了该值,链接器将报告错误。默认的取值为0xFFFFFFFF。
    ② 输出段的描述
    输出段包括名称、起始地址、属性、最大尺寸和一个输入段的集合。使用BNF语法描述,输出段的格式如下所示:

output_name     base_designator     attribute       max_size
{
……
}

  • output_name 输出段的名称,它用来唯一地标识一个输出段,还用来构成链接器生成的链接符号。
  • base_designator 用来表示本输出段的起始地址,它可以有两种格式:起始地址值或偏移量。
  • attribute   表示本输出段的属性,其可能的取值如下所示:
  •     PI          位置无关属性
  •     RELOC       重定位
  •     ABSOLUTE    绝对地址
  •     FIXED       固定地址
  •     UNINIT      未初始化的数据
  • max_size    指定本输出段的最大尺寸。
    ③ 输入段的描述
    输入段里描述了一个文本字符串的模式,匹配该模式的输入段都将被包含在当前域中。模式中可以使用匹配符,符号"*"代表零个或者多个字符,符号"?"代表单个字符。进行匹配时,所有字符是大小写无关的。
    下面介绍一些使用scatter文件配置映像文件地址映射模式的例子。在本例中,映像文件包括一个加载时域和3个连续的输出段,这种模式适合于那些将其他程序加载到RAM中的程序,如操作系统的引导程序和Angel等。
    例子    一个简单的scatter文件 

Load_1   0x4000             ;定义加载时域的名称为Load_1,起始地址为0x4000
{
         ER_RO    + 0     ;输出段名ER_RO,地址偏移量0,所以起始地址为0x4000
          { *( + RO) }       ;通配符*,包含了所有的RO属性的输入段,它们被连续放置
         ER_RW    + 0     ;输出段名称ER_RW,起始地址为前一个输出段的结束地址加偏移量0
          { *( +  RW) }      ;本输出段包含所有的RW属性的输入段,它们被连续放置
ER_ZI 0x5000       ;输出段名称ER_ZI,起始地址为0x5000
          { *( +  ZI) }      ;本输出段包含了所有的ZI属性的输入段,它们被连续放置
}

    按照例 scatter文件的描述,ARM链接器会生成相应的映像文件地址映射关系,如图2所示。
                  
 
                         图2 程序运行时地址映射关系
 
2、固定时域
    任何一个映像文件都需要指定一个初始入口点(initial entry point),它是影响文件运行时的入口点。初始入口点必须位于一个固定域中,所谓固定域是指该域的加载时地址和运行时地址是相同的。如果初始入口点不是位于一个固定域中,ARM链接器在链接时会产生下面的错误信息。
    L6203E:Entry point (0x0000 0000) lies within non-root region 32 bit RAM
    使用scatter文件时,可以有下面两种方法来设置固定域。
 
    ① 设置输出段地址
    第1种方法是设定一个加载域中第1个输出段的运行地址,使其和该加载域的加载地址相同。这样该输出段就是一个固定域。
    例1就使用这种方法确定固定域。其中,加载域LR_1的起始地址为0x8000,输出段ER_RO的起始地址指定为0x8000,与加载域LR_1的起始地址相同,因此,输出段ER_RO是一个固定域,并且是映像文件的初始入口点。
    例1 指定固定域

LR_1 0x08000                ;加载域LR_1的起始地址为0x8000
{
     ER_RO 0x08000          ;输出段ER_RO的起始地址为0x8000
     {
*( +  RO)          ;包含了所有的RO数据,包含初始入口点
     }
     ;其他部分内容
}

    ② 设置输出段属性
    第2种方法通过将某个输出段的属性设置成FIXED。
    例2指定固定域

LR_1 0x8000                 ;加载时域LR_1的起始地址为0x8000
{
     ER_RO    0x8000
     {
         *( +  RO)          ;除了init.o之外的其他RO数据
     }
     ER_INIT 0x9000 FIXED   ;设置输出段属性为FIXED,确定固定域
     {
     init.o( +  RO)         ;本输出段包含了init.o,包含映像文件的初始入口点
     }
     ;其他部分内容
}

 
3、一个实际系统的例子
    在一个嵌入式设备中,为了保持好的性价比,通常在系统中存在多种存储器。在一个实际的ARM开发板中,可能包括片内Flash、RAM和片外Flash、RAM。在本例中,我们假设用ARM芯片构造了一个嵌入式系统,包含了8KB片内Flash存储器、16KB片内RAM存储器、起始地址为0x80000000的片外Flash和起始地址为0x81000000的片外RAM,其地址空间分配关系如图3所示。
    在这样的ARM系统中,我们编写了程序,并且按照例3中的分散加载文件对映象文件的地址进行分配。分配后的地址映像关系如图4所示。
        
          
         图3 ARM系统中的地址空间                         图4 地址映像关系
    从图4中可以看出:可执行代码都放在片外Flash中,并且Vectors向量表放在片外Flash的起始地址上;Startup目标文件的数据放置在片内RAM中,堆栈放在片内RAM的顶端;其他数据放置在片外RAM中,堆空间紧跟其后。
    例3 片外Flash启动程序的scatter文件

ROM_LOAD  0x80000000                 ;定义加载区名称ROM_LOAD,起始地址0x80000000
{
     ROM_EXE  0x80000000              ;定义执行代码空间,起始地址与加载域地址相同
    {
        Startup.o (vectors,  +First)     ;首先放置Startup.o文件的向量表vectors
        * ( +RO)               ;后面地址空间放置其他RO属性代码
 
     IRAM  0x40000000                     ;定义数据空间
    {   Startup.o ( +RW, +ZI)   }
 
STACKS  0x40004000  UNINIT           ;定义堆栈空间
    {    stack.o ( +ZI)    }
 
    ERAM  0x81000000                     ;定义数据空间
    {   * ( +RW, +ZI)      }             ;剩下未指定空间的所有数据
   
    HEAP + 0  UNINIT                     ;定义堆空间
    {     heap.o ( +ZI)    }

阅读(6223) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~