ZHCADC3B February 2019 – October 2023
如节 4.1中所述,初始化后的读写变量会被收集到目标文件的专门段中,例如 .data。该段包含程序启动时该段初始状态的映像。
TI 工具链支持两种加载此类段的模型。在所谓的 RAM 模型 中,一些未指定的外部代理(如加载器)负责将数据从可执行文件获取到它在读写存储器中的位置。这是基于 OS 的系统(在某些情况下为引导加载系统)中使用的典型直接初始化模型。
另一种模型称为 ROM 模型,适用于裸机嵌入式系统,它们必须能够在没有操作系统或其他加载器支持的情况下冷启动。初始化程序所需的任何数据必须驻留在持久性离线存储 (ROM) 中,并在启动时复制到其 RAM 位置。TI 工具链通过利用Chapter14中所述的复制表功能实现此目的。初始化机制与复制表在概念上相似,但细节稍有不同。
图 14-4 展示了 ROM 模型变量初始化的概念工作原理。在此模型中,链接器将数据从包含初始化变量的段中移除。这些段变为未初始化段,分配到它们在 RAM 中的运行时地址(比如 .bss)。链接器将初始化数据编码为一个特殊段,被称为 .cinit(代表 C 初始化),来自运行时库的启动代码在这里解码并复制到其运行地址。
.cinit 表中的源数据可以压缩,也可以不压缩,与复制表类似。如果数据经过压缩,编码和解码方案与复制表相同,可以共享处理程序表和解压缩处理程序。
.cinit 段包含以下项目中的部分或全部:
这些项目顺序不限。
图 14-5 是展示 .cinit 段的原理图。
.cinit 段的段类型为 SHT_TI_INITINFO,将其标识为此格式。工具应识别段类型,而不是名称 .cinit。
定义了两种特殊符号,来分隔 cinit 表:__TI_CINIT_Base 指向 cinit 表,而 __TI_CINIT_Limit 指向表末尾往后 16 位。启动代码使用这些符号来引用该表。
cinit 表中的记录有以下格式:
typedef struct
{
uint32 source_data;
uint32 dest;
} CINIT_RECORD;
源数据与复制表压缩源数据格式相同(参阅节 14.2),并且处理程序的接口相同。除了 RLE 和 LZSS 格式,cinit 记录还定义了另外两种格式:未压缩和零初始化。
编码数据包含一个大小字段,它在处理程序索引之后下一个 32 位边界上对齐。大小字段指定数据有效载荷中有多少 16 位单元数据,它紧跟在大小字段之后开始算起。初始化操作会将大小 16 位单元数据从数据字段复制到目标地址。TI 运行时库包含一个处理程序,被称为 _ _TI_decompress_none,用于未压缩格式。
大小字段在处理程序索引之后下一个 32 位边界上对齐。初始化操作会在目标地址将大小连续 16 位单元数据填充为零。TI 运行时库包含一个处理程序,被称为 _ _TI_zero_init,用于此格式。
如果可以使用相同格式便利地进行编码,链接器就可以自由地将相邻对象的初始化合并到单一 cinit 记录中,作为一项优化。对于零初始化对象而言,这通常很重要。