Scatter file

来源:互联网 发布:淘宝衣服拍摄技巧 编辑:程序博客网 时间:2024/05/16 06:37
Part1  简介

一 概述

Scatter file (分散加载描述文件)用于armlink的输入参数,他指定映像文件内部各区域的download与运行时位置。Armlink将会根据scatter file生成一些区域相关的符号,他们是全局的供用户建立运行时环境时使用。(注意:当使用了scatter file 时将不会生成以下符号 Image$$RW$$Base, Image$$RW$$Limit, Image$$RO$$Base, Image$$RO$$Limit, Image$$ZI$$Base, and Image$$ZI$$Limit)

二 什么时候使用scatter file

       当然首要的条件是你在利用ADS进行项目开发,下面我们看看更具体的一些情况。

1 存在复杂的地址映射:例如代码和数据需要分开放在在多个区域。

2 存在多种存储器类型:例如包含 Flash,ROM,SDRAM,快速SRAM。我们根据代码与数据的特性把他们放在不同的存储器中,比如中断处理部分放在快速SRAM内部来提高响应速度,而把不常用到的代码放到速度比较慢的Flash内。

3 函数的地址固定定位:可以利用Scatter file实现把某个函数放在固定地址,而不管其应用程序是否已经改变或重新编译。

4 利用符号确定堆与堆栈:

5 内存映射的IO:采用scatter file可以实现把某个数据段放在精确的地指处。

因此对于嵌入式系统来说scatter file是必不可少的,因为嵌入式系统采用了ROM,RAM,和内存映射的IO。

三 scatter file 实例

1 简单的内存映射

LOAD_ROM 0x0000 0x8000

{

       EXEC_ROM 0x0000 0x8000

       {

       *( RO)

       }

      RAM 0x10000 0x6000

      {

       *( RW, ZI)

      }

}



LOAD_ROM(下载区域名称) 0x0000(下载区域起始地址) 0x8000(下载区域最大字节数)

{

        EXEC_ROM(第一执行区域名称) 0x0000(第一执行区域起始地址) 0x8000(第一执行区域最大字节数)

       {

       *( RO(代码与只读数据))

       }

      RAM(第二执行区域名称) 0x10000(第二执行区域起始地址) 0x6000(第二执行区域最大字节数)

      {

       *( RW(读写变量), ZI(未初始化变量))

      }

}

2 复杂内存映射

LOAD_ROM_1 0x0000

{

       EXEC_ROM_1 0x0000

       {

        program1.o( RO)

       }

      DRAM 0x18000 0x8000

      {

       program1.o ( RW, ZI)

      }

}



LOAD_ROM_2 0x4000

{

       EXEC_ROM_2 0x4000

       {

       program2.o( RO)

       }

       SRAM 0x8000 0x8000

      {

       program2.o ( RW, ZI)

      }

}



LOAD_ROM_1 0x0000(下载区域一起始地址)

{

       EXEC_ROM_1 0x0000(第一执行区域开始地址)

       {

        program1.o( RO) (program1.o内的Code与RO data 放在第一执行区域)

       }

       DRAM 0x18000(第二执行区域开始地址) 0x8000(第二执行区域最大字节数)

      {

       program1.o ( RW, ZI) (program1.o内的RW data与 ZI data 放在第二执行区域)

      }

}

LOAD_ROM_2 0x4000(下载区域二起始地址)

{

       EXEC_ROM_2 0x4000

       {

       program2.o( RO) (program2.o内的Code与RO data 放在第一执行区域)

      }

      SRAM 0x8000 0x8000

      {

       program2.o ( RW, ZI) (program2.o内的RW data与 ZI data 放在第二执行区域)

      }

}

Part2 基本语法

2.1   BNF 符号与语法

" :由引号赖标示的符号保持其字面原意,如A” ”B标示A B。

A ::= B :定义A为B。

[A] :标示可选部分,如A[B]C用来标示ABC或AC。

A :用来标示A可以重复任意次,如A 可标示A,AA,AAA, …

A* :同A 。

A | B :用来标示选择其一,不能全选。如A|B用来标示A或者B。

(A B) :标示一个整体,当和|符号或复杂符号的多次重复一起使用时尤其强大,如(AB) (C|D)标示ABC,ABD,ABABC,ABABD, …

2.2     分散加载文件各部分描述                        

                            (2.1)

如图2.1所示为一个完整的分散加载脚本描述结构图。下面我们对图示中各个部分进行讲述。

2.2.1 加载区描述

每个加载区有:

ó名称:供连接器确定不同下载区域

ó基地址:相对或绝对地址

ó属性:可选

ó最大字节数:可选

ó执行区域列:确定执行时各执行区域的类型与位置

load_region_name (base_address | (" " offset)) [attribute_list] [ max_size ]

"{"

execution_region_description

"}"



load_region_name:下载区域名称,最大有效字符数31。(并不像执行区域段名用于Load$$region_name,而是仅仅用于标示下载区域)。

base_address:本区域内部目标被连接到的地址(按字对齐)。

offset:相对前一个下载区域的偏移量(4的整数倍,如果为第一个区域)。



2.2.2 执行区描述

每个执行区有:

ó名称:供连接器确定不同下载区域

ó基地址:相对或绝对地址

ó属性:确定执行区域的属性

ó最大字节数:可选

ó输入段:确定放在该执行区域的模块

exec_region_name (base_address | " " offset) [attribute_list] [max_size]

"{"

input_section_description

"}"

exec_region_name:执行区域名称,最大有效字符数31。

base_address:本执行区域目标要被联接到的位置,按字对齐。

offset:相对于前一个执行区域结束地址的偏移量,4的整数倍;如果没有前继之能够行区域(本执行区域为该下载区域的第一个执行区域),则该偏移量是相对于该下载区域的基址偏移量。

attribute_list:PI,OVERLAY,ABSOLUTE,FIXED,UNINIT。

PI: 位置独立。

OVERLAY: 覆盖。

ABSOLUTE: 绝对地址。

FIXED: 固定地址,下载地址与执行地址具有该地址指示确定。

UNINIT: 未初始化数据。

RELOC:无法明确指定执行区域具有该属性,而只能通过继承前一个执行区或父区域获得。

对于PI,OVERLAY,ABSOLUTE,FIXED,我们只能选择一个,缺省属性为ABSOLUTE。一个执行区域要么直接继承其前面的执行区域的属性或者具有属性为ABSOLUTE。

具有PI,OVERLAY,RELOC属性的执行区域允许其地址空间重叠,对于BSOLUTE,FIXED 属性执行区域地址空间重叠Armlink会报错。

max_size:可选,他用于指使Armlink在实际分配空间大于指定值时报错。

input_section_description:指示输入段的内容。



2.2.3 输入段描述

输入段:

ó模块名:目标文件名,库成员名,库文件名。名称可以使用通配符。

ó输入段名,或输入段属性(READ-ONLY,CODE)。

module_select_pattern

["("

(" " input_section_attr | input_section_pattern)

([","] " " input_section_attr | "," input_section_pattern))*

")"]

2.2.3.1

module_select_pattern:选择的模块名称(目标文件,库文件成员,库文件),模块名可以使用通配符(*匹配任意多个字符,?匹配任意一个字符),名称不区分字母大小写,它是供选择的样本。

例1:*libtx.a ( RO)

libtx.a为threadX库文件。

例2:tx_ill.o (INIT)

       tx_ill.o为threadX中断向量目标文件。

2.2.3.2

input_section_attr:输入段属性选择子,每个选择子以” ”开头,选择子不区分大小写字符。

选择子可选RO-CODE,RO-DATA,RO( selects both RO-CODE and RO-DATA),RW-DATA,RW-CODE,RW( selects both RW-CODE and RW-DATA),ZI,ENTRY( that is a section containing an ENTRY point)。

以下同义词可以选择:CODE (for RO-CODE),CONST( for RO-DATA),TEXT (for RO),DATA (for RW),BSS (for ZI)。

还有两个伪属性:FIRST,LAST。如果各段的先后顺序比较重要时,可以使用FIRST,LAST标示一个执行区域的第一个和最后一个段。

例1:os_main_init.o (INIT , FIRST)

FIRST表示放于本执行区域的开始处。

例2:*libtx.a ( RO)

       RO 表示*libtx.a的只读部分。

2.2.3.3

input_section_pattern:输入段名。

例1:os_main_init.o (INIT , FIRST)

INIT 为os_main_init.o的一个段。

例2:os_stackheap.o (heap)

       heap 为os_stackheap.o的一个段。

例3:os_stackheap.o (stack)

       stack为os_stackheap.o的一个段。









//--------------------------------------------------------------------------------------------------------------------------

分散加载文件事例



ADS下的分散加载文件应用实例

load_region_name  start_address | " "offset  [attributes] [max_size]

{

    execution_region_name  start_address | " "offset  [attributes][max_size]

    {

        module_select_pattern  ["("

                                    (" " input_section_attr | input_section_pattern)

                                    ([","] " " input_section_attr | "," input_section_pattern)) *

                               ")"]

    }

}

load_region:       加载区,用来保存永久性数据(程序和只读变量)的区域;

execution_region:  执行区,程序执行时,从加载区域将数据复制到相应执行区后才能被正确执行;

load_region_name:  加载区域名,用于“Linker”区别不同的加载区域,最多31个字符;

start_address:     起始地址,指示区域的首地址;

offset:           前一个加载区域尾地址+offset 做为当前的起始地址,且“offset”应为“0”或“4”的倍数;

attributes:        区域属性,可设置如下属性:

                    PI       与地址无关方式存放;

                    RELOC    重新部署,保留定位信息,以便重新定位该段到新的执行区;

                    OVERLAY  覆盖,允许多个可执行区域在同一个地址,ADS不支持;

                    ABSOLUTE 绝对地址(默认);

max_size:          该区域的大小;

execution_region_name:执行区域名;

start_address:     该执行区的首地址,必须字对齐;

offset:           同上;

attributes:        同上;

                    PI          与地址无关,该区域的代码可任意移动后执行;

                    OVERLAY     覆盖;

                    ABSOLUTE    绝对地址(默认);

                    FIXED       固定地址;

                    UNINIT      不用初始化该区域的ZI段;

module_select_pattern: 目标文件滤波器,支持通配符“*”和“?”;

                        *.o匹配所有目标,* (或“.ANY”)匹配所有目标文件和库。

input_section_attr:    每个input_section_attr必须跟随在“+”后;且大小写不敏感;

                        RO-CODE 或 CODE

                        RO-DATA 或 CONST

                        RO或TEXT, selects both RO-CODE and RO-DATA

                        RW-DATA

                        RW-CODE

                        RW 或 DATA, selects both RW-CODE and RW-DATA

                        ZI 或 BSS

                        ENTRY, that is a section containing an ENTRY point.

                        FIRST,用于指定存放在一个执行区域的第一个或最后一个区域;

                        LAST,同上;

input_section_pattern: 段名;

汇编中指定段:

     AREA    vectors, CODE, READONLY

C中指定段:

#pragma arm section [sort_type[[=]"name"]] [,sort_type="name"]*

sort_type:      code、rwdata、rodata、zidata

                如果“sort_type”指定了但没有指定“name”,那么之前的修改的段名将被恢复成默认值。

#pragma arm section     // 恢复所有段名为默认设置。

应用:

    #pragma arm section rwdata = "SRAM",zidata = "SRAM"

        static OS_STK  SecondTaskStk[256];              // “rwdata”“zidata”将定位在“sram”段中。

    #pragma arm section                                 // 恢复默认设置

分散加载文件中定义如下:

    Exec_Sram  0x80000000  0x40000

    {

        * (sram)

    }

“PI” 属性使用示例:

LR_1 0x010000 PI                ; The first load region is at 0x010000.

{

    ER_RO 0                    ; The PI attribute is inherited from parent.

                                ; The default execution address is 0x010000, but the code can be moved.

    {

        *( RO)                  ; All the RO sections go here.

    }

    ER_RW 0 ABSOLUTE           ; PI attribute is overridden by ABSOLUTE.

    {

        *( RW)                  ; The RW sections are placed next. They cannot be moved.

    }

    ER_ZI 0                    ; ER_ZI region placed after ER_RW region.

    {

        *( ZI)                  ; All the ZI sections are placed consecutively here.

    }

}

LR_1 0x010000                   ; The first load region is at 0x010000.

{

    ER_RO 0                    ; Default ABSOLUTE attribute is inherited from parent. The execution address

                                ; is 0x010000. The code and ro data cannot be moved.

    {

        *( RO)                  ; All the RO sections go here.

    }

    ER_RW 0x018000 PI           ; PI attribute overrides ABSOLUTE

    {

        *( RW)                  ; The RW sections are placed at 0x018000 and they can be moved.

    }

    ER_ZI 0                    ; ER_ZI region placed after ER_RW region.

    {

        *( ZI)                  ; All the ZI sections are placed consecutively here.

    }

}

程序中对某区域地址等的引用方法:

Load$$region_name$$Base             Load address of the region.

Image$$region_name$$Base            Execution address of the region.

Image$$region_name$$Length          Execution region length in bytes (multiple of 4).

Image$$region_name$$Limit           Address of the byte beyond the end of the execution region.

Image$$region_name$$ZI$$Base        Execution address of the ZI output section in this region.

Image$$region_name$$ZI$$Length      Length of the ZI output section in bytes (multiple of 4).

Image$$region_name$$ZI$$Limit       Address of the byte beyond the end of the ZI output sectionin the execution region.

SectionName$$Base                   Input Address of the start of the consolidated section called SectionName.

SectionName$$Limit                  Input Address of the byte beyond the end of the consolidated section called SectionName.

Load:          加载区,即存放地址;

Image:         执行区,即运行地址;

Base:          区首地址;

Limit:         区尾地址;

Length:        区长度;

region_name:   RO、RW、ZI、load_region_name、execution_region_name;

例如:

    “RAM1”区域的首地址:      Image$$RAM1$$Base

    上例中“sram”段首地址:    sram$$Base

汇编引用示例:

  IMPORT |Load$$Exec_RAM1$$Base|              // Exec_RAM1 为“RW”段

  IMPORT |Image$$Exec_RAM1$$Base|

  IMPORT |Image$$Exec_RAM1$$Length|

  IMPORT |Image$$Exec_RAM1$$Limit|

  LDR  R0, =|Load$$Exec_RAM1$$Base|

  LDR  R1, =|Image$$Exec_RAM1$$Base|

  LDR  R2, =|Image$$Exec_RAM1$$Limit|

0

  CMP  R1,   R2

  LDRCC R3,   [R0], #4

  STRCC R3,   [R1], #4

  BCC  %b0

C 引用:

extern unsigned char Load$$Exec_RAM1$$Base;

extern unsigned char Image$$Exec_RAM1$$Base;

extern unsigned char Image$$Exec_RAM1$$Length;

void MoveRO(void)

{

unsigned char * psrc, *pdst;

unsigned int  count;

count = (unsigned int)   &Image$$Exec_RAM1$$Length;

psrc  = (unsigned char *)&Load$$Exec_RAM1$$Base;

pdst  = (unsigned char *)&Image$$Exec_RAM1$$Base;

while (count--) {

  *pdst = *psrc ;

}

}

加载文件示例一:

        起始地址      大小

ROM:    0x00000000    256K      ;0x1fc 保留为加密字,程序在ROM中运行;

RAM     0x40000000     16K      ;用于全局变量及任务堆栈;

SRAM    0x80000000    512K      ;SRAM速度慢,主要用于存放大的数据表;

LOAD_ROM1 0x00000000  0x1f8                 ; 指定该加载区域首地址、大小

{

    EXEC_ROM1  0  0x1f8                    ; 没有前一加载区域,所以该执行区域首地址为加载去首地址

                                            ; 并指定该区域长度

    {

        Startup.o (vectors, FIRST)         ; 目标文件的“vectors”段放在该执行区域的第一段

        irq.o ( RO)                         ; 目标文件的所有“RO”段放在该执行区域

    }

}

LOAD_ROM2 0x00000200                        ; 第二个加载区域

{

    EXEC_ROM2  0  0x3e600

    {

        * ( RO)                             ; 所有目标文件和库文件中的“RO”段存放在该区域

    }

    RAM1   0x40000000   0x4000

    {

        * ( RW, ZI)                        ; 所有目标文件和库文件的“RW”和“ZI”段存放在该区域

    }

    SRAM2  0x80000000  0x80000

    {

        * (sram)                            ; 所有目标文件中的“sram”段存放在该区域

    }

}

示例二:

    “iap.o”定义在“Exec_RAM1”中运行,所以设置“PI”属性;

    在调用“iap.c”中函数之前应该将其从“Load$$Exec_IAP$$Base”复制到指定的“Exec_RAM1”区域;

Load_region1  0x00000000  0x1fc

{

    EXEC_ROM1  0

    {

        Startup.o (vectors, FIRST)

        irq.o ( RO)

    }

}

Load_region2  0x00000200  0x3e600

{

    EXEC_ROM2  0

    {

        * ( RO)

    }

    Exec_IAP   0  PI               // 可能引起链接器未使用该属性警告,忽略

    {

        iap.o ( RO)

    }

    Exec_RAM1  0x40000000  0x4000

    {

        * ( RW, ZI)

    }

    Exec_Sram  0x80000000  0x40000

    {

        * (SRAM)

    }

}

// 移动“IAP.o”中的所有函数到“ImageExecIAPBase”加载区,并调用其中的函数

extern unsigned char Load$$Exec_IAP$$Base;

extern unsigned char Image$$Exec_IAP$$Length;

#define  ImageExecIAPBase  (0x40000000 0x1000)   // 加载区首址

void MoveIAPRO(void)

{

unsigned char * psrc, *pdst;

unsigned int  count;

count = (unsigned int)   &Image$$Exec_IAP$$Length;

psrc  = (unsigned char *)&Load$$Exec_IAP$$Base;

pdst  = (unsigned char *)ImageExecIAPBase;

while (count--) {

  *pdst = *psrc ;

}

}

// 调用“IAP.O”中的某函数

{

  void (* pfnIAPWrite)(unsigned long, int);

  pfnIAPWrite = (void (*)(unsigned long, int))

   (ImageExecIAPBase

   (unsigned int)IAPWrite -                        // 被调用函数名

   (unsigned int)&Load$$Exec_IAP$$Base);

  pfnIAPWrite((int)((CUPDATA *)CODESTARTADDR)->data,

     ((CUPDATA *)CODESTARTADDR)->length);

    }