home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programming Languages Suite
/
ProgLangD.iso
/
Fortran.51
/
DISK5
/
DOS
/
CRT0DAT.AS$
/
CRT0DAT.bin
Wrap
Text File
|
1990-02-02
|
20KB
|
917 lines
page ,132
title crt0dat - DOS and Windows shared startup and termination
;***
;crt0dat.asm - DOS and Windows shared startup and termination
;
; Copyright (c) 1985-1990, Microsoft Corporation. All rights reserved.
;
;Purpose:
; Shared startup and termination.
;
; NOTE: This source is included in crt0.asm for assembly purposes
; when building .COM startup. This is so the .COM startup resides
; in a single special object that can be supplied to the user.
;
;*******************************************************************************
_NFILE_ = 20 ; Maximum number of file handles
?DF = 1 ;; tell cmacros.inc we want to define our own segments
.xlist
include version.inc
include cmacros.inc
include msdos.inc
.list
ifdef FARSTACK
ife sizeD
error <You cannot have a far stack in Small or Medium memory models.>
endif
endif
ifdef _COM_
if sizeC or sizeD
error <Must use Small memory model for .COM files.>
endif
endif ;_COM_
createSeg _TEXT, code, word, public, CODE, <>
createSeg CDATA, cdata, word, common, DATA, DGROUP
createSeg _DATA, data, word, public, DATA, DGROUP
createSeg DBDATA, dbdata, word, common, DATA, DGROUP
createSeg XIQC, xiqcseg, word, common, DATA, DGROUP ; QC initializer -Zr (DOS only)
createSeg XIFB, xifbseg, word, public, DATA, DGROUP
createSeg XIF, xifseg, word, public, DATA, DGROUP ; far init's
createSeg XIFE, xifeseg, word, public, DATA, DGROUP
createSeg XIB, xibseg, word, public, DATA, DGROUP
createSeg XI, xiseg, word, public, DATA, DGROUP ; init's
createSeg XIE, xieseg, word, public, DATA, DGROUP
createSeg XOB, xobseg, word, public, BSS, DGROUP
createSeg XO, xoseg, word, public, BSS, DGROUP ; onexit table
createSeg XOE, xoeseg, word, public, BSS, DGROUP
createSeg XPB, xpbseg, word, public, DATA, DGROUP
createSeg XP, xpseg, word, public, DATA, DGROUP ; preterm's
createSeg XPE, xpeseg, word, public, DATA, DGROUP
createSeg XCB, xcbseg, word, public, DATA, DGROUP
createSeg XC, xcseg, word, public, DATA, DGROUP ; term's
createSeg XCE, xceseg, word, public, DATA, DGROUP
createSeg XCFB, xcfbseg, word, public, DATA, DGROUP
createSeg XCF, xcfseg, word, public, DATA, DGROUP ; far term's
createSeg XCFE, xcfeseg, word, public, DATA, DGROUP
ifdef _COM_
createSeg EMULATOR_DATA, EmData, para, public, FAR_DATA, DGROUP
createSeg EMULATOR_TEXT, EmCode, para, public, CODE, DGROUP
endif ;_COM_
defGrp DGROUP ; define DGROUP
codeOFFSET equ offset _TEXT:
dataOFFSET equ offset DGROUP:
page
sBegin xifbseg
xifbegin label byte
sEnd xifbseg
sBegin xifeseg
xifend label byte
sEnd xifeseg
sBegin xibseg
xibegin label byte
sEnd xibseg
sBegin xieseg
xiend label byte
sEnd xieseg
sBegin xobseg
xontab label byte ; start of onexit table
sEnd xobseg
sBegin xoeseg
xonend label byte
sEnd xoeseg
sBegin xpbseg
xpbegin label byte ; end of onexit table
sEnd xpbseg
sBegin xpeseg
xpend label byte
sEnd xpeseg
sBegin xcbseg
xcbegin label byte
sEnd xcbseg
sBegin xceseg
xcend label byte
sEnd xceseg
sBegin xcfbseg
xcfbegin label byte
sEnd xifbseg
sBegin xcfeseg
xcfend label byte
sEnd xcfeseg
sBegin cdata ; floating point setup segment
assumes ds,data
dw 0 ; force segment to be at least 0's
labelD <PUBLIC,_fpinit> ; public for signal
fpmath dd 1 dup (?) ; linking trick for fp
fpdata dd 1 dup (?)
fpsignal dd 1 dup (?) ; fp signal message
sEnd
sBegin dbdata ;*
assumes ds,data ;* Used to do the running under
externW __aDBswpflg ;* a debugger screen swapping
externW __aDBexit ;*
sEnd dbdata ;*
extrn __aDBdoswp:ABS ;*
sBegin xiqcseg
globalW __qczrinit, 0 ;* QC -Zr initializer call address
sEnd xiqcseg
ifdef _COM_
sBegin EmData
labelB _EmDataLabel
sEnd EmData
sBegin EmCode
globalW _EmDataSeg,0
sEnd EmCode
else ;not _COM
EMULATOR_DATA segment para public 'FAR_DATA'
EMULATOR_DATA ends
EMULATOR_TEXT segment para public 'CODE'
public __EmDataSeg
__EmDataSeg dw EMULATOR_DATA
EMULATOR_TEXT ends
endif ;not _COM_
sBegin data
assumes ds,data
; special C environment string
labelB <PUBLIC,_acfinfo>
cfile db '_C_FILE_INFO='
cfilex db 0
cfileln = cfilex-cfile
globalD _aintdiv,0 ; divide error interrupt vector save
globalT _fac,0 ; floating accumulator
globalW errno,0 ; initial error code
globalW _umaskval,0 ; initial umask value
;=============== following must be in this order
globalW _pspadr,0 ; psp:0 (far * to PSP segment)
globalW _psp,0 ; psp:0 (paragraph #)
;=============== above must be in this order
;=============== following must be in this order
labelW <PUBLIC,_osversion>
labelB <PUBLIC,_dosvermajor>
globalB _osmajor,0
labelB <PUBLIC,_dosverminor>
globalB _osminor,0
;=============== above must be in this order
globalB _osmode,0 ; 0 = real mode
labelW <PUBLIC,_oserr>
globalW _doserrno,0 ; initial DOS error code
globalW _nfile,_NFILE_ ; maximum number of file handles
labelB <PUBLIC,_osfile>
db 3 dup (FOPEN+FTEXT) ; stdin, stdout, stderr
db 2 dup (FOPEN) ; stdaux, stdprn
db _NFILE_-5 dup (0) ; the other 15 handles
globalW __argc,0
globalDP __argv,0
globalDP environ,0 ; environment pointer
labelD <PUBLIC,_pgmptr> ; pointer to program name
dw dataOFFSET dos2nam
ifdef _COM_
dw 0 ; No relocations in tiny model
elseifdef _QC2
dw 0 ; No DGROUP references allowed
elseifdef _WINDOWS
dw 0 ; No DGROUP references allowed
else ;DEFAULT
dw DGROUP
endif
dos2nam db 0 ; dummy argv[0] for DOS 2.X
; signal related common data
globalW _child,0 ; flag used to handle signals from child process
;Overlay related data
globalB _ovlflag,0 ;Overlay flag (0 = no overlays)
globalB _intno,0 ;Overlay interrupt value (e.g., 3F)
globalD _ovlvec,0 ;Address of original overlay handler
sEnd data
page
externNP _fptrap
externP _cintDIV
externP _nullcheck
ifdef FARSTACK
endif
sBegin code
assumes cs,code
if sizeC
global proc far
endif
page
;***
;_cinit - C initialization
;
;Purpose:
; This routine performs the shared DOS and Windows initialization.
; The following order of initialization must be preserved -
;
; 1. Integer divide interrupt vector setup
; 2. Floating point initialization
; 3. Copy ;C_FILE_INFO into _osfile
; 4. Check for devices for file handles 0 - 4
; 5. General C initializer routines
;
;Entry:
;
;Exit:
;
;Uses:
;
;Exceptions:
;
;*******************************************************************************
cProc _cinit,<PUBLIC>,<>
cBegin <nogen> ; no local frame to set up in standard libs
assumes ds,data
ifndef FARSTACK
assumes ss,data
endif
;
; Initialize the DGROUP portion of _pgmptr. We must do this at
; runtime since there are no load-time fixups in .COM files.
;
ifdef _COM_
mov word ptr [_pgmptr+2],ds ; init seg portion of _pgmptr
endif ;_COM_
; *** Increase File Handle Count ***
;
; (1) This code only works on DOS Version 3.3 and later.
; (2) This code is intentially commented out; the user must enable
; this code to access more than 20 files.
;
; mov ah,67h ; system call number
; mov bx,_NFILE_ ; number of file handles to allow
; callos ; issue the system call
; ;check for error here, if desired (if carry set, AX equals error code)
;
; *** End Increase File Handle Count ***
; 1. Integer divide interrupt vector setup
mov ax,DOS_getvector shl 8 + 0
callos ; save divide error interrupt
mov word ptr [_aintdiv],bx
mov word ptr [_aintdiv+2],es
push cs
pop ds
assumes ds,nothing
mov ax,DOS_setvector shl 8 + 0
mov dx,codeOFFSET _cintDIV
callos ; set divide error interrupt
push ss
pop ds
assumes ds,data
; 2. Floating point initialization
if memS
cmp word ptr [fpmath], 0 ; Note: make sure offset __fpmath != 0
je nofloat_i
mov word ptr [fpmath+2], cs ; fix up these far addresses
mov word ptr [fpsignal+2], cs ; in the small model math libs
ifdef _COM_
mov [_EmDataSeg], cs
mov ax, offset DGROUP:_EmDataLabel
sub ax, offset EMULATOR_DATA:_EmDataLabel
mov cl, 4
shr ax, cl
add [_EmDataSeg], ax
endif ;_COM_
else ;not memS
mov cx,word ptr [fpmath+2]
jcxz nofloat_i
endif ;not memS
mov es,[_psp] ; psp segment
mov si,es:[DOS_ENVP] ; environment segment
ifdef FARSTACK
mov ax, word ptr [fpdata]
mov dx, word ptr [fpdata+2]
else
lds ax,[fpdata] ; get task data area
assumes ds,nothing
mov dx,ds ; into dx:ax
endif
xor bx,bx ; (si) = environment segment
call [fpmath] ; fpmath(0) - init
ifdef FARSTACK
mov ax, DGROUP
mov ds, ax
endif
jnc fpok
ifndef FARSTACK
push ss ; restore ds from ss
pop ds
endif
jmp _fptrap ; issue "Floating point not loaded"
; error and abort
fpok:
ifdef FARSTACK
mov ax, word ptr [fpsignal]
mov dx, word ptr [fpsignal+2]
else
lds ax,[fpsignal] ; get signal address
assumes ds,nothing
mov dx,ds
endif
mov bx,3
call [fpmath] ; fpmath(3) - set signal address
ifdef FARSTACK
mov ax, DGROUP
mov ds, ax ; restore DS=DGROUP
else
push ss
pop ds
assumes ds,data
endif
nofloat_i:
; 3. Copy _C_FILE_INFO= into _osfile
; fix up files inherited from parent using _C_FILE_INFO=
mov es,[_psp] ; es = PSP
mov cx,word ptr es:[DOS_envp] ; es = user's environment
jcxz nocfi ; no environment !!!
mov es,cx
xor di,di ; start at 0
cfilp:
cmp byte ptr es:[di],0 ; check for end of environment
je nocfi ; yes - not found
mov cx,cfileln
mov si,dataOFFSET cfile
repe cmpsb ; compare for '_C_FILE_INFO='
je gotcfi ; yes - now do something with it
mov cx,07FFFh ; environment max = 32K
xor ax,ax
repne scasb ; search for end of current string
jne nocfi ; no 00 !!! - assume end of env.
jmp cfilp ; keep searching
; found _C_FILE_INFO= and transfer info into _osfile
gotcfi:
push es
push ds
pop es ; es = DGROUP
pop ds ; ds = env. segment
assumes ds,nothing
assumes es,data
mov si,di ; si = startup of _osfile info
mov di,dataOFFSET _osfile ; di = _osfile block
mov cl, 4
osfile_lp:
lodsb
sub al, 'A'
jb donecfi
shl al, cl
xchg dx, ax
lodsb
sub al, 'A'
jb donecfi
or al, dl
stosb
jmp short osfile_lp
donecfi:
ifdef FARSTACK
push es
else
push ss
endif
pop ds ; ds = DGROUP
assumes ds,data
nocfi:
; 4. Check for devices for file handles 0 - 4
;
; Clear the FDEV bit (which might be inherited from C_FILE_INFO)
; and then call DOS to see if it really is a device or not
;
mov bx,4
devloop:
and _osfile[bx],not FDEV ; clear FDEV bit on principal
mov ax,DOS_ioctl shl 8 + 0 ; issue ioctl(0) to get dev info
callos
jc notdev
test dl,80h ; is it a device ?
jz notdev ; no
or _osfile[bx],FDEV ; yes - set FDEV bit
notdev:
dec bx
jns devloop
; 5. General C initializer routines
mov si,dataOFFSET xifbegin
mov di,dataOFFSET xifend
if sizeC
call initterm ; call the far initializers
else
call farinitterm ; call the far initializers
endif
mov si,dataOFFSET xibegin
mov di,dataOFFSET xiend
call initterm ; call the initializers
ret
cEnd <nogen> ; standard C libs
page
;***
;exit(status), _exit(status), _cexit(void), _c_exit(void) - C termination
;
;Purpose:
;
; Entry points:
;
; exit(code): Performs all the C termination functions
; and terminates the process with the return code
; supplied by the user.
;
; _exit(code): Performs a quick exit routine that does not
; do certain 'high-level' exit processing. The _exit
; routine terminates the process with the return code
; supplied by the user.
;
; _cexit(): Performs the same C lib termination processing
; as exit(code) but returns control to the caller
; when done (i.e., does NOT terminate the process).
;
; _c_exit(): Performs the same C lib termination processing
; as _exit(code) but returns control to the caller
; when done (i.e., does NOT terminate the process).
;
; Termination actions:
;
; exit(), _cexit ():
;
; 1. call user's terminator routines
; 2. call C runtime preterminators
;
; _exit(), _c_exit():
;
; 3. call C runtime terminators
; 4. perform _nullcheck() for null pointer assignment
; 5. terminate floating point
; 6. reset divide by zero interrupt vector
; 7. restore int 3F handler
; 8. return to DOS or caller
;
; Notes:
;
; The termination sequence is complicated due to the multiple entry
; points sharing the common code body while having different entry/exit
; sequences.
;
;Entry:
; exit(), _exit()
; int status - exit status (0-255)
;
; _cexit(), _c_exit()
; <no input>
;
;Exit:
; exit(), _exit()
; <EXIT to DOS>
;
; _cexit(), _c_exit()
; Return to caller
;
;Uses:
;
;Exceptions:
;
;*******************************************************************************
;
;--- exit(): Full exit and term process ---
;
public _exit
_exit:
cProc dummy1,<>,<>
parmw status ; termination code
cBegin
xor cx,cx ; exit(): cl = 0, ch = 0
jmp short common1 ; join common code
cEnd <nogen>
;
;--- _exit(): Quickie exit and term process ---
;
public __exit
__exit:
cProc dummy2,<>,<>
parmw status ; termination code
cBegin
mov cx,1 ; _exit(): cl = 1, ch = 0
jmp short common1 ; join common code
cEnd <nogen>
if sizeC
global endp
endif
;
;--- _cexit(): Full exit and return to caller ---
;
cProc _cexit,<PUBLIC>,<SI,DI>
cBegin
mov cx,(1 SHL 8) ; _cexit(): ch = 1, cl = 0
jmp short common1 ; join common code
cEnd <nogen>
;
;--- _c_exit(): Quickie exit and return to caller ---
;
cProc _c_exit,<PUBLIC>,<SI,DI>
cBegin
mov cx,(1 SHL 8)+1 ; _c_exit(): ch = 1, cl = 1
;fall through
;
;--- Common entry point ---
; cx = entry value:
; cl = full vs quick exit path
; 0 = exit() code
; 1 = _exit() code
; ch = term process vs return to caller
; 0 = term process
; 1 = return to caller
;
common1: ; all code paths join here
assumes ds,data
ifndef FARSTACK
assumes ss,data
endif
;
; If _exit()/_c_exit(), jump over the initial termination processing
; cx = entry code
;
push cx ; save entry code on top of stack
or cl,cl ; cl != 0 means _exit()/_c_exit()
jnz short common2 ; if _exit()/_c_exit(), jump down
;fall thru ; continue (exit, _cexit)
; 1. call user terminators
; - onexit processing
mov si,dataOFFSET xontab ; beginning of onexit table
mov di,dataOFFSET xonend ; end of onexit table
call initterm
; 2. call C runtime preterminators
; - flushall
; - rmtmp
mov si,dataOFFSET xpbegin ; beginning of pre-terminators
mov di,dataOFFSET xpend ; end of pre-terminators
call initterm
;*
;* Tell the debugger we are going to exit
;*
; *** NOTE: Currently, this appears to be called for both
; exit() and _cexit(). Is this what we want?
;
cmp __aDBswpflg,__aDBdoswp ;* Are we under a debugger?
jne @F ;* No -- skip forward
cCall __aDBexit ;* Yes -- tell it we are exiting
@@:
;
;--- Common entry point ---
;
common2: ; __exit() enters here
; 3. perform C terminators
mov si,dataOFFSET xcbegin
mov di,dataOFFSET xcend
call initterm ; call the terminators
mov si,dataOFFSET xcfbegin
mov di,dataOFFSET xcfend
if sizeC
call initterm ; call the far terminators
else
call farinitterm ; call the far terminators
endif
; 4. perform _nullcheck() for null pointer assignment
ifndef _COM_ ; DS:0 is the PSP in .COM files!
call _nullcheck ; check data in NULL data segment at DS:0
; this must be far call in large code models
; since user can stub it out
or ax,ax ; zero if no null ptr assignment detected
jz afternullchk
pop ax ; get entry code
or ah,ah ; ah != 0 means _cexit()/_c_exit()
push ax ; put it back for later
jnz short afternullchk ; jump if no status value (_cexit/_c_exit)
cmp status,0 ; zero if no other error has occurred
jnz short afternullchk
mov status,255 ; nonzero status to indicate an
; null-pointer-assignment error
afternullchk:
endif ;_COM_
; 5. terminate floating point
; 6. reset divide by zero interrupt vector
; 7. restore int 3F handler
call _ctermsub ; fast cleanup
; 8. return to the DOS or caller
pop ax ; get entry code off top of stack
or ah,ah ; ah = 0 means term process
jnz returning ; skip down if not term'ing
; 8a. return to the DOS
exiting:
mov ax,status ; get return value
callos terminate ; exit with al = return code
;*** PROCESS IS TERMINATED ***
; 8b. Return to caller.
returning:
cEnd <nolocals>
page
;***
;_ctermsub - more C termination code
;
;Purpose:
; This routine
; (1) performs floating-point termination
; (2) resets the divide by zero interrupt vector
; (3) restore int 3F handler
;
;Entry:
;
;Exit:
;
;Uses:
; AX,BX,CX,DX.
;
;Exceptions:
;
;*******************************************************************************
labelNP <PUBLIC,_ctermsub>
; 4. terminate floating point
mov cx,word ptr [fpmath+2] ; test for floating point
jcxz nofloat_t ; no
mov bx,2 ; yes - cleanup
call [fpmath]
nofloat_t:
; 5. reset divide by zero interrupt vector
push ds
lds dx,[_aintdiv] ; ds:dx = restore vector
mov ax,DOS_setvector shl 8 + 0
callos ; set divide error interrupt
pop ds
; 6. restore overlay interrupt vector
cmp byte ptr [_ovlflag],0 ; Overlays in use ??
jz done_ovlvec ; if 0, don't restore overlay vector
push ds ; save ds
mov al,byte ptr [_intno] ; overlay interrupt number
lds dx,dword ptr [_ovlvec] ; original ovl interrupt vector
callos setvector ; restore the overlay vector
pop ds ; restore ds
done_ovlvec:
ret
page
;***
;initterm - do a set of initializers or terminators
;
;Purpose:
; The initializors and terminators may be written in C
; so we are assuming C conventions (DS=SS, CLD, SI and DI preserved)
; We go through them in reverse order for onexit.
;
;Entry:
; SI = start of procedure list
; DI = end of procedure list
;
;Exit:
;
;Uses:
;
;Exceptions:
;
;*******************************************************************************
initterm:
cmp si,di ; are we done?
jae itdone ; yes - no more
if sizeC
sub di,4
mov ax,[di]
or ax,[di+2]
jz initterm ; skip null procedures
call dword ptr [di]
else
dec di
dec di
mov cx,[di]
jcxz initterm ; skip null procedures
call cx
endif
jmp initterm ; keep looping
itdone:
ret
page
ife sizeC ; S/C models only
;***
;farinitterm - do a set of far initializers or terminators
;
;Purpose:
; The initializors and terminators may be written in C
; so we are assuming C conventions (DS=SS, CLD, SI and DI preserved)
; We go through them in reverse order for onexit.
;
;Entry:
; SI = start of procedure list
; DI = end of procedure list
;
;Exit:
;
;Uses:
;
;Exceptions:
;
;*******************************************************************************
farinitterm:
cmp si,di ; are we done?
jae faritdone ; yes - no more
sub di,4
mov ax,[di]
or ax,[di+2]
jz farinitterm ; skip null procedures
call dword ptr [di]
jmp farinitterm ; keep looping
faritdone:
ret
endif ;sizeC
sEnd
end