home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turbo Toolbox
/
Turbo_Toolbox.iso
/
tc20
/
c0.asm
< prev
next >
Wrap
Assembly Source File
|
1988-10-13
|
22KB
|
679 lines
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 ; Der Emulator simuliert nicht
; alle Details des 8087
; Segment- und Group-Deklarationen
_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
; Extern-Bezüge
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
;/* */
;/*-----------------------------------------------------*/
;/* */
;/* Startcode */
;/* --------- */
;/* */
;/*-----------------------------------------------------*/
;/* */
PSPHigh equ 00002h
PSPEnv equ 0002ch
PSPCmd equ 00080h
IFDEF __NOFLOAT__
MINSTACK equ 128 ; Minimal-Stackgröße 0x100 Bytes
ELSE
MINSTACK equ 256 ; Minimal-Stackgröße 0x200 Bytes
ENDIF
;
; Beim Start des Programms zeigen ES und DS auf das PSP.
; SS zeigt auf das Stacksegment (außer im Modell TINY - dort
; sind Stack- und Codesegment identisch)
;
_TEXT SEGMENT
IFDEF __TINY__
ORG 100h
ENDIF
STARTX PROC NEAR
; Sichern allgemeiner Informationen, wie:
; DGROUP-Segmentadresse
; DOS-Versionsnummer
; Programmsegment-Präfix
; Environment-Startadresse
; Obergrenze des Speichers
IFDEF __TINY__
mov dx, cs ; DX = GROUP-Segmentadresse
ELSE
mov dx, DGROUP ; DX = GROUP-Segmentadresse
ENDIF
mov cs:DGROUP@@, dx
mov ah, 30h ; "Get Version Number"
int 21h
mov bp, ds:[PSPHigh]; RamTop -> BP
mov bx, ds:[PSPEnv] ; Environment-Segmentadresse -> BX
mov ds, dx ; DS auf _DATA (bzw. CS für TINY)
mov _version@, ax ; DOS-Version -> globale Variable
mov _psp@, es ; Programmsegment-Präfix
mov _envseg@, bx ; Environment-Segmentadresse
mov word ptr _heaptop@ + 2, bp
mov _8087@, -1
;
; Speichern diverser Interrupt-Vektoren (incl. Division durch 0)
;
call SaveVectors ; INT-Vektoren 0, 4..6
; Suche nach einer Environment-Variablen '87'. In dieser Schleife
; wird gleichzeitig die Anzahl der Einträge und der gesamte Platz-
; bedarf des Environments bestimmt-
; Jeder Eintrag wird mit einem NUL-Zeichen beendet; ein Eintrag
; der Länge 0 markiert das Tabellenende. Die gesamte Tabelle kann
; NICHT größer als 32 KByte sein.
les di, dword ptr _envLng@ ; _envseg:0000
mov ax, di ; = 00
mov bx, ax ; Eintragszähler = 0
mov cx, 07FFFh ; Maximalgröße: 32767 Bytes
IsIt87Var label near
cmp word ptr es:[di], '78' ; umgedreht: "87"
jne GetVarLng ; -> nächste Variable
mov dx, es:[di+2] ; "87" gefunden. Nächstes Zeichen '='?
cmp dl, '='
jne GetVarLng
and dh, not ' ' ; ja! -> Großbuchstaben
inc _8087@ ; _8087 = 0
cmp dh, 'Y' ; folgt ein 'Y'?
jne GetVarLng
inc _8087@ ; ja - _8087 = 1
GetVarLng label near
repnz scasb ; Suche nach NUL-Zeichen
jcxz InitFailed ; Environment > 32 KByte -> Abbruch
inc bx ; Eintragzähler ++
cmp es:[di], al ; zweites NUL-Zeichen?
jne IsIt87Var ; nein, nächster Eintrag
or ch, 10000000b ; = 32768 - CX
neg cx
mov _envLng@, cx ; Environment-Länge
mov cx, dPtrSize / 2 ; Berechnung der Array-Größe:
shl bx, cl ; Eintragszahl * Zeigergröße
add bx, dPtrSize * 4 ; < Aufrundung >
and bx, not ((dPtrSize * 4) - 1)
mov _envSize@, bx ; Anzahl Env.-Einträge
; Wieviel Paragraphs braucht das Programm tatsächlich von DOS?
IF LDATA ; eigenes Stacksegment?
mov dx, ss ; ja: RamTop - Stacksegment
sub bp, dx ; = freier Platz
IFDEF __HUGE__
mov di, seg _stklen@
mov es, di
mov di, es:_stklen@ ; _stklen -> DI
ELSE
mov di, _stklen@ ; dito für COMPACT & LARGE
ENDIF
;
; LDATA: Stackgröße nach unten auf MINSTACK begrenzen
;
cmp di, 2*MINSTACK ; _stklen >= MINSTACK (0x200 Bytes)?
jae AskedStackOK
mov di, 2*MINSTACK ; nein, 0x0200 Bytes einsetzen
IFDEF __HUGE__
mov es:_stklen@, di ; und _stklen neu setzen
ELSE
mov _stklen@, di ; dito für COMPACT & LARGE
ENDIF
AskedStackOK label near
mov cl, 4
shr di, cl ; Stackgröße -> Paragraphs
inc di ; (Aufrundung)
cmp bp, di ; freier Platz > Stackgröße?
jnb ExcessOfMemory ; ja
ELSE ; kein eigenes Stacksegment
mov dx, ds
sub bp, dx ; RamTop - DS -> freier Platz
mov di, _stklen@ ; _stklen -> DI
;
; SMALL DATA: Stackgröße nach unten auf MINSTACK begrenzen
;
cmp di, 2*MINSTACK ; _stklen >= MINSTACK (0x0200 Bytes)?
jae AskedStackOK
mov di, 2*MINSTACK ; nein, 0x0200 Bytes einsetzen
mov _stklen@, di ; und neuer Wert für _stklen
AskedStackOK label near
add di, offset DGROUP: edata@ ; DS-Ende (= _BSSEND)
jb InitFailed ; Oha! DSeg > 64 KBytes
add di, _heaplen@ ; + Heapgröße
jb InitFailed ; -> 64 KBytes
mov cl, 4
shr di, cl ; Umrechnung in Paragraphs
inc di ; (Aufrundung)
cmp bp, di
jb InitFailed ; Nicht genug Speicher!
cmp _stklen@, 0 ; (?? ("never"))
je ExpandDS
cmp _heaplen@, 0 ; Standardvorgabe für _heaplen?
jne ExcessOfMemory ; nein - berechnete Größe setzen
ExpandDS label near
mov di, 1000h ; Vergrößerung DS auf 64 KByte
cmp bp, di ; immer noch genug Platz?
ja ExcessOfMemory ; -> ja
mov di, bp ; nein, Begrenzung
jmp short ExcessOfMemory
ENDIF
; Alle Initialisierungsfehler führen zu einem Sprung hierher
InitFailed label near
jmp near ptr abort@
; Rückgabe der nicht benötigten Segmente an DOS
; Setzen des "Far Heap"-Beginns
ExcessOfMemory label near
mov bx, di ; Größe von Daten- bzw. Stacksegment
add bx, dx ; + Datensegment bzw. Stacksegment
mov word ptr _heapbase@ + 2, bx ; => Beginn des FAR HEAP
mov word ptr _brklvl@ + 2, bx ; => 1. freie Speicherzelle
mov ax, _psp@ ; Programmstart
sub bx, ax ; Prog-Endadresse - PSP = Prog-Größe
mov es, ax ; PSP -> ES (Beginn des Speicherblocks)
mov ah, 04Ah ; "Modify allocated memory"
push di ;
int 021h ; this call clobbers SI,DI,BP !!!!!!
pop di
;
; Setzen des Programmstacks. Falls wir hier in der Mitte unterbrochen
; würden, wären die Ergebnisse katastrophal - deshalb werden Interrupts
; zeitweilig unterdrückt.
;
shl di, cl ; CL enthält immer noch den Wert 4
cli
mov ss, dx ; IF LDATA: DX=_STACK ELSE DX=_DATA
mov sp, di ; DI = Stack-Ende
sti
IFNDEF __HUGE__
; Uninitialisierte Daten ("_BSS") auf 0
xor ax, ax
mov es, cs:DGROUP@@ ; Ziel-Segment: _DATA
mov di, offset DGROUP: bdata@ ; Start: _BSS
mov cx, offset DGROUP: edata@ ; Ende: _BSSEND
sub cx, di
rep stosb ; _BSS-Inhalt auf 0
ENDIF
IFNDEF __NOFLOAT__
; Initialisierung des Emulators
push cs ; Routine _emu1st endet mit RETF
call ds:[__emu1st]
ENDIF
; Vorbereitung der Argumente von main()
call _setargv@ ; PSP.CmdLine -> argv[]
call _setenvp@ ; Environment -> envp[]
mov ah, 0
int 1ah ; "BIOS-Ticks"
mov word ptr _StartTime@,dx ; speichern für clock()
mov word ptr _StartTime@+2,cx
IFNDEF __OLDCONIO__
IF LPROG
push cs ; in den Modellen MEDIUM, LARGE und
; HUGE endet _c0crtinit mit RETF
ENDIF
call ds:[__crt1st] ; Initialisierung von conio
ENDIF
; ExitCode = main(argc,argv,envp);
IF LDATA
push word ptr environ@+2 ; envp und argv als FAR-Zeiger
push word ptr environ@
push word ptr _argv@+2 ; auf den Stack
push word ptr _argv@
ELSE
push word ptr environ@ ; sonst als NEAR-Zeiger
push word ptr _argv@
ENDIF
push _argc@ ; argc als letztes
call main@
; Programmende
push ax ; Ergebnis von main()
call exit@ ; "Aufruf" von exit()
;---------------------------------------------------------------------------
; _exit()
;
; Zurücksetzen der INT-Vektoren 0, 4..6 (von signal())
;
; Prüfung auf NULL-Zeiger
;
; Rücksprung zu DOS
;
;HINWEIS: exit() schließt keine offenen Dateien!
;---------------------------------------------------------------------------
PubProc@ _exit, __CDECL__
mov ds, cs:DGROUP@@
IF LPROG
call far ptr _restorezero@ ; INT-Vektoren zurück
ELSE
call near ptr _restorezero@ ; dito für kleine Codemodelle
ENDIF
IFNDEF __NOFLOAT__
; Emulator-Vektoren zurück
push cs ; _emuLast endet immer mit RETF
call ds:[__emuLast]
ENDIF
IF LDATA EQ false
IFNDEF __TINY__
; Prüfung auf NULL-Zeiger
xor ax, ax
mov si, ax
mov cx, lgth_CopyRight
cld
ComputeChecksum label near ; Aufaddieren von
add al, [si] ; "Turbo-C Copyright Borland..."
adc ah, 0
inc si
loop ComputeChecksum
sub ax, CheckSum
jz ExitToDOS ; Copyright unverändert
mov cx, lgth_NullCheck
mov dx, offset DGROUP: NullCheck
call ErrorDisplay ; "Null pointer assignment"
ENDIF
ENDIF
; Rücksprung zu DOS
ExitToDOS label near
mov bp,sp
mov ah,4Ch ; DOS-Funktionsnummer: Terminate
mov al,[bp+cPtrSize] ; <- Ergebnis von main()
int 21h ; "Terminate Process"
EndProc@ _exit, __CDECL__
STARTX ENDP
SUBTTL Vector save/restore & default Zero divide routines
PAGE
;[]------------------------------------------------------------[]
;| |
;| Speichern/Zurücksetzen von Interrupt-vektoren und die |
;| Standard-Behandlungsroutine für Divisionen durch Null |
;| |
;[]------------------------------------------------------------[]
ZeroDivision PROC FAR
mov cx, lgth_ZeroDivMSG
mov dx, offset DGROUP: ZeroDivMSG
jmp MsgExit3
ZeroDivision ENDP
;--------------------------------------------------------------------------
; savevectors()
;
; Speichert die Vektoren 0, 4, 5 und 6 für die erweiterten Versionen
; signal() und raise(), die diese Vektoren zur Laufzeit belegen können.
;--------------------------------------------------------------------------
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
;
; Installation der Standardroutine für Divisionen durch Null
;
mov ax, 2500h
mov dx, cs
mov ds, dx
mov dx, offset ZeroDivision
int 21h
pop ds
ret
SaveVectors ENDP
;--------------------------------------------------------------------------
; restorezero() setzt alle Interruptvektoren auf die Originale zurück
;
;HINWEIS: TSR-Programme müssen die Vektoren 4..6 selbst speichern, wenn
; sie signal()/raise() verwenden wollen - die entsprechenden
; Vektoren werden von exit bzw. keep zurückgesetzt!
;--------------------------------------------------------------------------
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
;[]------------------------------------------------------------[]
;| |
;| Diverses |
;| |
;[]------------------------------------------------------------[]
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__
; Die Variable DGROUP@ wird ausschließlich zum Setzen von DS
; auf das Datensegment des Programms verwendet
PubSym@ DGROUP@, <dw ?>, __PASCAL__
_TEXT ENDS
SUBTTL Start Up Data Area
PAGE
;[]------------------------------------------------------------[]
;| Datendefinitionen des Startcodes |
;| |
;| WARNUNG Veränderungen und sogar Umstellungen |
;| der Deklarations-Reihenfolge können |
;| hier merkwürdige Effekte zeitigen |
;| |
;[]------------------------------------------------------------[]
_DATA SEGMENT
; CopyRight *muß* an dieser Stelle definiert sein und darf
; nicht verändert werden - sonst klappt die Prüfung via
; exit() nicht mehr.
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
;
; Speicherbereiche für Interrupt-Vektoren
;
; Die Vektoren 0,4,5 & 6 werden beim Programmstart hier gespeichert,
; zur Laufzeit von signal()/raise() verändert bzw. benutzt und und
; via exit() wieder gesetzt.
;
PubSym@ _Int0Vector <dd 0>, __CDECL__
PubSym@ _Int4Vector <dd 0>, __CDECL__
PubSym@ _Int5Vector <dd 0>, __CDECL__
PubSym@ _Int6Vector <dd 0>, __CDECL__
;
; Diverse Variablen
;
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__
; Speicherlayout und -verwaltung
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-Variablen
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-Variablen
INCLUDE emuvars.asi
even
ENDIF
PUBLIC emuTop@ ; für Stack-Unterlauf-Prüfung
emuTop@ label byte
ENDIF
_STACK ENDS
ENDIF
END STARTX