📄 c0d.asm
字号:
;[]------------------------------------------------------------[]
;| C0D.ASM -- Start Up Code For Windows DLLs |
;[]------------------------------------------------------------[]
;
; C/C++ Run Time Library - Version 5.0
;
; Copyright (c) 1991, 1992 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
extrn __setupio:near ;required!
public LibEntry ;Entry point for the DLL
publicdll WEP
NULL segment
db 16 dup (?)
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 __8087
__8087 dw 0
public __StartTime
__StartTime dd 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 0 ;to pass to GlobalAlloc (used in DLLs)
public __LockWIN87EM ;Used do lock down WIN87EM to avoid
__LockWIN87EM dw 1 ;DLL unload ordering problem
_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 1991 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
;Save start time of DLL
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
or al,al ; was midnight flag set?
jz @@NotMidnight
mov ax,40h ; set BIOS midnight flag
mov es,ax ; at 40:70
mov bx,70h
mov byte ptr es:[bx],1
@@NotMidnight:
;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:
;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
mov __WinAllocFlag, 2000h ; GMEM_SHARE
call Initialize
mov __WinAllocFlag, 0
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)
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:
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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -