4 ;[]------------------------------------------------------------[]
\r
5 ;| C0.ASM -- Start Up Code |
\r
7 ;| Turbo C++ Run Time Library |
\r
9 ;| Copyright (c) 1987, 1991 by Borland International Inc. |
\r
10 ;| All Rights Reserved. |
\r
11 ;[]------------------------------------------------------------[]
\r
16 ; Segment and Group declarations
\r
18 _TEXT SEGMENT BYTE PUBLIC 'CODE'
\r
20 _FARDATA SEGMENT PARA PUBLIC 'FAR_DATA'
\r
22 _FARBSS SEGMENT PARA PUBLIC 'FAR_BSS'
\r
25 _OVERLAY_ SEGMENT PARA PUBLIC 'OVRINFO'
\r
27 _1STUB_ SEGMENT PARA PUBLIC 'STUBSEG'
\r
30 _DATA SEGMENT PARA PUBLIC 'DATA'
\r
32 _INIT_ SEGMENT WORD PUBLIC 'INITDATA'
\r
33 InitStart label byte
\r
35 _INITEND_ SEGMENT BYTE PUBLIC 'INITDATA'
\r
38 _EXIT_ SEGMENT WORD PUBLIC 'EXITDATA'
\r
39 ExitStart label byte
\r
41 _EXITEND_ SEGMENT BYTE PUBLIC 'EXITDATA'
\r
44 _CVTSEG SEGMENT WORD PUBLIC 'DATA'
\r
46 _SCNSEG SEGMENT WORD PUBLIC 'DATA'
\r
49 _BSS SEGMENT WORD PUBLIC 'BSS'
\r
51 _BSSEND SEGMENT BYTE PUBLIC 'BSSEND'
\r
55 _STACK SEGMENT STACK 'STACK'
\r
59 ASSUME CS:_TEXT, DS:DGROUP
\r
61 ; External References
\r
67 extrn __setupio:near ;required!
\r
70 extrn __heaplen:word
\r
73 SUBTTL Start Up Code
\r
76 ;/*-----------------------------------------------------*/
\r
78 ;/* Start Up Code */
\r
79 ;/* ------------- */
\r
81 ;/*-----------------------------------------------------*/
\r
93 MINSTACK equ 128 ; minimal stack size in words
\r
95 MINSTACK equ 256 ; minimal stack size in words
\r
98 ; At the start, DS and ES both point to the segment prefix.
\r
99 ; SS points to the stack segment except in TINY model where
\r
100 ; SS is equal to CS
\r
107 ; Save general information, such as :
\r
108 ; DGROUP segment address
\r
109 ; DOS version number
\r
110 ; Program Segment Prefix address
\r
111 ; Environment address
\r
115 mov dx, cs ; DX = GROUP Segment address
\r
117 mov dx, DGROUP ; DX = GROUP Segment address
\r
120 mov cs:DGROUP@@, dx ; __BOSS__
\r
123 int 21h ; get DOS version number
\r
124 mov bp, ds:[PSPHigh]; BP = Highest Memory Segment Addr
\r
125 mov bx, ds:[PSPEnv] ; BX = Environment Segment address
\r
127 mov _version@, ax ; Keep major and minor version number
\r
128 mov _psp@, es ; Keep Program Segment Prefix address
\r
129 mov _envseg@, bx ; Keep Environment Segment address
\r
130 mov word ptr _heaptop@ + 2, bp
\r
132 ; Save several vectors and install default divide by zero handler.
\r
136 ;===================
\r
138 ; IDsoft - Check to make sure that we're running on a 286 or better
\r
140 pushf ; Save original flags
\r
141 xor ax,ax ; Clear AX
\r
143 popf ; Try to pop the 0
\r
145 pop ax ; Get results of popping 0 into flags
\r
146 popf ; Restore original flags
\r
149 ;jns @@Have286 ; If no sign bit, have a 286
\r
152 mov cx, lgth_no286MSG
\r
153 mov dx, offset DGROUP: no286MSG
\r
157 ; IDsoft - End of modifications (there's also a code segment string)
\r
159 ;===================
\r
162 ; Determine if in real mode
\r
163 mov ax,0FB42h ; find out if DPMI loader is here
\r
164 mov bx,1 ; get info function
\r
168 mov ax, cs ; now, save DGROUP
\r
172 mov es:DGROUP@@, dx ;
\r
173 mov es:CSalias@@, ax ;
\r
176 ; cmp ax,0001h ; if not "TRUE"
\r
179 ; 8 is the value of the alias selector
\r
181 MOV _protected@, cx
\r
182 MOV _hugeincval@, cx
\r
194 mov _shiftcount@,cx
\r
198 ; MOV AX, 0E502H ; prot kernel function, get LDT alias
\r
203 ; cmp _protected@,0001h ; if not "TRUE"
\r
218 InRealMode label near
\r
222 ; Count the number of environment variables and compute the size.
\r
223 ; Each variable is ended by a 0 and a zero-length variable stops
\r
224 ; the environment. The environment can NOT be greater than 32k.
\r
226 les di, dword ptr _envLng@
\r
229 mov cx, 07FFFh ; Environment cannot be > 32 Kbytes
\r
233 jcxz InitFailed ; Bad environment !!!
\r
236 InitFailed: jmp near ptr _abort
\r
240 inc bx ; BX = Nb environment variables
\r
242 jne @@EnvLoop ; Next variable ...
\r
245 mov _envLng@, cx ; Save Environment size
\r
246 mov cx, dPtrSize / 2
\r
248 add bx, dPtrSize * 4
\r
249 and bx, not ((dPtrSize * 4) - 1)
\r
250 mov _envSize@, bx ; Save Environment Variables Nb.
\r
254 ; Determine the amount of memory that we need to keep
\r
261 sub bp, dx ; BP = remaining size in paragraphs
\r
263 mov di, seg __stklen
\r
265 mov di, es:__stklen ; DI = Requested stack size
\r
267 mov di, __stklen ; DI = Requested stack size
\r
270 ; Make sure that the requested stack size is at least MINSTACK words.
\r
272 cmp di, 2*MINSTACK ; requested stack big enough ?
\r
274 mov di, 2*MINSTACK ; no --> use minimal value
\r
276 mov es:__stklen, di ; override requested stack size
\r
278 mov __stklen, di ; override requested stack size
\r
281 AskedStackOK label near
\r
283 add di, offset DGROUP: edata@
\r
284 jb InitFailed ; DATA segment can NOT be > 64 Kbytes
\r
288 jb InitFailed ; DATA segment can NOT be > 64 Kbytes
\r
291 shr di, cl ; $$$ Do not destroy CL $$$
\r
292 inc di ; DI = DS size in paragraphs
\r
295 jb InitFailed ; Not enough memory
\r
297 je ExpandDS ; Expand DS up to 64 Kb
\r
299 jne ExcessOfMemory ; Much more available than needed
\r
300 ExpandDS label near
\r
303 ja ExcessOfMemory ; Enough to run the program
\r
305 jmp short ExcessOfMemory ; Enough to run the program
\r
307 jnb ExcessOfMemory ; Much more available than needed
\r
310 ; All initialization errors arrive here
\r
312 InitFailed label near
\r
313 jmp near ptr _abort
\r
315 ; Return to DOS the amount of memory in excess
\r
316 ; Set far heap base and pointer
\r
318 ExcessOfMemory label near
\r
321 mov word ptr _heapbase@ + 2, bx
\r
322 mov word ptr _brklvl@ + 2, bx
\r
324 sub bx, ax ; BX = Number of paragraphs to keep
\r
325 mov es, ax ; ES = Program Segment Prefix address
\r
327 push di ; preserve DI
\r
328 int 021h ; this call clobbers SI,DI,BP !!!!!!
\r
329 pop di ; restore DI
\r
331 shl di, cl ; $$$ CX is still equal to 4 $$$
\r
333 cli ; req'd for pre-1983 88/86s
\r
334 mov ss, dx ; Set the program stack
\r
339 mov ax, seg __stklen
\r
341 mov es:__stklen, di ; If separate stack segment, save size
\r
348 ; Reset uninitialized data area
\r
351 mov es, cs:DGROUP@@
\r
352 mov di, offset DGROUP: bdata@
\r
353 mov cx, offset DGROUP: edata@
\r
359 ; If default number of file handles have changed then tell DOS
\r
363 cmp _osmajor@, 3 ; Check for >= DOS 3.3
\r
369 mov ax, 5801h ; Set last fit allocation
\r
374 mov ah, 67h ; Expand handle table
\r
379 mov ah, 48h ; Allocate 16 bytes to find new
\r
380 mov bx, 1 ; top of memory address
\r
383 inc ax ; Adjust address to point after block
\r
384 mov word ptr _heaptop@ + 2, ax
\r
386 dec ax ; Change back and release block
\r
392 mov ax, 5801h ; Set first fit allocation
\r
397 @@BadInit: jmp near ptr _abort
\r
401 ; Prepare main arguments
\r
404 int 1ah ; get current BIOS time in ticks
\r
405 mov word ptr _StartTime@,dx ; save it for clock() fn
\r
406 mov word ptr _StartTime@+2,cx
\r
407 or al,al ; was midnight flag set?
\r
409 mov ax,40h ; set BIOS midnight flag
\r
410 mov es,ax ; at 40:70
\r
412 mov byte ptr es:[bx],1
\r
415 xor bp,bp ; set BP to 0 for overlay mgr
\r
417 mov es, cs:DGROUP@@
\r
418 mov si,offset DGROUP:InitStart ;si = start of table
\r
419 mov di,offset DGROUP:InitEnd ;di = end of table
\r
422 ; ExitCode = main(argc,argv,envp);
\r
425 push word ptr __C0environ+2
\r
426 push word ptr __C0environ
\r
427 push word ptr __C0argv+2
\r
428 push word ptr __C0argv
\r
430 push word ptr __C0environ
\r
431 push word ptr __C0argv
\r
436 ; Flush and close streams and files
\r
441 ;---------------------------------------------------------------------------
\r
442 ; _cleanup() call all #pragma exit cleanup routines.
\r
443 ; _checknull() check for null pointer zapping copyright message
\r
444 ; _terminate(int) exit program with error code
\r
446 ; These functions are called by exit(), _exit(), _cexit(),
\r
448 ;---------------------------------------------------------------------------
\r
450 ; Call cleanup routines
\r
452 __cleanup PROC DIST
\r
455 mov es, cs:DGROUP@@
\r
458 mov si,offset DGROUP:ExitStart
\r
459 mov di,offset DGROUP:ExitEnd
\r
466 ; Check for null pointers before exit
\r
468 __checknull PROC DIST
\r
475 mov es, cs:DGROUP@@
\r
478 mov cx, lgth_CopyRight
\r
479 ComputeChecksum label near
\r
483 loop ComputeChecksum
\r
486 mov cx, lgth_NullCheck
\r
487 mov dx, offset DGROUP: NullCheck
\r
498 __terminate PROC DIST
\r
502 mov al,[bp+cPtrSize]
\r
503 int 21h ; Exit to DOS
\r
508 SUBTTL Vector save/restore & default Zero divide routines
\r
510 ;[]------------------------------------------------------------[]
\r
512 ;| Interrupt Save/Restore routines and default divide by zero |
\r
515 ;[]------------------------------------------------------------[]
\r
517 ZeroDivision PROC FAR
\r
518 mov cx, lgth_ZeroDivMSG
\r
519 mov dx, offset DGROUP: ZeroDivMSG
\r
523 ;--------------------------------------------------------------------------
\r
526 ; Save vectors for 0, 4, 5 & 6 interrupts. This is for extended
\r
527 ; signal()/raise() support as the signal functions can steal these
\r
528 ; vectors during runtime.
\r
529 ;--------------------------------------------------------------------------
\r
530 SaveVectors PROC NEAR
\r
535 mov word ptr _Int0Vector@, bx
\r
536 mov word ptr _Int0Vector@+2, es
\r
540 mov word ptr _Int4Vector@, bx
\r
541 mov word ptr _Int4Vector@+2, es
\r
545 mov word ptr _Int5Vector@, bx
\r
546 mov word ptr _Int5Vector@+2, es
\r
550 mov word ptr _Int6Vector@, bx
\r
551 mov word ptr _Int6Vector@+2, es
\r
553 ; Install default divide by zero handler.
\r
558 mov dx, offset ZeroDivision
\r
565 ;--------------------------------------------------------------------------
\r
566 ; _restorezero() puts back all the vectors that SaveVectors took.
\r
568 ;NOTE : TSRs must BE AWARE that signal() functions which take these
\r
569 ; vectors will be deactivated if the keep() function is executed.
\r
570 ; If a TSR wants to use the signal functions when it is active it
\r
571 ; will have to save/restore these vectors itself when activated and
\r
573 ;--------------------------------------------------------------------------
\r
574 __restorezero PROC DIST
\r
575 PUBLIC __restorezero
\r
578 mov ds, cs: DGROUP@@
\r
582 lds dx, _Int0Vector@
\r
588 lds dx, _Int4Vector@
\r
594 lds dx, _Int5Vector@
\r
602 lds dx, _Int6Vector@
\r
609 ;------------------------------------------------------------------
\r
610 ; Loop through a startup/exit (SE) table,
\r
611 ; calling functions in order of priority.
\r
612 ; ES:SI is assumed to point to the beginning of the SE table
\r
613 ; ES:DI is assumed to point to the end of the SE table
\r
614 ; First 64 priorities are reserved by Borland
\r
615 ;------------------------------------------------------------------
\r
621 calltype db ? ; 0=near,1=far,ff=not used
\r
622 priority db ? ; 0=highest,ff=lowest
\r
627 StartExit proc near
\r
628 @@Start: cmp si,offset DGROUP:InitStart ; startup or exit?
\r
629 je @@StartLow ; it's startup
\r
630 xor ah,ah ; start with high priority
\r
631 jmp short @@SaveEnd
\r
632 @@StartLow: mov ah,0ffh ;start with lowest priority
\r
633 @@SaveEnd: mov dx,di ;set sentinel to end of table
\r
634 mov bx,si ;bx = start of table
\r
636 @@TopOfTable: cmp bx,di ;and the end of the table?
\r
637 je @@EndOfTable ;yes, exit the loop
\r
638 cmp es:[bx.calltype],NOTUSED;check the call type
\r
640 cmp si,offset DGROUP:InitStart ; startup or exit?
\r
641 je @@CompareHigh ; it's startup
\r
642 cmp ah,es:[bx.priority] ; it's exit
\r
643 jmp short @@CheckPrior ; if priority too low, skip
\r
644 @@CompareHigh: cmp es:[bx.priority],ah ;check the priority
\r
645 @@CheckPrior: ja @@Next ;too high? skip
\r
646 mov ah,es:[bx.priority] ;keep priority
\r
647 mov dx,bx ;keep index in dx
\r
648 @@Next: add bx,SIZE SE ;bx = next item in table
\r
651 @@EndOfTable: cmp dx,di ;did we exhaust the table?
\r
652 je @@Done ;yes, quit
\r
653 mov bx,dx ;bx = highest priority item
\r
654 cmp es:[bx.calltype],PNEAR ;is it near or far?
\r
655 mov es:[bx.calltype],NOTUSED;wipe the call type
\r
659 @@FarCall: call DWORD PTR es:[bx.addrlow]
\r
663 @@NearCall: call WORD PTR es:[bx.addrlow]
\r
670 ;------------------------------------------------------------------
\r
672 ErrorDisplay PROC NEAR
\r
681 mov cx, lgth_abortMSG
\r
682 mov dx, offset DGROUP: abortMSG
\r
683 MsgExit3 label near
\r
684 mov ds, cs: DGROUP@@
\r
686 CallExit3 label near
\r
689 call __exit ; _exit(3);
\r
692 ; The DGROUP@ variable is used to reload DS with DGROUP
\r
694 PubSym@ DGROUP@, <dw ?>, __PASCAL__
\r
697 PubSym@ CSalias@,<dw ?>, __PASCAL__
\r
701 ; __MMODEL is used to determine the memory model or the default
\r
702 ; pointer types at run time.
\r
709 SUBTTL Start Up Data Area
\r
711 ;[]------------------------------------------------------------[]
\r
712 ;| Start Up Data Area |
\r
714 ;| WARNING Do not move any variables in the data |
\r
715 ;| segment unless you're absolutely sure |
\r
716 ;| that it does not matter. |
\r
717 ;[]------------------------------------------------------------[]
\r
721 ; Magic symbol used by the debug info to locate the data segment
\r
723 DATASEG@ label byte
\r
725 ; The CopyRight string must NOT be moved or changed without
\r
726 ; changing the null pointer check logic
\r
728 CopyRight db 4 dup(0)
\r
729 db 'Borland C++ - Copyright 1991 Borland Intl.',0
\r
730 lgth_CopyRight equ $ - CopyRight
\r
734 CheckSum equ 00D5Ch
\r
735 NullCheck db 'Null pointer assignment', 13, 10
\r
736 lgth_NullCheck equ $ - NullCheck
\r
740 ZeroDivMSG db 'Divide error', 13, 10
\r
741 lgth_ZeroDivMSG equ $ - ZeroDivMSG
\r
743 abortMSG db 'Abnormal program termination', 13, 10
\r
744 lgth_abortMSG equ $ - abortMSG
\r
746 ; JAB - Added string for no 286
\r
747 no286MSG db 'Sorry, this program requires a 286 or better.', 13, 10
\r
748 lgth_no286MSG equ $ - no286MSG
\r
749 ; JAB - End of modifications
\r
752 ; Interrupt vector save areas
\r
754 ; Interrupt vectors 0,4,5 & 6 are saved at startup and then restored
\r
755 ; when the program terminates. The signal/raise functions might
\r
756 ; steal these vectors during execution.
\r
758 ; Note: These vectors save area must not be altered
\r
759 ; without changing the save/restore logic.
\r
761 PubSym@ _Int0Vector <dd 0>, __CDECL__
\r
762 PubSym@ _Int4Vector <dd 0>, __CDECL__
\r
763 PubSym@ _Int5Vector <dd 0>, __CDECL__
\r
764 PubSym@ _Int6Vector <dd 0>, __CDECL__
\r
766 ; Miscellaneous variables
\r
768 PubSym@ _C0argc, <dw 0>, __CDECL__
\r
769 dPtrPub@ _C0argv, 0, __CDECL__
\r
770 dPtrPub@ _C0environ, 0, __CDECL__
\r
771 PubSym@ _envLng, <dw 0>, __CDECL__
\r
772 PubSym@ _envseg, <dw 0>, __CDECL__
\r
773 PubSym@ _envSize, <dw 0>, __CDECL__
\r
774 PubSym@ _psp, <dw 0>, __CDECL__
\r
775 PubSym@ _version, <label word>, __CDECL__
\r
776 PubSym@ _osversion, <label word>, __CDECL__
\r
777 PubSym@ _osmajor, <db 0>, __CDECL__
\r
778 PubSym@ _osminor, <db 0>, __CDECL__
\r
779 PubSym@ errno, <dw 0>, __CDECL__
\r
780 PubSym@ _StartTime, <dw 0,0>, __CDECL__
\r
784 PubSym@ _protected <dw 0>, __CDECL__
\r
785 PubSym@ _shiftcount, <dw 12>, __CDECL__
\r
786 PubSym@ _hugeincval, <dw 1000h>, __CDECL__
\r
789 ; Memory management variables
\r
792 PubSym@ __heapbase, <dw DGROUP:edata@>, __CDECL__
\r
795 PubSym@ __brklvl, <dw DGROUP:edata@>, __CDECL__
\r
797 PubSym@ _heapbase, <dd 0>, __CDECL__
\r
798 PubSym@ _brklvl, <dd 0>, __CDECL__
\r
799 PubSym@ _heaptop, <dd 0>, __CDECL__
\r
801 ; If stack in DS and Large data model then override location of __emu
\r
806 __emu db 044h DUP (0)
\r
815 PubSym@ _RealCvtVector, <label word>, __CDECL__
\r
819 PubSym@ _ScanTodVector, <label word>, __CDECL__
\r
839 db 128 dup(?) ;minimum stack size
\r