ZHCADC4A September 2011 – March 2014
Linux 内核通过将程序的加载段和 PT_INTERP 标头指定的解释器程序的加载段复制或映射到存储器来开始加载程序的过程。内核随后跳转至解释器中的入口点,从而完成加载过程。对于 ELF 可执行文件,解释器通常是动态加载器 ld.so。
首次调用解释器时,它必须通过处理自己的动态重定位来引导自身。然后,它必须加载依赖库,执行任何动态符号解析,并处理程序本身的动态重定位。
内核通过称为加载映射的初始化数据结构将启动信息传递给解释器,声明如下:
struct elf32_dsbt_loadmap
{
/* Protocol version number, must be zero. */
Elf32_Word version;
/* Pointer to DSBT */
unsigned *dsbt_table;
unsigned dsbt_size;
unsigned dsbt_index;
/* Number of segments */
Elf32_Word nsegs;
/* The actual memory map. */
struct elf32_dsbt_loadseg segs[nsegs];
};
struct elf32_dsbt_loadseg
{
/* Core address to which the segment is mapped. */
Elf32_Addr addr;
/* Virtual address recorded in the program header. */
Elf32_Addr p_vaddr;
/* Size of this segment in memory. */
Elf32_Word p_memsz;
};
内核通过寄存器中的 4 个实参和栈上的其余实参来调用内核。寄存器实参是:
B4 | 可执行文件的加载映射的地址 |
A6 | 解释器的加载映射的地址 |
B6 | 解释器动态段的地址 |
B14 (DP) | 解释器的 _ _c6xabi_DSBT_BASE |
内核为此过程分配一个栈并初始化 SP。栈初始内容将提供程序的命令行实参和环境变量:
内核随后跳转至以符号 _start 标记的解释器的入口点。