Cygnus Solutions provides a crt0 file, although you may want to write your own crt0 file for each target. The crt0 file is usually written in assembler as ‘crt0.S’, and its object gets linked in first and bootstraps the rest of your application. The crt0 file defines a special symbol like _start that is both the default base address for the application and the first symbol in the executable binary image.
If you plan to use any routines from the standard C library, you’ll also need to implement the functions on which libgloss depends. The crt0 file accomplishes the following results. See also I/O support code.
The following is a typical basic initialization of crt0.S.
Set up concatenation macros.
#define CONCAT1(a, b) CONCAT2(a, b) #define CONCAT2(a, b) a ## bLater, you’ll use these macros.
Set up label macros, using the following example’s input.
#ifndef __USER_LABEL_PREFIX__ #define __USER_LABEL_PREFIX__ _ #endif
#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)These macros make the code portable between ‘coff’ and ‘a.out’. ‘coff’ always has an __ (underline) prepended to the front of its global symbol names. ‘a.out’ has none.
Set up register names (with the right prefix), using the following example’s input.
#ifndef __REGISTER_PREFIX__ #define __REGISTER_PREFIX__ #endif
/* Use the right prefix for registers. */ #define REG(x) CONCAT1 (__REGISTER_PREFIX__, x)
#define d0 REG (d0) #define d1 REG (d1) #define d2 REG (d2) #define d3 REG (d3) #define d4 REG (d4) #define d5 REG (d5) #define d6 REG (d6) #define d7 REG (d7) #define a0 REG (a0) #define a1 REG (a1) #define a2 REG (a2) #define a3 REG (a3) #define a4 REG (a4) #define a5 REG (a5) #define a6 REG (a6) #define fp REG (fp) #define sp REG (sp)Register names are for portability between assemblers. Some register names have a % or $ prepended to them.
Set up space for the stack and grab a chunk of memory.
.set stack_size, 0x2000 . comm SYM (stack), stack_sizeThis can also be done in the linker script, but it typically gets done at this point.
Define an empty space for the environment, using the following example’s input.
.data .align 2 SYM (environ): .long 0Th ffb is is bogus on almost any ROM monitor, but we set up a valid address for it and pass the address to main (). This way, if an application checks for an empty environment, it finds one.
Set up a few global symbols that get used elsewhere.
.align 2 .text .global SYM (stack)
.global SYM (main) .global SYM (exit) .global __bss_startThis really should be __bss_start, not SYM (__bss_start). __bss_start needs to be declared this way because its value is set in the linker script.
Set up the global symbol, start, for the linker to use as the default address for the .text section. This helps your program run.
SYM (start): link a6, #-8 moveal #SYM (stack) + stack_size, sp
moveal #__bss_start, a0 moveal #SYM (end), a1 1: movel #0, (a0) leal 4(a0), a0 cmpal a0, a1 bne 1bApplications can get wild side effects from the .bss section being left uncleared, and it can cause particular problems with some implementations of malloc().
For G++, the code generator i ffb nserts a branch to __main at the top of your main() routine. G++ uses __main to initialize its internal tables and then returns control to your main() routine.
For crt0 to call your main() routine, use the following example’s input. First, set up the environment pointer and jump to main(). Call the main routine from the application to get it going, using the following example’s input with main (argc, argv, environ)., using argv as a pointer to NULL.
pea 0 pea SYM (environ) pea sp@(4) pea 0 jsr SYM (main) movel d0, sp@-4
If you’re using a ROM monitor, you can usually call a user trap to make the ROM take over. Pick a safe vector with no sides effects. Some ROM’s have a built-in trap handler just for this case.
Implementing (exit) here is easy.. First, with _exit, exit from the application. Normally, this causes a user trap to return to the ROM monitor for another run. Then, using the following example’s input, you proceed with the call.
SYM (exit): trap #0Both rom68k and bug can handle a user-caused exception of 0 with no side effects. Although the bug monitor has a user-caused trap that returns control to the ROM monitor, the bug