dos_compilers/Borland Turbo C v2/C0.ASM
2024-07-02 06:22:27 -07:00

671 lines
21 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

NAME c0
PAGE 60,132
;[]------------------------------------------------------------[]
;| C0.ASM -- Start Up Code |
;| |
;| Turbo-C Run Time Library version 2.0 |
;| |
;| Copyright (c) 1988 by Borland International Inc. |
;| All Rights Reserved. |
;[]------------------------------------------------------------[]
INCLUDE RULES.ASI
_Strict87_ equ false ; emulation skips peculiar details
; Segment and Group declarations
_TEXT SEGMENT BYTE PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT PARA PUBLIC 'DATA'
_DATA ENDS
IFNDEF __NOFLOAT__
_EMUSEG SEGMENT WORD COMMON 'DATA'
_EMUSEG ENDS
ENDIF
_CRTSEG SEGMENT WORD COMMON 'DATA'
_CRTSEG ENDS
_CVTSEG SEGMENT WORD PUBLIC 'DATA'
_CVTSEG ENDS
_SCNSEG SEGMENT WORD PUBLIC 'DATA'
_SCNSEG ENDS
IFNDEF __HUGE__
_BSS SEGMENT WORD PUBLIC 'BSS'
_BSS ENDS
_BSSEND SEGMENT BYTE PUBLIC 'STACK'
_BSSEND ENDS
ENDIF
IFNDEF __TINY__
_STACK SEGMENT STACK 'STACK'
_STACK ENDS
ENDIF
IFNDEF __NOFLOAT__
IF LDATA
IFNDEF __HUGE__
DGROUP GROUP _DATA, _EMUSEG, _CRTSEG, _CVTSEG, _SCNSEG, _BSS, _BSSEND
ELSE
DGROUP GROUP _DATA, _EMUSEG, _CRTSEG, _CVTSEG, _SCNSEG
ENDIF
ELSE
IFNDEF __TINY__
DGROUP GROUP _DATA, _EMUSEG, _CRTSEG, _CVTSEG, _SCNSEG, _BSS, _BSSEND
ELSE
DGROUP GROUP _TEXT, _DATA, _EMUSEG, _CRTSEG, _CVTSEG, _SCNSEG, _BSS, _BSSEND
ENDIF
ENDIF
ELSE
IF LDATA
IFNDEF __HUGE__
DGROUP GROUP _DATA, _CRTSEG, _CVTSEG, _SCNSEG, _BSS, _BSSEND
ELSE
DGROUP GROUP _DATA, _CRTSEG, _CVTSEG, _SCNSEG
ENDIF
ELSE
IFNDEF __TINY__
DGROUP GROUP _DATA, _CRTSEG, _CVTSEG, _SCNSEG, _BSS, _BSSEND
ELSE
DGROUP GROUP _TEXT, _DATA, _CRTSEG, _CVTSEG, _SCNSEG, _BSS, _BSSEND
ENDIF
ENDIF
ENDIF
ASSUME CS:_TEXT, DS:DGROUP
; External References
ExtProc@ main, __CDECL__
ExtProc@ _setargv, __CDECL__
ExtProc@ _setenvp, __CDECL__
ExtProc@ exit, __CDECL__
IF LDATA EQ false
ExtSym@ _heaplen, WORD, __CDECL__
ENDIF
ExtSym@ _stklen, WORD, __CDECL__
SUBTTL Start Up Code
PAGE
;/* */
;/*-----------------------------------------------------*/
;/* */
;/* Start Up Code */
;/* ------------- */
;/* */
;/*-----------------------------------------------------*/
;/* */
PSPHigh equ 00002h
PSPEnv equ 0002ch
PSPCmd equ 00080h
IFDEF __NOFLOAT__
MINSTACK equ 128 ; minimal stack size in words
ELSE
MINSTACK equ 256 ; minimal stack size in words
ENDIF
;
; At the start, DS and ES both point to the segment prefix.
; SS points to the stack segment except in TINY model where
; SS is equal to CS
;
_TEXT SEGMENT
IFDEF __TINY__
ORG 100h
ENDIF
STARTX PROC NEAR
; Save general information, such as :
; DGROUP segment address
; DOS version number
; Program Segment Prefix address
; Environment address
; Top of far heap
IFDEF __TINY__
mov dx, cs ; DX = GROUP Segment address
ELSE
mov dx, DGROUP ; DX = GROUP Segment address
ENDIF
mov cs:DGROUP@@, dx
mov ah, 30h
int 21h
mov bp, ds:[PSPHigh]; BP = Highest Memory Segment Addr
mov bx, ds:[PSPEnv] ; BX = Environment Segment address
mov ds, dx
mov _version@, ax ; Keep major and minor version number
mov _psp@, es ; Keep Program Segment Prefix address
mov _envseg@, bx ; Keep Environment Segment address
mov word ptr _heaptop@ + 2, bp
mov _8087@, -1
;
; Save several vectors and install default divide by zero handler.
;
call SaveVectors
; Look for a '87' environment variable, and use this loop to
; count the number of environment variables and to compute the
; environment 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@
mov ax, di
mov bx, ax
mov cx, 07FFFh ; Environment cannot be > 32 Kbytes
IsIt87Var label near
cmp word ptr es:[di], '78'
jne GetVarLng
mov dx, es:[di+2]
cmp dl, '='
jne GetVarLng
and dh, not ' '
inc _8087@
cmp dh, 'Y'
jne GetVarLng
inc _8087@
GetVarLng label near
repnz scasb
jcxz InitFailed ; Bad environment !!!
inc bx ; BX = Nb environment variables
cmp es:[di], al
jne IsIt87Var ; 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.
; Determine the amount of memory that we need to keep
IF LDATA
mov dx, ss
sub bp, dx ; BP = remaining size in paragraphs
IFDEF __HUGE__
mov di, seg _stklen@
mov es, di
mov di, es:_stklen@ ; DI = Requested stack size
ELSE
mov di, _stklen@ ; DI = Requested stack size
ENDIF
;
; Make sure that the requested stack size is at least MINSTACK words.
;
cmp di, 2*MINSTACK ; requested stack big enough ?
jae AskedStackOK
mov di, 2*MINSTACK ; no --> use minimal value
IFDEF __HUGE__
mov es:_stklen@, di ; override requested stack size
ELSE
mov _stklen@, di ; override requested stack size
ENDIF
AskedStackOK label near
mov cl, 4
shr di, cl ; $$$ Do not destroy CL $$$
inc di ; DI = Stack size in paragraphs
cmp bp, di
jnb ExcessOfMemory ; Much more available than needed
ELSE
mov dx, ds
sub bp, dx ; BP = remaining size in paragraphs
mov di, _stklen@ ; DI = Requested stack size
;
; Make sure that the requested stack size is at least MINSTACK words.
;
cmp di, 2*MINSTACK ; requested stack big enough ?
jae AskedStackOK
mov di, 2*MINSTACK ; no --> use minimal value
mov _stklen@, di ; override requested stack size
AskedStackOK label near
add di, offset DGROUP: edata@
jb InitFailed ; DATA segment can NOT be > 64 Kbytes
add di, _heaplen@
jb InitFailed ; DATA segment can NOT be > 64 Kbytes
mov cl, 4
shr di, cl ; $$$ Do not destroy CL $$$
inc di ; DI = DS size in paragraphs
cmp bp, di
jb InitFailed ; Not enough memory
cmp _stklen@, 0
je ExpandDS ; Expand DS up to 64 Kb
cmp _heaplen@, 0
jne ExcessOfMemory ; Much more available than needed
ExpandDS label near
mov di, 1000h
cmp bp, di
ja ExcessOfMemory ; Enough to run the program
mov di, bp
jmp short ExcessOfMemory ; Enough to run the program
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, dx
mov word ptr _heapbase@ + 2, bx
mov word ptr _brklvl@ + 2, bx
mov ax, _psp@
sub bx, ax ; BX = Number of paragraphs to keep
mov es, ax ; ES = Program Segment Prefix address
mov ah, 04Ah
push di ; preserve DI
int 021h ; this call clobbers SI,DI,BP !!!!!!
pop di ; restore DI
;
; Set the program stack. Take care to prevent the disastrous
; interrupt that could happen with a stack that is half switched.
;
shl di, cl ; $$$ CX is still equal to 4 $$$
cli
mov ss, dx
mov sp, di
sti
IFNDEF __HUGE__
; Reset uninitialized data area
xor ax, ax
mov es, cs:DGROUP@@
mov di, offset DGROUP: bdata@
mov cx, offset DGROUP: edata@
sub cx, di
rep stosb
ENDIF
IFNDEF __NOFLOAT__
; Install floating point software
push cs ;Simulation of a FAR call
call ds:[__emu1st]
ENDIF
; Prepare main arguments
call _setargv@
call _setenvp@
mov ah, 0
int 1ah ; get current BIOS time in ticks
mov word ptr _StartTime@,dx ; save it for clock() fn
mov word ptr _StartTime@+2,cx
IFNDEF __OLDCONIO__
IF LPROG
push cs ; Simulation of a FAR call
ENDIF
call ds:[__crt1st] ; Initialize window sizes, etc.
ENDIF
; ExitCode = main(argc,argv,envp);
IF LDATA
push word ptr environ@+2
push word ptr environ@
push word ptr _argv@+2
push word ptr _argv@
ELSE
push word ptr environ@
push word ptr _argv@
ENDIF
push _argc@
call main@
; Flush and close streams and files
push ax
call exit@
;---------------------------------------------------------------------------
; _exit()
;
; Restore interrupt vectors taken during startup. signal() functions
; could have grabbed vectors 0, 4, 5 or 6.
;
; Check for NULL pointer errors.
;
; Exit to DOS.
;
;NOTE : _exit() doesn't close any files or run exit functions. This is a
; minimal 'cleanup & quit' program exit.
;---------------------------------------------------------------------------
PubProc@ _exit, __CDECL__
mov ds, cs:DGROUP@@
IF LPROG
call far ptr _restorezero@ ; restore captured INT vectors
ELSE
call near ptr _restorezero@
ENDIF
IFNDEF __NOFLOAT__
; Restore interrupt vectors taken by __emu1st
push cs ;Simulation of a FAR call
call ds:[__emuLast]
ENDIF
IF LDATA EQ false
IFNDEF __TINY__
; Check for null pointers before exit
xor ax, ax
mov si, ax
mov cx, lgth_CopyRight
cld
ComputeChecksum label near
add al, [si]
adc ah, 0
inc si
loop ComputeChecksum
sub ax, CheckSum
jz ExitToDOS
mov cx, lgth_NullCheck
mov dx, offset DGROUP: NullCheck
call ErrorDisplay
ENDIF
ENDIF
; Exit to DOS
ExitToDOS label near
mov bp,sp
mov ah,4Ch
mov al,[bp+cPtrSize]
int 21h ; Exit to DOS
EndProc@ _exit, __CDECL__
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
mov dx, 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
push ds
; Save INT 0
mov ax, 3500h
int 021h
mov word ptr _Int0Vector@, bx
mov word ptr _Int0Vector@+2, es
; Save INT 4
mov ax, 3504h
int 021h
mov word ptr _Int4Vector@, bx
mov word ptr _Int4Vector@+2, es
; Save INT 5
mov ax, 3505h
int 021h
mov word ptr _Int5Vector@, bx
mov word ptr _Int5Vector@+2, es
; Save INT 6
mov ax, 3506h
int 021h
mov word ptr _Int6Vector@, bx
mov word ptr _Int6Vector@+2, es
;
; Install default divide by zero handler.
;
mov ax, 2500h
mov dx, cs
mov ds, dx
mov dx, 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.
;--------------------------------------------------------------------------
PubProc@ _restorezero, __CDECL__
IFDEF __HUGE__
push ds
mov ds, cs: DGROUP@@
ENDIF
push ds
mov ax, 2500h
lds dx, _Int0Vector@
int 21h
pop ds
push ds
mov ax, 2504h
lds dx, _Int4Vector@
int 21h
pop ds
push ds
mov ax, 2505h
lds dx, _Int5Vector@
int 21h
pop ds
IFNDEF __HUGE__
push ds
ENDIF
mov ax, 2506h
lds dx, _Int6Vector@
int 21h
pop ds
ret
EndProc@ _restorezero, __CDECL__
SUBTTL Miscellaneous
PAGE
;[]------------------------------------------------------------[]
;| |
;| Miscellaneous functions |
;| |
;[]------------------------------------------------------------[]
IFNDEF __NOFLOAT__
NoEmulator PROC FAR
mov _8087@, 0
ret
NoEmulator ENDP
ENDIF
IFNDEF __OLDCONIO__
Proc@ NoConsole, __CDECL__
ret
EndProc@ NoConsole, __CDECL__
ENDIF
ErrorDisplay PROC NEAR
mov ah, 040h
mov bx, 2
int 021h
ret
ErrorDisplay ENDP
PubProc@ abort, __CDECL__
mov cx, lgth_abortMSG
mov dx, offset DGROUP: abortMSG
MsgExit3 label near
mov ds, cs: DGROUP@@
call ErrorDisplay
CallExit3 label near
mov ax, 3
push ax
call _exit@ ; _exit(3);
EndProc@ abort, __CDECL__
; The DGROUP@ variable is used to reload DS with DGROUP
PubSym@ DGROUP@, <dw ?>, __PASCAL__
_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
; The CopyRight string must NOT be moved or changed without
; changing the null pointer check logic
CopyRight db 4 dup(0)
db 'Turbo-C - Copyright (c) 1988 Borland Intl.',0
lgth_CopyRight equ $ - CopyRight
IF LDATA EQ false
IFNDEF __TINY__
CheckSum equ 00D37h
NullCheck db 'Null pointer assignment', 13, 10
lgth_NullCheck equ $ - NullCheck
ENDIF
ENDIF
ZeroDivMSG db 'Divide error', 13, 10
lgth_ZeroDivMSG equ $ - ZeroDivMSG
abortMSG db 'Abnormal program termination', 13, 10
lgth_abortMSG equ $ - abortMSG
;
; 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.
;
PubSym@ _Int0Vector <dd 0>, __CDECL__
PubSym@ _Int4Vector <dd 0>, __CDECL__
PubSym@ _Int5Vector <dd 0>, __CDECL__
PubSym@ _Int6Vector <dd 0>, __CDECL__
;
; Miscellaneous variables
;
PubSym@ _argc, <dw 0>, __CDECL__
dPtrPub@ _argv, 0, __CDECL__
dPtrPub@ environ, 0, __CDECL__
PubSym@ _envLng, <dw 0>, __CDECL__
PubSym@ _envseg, <dw 0>, __CDECL__
PubSym@ _envSize, <dw 0>, __CDECL__
PubSym@ _psp, <dw 0>, __CDECL__
PubSym@ _version, <label word>, __CDECL__
PubSym@ _osmajor, <db 0>, __CDECL__
PubSym@ _osminor, <db 0>, __CDECL__
PubSym@ errno, <dw 0>, __CDECL__
PubSym@ _8087, <dw 0>, __CDECL__
PubSym@ _StartTime, <dw 0,0>, __CDECL__
; Memory management variables
IF LDATA EQ false
PubSym@ __heapbase, <dw DGROUP:edata@>, __CDECL__
PubSym@ __brklvl, <dw DGROUP:edata@>, __CDECL__
PubSym@ __heaptop, <dw DGROUP:edata@>, __CDECL__
ENDIF
PubSym@ _heapbase, <dd 0>, __CDECL__
PubSym@ _brklvl, <dd 0>, __CDECL__
PubSym@ _heaptop, <dd 0>, __CDECL__
IF LDATA EQ false
IFNDEF __NOFLOAT__
; Emulator variables
INCLUDE emuvars.asi
ENDIF
ENDIF
_DATA ENDS
IFNDEF __NOFLOAT__
_EMUSEG SEGMENT
__emu1st dw NoEmulator
__emuLast dw NoEmulator
_EMUSEG ENDS
ENDIF
IFNDEF __OLDCONIO__
_CRTSEG SEGMENT
__crt1st dw NoConsole@
_CRTSEG ENDS
ENDIF
_CVTSEG SEGMENT
PubSym@ _RealCvtVector, <label word>, __CDECL__
_CVTSEG ENDS
_SCNSEG SEGMENT
PubSym@ _ScanTodVector, <label word>, __CDECL__
_SCNSEG ENDS
IFNDEF __HUGE__
_BSS SEGMENT
bdata@ label byte
_BSS ENDS
_BSSEND SEGMENT
edata@ label byte
_BSSEND ENDS
ENDIF
IFNDEF __TINY__
_STACK SEGMENT
dw 64 dup (?)
IF LDATA
org 0
IFNDEF __NOFLOAT__
; Emulator variables
INCLUDE emuvars.asi
even
ENDIF
PUBLIC emuTop@ ; for use in stack-underflow checks.
emuTop@ label byte
ENDIF
_STACK ENDS
ENDIF
END STARTX