Start/Exit

Technical Notes

Overview
Startup Code
Starting a Program
Specifying Additional Termination Functions
Exiting a Program
Using the Startup Code
Creating a Stack with C/C++

Overview

This unit provides startup and exit code to replace the standard startup and exit code provided with C compilers.

Startup Code

A significant C optimization that is often overlooked is replacing the compiler's startup code. The size of the Spontaneous Assembly startup code is minimal (roughly 100 bytes), while the startup code provided with C compilers is generally several thousand bytes in size. C programs can use the Spontaneous Assembly startup code if Spontaneous Assembly library routines will be used in place of their C counterparts. C++ programs should NOT use the Spontaneous Assembly startup code.

WARNING! The startup code provided by compilers performs initializations for compiler library functions. The Spontaneous Assembly startup code is intended for C programs that use the Spontaneous Assembly library in place of the compiler's library.

The startup code is contained entirely in the _start function. The startup code also includes the _exit and _exit_ok functions (described below). Generally, only those setup functions are performed by _start which are difficult to perform later (e.g., remembering the segment address of the PSP in models other than TINY). Other initialization or setup required by specific library functions must be performed using separate initialization functions provided for that purpose. This allows initialization code to be included in the final program on an as-needed basis.

Starting a Program

_start
Accepts control from DOS, passes control to main, and returns control to DOS when main terminates.
main
Starting point for program execution.
_start accepts control from DOS, performs a minimal amount of housekeeping (i.e., stores the PSP address, sets up segment registers, normalizes the stack pointers in the SMALL and MEDIUM models), shrinks the program down to its minimum acceptable size, and passes control to main. _start is never called directly. Instead, _start is linked with the object module containing main.

main is called by _start and serves as the starting point for the program. When main has finished executing, it usually returns to _start, terminating the program.

WARNING! main is NOT called with the standard argc, argv, and env parameters. Spontaneous Assembly command line parsing functions should be used instead.

Specifying Additional Termination Functions

_on_exit
Adds a cleanup function to the list of exit cleanup functions.
This function maintains a list of functions to be executed before exiting to DOS. A maximum of 16 functions can be added to the _on_exit list. Functions in the _on_exit list are executed in last-in/first-out (LIFO) order. Functions added to this list are executed only if an _on_exit-aware function is called to return to DOS, as in the following example:

                         ...
   _on_exit (restore_ints);                     /* add function to restore interrupts */
                         ...
   _exit_cleanup (1);                                   /* execute ON_EXIT list before exiting */
The following functions are _on_exit-aware: _exit_cleanup, _progid_hremtsr, _progid_remtsr, _tsr_hremove, and _tsr_remove.

Exiting a Program

_exit
Exits to DOS with a specified ERRORLEVEL.
_exit_ok
Exits to DOS with an ERRORLEVEL of 0.
_exit_cleanup
Exits to DOS with a specified ERRORLEVEL, after executing all functions in _on_exit list.
These functions set an ERRORLEVEL and terminate the program. _exit and _exit_cleanup set a specified ERRORLEVEL. _exit_ok forces an ERRORLEVEL of 0. The program may also be terminated by returning from main (this is equivalent to calling _exit). ERRORLEVEL is set to the value returned by main.

_exit and _exit_ok are only available when the Spontaneous Assembly startup code has been used. Otherwise the standard C exit function should be used (this function cleans up after the compiler's startup code).

By default, the _exit and _exit_ok functions perform the normal file closing cleanup performed by DOS when a program terminates. The programmer may use _on_exit and _exit_cleanup to maintain and execute a list of additional termination functions (e.g., restoring interrupt vectors or flushing buffers) to be performed prior to exiting the program (see Specifying Additional Termination Functions in this chapter).

Using the Startup Code

_start does not reside in the Spontaneous Assembly library files (_SA?.LIB) because it cannot be linked into the final program automatically. Special handling is required to use _start.

_start must be linked manually into the final program, and its object file must be the first object file linked. Linking order is important to these files because they define the segment order of the selected memory model as well as the starting program offset in the TINY model.

Four versions of _start are provided:

_START?.OBJ
Standard startup code. DOSSEG segment ordering is used.
_NSTART?.OBJ
Startup code for non-TSR programs which use TSR functions, or for TSRs where main is compiled with Microsoft C 6.0 or earlier, Zortech C/C++, or TopSpeed C/C++. TSR segment ordering is used and main is expected to be in a resident code segment.
_TSTART?.OBJ
Startup code for TSRs. TSR segment ordering is used and _start and main are expected to be in a transient code segment.
_DSTARTT.OBJ
Startup code for device drivers. TSR segment ordering is used.
The "?" in the file names above must be replaced with T, S, M, C, or L to denote TINY, SMALL, MEDIUM, COMPACT, or LARGE.

Creating a Stack with C/C++

STACK_1K
(Macro) Causes a 1k stack to be linked into the program.
STACK_2K
(Macro) Causes a 2k stack to be linked into the program.
STACK_4K
(Macro) Causes a 4k stack to be linked into the program.
STACK_8K
(Macro) Causes a 8k stack to be linked into the program.
STACK_16K
(Macro) Causes a 16k stack to be linked into the program.
STACK_32K
(Macro) Causes a 32k stack to be linked into the program.
One of the housekeeping functions performed by start is normalization of the stack. The startup code provided by C compilers defines the stack at run time by allocating the stack at the end of program data. This is less efficient than defining a standard stack within the program, and is incompatible with TSRs. For these reasons, a stack must be linked from the library when using startup code provided by Spontaneous Assembly. This is accomplished by invoking the STACK_1K, STACK_2K, STACK_4K, STACK_8K, STACK_16K, and STACK_32K. The size indicated in the name of each macro indicates the amount of stack space that is linked into the program when that macro is used.

Creating a Program Which Uses Spontaneous Assembly Startup Code

It is a relatively simple matter to create a new program that uses the Spontaneous Assembly startup code. The steps are as follows:

  1. Create a C source file with the main function required by C and C++.
  2. Define the program stack as described above.
  3. Link the Spontaneous Assembly startup code (_START?.OBJ, _NSTART?.OBJ, _TSTART?.OBJ, or _DSTARTT.OBJ) into the final program. The startup code should be the first module linked.
If MS-LINK were used and the name of the C source file were PROGMAIN.C, the linker commands would look like this in the MEDIUM model:

LINK
Object Modules [.OBJ]: _startm progmain
Run File [STARTM.EXE]: progname
List File [NUL.MAP]:
Libraries [.LIB]: _sam.lib
Or to link a program as a TSR:

LINK
Object Modules [.OBJ]: _tstartm progmain
Run File [STARTM.EXE]: progname
List File [NUL.MAP]:
Libraries [.LIB]: _sam.lib _tsam.lib
The examples above would create MEDIUM model executable files (as indicated by the use of _SAM.LIB, the medium model library) named progname.EXE.

Note that in the examples above, the Spontaneous Assembly startup code file is always listed first. Also, the Spontaneous Assembly library file (_SAM.LIB) is specified as a library (not as an object file) to allow the linker to link in only those Spontaneous Assembly functions it needs. Finally, both the resident (_SAM.LIB) and transient (_TSAM.LIB) versions of the Spontaneous Assembly library must be linked into the program if transient functions are used in the TSR. This is demonstrated in the second example above.