- BORLAND/: Borland C++ 4.52 (chosen over 4.5 by byte-match: CODE/RP/CW32.LIB
is identical to 4.52's install lib). BCC32/TLINK32/TLIB/MAKE run natively on
Win11; CODE/BT/OPT.MAK is the shipped BTL4OPT.EXE's exact flag recipe
(extender = Borland PowerPack DPMI32, not Phar Lap TNT).
- restoration/source410/: the literal 1995-form reconstruction of the missing
BT game source (never mixed into CODE/). Round 1-3 state:
* 6 of 10 surviving original TUs COMPILE CLEAN under the period toolchain
(BTMSSN, BTCNSL, BTSCNRL, BTTEAM, BTL4MODE, BTL4ARND) - first builds
since 1996.
* BT_L4/BTL4APP.CPP pilot reconstruction: 12/12 functions, Fail() lands on
its binary-recorded line 400 exactly.
* BT/BTCNSL.HPP: console wire IDs recovered from the binary's ctors
(Killed=9, Damaged=10, ScoreUpdate=13, DeathWithoutHonor=15 [T1];
TeamScore=12 flagged [T4]).
* MUNGA/: 8 engine-header backfills back-dated from the BT412 WinTesla tree
(VDATA numbering decomp-verified; AUDREND's OpenAL-era virtual removed -
the period compiler is the drift detector).
* Tooling: backdate.py (WinTesla->1995 header transform), compile410.sh
(per-TU verification sweep under authentic OPT.MAK flags).
* README: corrected roadmap - MECH.HPP is the capstone grown with the mech
TU reconstructions; BTREG.CPP green = the header-family milestone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
427 lines
15 KiB
NASM
427 lines
15 KiB
NASM
;[]------------------------------------------------------------[]
|
|
;| C0D.ASM -- Start Up Code For Windows DLLs |
|
|
;[]------------------------------------------------------------[]
|
|
|
|
;
|
|
; C/C++ Run Time Library - Version 6.5
|
|
;
|
|
; Copyright (c) 1991, 1994 by Borland International
|
|
; All Rights Reserved.
|
|
;
|
|
|
|
locals
|
|
|
|
__C0__ = 1
|
|
include RULES.ASI
|
|
|
|
ASSUME CS:_TEXT, DS:DGROUP
|
|
|
|
public __acrtused ;satisfy MS for now
|
|
__acrtused equ 0
|
|
|
|
|
|
extrn LIBMAIN:far ;the C routine to be called
|
|
extrn LOCALINIT:far ;Windows heap init routine
|
|
extrn LOCKSEGMENT:far
|
|
extrn UNLOCKSEGMENT:far
|
|
extrn GETWINFLAGS:far
|
|
extrn __WEP:far
|
|
extrn __cexit:DIST
|
|
ifdef __LARGE__
|
|
ifndef _BUILDRTLDLL
|
|
extrn FREELIBRARY:far
|
|
extrn __LockDLL:DIST
|
|
endif
|
|
endif
|
|
extrn __setupio:near ;required!
|
|
|
|
public LibEntry ;Entry point for the DLL
|
|
publicdll WEP
|
|
|
|
NULL segment
|
|
db 16 dup (0) ;Windows
|
|
db 4 dup (0) ;destructor count
|
|
db 2 dup (0) ;exception list
|
|
db 4 dup (0) ;exception vptr
|
|
db 6 dup (0) ;reserved
|
|
db 2 dup (0) ;VBX control jump vector
|
|
;MUST be at SS:20h
|
|
db 2 dup (0) ;reserved
|
|
ends
|
|
|
|
_CVTSEG segment
|
|
public __RealCvtVector
|
|
__RealCvtVector label word
|
|
ends
|
|
|
|
_SCNSEG segment
|
|
public __ScanTodVector
|
|
__ScanTodVector label word
|
|
ends
|
|
|
|
_FPSEG segment
|
|
public __FPVector
|
|
__FPVector dd 0
|
|
ends
|
|
|
|
_DATA segment
|
|
public _errno
|
|
_errno dw 0
|
|
public __protected
|
|
__protected dw 0
|
|
public __8086
|
|
__8086 dw 0
|
|
public __8087
|
|
__8087 dw 0
|
|
public __version
|
|
__version label word
|
|
public __osversion
|
|
__osversion label word
|
|
public __osmajor
|
|
__osmajor db 0
|
|
public __osminor
|
|
__osminor db 0
|
|
public __osmode ;Used for OS/2 protected mode by MS,
|
|
__osmode db 0 ;currently set to 0 under Windows
|
|
public __hInstance
|
|
__hInstance dw 0
|
|
public __WinAllocFlag ;Used by malloc for additional flags
|
|
__WinAllocFlag dw 2000h ;to pass to GlobalAlloc (used in DLLs)
|
|
;default value is GMEM_SHARE
|
|
public __LockWIN87EM ;Used do lock down WIN87EM to avoid
|
|
__LockWIN87EM dw 1 ;DLL unload ordering problem
|
|
|
|
ifdef __LARGE__
|
|
ifndef _BUILDRTLDLL
|
|
public __LockRTLHandle
|
|
__LockRTLHandle dw 0 ;Handle of RTLDLL (locked)
|
|
endif
|
|
endif
|
|
|
|
public __abend
|
|
__abend label word
|
|
_abend dw 1 ;If LibEntry is called gets set to
|
|
;normal state (0). If it is 1 then
|
|
;exit routines are not performed
|
|
;Gets set to 1 if DLL is terminated
|
|
;by a call to abort() or _exit().
|
|
|
|
CopyRight db 'Borland C++ - Copyright 1994 Borland Intl.',0
|
|
ends
|
|
|
|
_TEXT segment
|
|
|
|
LibEntry proc far
|
|
mov __hInstance, di ;save SI and DI
|
|
push si
|
|
|
|
push di ;handle of the module instance
|
|
push ds ;library data segment
|
|
push cx ;heap size
|
|
push es ;command line segment
|
|
push si ;command line offset
|
|
|
|
;if we have some heap then initialize it
|
|
jcxz @@Init ;jump if no heap specified
|
|
|
|
;call the Windows function LocalInit() to set up the heap
|
|
;LocalInit((LPSTR)start, WORD cbHeap);
|
|
|
|
push ds ;Heap segment
|
|
xor ax,ax
|
|
push ax ;Heap start offset in segment
|
|
push cx ;Heap end offset in segment
|
|
call LOCALINIT
|
|
xchg ax,cx
|
|
jcxz @@JmpExit ;quit if it failed
|
|
jmp short @@Init
|
|
@@JmpExit: jmp @@Exit
|
|
|
|
@@Init:
|
|
|
|
IF LDATA EQ false
|
|
mov ax,-1
|
|
push ax
|
|
call LOCKSEGMENT
|
|
ENDIF
|
|
|
|
;Clear _BSS, uninitialized data area
|
|
|
|
xor ax, ax
|
|
push ds
|
|
pop es
|
|
mov di,offset DGROUP:BeginBSS
|
|
mov cx,offset DGROUP:EndBSS
|
|
sub cx,di
|
|
cld
|
|
rep
|
|
stosb
|
|
|
|
;Determine DOS version
|
|
|
|
mov ah, 30h
|
|
int 21h
|
|
mov __version, ax ; save minor and major revision
|
|
|
|
;Determine whether we are in protected mode
|
|
|
|
call GETWINFLAGS
|
|
test ax,1 ; WF_PMODE = 1
|
|
jz @@realmode ; Note: GETWINFLAGS returns a long,
|
|
; so if WF_PMODE changed it could be
|
|
; in the high word.
|
|
mov __protected, 8 ; Eight is for convenience.
|
|
@@realmode:
|
|
|
|
;Test for 8087 presence
|
|
|
|
test ax,0400h ; WF_8087 = 0x0400
|
|
jz @@no8087
|
|
mov __8087, 1
|
|
@@no8087:
|
|
and ax,08h+04h+02h ; WF_CPU486|WF_CPU386|WF_CPU286
|
|
shr ax,1 ; Convert to 4 or 2 or 1 or 0
|
|
test ax,0004h ; Have 4, 486 done
|
|
jnz @@NoAdjust
|
|
or ax,ax ; Have 0, 8086 done
|
|
jz @@NoAdjust
|
|
inc ax ; Have 2 or 1, need 3 or 2
|
|
@@NoAdjust:
|
|
mov __8086,ax ; Set CPU Type
|
|
|
|
;Call our initialization functions, including C++ static constructors.
|
|
|
|
mov ax,ds
|
|
mov es,ax
|
|
mov si,offset DGROUP:InitStart ;si = start of table
|
|
mov di,offset DGROUP:InitEnd ;di = end of table
|
|
|
|
call Initialize
|
|
mov _abend, 0 ; Set LibEntry called
|
|
|
|
;invoke the C routine to do any special initialization
|
|
@@Main: call LIBMAIN ;invoke the 'C' routine (result in AX)
|
|
or ax, ax
|
|
|
|
ifdef __LARGE__
|
|
ifndef _BUILDRTLDLL
|
|
jz @@LibMainRet
|
|
|
|
push ax
|
|
call __LockDLL
|
|
mov __LockRTLHandle, ax
|
|
pop ax
|
|
@@LibMainRet:
|
|
endif
|
|
endif
|
|
mov di, __hInstance ;restore SI and DI
|
|
pop si
|
|
ret
|
|
|
|
@@Exit: mov ax, 0 ;set return code
|
|
pop si ;remove arguments to LIBMAIN
|
|
pop es ; since we didn't call it.
|
|
pop cx
|
|
pop ds
|
|
pop di
|
|
pop si ;restore saved SI. DI is restored
|
|
ret ; by removing arguments to LIBMAIN
|
|
endp
|
|
|
|
;---------------------------------------------------------------------------
|
|
; _cleanup() call all #pragma exit cleanup routines.
|
|
; _checknull() check for null pointer zapping copyright message
|
|
; _terminate(exitcode, quick) exit program with error code
|
|
; _restorezero() restore interrupt vectors
|
|
;
|
|
; These functions are called by exit(), _exit(), _cexit(),
|
|
; and _c_exit().
|
|
;---------------------------------------------------------------------------
|
|
|
|
; Call cleanup routines
|
|
|
|
__cleanup PROC DIST
|
|
PUBLIC __cleanup
|
|
|
|
mov ax,ds
|
|
mov es,ax
|
|
push si
|
|
push di
|
|
mov si,offset DGROUP:ExitStart
|
|
mov di,offset DGROUP:ExitEnd
|
|
call Cleanup
|
|
pop di
|
|
pop si
|
|
ret
|
|
__cleanup ENDP
|
|
|
|
; Check for null pointers before exit. NO-OP on Windows.
|
|
|
|
__checknull PROC DIST
|
|
PUBLIC __checknull
|
|
ret
|
|
__checknull ENDP
|
|
|
|
; Restore grabbed interrupt vectors. NO-OP on Windows.
|
|
|
|
__restorezero PROC DIST
|
|
PUBLIC __restorezero
|
|
ret
|
|
__restorezero ENDP
|
|
|
|
; Exit to DOS
|
|
;
|
|
; Usage: void _terminate(int exitcode, int quick);
|
|
|
|
__terminate PROC DIST
|
|
PUBLIC __terminate
|
|
|
|
mov bp,sp
|
|
mov al,[bp+cPtrSize] ; get exitcode
|
|
mov ah,4ch
|
|
int 21h
|
|
ret
|
|
endp
|
|
|
|
WEP proc windows pascal far nParam:WORD
|
|
push si
|
|
push di
|
|
|
|
cmp _abend, 0
|
|
jne @@error
|
|
push nParam
|
|
call __WEP
|
|
push ax
|
|
call __cexit ; perform cleanup without exiting
|
|
|
|
@@unlock:
|
|
|
|
ifdef __LARGE__
|
|
ifndef _BUILDRTLDLL
|
|
mov ax, __LockRTLHandle
|
|
or ax, ax
|
|
jz @@RTLNotLocked
|
|
push ax
|
|
call FreeLibrary
|
|
@@RTLNotLocked:
|
|
endif
|
|
endif
|
|
|
|
IF LDATA EQ false
|
|
mov ax,-1
|
|
push ax
|
|
call UNLOCKSEGMENT
|
|
ENDIF
|
|
|
|
pop ax
|
|
pop di
|
|
pop si
|
|
ret
|
|
|
|
@@error:
|
|
push 1
|
|
jmp @@unlock
|
|
|
|
endp
|
|
|
|
; Return default data segment in AX
|
|
|
|
__GetDGROUP PROC FAR
|
|
PUBLIC __GetDGROUP
|
|
mov ax, DGROUP
|
|
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 EQU 1
|
|
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
|
|
|
|
Initialize proc near
|
|
@@Start: mov ax,100h ;start with lowest priority
|
|
mov dx,di ;set sentinel to end of table
|
|
mov bx,si ;bx = start of table
|
|
|
|
@@TopOfTable: cmp bx,di ;and the end of the table?
|
|
je @@EndOfTable ;yes, exit the loop
|
|
cmp es:[bx.calltype],NOTUSED;check the call type
|
|
je @@Next
|
|
mov cl, es:[bx.priority] ;move priority to CX
|
|
xor ch, ch
|
|
cmp cx,ax ;check the priority
|
|
jae @@Next ;too high? skip
|
|
mov ax,cx ;keep priority
|
|
mov dx,bx ;keep index in dx
|
|
@@Next: add bx,SIZE SE ;bx = next item in table
|
|
jmp @@TopOfTable
|
|
|
|
@@EndOfTable: cmp dx,di ;did we exhaust the table?
|
|
je @@Done ;yes, quit
|
|
mov bx,dx ;bx = highest priority item
|
|
cmp 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
|
|
|
|
Cleanup proc near
|
|
@@Start: mov ah,0 ;start with highest priority
|
|
mov dx,di ;set sentinel to end of table
|
|
mov bx,si ;bx = start of table
|
|
|
|
@@TopOfTable: cmp bx,di ;and the end of the table?
|
|
je @@EndOfTable ;yes, exit the loop
|
|
cmp es:[bx.calltype],NOTUSED;check the call type
|
|
je @@Next
|
|
cmp es:[bx.priority],ah ;check the priority
|
|
jb @@Next ;too low? skip
|
|
mov ah,es:[bx.priority] ;keep priority
|
|
mov dx,bx ;keep index in dx
|
|
@@Next: add bx,SIZE SE ;bx = next item in table
|
|
jmp @@TopOfTable
|
|
|
|
@@EndOfTable: cmp dx,di ;did we exhaust the table?
|
|
je @@Done ;yes, quit
|
|
mov bx,dx ;bx = highest priority item
|
|
cmp 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
|
|
|
|
ends
|
|
end LibEntry
|