Technical
Note
分散加载文件浅释
ARM 嵌入式开发
TN01010101
V0.00
Date:2008/01/01
工程技术笔记
类别
关键词
摘 要
内容
分散加载、Scatter
本文主要介绍分散加载文件的格式及应用
广州周立功单片机科技有限公司
广州周立功单片机科技有限公司
分散加载文件浅释
ARM 嵌入式开发
目 录
4.1
2.1
1. 适用范围 ................................................................................................................... 1
2. 基础知识 ................................................................................................................... 2
基本概念 ................................................................................................................... 2
3. 分散加载文件概述 ................................................................................................... 3
4. 分散加载文件语法 ................................................................................................... 4
加载时域的描述 ....................................................................................................... 4
运行时域的描述 ....................................................................................................... 5
输入段描述 ............................................................................................................... 6
5. 分散加载应用实例 ................................................................................................... 8
一个普通的分散加载配置 ....................................................................................... 8
多块 RAM 的分散加载文件配置 ............................................................................ 8
多块 Flash 的分散加载文件配置 .......................................................................... 10
Flash 特殊要求应用 ............................................................................................... 13
段在分散加载文件中的应用 ................................................................................. 13
程序拷贝到 RAM 中执行应用 .............................................................................. 14
5.2
5.3
5.4
5.5
5.6
4.2
4.3
5.1
工程技术笔记 ©2008 Guangzhou ZHIYUAN Electronics CO., LTD.
1
广州周立功单片机科技有限公司
分散加载文件浅释
ARM 嵌入式开发
1. 适用范围
有时候用户希望将不同代码放在不同存储空间,也就是通过编译器生成的映像文件需要
包含多个域,每个域在加载和运行时可以有不同的地址。要生成这样的映像文件,必须通过
某种方式告知编译器相关的地址映射关系。
在 Keil/ADS/IAR 等编译工具中,可通过分散加载机制实现。分散加载通过配置文件实
现,这样的文件称为分散加载文件。本文重点介绍 Keil 的分散加载文件配置。
工程技术笔记 ©2008 Guangzhou ZHIYUAN Electronics CO., LTD.
1
广州周立功单片机科技有限公司
分散加载文件浅释
ARM 嵌入式开发
2. 基础知识
2.1 基本概念
要了解分散加载文件前首先需要对以下各个概念进行了解,可参考程序清单 2.1。
Code:为程序代码部分;
RO-Data:表示程序定义的常量及 const 型数据;
RW-Data:表示已经初始化的静态变量,变量有初值;
ZI-Data:表示未初始化的静态变量,变量无初值。
程序清单 2.1 各类型数据声明
#define DATA
(0x10000000)
/* RO-Data */
char const GcChar = 5;
/* RO-Data */
char GcStr[] = "string.";
/* RW-Data */
char GcZero;
/* ZI-Data */
Keil 工程编译完成后,查看其的 map 文件,可得到结果如程序清单 2.2 类似。
程序清单 2.2 map 文件信息
==============================================================================
Total RO Size (Code + RO-Data) 768 ( 0.75kB)
Total RW Size (RW-Data + ZI-Data) 2060 ( 2.01kB)
Total ROM Size (Code + RO-Data + RW-Data) 780 ( 0.76kB)
==============================================================================
由程序清单 2.2 所示的 map 文件可看出:
ROM(Flash)Size = Code+RO-Data+RW-Data = 0.76KB;
RAM Size = RW-Data+ZI-Data = 2.01KB。
为什么上述的 RW-Data 既占用 Flash 又占用 RAM 么,变量不是放在 RAM 中的么,为
什么会占用 Flash?因为 RW 数据不能像 ZI 那样“无中生有”的,ZI 段数据只要求其所在
的区域全部初始化为零,所以只需要程序根据编译器给出的 ZI 基址及大小来将相应的 RAM
清零。但 RW 段数据却不这样做,所以编译器为了完成所有 RW 段数据赋值,其先将 RW 段
的所有初值,先保存到 Flash 中,程序执行时,再 Flash 中的数据搬运到 RAM 中,所以 RW
段即占用 Flash 又占用 RAM,且占用的空间大小是相等的。
这里有必要再了解一下,ZI 和 RW 段数据的赋值在一工程中是在什么地方实现的?首
先,变量必先要初始化才能使用,否则初值不正确,而在 main()函数后变量已经可以正常使
用,那就是说变量的初始化是在之前完成的,查看这之前的代码只有__main()一个函数,除
了赋初值外,都还做了什么呢?
__main()这个函数主要由以下两部分功能组成,如下所示。
_main():完成代码和数据的拷贝,并把 ZI 数据区清零。代码拷贝可将代码拷贝到
另外一个映射空间并执行,如将代码拷贝到 RAM 执行;数据拷贝完成 RW 段数据
赋值;数据区清零完成 ZI 段数据赋值。以上的代码和分散加载文件密切相关。
_rt_entry():进行 STACK 和 HEAP 等的初始化。最后_rt_entry 跳进 main()函数入口。
当 main()函数执行完后,_rt_entry 又将控制权交还给调试器。
工程技术笔记 ©2008 Guangzhou ZHIYUAN Electronics CO., LTD.
2
广州周立功单片机科技有限公司
分散加载文件浅释
ARM 嵌入式开发
3. 分散加载文件概述
分散加载(scatter)文件是一个文本文件,它可以用来描述连接器生成映像文件时需要
的信息。通过编写一个分散加载文件来指定 ARM 连接器在生成映像文件时如何分配 Code、
RO-Data,RW-Data,ZI-Data 等数据的存放地址。如果不用分散加载文件指定,那么 ARM
连接器会按照默认的方式来生成映像文件。一般情况下我们不需要使用分散加载文件。但对
一些特殊的情况例如需要将不同的程序代码存储到不同的地址区域时需要修改分散加载文
件。
1. 何时使用分散加载
链接器的命令行选项提供了一些对数据和代码位置的控制,但要对位置进行全面控制,
则需要使用比命令行中的输入内容更详细的指令。需要或最好使用分散加载描述的情况包括:
2. 复杂内存映射
如果必须将代码和数据放在多个不同的内存区域中,则需要使用详细指令指定将哪些数
据放在哪个内存空间中。
3. 不同类型的内存
许多系统都包含多种不同的物理内存设备,如闪存、ROM、SDRAM 和快速 SRAM。
分散加载描述可以将代码和数据与最适合的内存类型相匹配。例如,可以将中断代码放在快
速 SRAM 中以缩短中断等待时间,而将不经常使用的配置信息放在较慢的闪存中。
4. 内存映射的 I/O
分散加载描述可以将数据节准确放在内存映射中的某个地址,以便能够访问内存映射的
外围设备。
5. 位于固定位置的函数
可以将函数放在内存中的固定位置,即使已修改并重新编译周围的应用程序。
6. 使用符号标识堆和堆栈
链接应用程序时,可以为堆和堆栈位置定义一些符号。
工程技术笔记 ©2008 Guangzhou ZHIYUAN Electronics CO., LTD.
3
广州周立功单片机科技有限公司
分散加载文件浅释
ARM 嵌入式开发
4. 分散加载文件语法
分散加载文件主要由一个加载时域和多个运行时域组成,其大致结构如图 4.1 所示。
图 4.1 分散加载文件语法结构
下面分别介绍一下加载时域和运行时域特点及用法。
4.1 加载时域的描述
加载时域语法格式如程序清单 4.1 所示,其每项含义解释如下。
程序清单 4.1 加载时域描述语法描述
load_region_name(base_address|("+"offset))[attribute_list][max_size]
{
execution_region_description+
}
load_region_name:为本加载时域的名称,名称可以按照用户意愿自己定义,该名
称中只有前 31 个字符有意义;
base_designator:用来表示本加载时域的起始地址,可以有下面两种格式中的一种:
base_address:表示本加载时域中的对象在连接时的起始地址,地址必须是字
对齐的;
+offset:表示本加载时域中的对象在连接时的起始地址是在前一个加载时域的
结束地址后偏移量 offset 字节处。本加载时域是第一个加载时域,则它的起始地址
即为 offset,offset 的值必须能被 4 整除。
attribute_list:指定本加载时域内容的属性,包含以下几种,默认加载时域的属性是
ABSOLUTE。
ABSOLUTE:绝对地址;
PI:与位置无关;
RELOC:可重定位;
OVERLAY:覆盖;
工程技术笔记 ©2008 Guangzhou ZHIYUAN Electronics CO., LTD.
4
广州周立功单片机科技有限公司
分散加载文件浅释
ARM 嵌入式开发
NOCOMPRESS:不能进行压缩。
max_size:指定本加载时域的最大尺寸。如果本加载时域的实际尺寸超过了该值,
连接器将报告错误,默认取值为 0xFFFFFFFF;
execution_region_description:表示运行时域,后面有个+号,表示其可以有一个或
者多个运行时域,关于运行时域的介绍请看后面。
注:程序清单 4.1 中’|’、‘[]’符号的使用请参考 BNF 语法。
4.2 运行时域的描述
加载时域语法格式如程序清单 4.2 所示,其每项含义解释如下。
程序清单 4.2 运行时域语法描述
exec_region_name(base_address|"+"offset)[attribute_list][max_size|" "length]
{
input_section_description*
}
exec_region_name:为为本加载时域的名称,名称可以按照用户意愿自己定义,该
名称中只有前 31 个字符有意义;
base_address:用来表示本加载时域的起始地址,可以有下面两种格式中的一种:
base_address:表示本加载时域中的对象在连接时的起始地址,地址必须是字
对齐的;
+offset:表示本加载时域中的对象在连接时的起始地址是在前一个加载时域的
结束地址后偏移量 offset 字节处,offset 的值必须能被 4 整除。
attribute_list:指定本加载时域内容的属性:
ABSOLUTE:绝对地址;
PI:与位置无关;
RELOC:可重定位;
OVERLAY:覆盖;
FIXED:固定地址。区加载地址和执行地址都是由基址指示符指定的,基址指
示符必须是绝对基址,或者偏移为 0。
ALIGNalignment:将执行区的对齐约束从 4 增加到 alignment。alignment 必须
为 2 的正数幂。如果执行区具有 base_address,则它必须为 alignment 对齐。如果执
行区具有 offset,则链接器将计算的区基址与 alignment 边界对齐;
EMPTY:在执行区中保留一个给定长度的空白内存块,通常供堆或堆栈使用。
ZEROPAD:零初始化的段作为零填充块写入 ELF 文件,因此,运行时无需使
用零进行填充;
PADVALUE:定义任何填充的值。如果指定 PADVALUE,则必须为其赋值;
NOCOMPRESS:不能进行压缩;
UNINIT:未初始化的数据。
max_size:指定本加载时域的最大尺寸。如果本加载时域的实际尺寸超过了该值,
连接器将报告错误,默认取值为 0xFFFFFFFF;
工程技术笔记 ©2008 Guangzhou ZHIYUAN Electronics CO., LTD.
5
广州周立功单片机科技有限公司
分散加载文件浅释
ARM 嵌入式开发
length:如果指定的长度为负值,则将 base_address 作为区结束地址。它通常与
EMPTY 一起使用,以表示在内存中变小的堆栈。
input_section_description:指定输入段的内容。
4.3 输入段描述
输入段语法描述如程序清单 4.3 所示。
程序清单 4.3 输入段语法描述
module_select_pattern [ "(" input_section_selector ( "," input_section_selector )* ")" ]
("+" input_section_attr | input_section_pattern | input_symbol_pattern)
module_select_pattern:目标文件滤波器,支持使用通配符“*”与“?”。其中符号
“*”代表零个或多个字符,符号“?”代表单个字符。进行匹配时所有字符不区
分大小写。当 module_select_pattern 与以下内容之一相匹配时,输入段将与模块选
择器模式相匹配:
包含段和目标文件的名称;
库成员名称(不带前导路径名);
库的完整名称(包括路径名)。如果名称包含空格,则可以使用通配符简化搜
索。例如,使用*libname.lib 匹配 C:\lib dir\libname.lib。
nput_section_attr:属性选择器与输入段属性相匹配。每个 input_section_attr 的前面
有一个“+”号。如果指定一个模式以匹配输入段名称,名称前面必须有一个“+”
号。可以省略紧靠“+”号前面的任何逗号。选择器不区分大小写。可以识别以下
选择器:
RO-CODE;
RO-DATA;
RO,同时选择 RO-CODE 和 RO-DATA;
RW-DATA;
RW-CODE;
RW,同时选择 RW-CODE 和 RW-DATA;
ZI;
ENTRY:即包含 ENTRY 点的段。
可以识别以下同义词:
CODE 表示 RO-CODE;
CONST 表示 RO-DATA;
TEXT 表示 RO;
DATA 表示 RW;
BSS 表示 ZI。
可以识别以下伪属性:
FIRST;
LAST。
通过使用特殊模块选择器模式.ANY 可以将输入段分配给执行区,而无需考虑其父模块。
工程技术笔记 ©2008 Guangzhou ZHIYUAN Electronics CO., LTD.
6