认识分散加载文件¶
记录一些分散加载相关的知识点,并通过例子加以说明。
分散加载文件说明¶
编译器在生成可执行文件时,先将每个.c.h文件经预处理和编译生成.o文件,然后将很多个.o文件链接成可执行文件。在链接的过程中,会用到一个描述文件,用来指定链接时的行为。这个描述文件叫做链接文件,如linux下的.ld文件,keil中的分散加载文件(.sct文件)。 通过分散加载文件可以对Code、RO-Data、RW-Data、ZI-Data等数据指定存放地址。
何时使用分散加载文件¶
- 复杂内存映射
- 不同类型的内存
- 内存映射的 I/O
- 固定位置的函数
- 使用符号标识堆和堆栈
分散加载文件组成¶
一个分散加载文件由一个或者多个加载域(load regions)组成。每个加载域由一个或者多个执行域(execution regions)组成。执行域中又包含很多个输入段描述(Input section description)

BNF语法¶
BNF语法表示方式巴科斯范式:以美国人巴科斯(Backus)和丹麦人诺尔(Naur)的名字命名的一种形式化的语法表示方法,用来描述语法的一种形式体系,是一种典型的元语言。符号含义如下:
- " 在双引号中的字代表字符本身。
- A::=B 表示被定义为的意思。
- [A] 方括号中包含的为可选项。
- A|B 竖线表示其左右两边只能选一项。
- A* 表示元素A可以有0次或多次出现。
- A+ 表示元素A可以有1次或多次出现。
- (A B) 元素A和B被组合在一起
什么是加载域¶
加载域控制可执行文件的哪些部分放置在该区域中
加载域描述包含以下组件
- 链接器用来标识不同加载区域的名称
- 指定加载代码和数据的起始地址的基地址
- 用于指定加载区域的属性
- 可选的最大范围
- 一个或多个执行区域
1.语法格式

2.load_region_name:加载域的名称,用户自定义。该名称中只有前 31 个字符有意义。
3.起始地址: 本加载域的起始地址。分两种表达格式
- base_address:直接指明本加载域的起始地址。地址必须是字对齐的;
- +offset:表示此加载域的起始地址为前一个加载域的结束地址+offset字节。本加载时域是第一个加载时域,则它的起始地址即为 offset, offset 的值必须能被 4 整除。
4.属性(attribute_list)(可选): 用于指定加载域的特征。具体值如下
- ABSOLUTE:绝对地址(默认属性)。
- ALIGN alignment:将加载区域的对齐限制从4增加到alignment,如果加载区域有一个基地址,则它必须是alignment对齐的。如果加载区域有一个偏移(+offset),那么链接器将计算出的区域基地址对齐到一个alignment边界。
- PI:该区域是位置无关的。内容不依赖于任何固定的地址,可以在链接后移动而不需要额外的处理。
- OVERLAY:允许您在同一地址处有多个加载区域。Arm工具不提供叠加机制。要在同一地址处使用多个加载区域,您必须提供自己的叠加管理器。内容可能与其他被指定为OVERLAY区域的区域重叠。
- RELOC:这个区域可以重新定位。内容依赖于固定地址。输出重新定位信息,使内容能够通过其他工具移动到另一个位置。
- NOCOMPRESS:不能进行压缩。
- 属性继承:地址设置未+offset且未设置属性的加载域继承前面加载域的属性。
5.加载域大小(max_size)(可选)
指定本加载时域的最大尺寸。如果本加载时域的实际尺寸超过了该值,连接器将报告错误, 默认取值为 0xFFFFFFFF;
6.一个或者多个执行域.
执行域的组成见执行域的介绍。
7.example
什么是执行域¶
执行域描述了可执行文件在执行时内存(RAM+ROM)的分配。 执行域的组成类似加载域,如下:
1.语法格式

2.名称(exec_region_name): 执行域的名称,用户自定义。该名称中只有前 31 个字符有意义。
3.起始地址: 本执行域的起始地址。分两种表达格式
- base_address: 表示本加载时域中的对象在连接时的起始地址, 地址必须是字对齐的。
- +offset: 表示本加载时域中的对象在连接时的起始地址是在前一个加载时域的结束地址后偏移量 offset 字节处, offset 的值必须能被 4 整除。
4.属性(attribute_list)(可选): 用于指定加载域的特征。具体值如下
- ABSOLUTE:绝对地址(默认属性)。
- PI:与位置无关;
- RELOC:可重定位;
- OVERLAY:覆盖;
- FIXED:固定地址;区加载地址和执行地址都是由基址指示符指定的,基址指示符必须是绝对基址,或者偏移为 0;
- ALIGN alignment:将执行区的对齐约束从 4 增加到 alignment。 alignment 必须为 2 的正数幂。如果执行区具有 base_address,则它必须为 alignment 对齐。如果执行区具有 offset,则链接器将计算的区基址与 alignment 边界对齐;
- EMPTY:在执行域中保留指定长度的空内存块,通常提供堆栈使用;
- ZEROPAD:零初始化的段作为零填充块写入 ELF 文件,因此,运行时无需使用零进行填充;
- PADVALUE:定义任意填充值。如果指定PADVALUE则必须为其赋值;
- NOCOMPRESS:不能进行压缩;
- UNINIT:未初始化的数据。
- FILL :创建一个由链接器生成的包含一个值的区域。如果你指定了FILL,你必须给一个值,例如:FILL 0xFFFFFFFF。
5.加载域大小(max_size)(可选)
指定本加载时域的最大尺寸。如果本加载时域的实际尺寸超过了该值,连接器将报告错误, 默认取值为 0xFFFFFFFF;
6.Length:
仅在 EMPTY 的情况下使用,表示堆栈在内存中向下生长。如果将长度作为负值给出,则基地址将被视为该区域的结束地址。
7.一个或者多个输入段描述.
输入段描述的组成见输入段描述的介绍。
什么是输入段描述¶
输入段描述的组成部分可以确定应放置在执行区域中的ELF文件的部分
输入部分描述通过以下方式识别输入部分
- 模块名称(对象文件名、库成员名称或库文件名)。模块名称可以使用通配符。
- 输入部分名称、类型或属性,例如READ-ONLY或CODE。输入部分名称可以使用通配符。
- 符号名称。
1.语法格式

2.目标文件过滤器。支持通配符*、?。不区分大小写。如main.o,user*.o等。可匹配的文件可以为目标文件名、库名(不带前导路径名)、库完整路径名。
- 可以使用*.o匹配所有的目标文件。用*匹配所有文件,包括目标文件和库。
- 可以使用.ANY进行任意的匹配。它的优先级低于*。
3.属性,不区分大小写:
| 属性 | 描述 | 备注 |
|---|---|---|
| RO-CODE | 只读程序代码 | 同义词有CODE |
| RO-DATA | 常量数据 | 同义词有CONST |
| RO | 包含RO-CODE和RO-DATA | 同义词有TEXT |
| RW-DATA | 全局变量和静态变量 | |
| RW-CODE | ||
| RW | 包含RW-DATA和RW-CODE | 同义词有DATA |
| ZI | 未初始化变量和初始化为0的变量 | 同义词有BSS |
| ENTRY | 即包含ENTRY的段 | |
| FIRST | 标记执行区域中的第一个部分 | |
| LAST | 标记执行区域中的最后一个部分 |
ARM ELF目标文件的主要构成
ARM ELF(Executable and Linking Format)目标文件主要由.Text段、.Data段、.BSS段构成,其他段如.debug段、.comment等。
- .Text 段由可执行代码组成,段类型为Code,属性为RO;
- .Data 段由已初始化数据组成,段类型为Data, 属性为RO;
- .BSS 段由未初始化数据组成,段类型为Zero, 属性为RW,在应用个程序启动时对该段的数据初始化为零。如果在分散加载文件中指定了UNINIT属性,则在应用程序启动时不初始化该段。
4.example:
*.o (RESET, +First) 任何目标文件中的RESET段放在起始位置。
.ANY (+RW +ZI)匹配任意文件的数据段。
.ANY (+RO) 匹配任意文件的代码段。
输入段描述另一种说法¶
1.语言定义
2.module_select_pattern:目标文件选择器支持通配符 * 、? ,不区分大小写。使用*.o匹配所有对象。使用*匹配所有对象文件和库。可以使用引号括起的文件名,例如“file one.o”,*模块选择器优先于.ANY。
3.input_section_attr:一个针对输入部分属性的属性选择器,每个输入部分属性都跟随一个 +
- RO-CODE:同义词有CODE
- RO-DATA:同义词有CONST
- RO:即同时选择RO-CODE 和RO-DATA,同义词有TEXT
- RW-DATA
- RW-CODE
- RW:即同时选择RW-DATA和RW-CODE,同义词有DATA
- ZI:同义词有BSS
- ENTRY:即包含ENTRY的段。
可以识别以下同义词:
- CODE 表示 RO-CODE;
- CONST 表示 RO-DATA;
- TEXT 表示 RO;
- DATA 表示 RW;
- BSS 表示 ZI。
可以识别以下伪属性:
- FIRST:标记执行区域中的第一个部分
- LAST:标记执行区域中的最后一个部分

4.input_section_pattern:一个模式,不区分大小写,与输入部分名称匹配。它由文字文本构成。通配符*匹配0个或多个字符,而问号匹配任何单个字符。您可以使用带引号的输入部分名称。
5.input_section_type:与输入部分类型进行比较的数字。该数字可以是十进制或十六进制。
6.input_symbol_pattern:可以通过该部分定义的全局符号名称选择输入部分。全局名称使你能够从部分链接对象中选择具有相同名称的个别部分。
7.section_properties :包括+FIRST、+LAST和OVERALIGN值。
note
通过使用特殊模块选择器模式.ANY 可以将输入段分配给执行区,而无需考虑其父模块。可以使用一个或多个.ANY 模式以任意分配方式填充运行时域。在大多数情况下,使用单个.ANY 等效于使用*模块选择器。
表达式¶
- Load and execution region base_address.
- Load and execution region +offset.
- Load and execution region max_size.
- Parameter for the ALIGN, FILL or PADVALUE keywords.
- Parameter for the ScatterAssert function.

注意¶
有些代码必须始终放在根区域中。这与放置命名段的方式类似。要将所有必须放在根区域中的节,使用节选择器InRoot$$ sections。

应用¶
函数和变量通过分散加载文件指定到特定地址¶



M0通过.s文件赋值堆栈,使用分散加载文件分配链接地址¶



生成8字节对齐的hex文件不对齐的数据补固定数据¶



IAR ICF修改Hex对齐¶
