SPRAB89A September 2011 – March 2014
There are many system-specific aspects of loading a program and starting its execution. This section describes in general terms aspects of the process that are common to most systems, with an emphasis on items that are specific to C6000.
These steps may be performed by a combination of an offline agent such as a host-based loader, run-time components of the target system such an operating system, or library components that are linked into the program itself such as self-boot code.
In general, loading a program consists of four series of actions: creating the process image, initializing the execution environment, executing the program, and performing termination actions.
Creating the process image involves copying the program and its subcomponents into memory and performing relocation if needed. These steps must necessarily be performed by some external agent such as a host-based loader or operating system.
Initializing the execution environment involves steps that must occur before the program starts running (i.e. before main is called). These steps can be performed either by an external agent or by the program itself. Likewise, termination actions occur when main returns (or calls exit), and can be performed either externally or by the program.
Table 14-1, Table 14-2 and Table 14-3 list the steps to create, initialize, and terminate a program. While the order of the steps is not absolute, there are dependencies that must be honored. The column labeled "DL Only" indicates steps that apply only to systems using dynamic linking or loading.
Step | DL Only | |
---|---|---|
1. | Determine the address for each loadable segment. In bare-metal or non-dynamic systems, this is usually the address in the p_vaddr field of the segment's program header. Other considerations are discussed in Section 14.2. | |
2. | Initialize the memory system and allocate memory. | |
3. | Copy the contents of each segment into memory. If a segment has unfilled space (that is, its file size is less than its memory size), initialize the unfilled space to 0. | |
4. | Create the process image for dependent libraries. Dependent libraries are identified by DT_NEEDED entries in the dynamic section. Libraries should be checked for compatibility with respect to target processor, ABI, OS, and DSBT indexing. | √ |
5. | Assign DSBT indexes for this module and all dependent libraries. Indexes must be unique among an executable and all its libraries. A given instance of a library must have only one index even if shared among multiple programs. See Section 6.8. | √ |
6. | Resolve symbolic references between imported and exported symbols. Symbols with dynamic linkage are represented in the dynamic symbol table, identified by the DT_SYMTAB tag in the dynamic section. Exported symbols with visibility STV_DEFAULT may be preempted by definitions from parent files. For symbols that have version information, identified by a DT_SYMVER tag in the dynamic section, the loader should insure that references are matched up with the proper definitions. | √ |
7. | Perform relocation if needed. Load-time relocations are indicated by DT_REL and/or DT_RELA tags in the dynamic section. Relocations are processed as specified in Section 13.6. | √ |
8. | Initialize DSBT entries for the executable and dependent libraries. This step has two parts. First, the DSBT for the current executable must be initialized with the static base address of all loaded modules (including itself, at index 0). Second, the DSBTs for all the other loaded modules must be updated with this module's base address, at the index assigned to this module in step 5. | √ |
9. | Marshall command line arguments and environment variables. This step is platform specific. |
Step | DL Only | |
---|---|---|
10. | Set SP. SP (B15) should be set to the value of the symbol _ _TI_STACK_END, properly aligned on an 8-byte boundary. | |
11. | Set DP. DP (B14) should be set to the value of the symbol _ _C6000_DSBT_BASE, corresponding to the lowest address of any DP-relative segment. | |
12. | Initialize variables. For self-booting ROM-based systems, some mechanism is required to initialize RAM-based (read-write) variables with their initial values. The mechanism is toolchain and platform specific. One such mechanism, implemented in the TI tools, is described in Chapter 18. | |
13. | Perform preinit calls. These are calls to initialization functions defined to occur before those of dependent libraries. Preinit calls are identified by the DT_PREINIT_ARRAY tag in the dynamic section, as specified in the System V ABI. | √ |
14. | Recursively perform the initialization calls (step 15) for dependent libraries, according to the ordering defined in the section on Initialization and Termination Functions of the System V ABI. | √ |
15. | Perform initialization calls. Generally these are calls to constructors for global objects defined in the module. They occur after those of dependent libraries. Pointers to initialization functions are stored in a table. In files with dynamic information, the table is identified by the DT_INIT_ARRAY and/or DT_INIT tags. In other files, the table is delimited by a pair of global symbols: _ _TI_INITARRAY_Base and _ _TI_INITARRAY_Limit. | |
16. | Branch to the entry point. The entry point is specified in the e_entry field of the ELF header. On systems with some underlying software fabric such an OS, the entry point is typically the main function. On bare-metal systems, most of the initialization steps listed in this table may be performed by the program itself, via library code that executes before main. In that case the ELF entry point is the address of that code. For example the TI tools provide an entry routine called _c_int00 that begins the sequence in Step 10 (set SP) once the process image is created. |
Step | DL Only | |
---|---|---|
17. | Perform atexit calls. Functions registered by atexit are called, in reverse order of registration. | |
18. | Recursively perform the termination calls (step 19) for dependent libraries, according to the ordering defined in the System V ABI. | √ |
19. | Call the termination functions for the current module, identified by the DT_FINI and/or DT_FINI_ARRAY tags.) | √ |