分散加载文件 scatter files

参考

分散加载文件 scatter files

一、加载域和执行域

镜像的各个域在加载时是被放置在系统存储器中的。 在执行镜像之前,可能必须将一些域移动到它们的执行地址,并创建 ZI 输出节。例如,初始化的 RW 数据可能必须从 ROM 中的加载地址复制到 RAM 中的执行地址。为了可以灵活的处理这种情况,ARM 定义了如下两个视图:
在这里插入图片描述
Load view: 根据镜像在加载到内存中时所位于的地址(镜像执行开始前的位置),描述每个镜像域和节。
Execution view: 根据镜像执行过程中所位于的地址,描述每个镜像域和节。

下面是两种视图的对比:
在这里插入图片描述

二、Image entry points

镜像中入口点(Image entry points)就是镜像中的一个位置(地址),该位置(地址)会被加载到 PC 寄存器。 它是程序执行开始的位置。 虽然镜像中可以有多个入口点,但在链接时只能指定一个入口点。并非每个 ELF 文件都必须有入口点。 不允许在单个 ELF 文件中存在多个入口点。

对于嵌入式 Cortex-M 核的程序,程序的执行是从复位向量所在的位置(地址)开始执行。复位向量会被加载到 PC 寄存器中,且复位向量的位置(地址)并不固定。 通常,复位向量指向 Reset_Handler 函数。

有两种不同类型的入口点:
1.初始化入口点(Initial entry point): 镜像的初始入口点是存储在 ELF 头文件中的单个值。 对于那些需要由操作系统或引导加载程序加载到 RAM 中的程序,加载程序通过将控制转移到镜像中的初始入口点来启动镜像执行。一个镜像只能有一个初始化入口点。初始入口点可以是 ENTRY 指令设置的入口点之一,但不是必需的。

2.ENTRY 指令指定的入口点: ENTRY 指令可以为镜像从多个可能的入口点中选择其中一个。每个镜像只能有一个入口点。您可以在汇编程序文件中使用 ENTRY 指令在对象中创建入口点。 在嵌入式系统中,该指令的典型用途是标记进入处理器异常向量(例如 RESET,IRQ 和 FIQ)的代码。该指令使用 ENTRY 关键字标记输出代码部分,该关键字指示链接器在执行未使用的部分消除时不删除该部分。对于 C/C++ 程序,C 库中的 __main 就是入口点。

如果加载程序要使用嵌入式的镜像,则它必须在标头中指定一个初始入口点。 使用 --entry 命令行选项选择入口点。

三、映射符号

映射符号由编译器和汇编器生成,以识别文字池边界处的代码和数据之间的内联转换,以及 ARM 代码和 Thumb 代码之间的内联转换。例如 ARM/Thumb 交互操作胶合代码。其必须由 armlink 的参数 --list_mapping_symbols 和 --no_list_mapping_symbols 分别来控制显示与不显示。在默认情况下为 `–no_list_mapping_symbols,即不显示这部分符号。映射符号有如下这些:
$a:一系列 ARM 指令的开始
$t:一系列 Thumb 指令的开始
$t.x:一系列 ThumbEE 指令的开始
$d:一系列数据项的开始,如文字池

补充说明:
1.文字池: 是代码段中存放常量数据的区域。因为没有一条指令可以生成一个 4 字节的常量,因此编译器将这些常量放到文字池中,然后生成从文字池加载这些常量的代码。
2.ARM/Thumb交互(ARM/Thumb interworking): 是指对汇编语言和 C/C++ 语言的 ARM 和 Thumb 代码进行连接的方法,它进行两种状态(ARM 和 Thumb)间的切换。
3.胶合代码(Veneer): 在进行 ARM/Thumb 交互时,有时需使用额外的代码,这些代码被称为 胶合代码(Veneer)。
4.AAPCS: 定义了 ARM 和 Thumb 过程调用的标准。

此外, armlink 还会生成 $d.realdata 映射符号,以告诉 fromelf 该数据是来自非可执行节区。因此, fromelf -z 输出的代码和数据大小与 armlink --info sizes 的输出相同。

四、链接器预定义符号

当链接器创建镜像文件时,它会创建一些 ARM 预定义的与域或者节相关的符号。这些符号就代表了链接器创建创建镜像的依据。

链接器定义了一些 ARM 保留的符号,我们可以在需要时访问这些符号。 这些符号是包含 SS字符序列的符号以及所有其他包含 $$ 字符序列的外部名称。我们可以导入这些符号地址,并将它们作为汇编语言程序的可重定位地址使用,或者将它们作为 C 或 C++ 源代码中的 extern 符号来引用。

如果使用 --strict 编译器命令行选项,则编译器不接受包含 $ 的符号名称。要重新启用支持,请在编译器命令行中包含 --dollar选项。

链接器定义的符号只有在代码引用它们时才会生成。
如果存在仅执行(XO)节,则链接器定义的符号受以下约束:
不能对没有 XO 节的域或者空域定义 XO 连接器定义符号
不能对仅包含 RO 节的域定义 XO 连接器定义符号
对于仅包含 XO 节的域,不能定义 RO 连接器定义符号

1、将符号引入到程序中

1.1 引入到 C/C++

可以通过 值引用 或 地址引用 这两种方式将链接器定义的符号导入到的 C 或 C++ 源代码中来供我们使用:
值引用:extern unsigned int symbol_name;
地址引用:extern void *symbol_name;

注意,如果将符号声明为 int 类型的值引用,则必须使用寻址操作符(&)来获得正确的值,如下例所示:

// Importing a linker-defined symbol
extern unsigned int Image$$ZI$$Limit;
config.heap_base = (unsigned int) &Image$$ZI$$Limit;

// Importing symbols that define a ZI output section
extern unsigned int Image$$ZI$$Length;
extern char Image$$ZI$$Base[];
memset(Image$$ZI$$Base, 0, (unsigned int
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值