SPRAB89A September 2011 – March 2014
The Linux kernel begins the process of loading a program by copying or mapping both its load segments and those of the interpreter program specified by its PT_INTERP header into memory. The kernel then jumps to an entry point in the interpreter, which completes the loading process. For ELF executables the interpreter is usually the dynamic loader, ld.so.
The first time the interpreter is invoked, it must bootstrap itself by processing its own dynamic relocations. It must then load dependent libraries, perform any dynamic symbol resolution, and process the dynamic relocations of the program itself.
The kernel communicates startup information to the interpreter via an initialized data structure called the load map, declared as follows:
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;
};
The kernel invokes the kernel with the 4 arguments in registers and the rest on the stack. The register arguments are:
B4 | address of the executable's load map |
A6 | address of the interpreter's load map |
B6 | address of the interpreter's dynamic section |
B14 (DP) | _ _c6xabi_DSBT_BASE for the interpreter |
The kernel allocates a stack for the process and initializes SP. The initial contents of the stack provide the program's command-line arguments and environment variables:
The kernel then jumps to the entry point of the interpreter, labeled with the symbol _start.