NAME c0
PAGE 60,132
LOCALS
;[]------------------------------------------------------------[]
;| C0.ASM -- start Up Code |
;| |
;| Turbo C++ Run Time Library |
;| |
;| Copyright (c) 1987, 1991 by Borland International Inc. |
;| All Rights Reserved. |
;[]------------------------------------------------------------[]
__C0__ = 1INCLUDE RULES.ASI
; SEGMENT and Group declarations
_TEXT SEGMENT BYTE PUBLIC 'CODE'
ENDS
_FARDATA SEGMENTPARAPUBLIC 'FAR_DATA'
ENDS
_FARBSS SEGMENTPARAPUBLIC 'FAR_BSS'
ENDS
IFNDEF __TINY__
_OVERLAY_ SEGMENTPARAPUBLIC 'OVRINFO'
ENDS
_1STUB_ SEGMENTPARAPUBLIC 'STUBSEG'
ENDS
ENDIF
_DATA SEGMENTPARAPUBLIC 'DATA'
ENDS
_INIT_ SEGMENT WORD PUBLIC 'INITDATA'
Initstart label byte
ENDS
_INITEND_ SEGMENT BYTE PUBLIC 'INITDATA'
InitEnd label byte
ENDS
_EXIT_ SEGMENT WORD PUBLIC 'EXITDATA'
Exitstart label byte
ENDS
_EXITEND_ SEGMENT BYTE PUBLIC 'EXITDATA'
ExitEnd label byte
ENDS
_CVTSEG SEGMENT WORD PUBLIC 'DATA'
ENDS
_SCNSEG SEGMENT WORD PUBLIC 'DATA'
ENDS
IFNDEF __HUGE__
_BSSSEGMENT WORD PUBLIC 'BSS'
ENDS
_BSSEND SEGMENT BYTE PUBLIC 'BSSEND'
ENDS
ENDIF
IFNDEF __TINY__
_STACK SEGMENT STACK 'STACK'
ENDS
ENDIF
ASSUME CS:_TEXT, DS:DGROUP
; External References
extrn _main:DISTextrn _exit:DISTextrn __exit:DISTextrn __nfile:wordextrn __setupio:near ;required!
extrn __stklen:word
IF LDATA EQ false
extrn __heaplen:wordENDIF
SUBTTL start Up Code
PAGE
;/* */
;/*-----------------------------------------------------*/
;/* */
;/* start Up Code */
;/* ------------- */
;/* */
;/*-----------------------------------------------------*/
;/* */
PSPHigh equ 00002h
PSPEnv equ 0002ch
PSPCmd equ 00080h
PUBLIC __AHINCR
__AHINCR equ1000h
PUBLIC __AHSHIFT
__AHSHIFT equ12
IFDEF __NOFLOAT__
MINSTACK equ128 ; minimal stack size in wordselse
MINSTACK equ 256 ; minimal stack size in wordsENDIF
;
; At the start, DS and ES both point to the SEGMENT prefix.
; SS points to the stackSEGMENT except in TINY model where
; SS is equal to CS
;
_TEXT SEGMENTIFDEF __TINY__
ORG 100h
ENDIFstartX PROC NEAR
; Save general information, such as :
; DGROUP SEGMENTaddress
; DOS version number
; Program SEGMENT Prefix address
; Environment address
; Top of far heap
IFDEF __TINY__
movdx, cs ; DX = GROUP SEGMENTaddresselsemovdx, DGROUP ; DX = GROUP SEGMENTaddressENDIF
IFNDEF __BOSS__
mov cs:DGROUP@@, dx ; __BOSS__
ENDIFmov ah, 30h
int 21h ; get DOS version number
mov bp, ds:[PSPHigh]; BP = Highest Memory SEGMENT Addr
mov bx, ds:[PSPEnv] ; BX = Environment SEGMENTaddressmovds, dxmov _version@, ax ; Keep major and minor version number
mov _psp@, es ; Keep Program SEGMENT Prefix addressmov _envseg@, bx ; Keep Environment SEGMENTaddressmovword ptr _heaptop@ + 2, bp
;
; Save several vectors and install default divide by zero handler.
;
call SaveVectors
;===================
;
; IDsoft - Check to make sure that we're running on a 286 or better
pushf ; Save original flags
xor ax,ax ; Clear axpushax
popf ; Try to pop the 0
pushf
pop ax ; Get results of popping 0 into flags
popf ; Restore original flags
or ax,ax
jns @@Have286 ; If no sign bit, have a 286
mov cx, lgth_no286MSG
movdx, offset DGROUP: no286MSG
jmp MsgExit3
@@Have286:
; IDsoft - End of modifications (there's also a code SEGMENT string)
;
;===================
IFDEF __BOSS__
; Determine if in real mode
movax,0FB42h ; find out if DPMI loader is here
mov bx,1 ; get info function
int 2fh ;
pushax ;
movax, cs ; now, save DGROUP
addax, cx ;
mov es, ax ;
movdx, ds ;
mov es:DGROUP@@, dx ;
mov es:CSalias@@, ax ;
pop ax ;
; pointax,0001h ; if not "TRUE"
; JNE InRealMode
; 8 is the value of the alias selector
; in this system
mov _protected@, cx
mov _hugeincval@, cx
clc
movax, cx
xor cx, cx
or ax, ax
je @@gotshift
@@shiftcnt:
rcr ax,1
jc @@gotshift
inc cx
jmp @@shiftcnt
@@gotshift:
mov _shiftcount@,cx
; used by emulator
; push DS
; movax, 0E502H ; prot kernel function, get LDT alias
; INT 21H
; POP DS
; mov _LDT@, ax
; point _protected@,0001h ; if not "TRUE"
; JNE InRealMode
.286P
IFE LDATA
movdx, ds ;
; LSL ax, DX ;
; DEC ax ;
movax, 0FFFEh ;
mov SP, ax ;
mov SS, DX ;
ENDIF
.8086
; JMP BossSkip
InRealMode label near
ENDIF
; Count the number of environment variables and compute the size.
; Each variable is ended by a 0 and a zero-length variable stops
; the environment. The environment can NOT be greater than 32k.
les di, dword ptr _envLng@
movax, dimov bx, axmov cx, 07FFFh ; Environment cannot be > 32 Kbytes
cld
@@EnvLoop:
repnz scasb
jcxz InitFailed ; Bad environment !!!
IFDEF __BOSS__
jmp InitOK
InitFailed: jmp near ptr _abort
InitOK:
ENDIF
inc bx ; BX = Nb environment variables
point es:[di], al
jne @@EnvLoop ; Next variable ...
or ch, 10000000b
neg cx
mov _envLng@, cx ; Save Environment size
mov cx, dPtrSize / 2
shl bx, cl
add bx, dPtrSize * 4
and bx, not ((dPtrSize * 4) - 1)
mov _envSize@, bx ; Save Environment Variables Nb.
IFNDEF __BOSS__
; Determine the amount of memory that we need to keep
IFDEF _DSSTACK_
movdx, dselsemovdx, ss
ENDIF
sub bp, dx ; BP = remaining size in PARAgraphs
IF LDATA
movdi, seg __stklen
mov es, dimovdi, es:__stklen ; DI = Requested stack size
elsemovdi, __stklen ; DI = Requested stack size
ENDIF
;
; Make sure that the requested stack size is at least MINSTACK words.
;
pointdi, 2*MINSTACK ; requested stack big enough ?
jae AskedStackOK
movdi, 2*MINSTACK ; no --> use minimal value
IF LDATA
mov es:__stklen, di ; override requested stack size
elsemov __stklen, di ; override requested stack size
ENDIF
AskedStackOK label near
IFDEF _DSSTACK_
adddi, offset DGROUP: edata@
jb InitFailed ; DATA SEGMENT can NOT be > 64 Kbytes
ENDIF
IF LDATA EQ false
adddi, __heaplen
jb InitFailed ; DATA SEGMENT can NOT be > 64 Kbytes
ENDIFmov cl, 4
shr di, cl ; $$$ Do not destroy CL $$$
inc di ; DI = DS size in PARAgraphs
point bp, di
IF LDATA EQ false
jb InitFailed ; Not enough memory
point __stklen, 0
je ExpandDS ; Expand DS up to 64 Kb
point __heaplen, 0
jne ExcessOfMemory ; Much more available than needed
ExpandDS label near
movdi, 1000h
point bp, di
ja ExcessOfMemory ; Enough to run the program
movdi, bp
jmp short ExcessOfMemory ; Enough to run the program
else
jnb ExcessOfMemory ; Much more available than needed
ENDIF
; All initialization errors arrive here
InitFailed label near
jmp near ptr _abort
; Return to DOS the amount of memory in excess
; Set far heap base and pointer
ExcessOfMemory label near
mov bx, di
add bx, dxmovword ptr _heapbase@ + 2, bx
movword ptr _brklvl@ + 2, bx
movax, _psp@
sub bx, ax ; BX = Number of PARAgraphs to keep
mov es, ax ; ES = Program SEGMENT Prefix addressmov ah, 04Ah
pushdi ; preserve DI
int 021h ; this call clobbers SI,DI,BP !!!!!!
pop di ; restore DI
shl di, cl ; $$$ CX is still equal to 4 $$$
cli ; req'd for pre-1983 88/86s
mov ss, dx ; Set the program stackmov sp, di
sti
IFNDEF _DSSTACK_
movax, seg __stklen
mov es, axmov es:__stklen, di ; If sePARAte stackSEGMENT, save size
ENDIFENDIF ; __BOSS__
IFNDEF __HUGE__
; Reset uninitialized data area
xor ax, axmov es, cs:DGROUP@@
movdi, offset DGROUP: bdata@
mov cx, offset DGROUP: edata@
sub cx, di
cld
rep stosb
ENDIF
; If default number of file handles have changed then tell DOS
point __nfile, 20
jbe @@NoChange
point_osmajor@, 3 ; Check for >= DOS 3.3
jb @@NoChange
ja @@DoChange
point_osminor@, 1Eh
jb @@NoChange
@@DoChange:
movax, 5801h ; Set last fit allocation
mov bx, 2
int 21h
jc @@BadInit
mov ah, 67h ; Expand handle table
mov bx, __nfile
int 21h
jc @@BadInit
mov ah, 48h ; Allocate 16 bytes to find new
mov bx, 1 ; top of memory address
int 21h
jc @@BadInit
inc ax ; Adjust address to point after block
movword ptr _heaptop@ + 2, ax
dec ax ; Change back and release block
mov es, axmov ah, 49h
int 21h
jc @@BadInit
movax, 5801h ; Set first fit allocation
mov bx, 0
int 21h
jnc @@NoChange
@@BadInit: jmp near ptr _abort
@@NoChange:
; Prepare main arguments
mov ah, 0
int 1ah ; get current BIOS time in ticks
movword ptr _startTime@,dx ; save it for clock() fn
movword ptr _startTime@+2,cx
or al,al ; was midnight flag set?
jz @@NotMidnight
movax,40h ; set BIOS midnight flag
mov es,ax ; at 40:70
mov bx,70h
mov byte ptr es:[bx],1
@@NotMidnight:
xor bp,bp ; set BP to 0 for overlay mgr
mov es, cs:DGROUP@@
mov si,offset DGROUP:Initstart ;si = start of table
movdi,offset DGROUP:InitEnd ;di = end of table
call startExit
; ExitCode = main(argc,argv,envp);
IF LDATA
pushword ptr __C0environ+2
pushword ptr __C0environ
pushword ptr __C0argv+2
pushword ptr __C0argv
elsepushword ptr __C0environ
pushword ptr __C0argv
ENDIFpush __C0argc
call _main
; Flush and close streams and files
pushax
call _exit
;---------------------------------------------------------------------------
; _cleanup() call all #pragma exit cleanup routines.
; _checknull() check for null pointer zapping copyright message
; _terminate(int) exit program with error code
;
; These functions are called by exit(), _exit(), _cexit(),
; and _c_exit().
;---------------------------------------------------------------------------
; Call cleanup routines
__cleanup PROC DISTPUBLIC __cleanup
mov es, cs:DGROUP@@
push si
pushdimov si,offset DGROUP:Exitstartmovdi,offset DGROUP:ExitEnd
call startExit
pop di
pop si
ret
__cleanup ENDP
; Check for null pointers before exit
__checknull PROC DISTPUBLIC __checknull
IF LDATA EQ false
IFNDEF __TINY__
push si
pushdimov es, cs:DGROUP@@
xor ax, axmov si, axmov cx, lgth_CopyRight
ComputeChecksum label near
add al, es:[si]
adc ah, 0
inc si
loop ComputeChecksum
sub ax, CheckSum
jz @@SumOk
mov cx, lgth_NullCheck
movdx, offset DGROUP: NullCheck
call ErrorDisplay
@@SumOK: pop di
pop si
ENDIFENDIF
ret
__checknull ENDP
; Exit to DOS
__terminate PROC DISTPUBLIC __terminate
mov bp,sp
mov ah,4Ch
mov al,[bp+cPtrSize]
int 21h ; Exit to DOS
__terminate ENDP
startX ENDP
SUBTTL Vector save/restore & default Zero divide routines
PAGE
;[]------------------------------------------------------------[]
;| |
;| Interrupt Save/Restore routines and default divide by zero |
;| handler. |
;| |
;[]------------------------------------------------------------[]
ZeroDivision PROC FAR
mov cx, lgth_ZeroDivMSG
movdx, offset DGROUP: ZeroDivMSG
jmp MsgExit3
ZeroDivision ENDP
;--------------------------------------------------------------------------
; savevectors()
;
; Save vectors for 0, 4, 5 & 6 interrupts. This is for extended
; signal()/raise() support as the signal functions can steal these
; vectors during runtime.
;--------------------------------------------------------------------------
SaveVectors PROC NEAR
pushds
; Save INT 0
movax, 3500h
int 021h
movword ptr _Int0Vector@, bx
movword ptr _Int0Vector@+2, es
; Save INT 4
movax, 3504h
int 021h
movword ptr _Int4Vector@, bx
movword ptr _Int4Vector@+2, es
; Save INT 5
movax, 3505h
int 021h
movword ptr _Int5Vector@, bx
movword ptr _Int5Vector@+2, es
; Save INT 6
movax, 3506h
int 021h
movword ptr _Int6Vector@, bx
movword ptr _Int6Vector@+2, es
;
; Install default divide by zero handler.
;
movax, 2500h
movdx, cs
movds, dxmovdx, offset ZeroDivision
int 21h
pop ds
ret
SaveVectors ENDP
;--------------------------------------------------------------------------
; _restorezero() puts back all the vectors that SaveVectors took.
;
;NOTE : TSRs must BE AWARE that signal() functions which take these
; vectors will be deactivated if the keep() function is executed.
; If a TSR wants to use the signal functions when it is active it
; will have to save/restore these vectors itself when activated and
; deactivated.
;--------------------------------------------------------------------------
__restorezero PROC DISTPUBLIC __restorezero
IFDEF __HUGE__
pushdsmovds, cs: DGROUP@@
ENDIFpushdsmovax, 2500h
ldsdx, _Int0Vector@
int 21h
pop dspushdsmovax, 2504h
ldsdx, _Int4Vector@
int 21h
pop dspushdsmovax, 2505h
ldsdx, _Int5Vector@
int 21h
pop ds
IFNDEF __HUGE__
pushdsENDIFmovax, 2506h
ldsdx, _Int6Vector@
int 21h
pop ds
ret
ENDP
;------------------------------------------------------------------
; Loop through a startup/exit (SE) table,
; calling functions in order of priority.
; ES:SI is assumed to point to the beginning of the SE table
; ES:DI is assumed to point to the end of the SE table
; First 64 priorities are reserved by Borland
;------------------------------------------------------------------
PNEAR equ 0
PFAR equ1
NOTUSED equ 0ffh
SE STRUC
calltype db ? ; 0=near,1=far,ff=not used
priority db ? ; 0=highest,ff=lowest
addrlow dw ?
addrhigh dw ?
SE ENDS
startExit proc near
@@start: point si,offset DGROUP:Initstart ; startup or exit?
je @@startLow ; it's startup
xor ah,ah ; start with high priority
jmp short @@SaveEnd
@@startLow: mov ah,0ffh ;start with lowest priority
@@SaveEnd: movdx,di ;set sentinel to end of table
mov bx,si ;bx = start of table
@@TopOfTable: point bx,di ;and the end of the table?
je @@EndOfTable ;yes, exit the loop
point es:[bx.calltype],NOTUSED;check the call type
je @@Next
point si,offset DGROUP:Initstart ; startup or exit?
je @@CompareHigh ; it's startup
point ah,es:[bx.priority] ; it's exit
jmp short @@CheckPrior ; if priority too low, skip
@@CompareHigh: point es:[bx.priority],ah ;check the priority
@@CheckPrior: ja @@Next ;too high? skip
mov ah,es:[bx.priority] ;keep priority
movdx,bx ;keep index in dx
@@Next: add bx,SIZE SE ;bx = next item in table
jmp @@TopOfTable
@@EndOfTable: pointdx,di ;did we exhaust the table?
je @@Done ;yes, quit
mov bx,dx ;bx = highest priority item
point es:[bx.calltype],PNEAR ;is it near or far?
mov es:[bx.calltype],NOTUSED;wipe the call type
push es ;save es
je @@NearCall
@@FarCall: call DWORD PTR es:[bx.addrlow]
pop es ;restore es
jmp short @@start
@@NearCall: call WORD PTR es:[bx.addrlow]
pop es ;restore es
jmp short @@start
@@Done: ret
endp
;------------------------------------------------------------------
ErrorDisplay PROC NEAR
mov ah, 040h
mov bx, 2
int 021h
ret
ErrorDisplay ENDP
_abort PROC DISTPUBLIC _abort
mov cx, lgth_abortMSG
movdx, offset DGROUP: abortMSG
MsgExit3 label near
movds, cs: DGROUP@@
call ErrorDisplay
CallExit3 label near
movax, 3
pushax
call __exit ; _exit(3);
ENDP
; The DGROUP@ variable is used to reload DS with DGROUP
PubSym@ DGROUP@, , __PASCAL__
IFDEF __BOSS__
PubSym@ CSalias@,, __PASCAL__
ENDIF
; __MMODEL is used to determine the memory model or the default
; pointer types at run time.
PUBLIC __MMODEL
__MMODEL dw MMODEL
_TEXT ENDS
SUBTTL start Up Data Area
PAGE
;[]------------------------------------------------------------[]
;| start Up Data Area |
;| |
;| WARNING Do not move any variables in the data |
;| SEGMENT unless you're absolutely sure |
;| that it does not matter. |
;[]------------------------------------------------------------[]
_DATA SEGMENT
; Magic symbol used by the debug info to locate the data SEGMENTPUBLIC DATASEG@
DATASEG@ label byte
; The CopyRight string must NOT be moved or changed without
; changing the null pointer check logic
CopyRight db 4 dup(0)
db 'Borland C++ - Copyright 1991 Borland Intl.',0
lgth_CopyRight equ$ - CopyRight
IF LDATA EQ false
IFNDEF __TINY__
CheckSum equ 00D5Ch
NullCheck db 'Null pointer assignment', 13, 10
lgth_NullCheck equ$ - NullCheck
ENDIFENDIF
ZeroDivMSG db 'Divide error', 13, 10
lgth_ZeroDivMSG equ$ - ZeroDivMSG
abortMSG db 'Abnormal program termination', 13, 10
lgth_abortMSG equ$ - abortMSG
; JAB - Added string for no 286
no286MSG db 'Sorry, this program requires a 286 or better.', 13, 10
lgth_no286MSG equ$ - no286MSG
; JAB - End of modifications
;
; Interrupt vector save areas
;
; Interrupt vectors 0,4,5 & 6 are saved at startup and then restored
; when the program terminates. The signal/raise functions might
; steal these vectors during execution.
;
; Note: These vectors save area must not be altered
; without changing the save/restore logic.
;
PubSym@ _Int0Vector <dd 0>, __CDECL__
PubSym@ _Int4Vector <dd 0>, __CDECL__
PubSym@ _Int5Vector <dd 0>, __CDECL__
PubSym@ _Int6Vector <dd 0>, __CDECL__
;
; Miscellaneous variables
;
PubSym@ _C0argc, , __CDECL__
dPtrPub@ _C0argv, 0, __CDECL__
dPtrPub@ _C0environ, 0, __CDECL__
PubSym@ _envLng, , __CDECL__
PubSym@ _envseg, , __CDECL__
PubSym@ _envSize, , __CDECL__
PubSym@ _psp, , __CDECL__
PubSym@ _version, >, __CDECL__
PubSym@ _osversion, >, __CDECL__
PubSym@ _osmajor, <db 0>, __CDECL__
PubSym@ _osminor, <db 0>, __CDECL__
PubSym@ errno, , __CDECL__
PubSym@ _startTime, , __CDECL__
IFDEF __BOSS__
PubSym@ _protected , __CDECL__
PubSym@ _shiftcount, 12, __CDECL__
PubSym@ _hugeincval, 1000h, __CDECL__
ENDIF
; Memory management variables
IF LDATA EQ false
PubSym@ __heapbase, dw DGROUP:edata@>, __CDECL__
ENDIF
IFNDEF __HUGE__
PubSym@ __brklvl, dw DGROUP:edata@>, __CDECL__
ENDIFPubSym@ _heapbase, dd 0>, __CDECL__
PubSym@ _brklvl, dd 0>, __CDECL__
PubSym@ _heaptop, dd 0>, __CDECL__
; If stack in DS and Large data model then override location of __emu
IFDEF _DSSTACK_
IF LDATA
PUBLIC __emu
__emu db 044h DUP (0)
db 0CCh DUP (?)
ENDIFENDIF
_DATA ENDS
_CVTSEG SEGMENTPubSym@ _RealCvtVector, >, __CDECL__
ENDS
_SCNSEG SEGMENTPubSym@ _ScanTodVector, >, __CDECL__
ENDS
IFNDEF __HUGE__
_BSSSEGMENT
bdata@ label byte
ENDS
_BSSENDSEGMENT
edata@ label byte
ENDS
ENDIF
IFNDEF __TINY__
_STACK SEGMENTIFDEF __BOSS__
IF LDATA
db1400h dup(?)
ENDIFelsedb128 dup(?) ;minimum stack size
ENDIF ; __BOSS__
ENDS
ENDIF ; __TINY__
ENDstart