ZHCADC4A September 2011 – March 2014
加载程序并开始执行程序时,有许多系统特定的方面。本节说明了常见于大多数系统的一般过程方面,重点介绍了特定于 C6000 的项目。
这些步骤可以通过结合使用离线代理(例如基于主机的加载器)、目标系统(例如操作系统)的运行时组件或链接到程序本身的库组件(例如自引导代码)来执行。
加载程序通常包括四组操作:创建过程映像、初始化执行环境、执行程序和执行终止操作。
创建过程映像包括将程序及其子组件复制到存储器中,并在需要时执行重定位。这些步骤必须由某些外部代理执行,例如基于主机的加载器或操作系统。
初始化执行环境中的一些步骤必须在程序开始运行之前(即在调用 main 之前)进行。这些步骤可由外部代理或程序本身执行。同样,终止操作在 main 返回(或调用 exit)时发生,并且可在外部执行或由程序执行。
表 14-1、表 14-2 和表 14-3 列出了创建、初始化和终止程序的步骤。虽然步骤的顺序不是绝对的,但必须遵守一定的依赖性。标有“仅 DL”的列表示步骤仅适用于使用动态链接或加载的系统。
步骤 | 仅 DL | |
---|---|---|
1. | 确定每个可加载段的地址。在裸机或非动态系统中,这通常是段的程序标头的 p_vaddr 字段中的地址。有关其他注意事项,请参阅节 14.1。 | |
2. | 初始化存储器系统并分配存储器。 | |
3. | 将每段的内容复制到存储器中。如果某个段有未填充空间(即其文件大小小于其存储器大小),则将未填充空间初始化为 0。 | |
4. | 为依赖库创建过程映像。依赖库由动态段中的 DT_NEEDED 条目标识。应检查库与目标处理器、ABI、操作系统和 DSBT 索引的兼容性。 | √ |
5. | 为此模块和所有依赖库分配 DSBT 索引。索引在可执行文件及其所有库中必须唯一。即使在多个程序之间共享,库的给定实例也必须只有一个索引。请参阅节 6.7。 | √ |
6. | 解析导入和导出符号之间的符号引用。具有动态链接的符号显示在动态符号表中,由动态段中的 DT_SYMTAB 标记标识。具有可见性 STV_DEFAULT 的导出符号可能会被父文件中的定义抢占。对于具有版本信息的符号(由动态段中的 DT_SYMVER 标记标识),加载器应确保引用与适当定义相匹配。 | √ |
7. | 如果需要,可进行重定位。加载时重定位由动态段中的 DT_REL 和/或 DT_RELA 标记指示。重定位按照节 13.5中的说明进行处理。 | √ |
8. | 初始化可执行文件和依赖库的 DSBT 条目。此步骤有两个部分。首先,当前可执行文件的 DSBT 必须使用所有已加载模块(包括它在索引 0 处的自身)的静态基址进行初始化。其次,所有其他已加载模块的 DSBT 必须使用此模块的基址(在步骤 5 中分配给此模块的索引处)进行更新。 | √ |
9. | Marshall 命令行实参和环境变量。此步骤特定于平台。 |
步骤 | 仅 DL | |
---|---|---|
10. | 设置 SP。SP (B15) 应设置为符号 _ _TI_STACK_END 的值,在 8 字节边界上正确对齐。 | |
11. | 设置 DP。DP (B14) 应设置为符号 _ _C6000_DSBT_BASE 的值,对应于任何 DP 相对段的最低地址。 | |
12. | 初始化变量。对于基于 ROM 的自引导系统,需要通过某种机制将基于 RAM(读写)的变量初始化为其初始值。此机制特定于工具链和平台。Chapter18说明了在 TI 工具中实现的一种此类机制。 | |
13. | 执行 preinit 调用。这些调用是对初始化函数的调用,初始化函数定义为在依赖库的函数发生之前发生。preinit 调用由 System V ABI 中指定的动态段中的 DT_PREINIT_ARRAY 标记标识。 | √ |
14. | 根据 System V ABI“初始化和终止函数”一节中定义的顺序,以递归方式执行依赖库的初始化调用(步骤 15)。 | √ |
15. | 执行初始化调用。通常,这些调用是对模块中定义的全局对象的构造函数的调用。这些函数发生在依赖库的函数之后。指向初始化函数的指针存储在表中。在包含动态信息的文件中,此表由 DT_INIT_ARRAY 和/或 DT_INIT 标记标识。在其他文件中,此表由一对全局符号分隔:_ _TI_INITARRAY_Base 和 _ _TI_INITARRAY_Limit。 | |
16. | 分支到入口点。入口点在 ELF 标头的 e_entry 字段中指定。在具有某些基础软件结构(例如操作系统)的系统上,入口点通常是 main 函数。在裸机系统上,此表列出的大多数初始化步骤可以由程序本身通过在执行 main 函数之前执行的库代码来执行。在此情况下,ELF 入口点是该代码的地址。例如,TI 工具提供了一个名为 _c_int00 的条目例程,此例程会在过程映像创建后开始步骤 10(设置 SP)中的序列。 |
步骤 | 仅 DL | |
---|---|---|
17. | 执行 atexit 调用。以与注册相反的顺序调用由 atexit 注册的函数。 | |
18. | 根据 System V ABI 中定义的顺序,以递归方式对依赖库执行终止调用(步骤 19)。 | √ |
19. | 调用当前模块的终止函数,由 DT_FINI 和/或 DT_FINI_ARRAY 标记标识。 | √ |