469 lines
9.8 KiB
NASM
469 lines
9.8 KiB
NASM
title crt0dat - DOS and Windows shared startup and termination
|
|
|
|
;--------------------------------------------------------------------------
|
|
;
|
|
; Microsoft C Compiler Runtime for MS-DOS
|
|
;
|
|
; (C)Copyright Microsoft Corporation, 1984, 1985, 1986
|
|
;
|
|
;--------------------------------------------------------------------------
|
|
|
|
?DF = 1 ;; tell cmacros.inc we want to define our own segments
|
|
|
|
include version.inc
|
|
.xlist
|
|
include cmacros.inc
|
|
include msdos.inc
|
|
.list
|
|
|
|
createSeg _TEXT, code, byte, public, CODE, <>
|
|
createSeg CDATA, cdata, word, common, DATA, DGROUP
|
|
createSeg _DATA, data, 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
|
|
|
|
defGrp DGROUP ;; define DGROUP
|
|
|
|
codeOFFSET equ offset _TEXT:
|
|
dataOFFSET equ offset DGROUP:
|
|
|
|
page
|
|
|
|
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 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 data
|
|
assumes ds,data
|
|
|
|
; special C environment string
|
|
|
|
cfile db ';C_FILE_INFO'
|
|
cfileln = $-cfile
|
|
|
|
globalD _aintdiv,0 ; divide error interrupt vector save
|
|
|
|
globalQ _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 #)
|
|
|
|
labelB <PUBLIC,_dosvermajor>
|
|
globalB _osmajor,0
|
|
labelB <PUBLIC,_dosverminor>
|
|
globalB _osminor,0
|
|
|
|
; ************* above must be in this order
|
|
|
|
labelW <PUBLIC,_oserr>
|
|
globalW _doserrno,0 ; initial DOS error code
|
|
|
|
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
|
|
|
|
|
|
; signal related common data
|
|
|
|
globalW _child,0 ; flag used to handle signals from child process
|
|
|
|
; note - if any changes are made to this structure, corresponding changes
|
|
; are needed in both doexec.asm and signal.asm
|
|
|
|
entry struc
|
|
dftoff dw 0 ; default return address: offset
|
|
dftseg dw 0 ; default return address: segment
|
|
shfoff dw 0 ; signal-handling function: offset
|
|
shfseg dw 0 ; signal-handling function: segment
|
|
entry ends
|
|
|
|
public __csigtab
|
|
__csigtab entry <> ; table of just one entry for now
|
|
|
|
sEnd data
|
|
|
|
page
|
|
sBegin code
|
|
assumes cs,code
|
|
|
|
if sizeC
|
|
global proc far
|
|
endif
|
|
|
|
;-----------------------------------------------------------------------------
|
|
;
|
|
; _cinit () - C initialization
|
|
;
|
|
; This routine performs the shared DOS and Windows initialization.
|
|
; The following order of initialization must be preserved -
|
|
;
|
|
; 1. Save DOS version
|
|
; 2. Check for devices for file handles 0 - 4
|
|
; 3. Integer divide interrupt vector setup
|
|
; 4. Floating point initialization
|
|
; 5. Copy ;C_FILE_INFO into _osfile
|
|
; 6. General C initializor routines
|
|
|
|
externP _cintDIV
|
|
externP _nullcheck
|
|
|
|
cProc _cinit,<PUBLIC>,<>
|
|
|
|
cBegin nogen ; no local frame to set up
|
|
assumes ds,data
|
|
assumes ss,data
|
|
|
|
; 1. Save DOS version
|
|
|
|
callos VERSION
|
|
mov word ptr [_osmajor],ax ; set _osmajor and _osminor
|
|
|
|
; 2. Check for devices for file handles 0 - 4
|
|
|
|
mov bx,4
|
|
|
|
devloop:
|
|
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
|
|
|
|
; 3. 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
|
|
|
|
; 4. Floating point initialization
|
|
|
|
mov cx,word ptr [fpmath+2]
|
|
jcxz nofloat_i
|
|
|
|
mov es,[_psp] ; psp segment
|
|
mov si,es:[DOS_ENVP] ; environment segment
|
|
lds ax,[fpdata] ; get task data area
|
|
assumes ds,nothing
|
|
mov dx,ds ; into dx:ax
|
|
xor bx,bx ; (si) = environment segment
|
|
call [fpmath] ; fpmath(0) - init (never fails)
|
|
lds ax,[fpsignal] ; get signal address
|
|
assumes ds,nothing
|
|
mov dx,ds
|
|
mov bx,3
|
|
call [fpmath] ; fpmath(3) - set signal address
|
|
push ss
|
|
pop ds
|
|
assumes ds,data
|
|
|
|
nofloat_i:
|
|
|
|
; 5. Copy ;C_FILE_INFO into _osfile
|
|
|
|
; fix up files inherited from child 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
|
|
|
|
lodsb ; must be less than 20
|
|
cbw
|
|
xchg cx,ax ; cx = number of entries
|
|
|
|
osflp:
|
|
lodsb ; get next byte
|
|
inc al
|
|
jz saveit ; was FF - save as 00
|
|
dec ax ; restore al
|
|
saveit:
|
|
stosb
|
|
loop osflp ; transfer next character
|
|
|
|
nocfi:
|
|
|
|
; 6. General C initializor routines
|
|
|
|
push ss
|
|
pop ds ; ds = DGROUP
|
|
mov si,dataOFFSET xibegin
|
|
mov di,dataOFFSET xiend
|
|
call initterm ; call the initializors
|
|
|
|
ret
|
|
cEnd nogen
|
|
|
|
page
|
|
;-----------------------------------------------------------------------------
|
|
;
|
|
; C termination
|
|
;
|
|
; The termination sequence is more complicated due to the multiple
|
|
; entry points - exit(code) and _exit(code). The _exit() routine
|
|
; is a quick exit routine that does not do certain C exit functions
|
|
; like stdio buffer flushing and onexit processing.
|
|
;
|
|
; exit (status):
|
|
;
|
|
; 1. call runtime preterminators
|
|
;
|
|
; _exit (status):
|
|
;
|
|
; 2. perform C terminators
|
|
; 3. perform _nullcheck() for null pointer assignment
|
|
; 4. close all open files
|
|
; 5. terminate floating point
|
|
; 6. reset divide by zero interrupt vector
|
|
; 7. terminate with return code to DOS
|
|
|
|
public _exit
|
|
_exit:
|
|
cProc dummy1,<>,<>
|
|
|
|
parmw status
|
|
|
|
cBegin
|
|
assumes ds,data
|
|
assumes ss,data
|
|
|
|
; 1. call runtime preterminators
|
|
; - onexit processing
|
|
; - flushall
|
|
; - rmtmp
|
|
|
|
mov si,dataOFFSET xontab ; beginning of onexit table
|
|
mov di,dataOFFSET xonend ; end of onexit table
|
|
call initterm
|
|
|
|
mov si,dataOFFSET xpbegin ; beginning of pre-terminators
|
|
mov di,dataOFFSET xpend ; end of pre-terminators
|
|
call initterm
|
|
|
|
jmp short exiting ; jump into _exit
|
|
|
|
cend nogen
|
|
|
|
public __exit
|
|
__exit:
|
|
cProc dummy2,<>,<>
|
|
|
|
parmw status
|
|
|
|
cBegin
|
|
assumes ds,data
|
|
assumes ss,data
|
|
|
|
exiting:
|
|
|
|
; 2. perform C terminators
|
|
|
|
mov si,dataOFFSET xcbegin
|
|
mov di,dataOFFSET xcend
|
|
call initterm
|
|
|
|
; 3. perform _nullcheck() for null pointer assignment
|
|
|
|
call _nullcheck ; perform null check (ignore return)
|
|
|
|
; 4. close all files
|
|
|
|
mov cx,_NFILE
|
|
xor bx,bx
|
|
|
|
closeloop:
|
|
test _osfile[bx],FOPEN
|
|
jz notopen
|
|
|
|
callos close
|
|
|
|
notopen:
|
|
inc bx
|
|
loop closeloop
|
|
|
|
; 5. terminate floating point
|
|
; 6. reset divide by zero interrupt vector
|
|
|
|
call _ctermsub ; fast cleanup
|
|
|
|
; 7. return to the DOS
|
|
|
|
mov ax,status ; get return value
|
|
callos terminate ; exit with al = return code
|
|
|
|
cEnd nogen
|
|
|
|
if sizeC
|
|
global endp
|
|
endif
|
|
|
|
|
|
labelNP <PUBLIC,_ctermsub>
|
|
|
|
; 5. 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:
|
|
|
|
; 6. 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
|
|
ret
|
|
|
|
|
|
page
|
|
;-----------------------------------------------------------------------------
|
|
;
|
|
; initterm - do all the initializors and terminators
|
|
;
|
|
; 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.
|
|
;
|
|
; si = start of procedure list
|
|
; di = end of procedure list
|
|
|
|
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
|
|
|
|
|
|
sEnd
|
|
|
|
end
|