;[]------------------------------------------------------------[] ;| 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