world leader in high performance signal processing
Trace: » startup

Startup code in GCC

A startup code is usually employed for performing house keeping operations before the main() function is executed. - basically to bring up the part to a known state. These operations could be anything from setting up the Stack / Frame pointers, changing mode of operation (user / supervisor), configuring cache / cplbs, configuring PLL, installing exception handler etc (can be thought of as low level target-specific & board-specific initializations) .

Startup codes are now part of the libgloss (earlier they were part of the newlib library itself). These startup codes are written as pre-processed *.S file. The default code used by compiler is available here:

Default startup code

file: trunk/binutils-2.21/libgloss/bfin/basiccrt.S

scm failed with exit code 1:
file does not exist in git

Providing own startup code

User can write their own startup codes, if they are aware of the target-specific initializations. The default startup codes can be removed from compilation through the option -nostartfiles.

Although the Startup codes can perform many tasks, there are a couple of specific items, without which the subsequent operations in the application code many not work at all, on Blackfin:

  • Initialization of SP/FP pointers with the stack_end variable from Linker Script. No Stack operations such as push or pop can be done unless this is fixed.
  • Exiting from Reset event to a low level Supervisor mode in IVG15 handler. This ensures that all interrupts initialized by the application can be serviced (otherwise the high priority reset event cannot be pre-empted by any user interrupt). Further, by jumping to IVG15, supervisor mode is retained so that all MMRs can be accessed from application.
  • Initialization of default exception handler. Application may setup the exception handler itself, but since exceptions can be triggered from any instruction, it is safer to pre-initialize a handler that basically jumps to IDLE upon an exception.

A simple basiccrt.S is given below. It basically initializes stack, runs the operating mode routine (taken from Programming Reference Manual), and then calls the main() function.

#include <sys/platform.h>
#include <cplb.h>
#include <sys/anomaly_macros_rtl.h>
#include <defBF533.h>
#include <def_LPBlackfin.h>
 
	.text;
	.align 2;
	.global __start;
	.extern _main;
	.type __start, STT_FUNC;
__start:
 
	R7 = 0;
	LC0 = R7;
	LC1 = R7;
	L0 = R7;
	L1 = R7;
	L2 = R7;
	L3 = R7;
	I0.L = (ITEST_COMMAND & 0xFFFF);
	I0.H = (ITEST_COMMAND >> 16);
	I1.L = (DTEST_COMMAND & 0xFFFF);
	I1.H = (DTEST_COMMAND >> 16);
	R7 = 0;
	[I0] = R7;
	[I1] = R7;
 
	CSYNC;
 
	SP.L=__stack_end - 12;
	SP.H=__stack_end - 12;
	FP = SP;
	SP += -12;
 
 
	///////////////from PRM/////////////////////////////////////
	P0.L = (EVT15 & 0xFFFF) ; /* Point to IVG15 in Event Vector Table */
	P0.H = ((EVT15 >> 16) & 0xFFFF) ;
	P1.L = START; /* Point to start of User code */
	P1.H = START;
	[P0] = P1 ; /* Place the address of START in IVG15 of EVT */
	P0.L = (IMASK & 0xFFFF) ;
	R0 = [P0] ;
	R1.L = (EVT_IVG15 & 0xFFFF) ;
	R0 = R0 | R1 ;
	[P0] = R0 ; /* Set (enable) IVG15 bit in IMASK register */
	RAISE 15 ; /* Invoke IVG15 interrupt */
	P0.L = WAIT_HERE ;
	P0.H = WAIT_HERE ;
	RETI = P0 ; /* RETI loaded with return address */
	RTI ; /* Return from Reset Event */
	WAIT_HERE : /* Wait here till IVG15 interrupt is serviced */
	JUMP WAIT_HERE ;
	START: /* IVG15 vectors here */
	/* Enables interrupts and saves return address to stack */
	[--SP] = RETI ;
    ///////////////from PRM/////////////////////////////////////
 
	[--SP]=R0;
	[--SP]=R0;
	FP = SP;
	SP += -12;
 
	CALL.X _main;
    NOP;
__end:
	IDLE;
	JUMP __end;

CRT libraries in GCC

Other libraries such as crti.o, crtbegin.o, crtend.o, crtn.o also co-exist with default compilation, the usage in most cases tied closely with the C++ proramming language. As explained in GCC Initializations, “The compiled code for certain languages includes constructors (also called initialization routines)—functions to initialize data in the program when the program is started. These functions need to be called before the program is “started”—that is to say, before main is called.The linker must build two lists of these functions—a list of initialization functions, called _CTOR_LIST_, and a list of termination functions, called _DTOR_LIST_.”

Because of the changes GCC initialization went through (especially for embedded systems), standard documentations on each CRT file is difficult to find. Refer to the following links for quick overview of what each files are:

Mike's link on CRT

Univ of Mississippi

If one wants to peek in to the source of crtstuff.c (from where the above object files originate), it is provided in toolchain (source not included here, because it is un necessary): crtstuff.c