William Chang

main and __main

Blog Post created by William Chang on May 13, 2018

The function label main() has a special significance. The presence of a main() function forces the linker to link in the initialization code in __main and __rt_entry. Without a function labeled main() the initialization sequence is not linked in, and as a result, some standard C library functionality is not supported.

 

Let's see the big picture first.

The following figure shows a possible initialization sequence fro an embedded system based on an ARM architecture:

 

The reset handler is normally a short module coded in assembler that executes immediately on system

startup. As a minimum, your reset handler initializes stack pointers for the modes that your application is

running in. For processors with local memory systems, such as caches, TCMs, MMUs, and MPUs, some

configuration must be done at this stage in the initialization process. After executing, the reset handler

typically branches to __main to begin the C library initialization sequence.

 

There are some components of system initialization, for example, the enabling of interrupts, that are

generally performed after the C library initialization code has finished executing. The block of code

labeled $sub$$main( ) performs these tasks immediately before the main application begins executing.

/*

$Sub$$

There are special patterns you can use for situations where an existing symbol cannot be modified.

An existing symbol cannot be modified, for example, if it is located in an external library or in ROM code. In such

cases you can use the $Sub$$ patterns to patch an existing symbol.

*/

 

__main is responsible for setting up the memory

__rt_entry is responsible for setting up the run-time environment.

 

__main performs code and data copying, decompression, and zero initialization of the ZI data.

then

it calls __rt_entry, This lists the functions that __rt_entry can call. The function are listed in the order the get called.

1. _platform_pre_stackheap_init

2. __user_setup_stackheap or setup the SP by another method

3. _platform_post_stackheap_init

4. __rt_lib_init   // initialize the run time library functions

5. _platform_post_lib_init

6. main()

7. exit()

to set up the stack and heap, by calling __rt_lib_init. and call any top level C++ constructors.

then

branches to main(), the entry to your application.

 

/*

The _platform_* functions are not part of the standard C library. If you define them, then the linker places calls to them

In __rt_entry.

 

setting up the stack and heap depends on the method specified by the user. The stack and heap can be setup by any of the following methods:

1. Calling __user_setup_stackheap. This also obtains the bounds of the memory used by the heap (heap top

and heap base).

2. Loading the SP with the value of the symbol __initial_sp.

3. Using the top of the ARM_LIB_STACK or ARM_LIB_STACKHEAP region specified in the linker scatter file.

 

main is the entry point to the application at the user-level. Registers r0 and r1 contain the arguments to main(). If

main returns, its return value is passed to exit( ) and the application exits.

 

__rt_entry and __rt_lib_init do not exist as complete functions in the C library. Small sections of these functions

are present in several internal objects that are part of the C library. Not all of these code sections are useful for a given

user application The linker decides which subset of those code sections are needed for a given application, and

includes just those sections in the startup code. The linker places these sections in the correct order to create custom

entry and functions as required by the user application.

*/

Outcomes