SPRAC71B February 2019 – October 2023
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 C28x.
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 12-1, Table 12-2 and Table 12-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.
Step | ||
---|---|---|
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 12.1. | |
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. | |
. | Marshall command line arguments and environment variables. This step is platform specific. |
Step | ||
---|---|---|
. | Set SP. SP (R1) should be set to the value of the symbol _ _TI_STACK_END, properly aligned on an 8-byte boundary. | |
. | 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 14. | |
. | Perform initialization calls. Generally these are calls to constructors for global objects defined in the module. Pointers to initialization functions are stored in a table. he table is delimited by a pair of global symbols: _ _TI_INITARRAY_Base and _ _TI_INITARRAY_Limit. | |
. | 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 | ||
---|---|---|
. | Perform atexit calls. Functions registered by atexit are called, in reverse order of registration. |