分散加载作用:
可以将代码放入不同的存储空间。
5个G的计算机,电子专业书籍分享。
链接:https://pan.baidu.com/s/1y8BnUlGmiJMujLlTyrhznA
提取码:j9na
1.基本概念
了解分散加载文件之前,首先需要了解Code、RO-Data、RW-Data、ZI-Data。
Code:程序代码
RO-Data:程序中定义的常量以及const型数据
RW-Data:已经初始化的静态变量,变量有初始值
ZI-Data:没有初始化的静态变量,变量没有初始值
#define num 10 /*RO-Data*/
char const flage = 5; /*RO-Data*/
char str[] = "str"; /*RW-Data*/
char a; /*ZI-Data*/
下图为keil的map文件
ROM(Flash)Size = Code + RO-Data + RW-Data
RAM Size = ZI-Data + RW-Data
RW-Data既占ROM,又占RAM原因:(RW-Data与ZI-Data存储不同原因)
ZI段数据:程序只需要根据编译器分配给ZI段的基地址以及大小,将对应的RAM全部初始化为0即可。
RW段数据:首先编译器需要将RW段数据的所有初始值保存在ROM中,程序在执行时,再将ROM中保存的数据搬到RAM中。因此,RW段数据两者都占用空间,并且大小相同。
ZI段与RW段数据初始化
在执行main()函数之前,程序会执行__main()函数。该函数只要包括_main()与_rt_entry()函数
_main():完成代码与数据的拷贝,将ZI段数据清零。
将代码拷贝到映射的空间运行。比如:将代码拷贝到RAM中运行
数据拷贝:完成ZI段数据清零与RW段数据赋值
_rt_entry():将堆、栈等初始化。之后该函数会跳转到main()函数
2.分散加载文件介绍
该文件用来描述链接器生成映像文件时需要的信息。
该可以指定生成映像文件时Code、RO-Data、RW-DATA、ZI-DATA数据的存放地址。
2.1分散加载文件语法
分散加载文件由一个加载时域与多个运行时域构成。基本结构如下图:
2.1.1加载时域语法:
load_region_name(base_address|("+"offset))[attribute_list][max_size] {
execution_region_description+
}
load_region_name:该加载时域的名字
base_address:该加载时域的起始地址。有两种书写方式:
base_address:表示该加载时域中的对象在连接时的起始地址,地址必须字节对齐
+offset:表示本加载时域的中的对象在连接时的起始地址是前一个加载时域的结束地址后偏移offset字节处。若该加载时域为第一个加载时域,则其起始地址为offset。offset数值必须能够被4整除。attribute_list:指定该加载时域内容的属性。一般为ABSOLUTE。
ABSOLUTE:绝对地址;
PI:与位置无关;
RELOC:可重定位;
OVERLAY:覆盖;
NOCOMPRESS:不能压缩;max_size:该加载时域的最大尺寸。若该加载时域的实际尺寸超出了max_size,连接器将会报错。
execution_region_description:运行时域。+表示可以有一个或多个运行时域。
2.1.2运行时域语法:
exec_region_name(base_address|"+"offset)[attribute_list][max_size|" "length]) {
input_section_description*
}
exec_region_name:该运行时域的名字
base_address:同加载时域
attribute_list:指本运行时域的内容属性
ABSOLUTE:绝对地址;
PI:与位置无关;
RELOC:可重定位;
OVERLAY:覆盖;
FIXED:固定地址。
ALIGNalignment:将执行区的对齐约束从4增加到alignment。alignment的值必须为2的正数幂。若执行区有base_address,则它需要与alignment对齐。若执行区有offset,则链接器将计算的区基址与alignment边界对齐。
EMPTY:将执行区中保留一个给定长度的空白内存块,一般提供给堆或栈使用。
ZEROPAD:零初始化的段作为零填充块写入ELF文件。因此,运行时不需要使用零进行填充。
PADVALUE:定义任何填充的值。
NOCOMPRESS:不能进行压缩。
UNINIT:未初始化的数据。max_size:同加载时域。
length:若指定的长度为负值,则将base_address作为区的结束地址。通常与EMPTY一起使用,用来表示内存中变小的堆栈。
input_section_description:指定输入段的内容。
2.1.3输入段描述:
module_select_pattern [ "(" input_section_selector ( "," input_section_selector )* ")" ]
("+" input_section_attr | input_section_pattern | input_symbol_pattern)
module_select_pattern :文件过滤器。支持使用通配符"*“与”?"。字符匹配时,不区分大小写。
*:表示零个或多个字符。
?:表示单个字符。
input_section_attr :属性选择器与输入段属性相匹配。每个input_section_attr前都会有+号。紧靠+号前的逗号都可以省略。若要指定一个模式以匹配输入段名称,则名称前面需要有+号。选择器不区分大小写。可以识别以下选择器。
RO-CODE(CODE)
RO-DATA(CONST)
RO,包含RO-DATA与 RO-CODE(TEXT)
RW-CODE
RW-DATA
RW,包含RW-DATA与 RW-CODE(DATA)
ZI(BSS)
ENTRY,包含ENTRY之外的段。
通过使用特殊模块选择器模式.ANY可以将输入段分配给执行区,而无需考虑其父模块。可以使用一个或多个.ANY模式以任意分配方式填充运行时域。在大多数情况下,使用单个.ANY等效于使用*模块选择器。