NAME c0 PAGE 60,132 ;[]------------------------------------------------------------[] ;| C0.ASM -- Start Up Code | ;| | ;| Turbo-C Run Time Library version 1.0 | ;| | ;| Copyright (c) 1987 by Borland International Inc. | ;| All Rights Reserved. | ;[]------------------------------------------------------------[] INCLUDE RULES.ASI ; Segment and Group declarations _TEXT SEGMENT BYTE PUBLIC 'CODE' _TEXT ENDS _DATA SEGMENT PARA PUBLIC 'DATA' _DATA ENDS _EMUSEG SEGMENT WORD PUBLIC 'DATA' _EMUSEG ENDS _CVTSEG SEGMENT WORD PUBLIC 'DATA' _CVTSEG ENDS _SCNSEG SEGMENT WORD PUBLIC 'DATA' _SCNSEG ENDS _BSS SEGMENT WORD PUBLIC 'BSS' _BSS ENDS _BSSEND SEGMENT BYTE PUBLIC 'BSSEND' _BSSEND ENDS IFNDEF __TINY__ _STACK SEGMENT STACK 'STACK' _STACK ENDS ENDIF IF LDATA DGROUP GROUP _DATA, _EMUSEG, _CVTSEG, _SCNSEG, _BSS, _BSSEND ELSE IFNDEF __TINY__ DGROUP GROUP _DATA, _EMUSEG, _CVTSEG, _SCNSEG, _BSS, _BSSEND, _STACK ELSE DGROUP GROUP _TEXT, _DATA, _EMUSEG, _CVTSEG, _SCNSEG, _BSS, _BSSEND ENDIF ENDIF ASSUME CS:_TEXT, DS:DGROUP ; External References ExtProc@ main, __CDECL__ ExtProc@ _setargv, __CDECL__ ExtProc@ _setenvp, __CDECL__ ExtProc@ exit, __CDECL__ ExtSym@ _stklen, WORD, __CDECL__ ExtSym@ _emufak, ABS, __CDECL__ SUBTTL Start Up Code PAGE ;/* */ ;/*-----------------------------------------------------*/ ;/* */ ;/* Start Up Code */ ;/* ------------- */ ;/* */ ;/*-----------------------------------------------------*/ ;/* */ PSPHigh equ 00002h PSPEnv equ 0002ch PSPCmd equ 00080h MINSTACK equ 128 ; ; 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 ; Sometimes the compiler needs to load the DS register with the ; DGROUP value. In TINY model the DGROUP symbol cannot appear, ; otherwise it becomes impossible to EXE2BIN the .EXE file. For this ; reason, the DGROUP is saved in a variable of the code segment. IFDEF __TINY__ mov dx, cs ; DX = GROUP Segment address ELSE mov dx, DGROUP ; DX = GROUP Segment address ENDIF mov cs:DGROUP@@, dx ; Save general information, such as : ; DOS version number ; Program Segment Prefix ; Environment address ; Top of far heap 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 ; 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. mov es, bx xor ax, ax mov cx, 07FFFh ; Environment cannot be > 32 Kbytes mov di, ax mov bx, ax IsIt87Var label near cmp word ptr es:[di], '78' jne GetEnvLng mov dx, es:[di+2] cmp dl, '=' jne GetEnvLng and dh, not ' ' inc _8087@ cmp dh, 'Y' jne GetEnvLng inc _8087@ GetEnvLng 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 add bx, 7 and bx, not 3 shl bx, 1 IF LDATA shl bx, 1 ENDIF mov _envSize@, bx ; Save Environment Variables Nb. ; Capture "Divide overflow" interrupt push ds mov ax, 03500h int 021h mov word ptr ZeroDivVector, bx mov word ptr ZeroDivVector+2, es mov ax, 02500h push cs pop ds mov dx, offset ZeroDivision int 021h pop ds ; Install floating point software IFNDEF __NOFLOAT push cs call word ptr ds:[__emu1st] ENDIF ; Adjust _stklen if necessary IFDEF __HUGE__ mov di, seg _stklen@ mov es, di mov di, es:_stklen@ ELSE mov di, _stklen@ ENDIF mov bx, MINSTACK * 2 cmp di, bx ja _stklenOk mov di, bx _stklenOk label near ; Determine the amount of memory that we need to keep IF LDATA mov dx, ss mov cl, 4 shr di, cl ; $$$ Do not destroy CL $$$ inc di ; DI = Stack size in paragraphs ELSE mov dx, ds add bx, offset DGROUP: edata@ jb InitFailed ; STACK could not be > 64 Kbytes mov di, 1000h ; DI = Stack size in paragraphs mov cl, 4 ENDIF shr bx, cl ; $$$ Do not destroy CL $$$ inc bx ; MINIMUM needed sub bp, dx cmp bp, di ja ExcessOfMemory ; Much more available than needed xchg bx, di cmp bp, di ja ExcessOfMemory ; Enough to run the program ; 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 int 021h ; Set the program stack shl di, cl ; $$$ CX is still equal to 4 $$$ IF LDATA EQ false mov ss, dx ENDIF mov sp, di ; Prepare main arguments call _setargv@ call _setenvp@ IFNDEF __HUGE__ ; Reset un-initialized datas xor ax, ax mov es, cs:DGROUP@@ mov di, offset DGROUP: bdata@ mov cx, offset DGROUP: edata@ sub cx, di rep stosb 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@ ; Restore "Divide overflow" interrupt vector PubProc@ _exit, __CDECL__ mov ax, 2500h lds dx, ZeroDivVector int 021h ; Set DS to DGROUP mov ds, cs:DGROUP@@ ; Restore interrupt vectors taken by __emu1st IFNDEF __NOFLOAT push cs ;Simulation of a FAR call call word ptr 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 IF LPROG mov al,[bp+4] ELSE mov al,[bp+2] ENDIF mov ah,4Ch int 21h ; Exit to DOS EndProc@ _exit, __CDECL__ STARTX ENDP SUBTTL Miscellaneous PAGE ;[]------------------------------------------------------------[] ;| | ;| Miscellaneous functions | ;| | ;[]------------------------------------------------------------[] ErrorDisplay PROC NEAR mov ah, 040h mov bx, 2 mov ds, cs: DGROUP@@ int 021h ret ErrorDisplay ENDP PubProc@ abort, __CDECL__ mov cx, lgth_abortMSG mov dx, offset DGROUP: abortMSG call ErrorDisplay CallExit3 label near mov ax, 3 push ax call _exit@ ; _exit(3); EndProc@ abort, __CDECL__ ZeroDivision PROC FAR mov cx, lgth_ZeroDivMSG mov dx, offset DGROUP: ZeroDivMSG call ErrorDisplay jmp short CallExit3 ZeroDivision ENDP ; The DGROUP@ variable is used to reaload DS with DGROUP PubSym@ DGROUP@, , __PASCAL__ _TEXT ENDS SUBTTL Start Up Datas PAGE ;/* */ ;/*-----------------------------------------------------*/ ;/* */ ;/* Start Up Data */ ;/* -------------- */ ;/* */ ;/*-----------------------------------------------------*/ ;/* */ _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) 1987 Borland Intl.',0 lgth_CopyRight equ $ - CopyRight IF LDATA EQ false IFNDEF __TINY__ Checksum equ 00D36h 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 ; Miscellaneous variables ZeroDivVector dd 0 PubSym@ __argc, , __CDECL__ dPtrPub@ __argv, 0, __CDECL__ dPtrPub@ environ, 0, __CDECL__ PubSym@ _envLng, , __CDECL__ PubSym@ _envseg, , __CDECL__ PubSym@ _envSize, , __CDECL__ PubSym@ _psp, , __CDECL__ PubSym@ _version,