Source Files Available for Customization

With the Green Hills runtime libraries, you need to customize just a few low- level source files and routines to implement or enhance the runtime environment for a particular hardware system. A description of each file follows. Each source file, including files with only assembly language, are fully commented to provide more detailed documentation.

The linker directives files, which specify the location and, sometimes, the size of program sections, are also improved. Some of the improved functionality in the low-level libraries require use of some of these linker directives.

crt0.mco

The startup module crt0.mco is assembled from a small architecture-specific assembly language file and contains only a minimal amount of code to setup a C program environment before calling into a high level language C function. This minimal assembly code is located in a function named _start, the default entry point for programs in the Green Hills environment. On program startup, an initial system call is made to determine whether a Green Hills debug agent (or debug server) is controlling execution of the program (as opposed to the program running standalone, without being connected to a debug server). If the system call is successful, some required register initialization is assumed to have been accomplished by the debug server; otherwise the code in crt0.mco may do some more initialization. The source code in crt0.mco should be consulted since the actual register manipulation varies widely across different architectures.

The most commonly required register initialization is that of the processor stack pointer, since a valid stack is generally required before a high level language can be called. Most crt0.o modules reference the special symbol _ _ghsend_stack when initializing the stack pointer. _ _ghsbegin_section and _ _ghsend_section, where section is the name of your section preceded by an underscore (_) and not a period (.), are special linker-defined symbols which reference the respective start and end of each user program section.

The .stack section is an improved method for specifying the location of the runtime stack. You can place a .stack section into the linker directives file to specify the location and size of the runtime stack. The Green Hills startup code sets up the stack pointer to point to the end of this section if the stack grows downward. Otherwise the stack pointer is written with the address of the start of the .stack section. You can change the location or size of the stack by changing the linker directives file.

Green Hills debug servers automatically detect the existence of the .stack section and automatically initialize the stack pointer. An example .stack section specified in the preceding example directives file is:

.heap align(16) pad(0x100000) :
.stack align (16) pad(0x80000) :

This specifies that the stack starts on the first 16-byte aligned address following the .heap section in memory. Also, the stack is configured to be 0x80000 bytes in size.

Using the .stack to specify the stack configuration permits stack checking code is to be easily built into a program; code need only compare the current value of the stack pointer register with the value of _ _ghsbegin_stack to determine whether the available stack area is exhausted.

Finally, _start calls the function _ _ghs_ind_crt0, the architecture-independent startup routine located in libsys.a.

ind_crt0.c

As described above, this module contains machine-independent startup code. In particular, ind_crt0.c clears the uninitialized data sections (.bss and .sbss, if present), and copies initialized data sections from their location in ROM to their final location in RAM. Whether a program requires this ROM to RAM copy depends on the use of the linker directives file for that program. In the example linker directives file above, the ROM directives specify that the sections .romdata and .romsdata are "shadow" or ROM copies of the actual .data section in RAM. The ROM sections are copied to RAM by the startup code in this module. You do not have to write code to clear or copy sections at startup; ind_crt0.o does it automatically. The ind_crt0.c module should be customized and rebuilt should you want to do this initialization without the aid of the library.

When your program requires PIC/PID, the ind_crt0.o module will relocate initialized pointers to any position independent object. For example, consider the following C code:

extern int foo();
int (*ptr)() = &foo;

This declares a global function pointer which is initialized to the address of the function foo. This declaration is not valid with other compilers when utilizing position independent code because the address of foo is unknown at link-time and hence unresolvable by the linker/loader. Green Hills, however, supports this. The compiler emits a small amount of data which describes each relocated initialization in the program. For example, when compiling for PIC, the compiler generates data to inform ind_crt0.o that the initializer of the variable ptr requires a runtime modification specifying the runtime location of the program's code, as desired. After ind_crt0.o finishes, all initialized pointers contain valid runtime addresses.

Finally, ind_crt0.c calls into the user code, that is, to main().

ind_call.mco

ind_dots.mco

These modules contain architecture-specific language and handle lowest level system call capability. The routine _ _ghs_syscall is called from various system call routines, such as open, close, read and write. The _ _ghs_syscall routine transfers control to a special address, the start address of the special .syscall section (see the earlier linker directives example.).

Debug servers or monitors can key in this special address to accomplish the emulation of system calls in the Green Hills environment. For example, many MULTI debug servers set a special breakpoint on this address; then, when the breakpoint is encountered during execution, the debug server knows that a system call occurred. The arguments are then retrieved and the system call is emulated on the host by the debug server. This mechanism provides a more generic system call interface and brings system call capability to some targets where this functionality was previously unavailable.

ind_mcpy.c

ind_mset.c

These modules contain the C runtime library functions memcpy and memset. They are needed to clear and copy data sections during initialization. You can modify and change these routines if desired. For some architectures, either or both of these functions are provided in assembly code. On other architectures, high level C functions are used and compiled into the libsys.a library with the highest optimization level.

ind_mcnt.mco

ind_gcnt.mco

ind_bcnt.c

ind_mprf.c

ind_gprf.c

These modules provide profiling support. Two routines are used: __ghs_mcount for call count profiling and _ _ghs_gcount for call graph profiling. The module ind_bcnt.c contains the profiling routine, __ghs_bcount, which handles calls that are emitted by the compiler to implement code coverage analysis. The ind_mprf.c and ind_gprf.c modules contain routines that accomplish profiling functions such as starting a profiling timer (only on certain processors) and writing profile data to disk.

ind_heap.c

The ind_heap.c module contains the dynamic memory allocation routines, in particular the system call routine sbrk. The .heap section specifies the location, size, and alignment of the heap in the linker directive file.

For example, in the preceding linker directives example, the heap section is specified as follows:

. . .
.bss :
.heap align(16) pad(0x100000) :
.stack align(16) pad(0x80000) :
. . .

This specifies that the heap starts on the first 16-byte aligned address following the .bss section in memory and is 0x100000 bytes in size. The .stack section then follows the heap area. The pad directive instructs the linker that the heap is uninitialized on startup. This directive enables you to place the runtime heap anywhere in memory; the runtime library automatically allocates heap memory where you place this section.

In addition, the ability to hardcode a size for the heap assures you that the program does not use more heap memory than desired or expected. Attempting to allocate memory at an address which is higher than that specified by the size in the linker directive will cause sbrk to fail and return an error value.

ind_io.c

ind_io.c, ind_gmtm.c, ind_sgnl.c, ind_stat.c, ind_time.c, ind_exit.c, ind_tmzn.c, ind_renm.c, and ind_syst.c contain a basic set of UNIX-like operating system routines. Each routine is documented to show the function it performs and the values it returns. These routines allow the linker to resolve an operating system's symbols, referenced by the Green Hills runtime libraries. The ind_io.c system routines most likely to be needed for a basic UNIX-like implementation are:

int open(const char *filename, int mode, . . . );
int creat(const char *filename, int prot);
int close(int fno);
int read(int fno, void *buf, int size);
int write(int fno, const void *buf, int size);
int unlink(char *name);
void _exit(int code);

These system calls enable the embedded system program to open, read, write, and close files. In many embedded systems, this basic support is not required. For example, on some systems, the application never ends and hence does not need an exit routine.

Other system calls, enabling a more robust interface and used in the default Green Hills runtime environment, include:

int brk(void *addr);
void *sbrk(int size);
long lseek(int fno, long offset, int end);
int fcntl(int fno, int cmd, int arg);
int getpid(void);
int isatty(int fno);
void _enter(void);

The _enter routine is called at startup and can be used as a separate routine to initialize the I/O system, initialize caching options, etc. Also, a few of the above listed routines only provide rudimentary support; you should consult the implementation before using them. Many of the Green Hills ind_io.c and related system call modules filter down to calls to the generic system call interface routine, _ _ghs_syscall, described above.

ind_exit.c

_enter Called up at startup and is used as a separate routine to initialize the I/O system, initializing caching options, etc.

_ghs_at_exit Registers functions that need to be called upon _exit (similar to the ANSI atexit().)

_exit Calls cleanup routines registered by the program via

_ _ghs_at_exit() or atexit() and allows the program to terminate gracefully via an exit system call.

FORTRAN Runtime Support

The system routines needed specifically for FORTRAN are tabulated below. These routines are used by the Green Hills FORTRAN runtime library, libf.a. Descriptions of the routines are in the noted source files.
Source File Routine
ind_trnc.c
int truncate(const char *path, int length);
ind_stat.c
int fstat(int fno, struct stat *statptr);
int stat(char *name, struct stat *statptr);

Other Low-Level Functions
Source File Routine
ind_gmtm.c
struct tm *gmtime(const time_t *timer);
ind_sgnl.c
int raise(int sig);
void (*signal(int sig, void (*func)(int)))(int);
unsigned int ualarm(unsigned int value, unsigned int interval);
unsigned int alarm(unsigned int seconds);
ind_stat.c
int access(char *name, int mode);
ind_time.c
time_t time(time_t *tptr);
int times (struct tms *buffer);
ind_tmzn.c
struct tm *localtime(const time_t *timer);
void tzset(void);
int __gh_timezone(void);
ind_renm.c
int rename(const char *old, const char *new);
ind_syst.c
int system(const char *string);


Previous

Next



Copyright © 1999, Green Hills Software. All rights reserved.