novlmain.asm
来自「开放源码的编译器open watcom 1.6.0版的源代码」· 汇编 代码 · 共 783 行 · 第 1/2 页
ASM
783 行
;*****************************************************************************
;*
;* Open Watcom Project
;*
;* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
;*
;* ========================================================================
;*
;* This file contains Original Code and/or Modifications of Original
;* Code as defined in and that are subject to the Sybase Open Watcom
;* Public License version 1.0 (the 'License'). You may not use this file
;* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
;* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
;* provided with the Original Code and Modifications, and is also
;* available at www.sybase.com/developer/opensource.
;*
;* The Original Code and all software distributed under the License are
;* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
;* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
;* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
;* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
;* NON-INFRINGEMENT. Please see the License for the specific language
;* governing rights and limitations under the License.
;*
;* ========================================================================
;*
;* Description: Dynamic Overlay Manager
;*
;*****************************************************************************
; page 64,110
; NOTE! A few of the routines that walk up the stack here assume that
; BP != 0 on entry. This seems reasonable, but means that _cstart_
; should do:
; xor bp,bp
; push bp
; mov bp,sp
; As soon as it creates the stack. Just doing a xor bp,bp is not good
; enough - if somehow an init routine ends up in an overlay (i.e.,
; someone puts it there) then bp could be zero on entry.
;
; For multithreaded database, there will be several stack chains to chase
; This involves:
; Chasing through Context_list, a linked list of task contexts
; 0 saved bp (0 if active task, use BPChain instead)
; 2 saved sp
; 4 link to next context
; There may be multiple return traps per overlay (up to one per stack)
; Since we don't want to have more than one segment per overlay, all
; the return traps point to the same trap; there is a list of
; (bp,list,offset) sets at the end of the trap followed by a zero bp
; value. This increases the size of a return trap to:
; 14 original size (one thread)
; 24 6 bytes times 4 additional threads
; 2 0 at end of list
; --
; 40
include struct.inc
include novlldr.inc
name novlmain
comm __get_ovl_stack:dword
comm __restore_ovl_stack:dword
comm __close_ovl_file:dword
comm __pcode_ret_trap:dword
OVL_DBG_INFO STRUC
location dw 0
section dw 0
bitsize dw 0
OVL_DBG_INFO ENDS
DGROUP group _DATA
_DATA segment byte 'DATA' PUBLIC
ifdef OVL_MULTITHREAD
extrn "C",Context_list:word
endif
_DATA ends
_TEXT segment para '_OVLCODE' PUBLIC
ifdef OVL_MULTITHREAD
assume SS:DGROUP
endif
extrn "C",__NOVLTINIT__:near
extrn "C",__WOVLLDR__:near
extrn "C",__OvlExit__:near
extrn "C",__OVLMAXSECT__:near
extrn "C",__FINDOVLADDR__:far
extrn "C",__OVLLONGJMP__:near
extrn "C",__NDBG_HANDLER__:far
extrn __OVLTAB__:near
extrn __OVLTABEND__:near
extrn "C",__OVLPSP__:word
extrn "C",__OVLCAUSE__:word
extrn "C",__LoadNewOverlay__:near
extrn "C",__OVLINITAREA__:near
extrn "C",__OVLFLAGS__:word
extrn "C",__CloseOvl__:far
public "C",__NDBG_HOOK__
public "C",__OVLAREALIST__
public "C",__OVLROVER__
public "C",__OVLSTARTPARA__
public "C",__OVLDBGINFO__
;
; void __NOVLINIT__( DOS EXE startup parms )
;
public __NOVLINIT__
__NOVLINIT__ proc far
;
; the program entry point. The original stack cannot be used before the call
; to NOVLTINIT since NOVLTINIT loads the program's initial data area and
; can potentially clobber the stack. In this case, it is assumed that
; the first overlay section in the table points to an area at least 256
; bytes long that we can use.
;
jmp short around
dw OVL_SIGNATURE; the overlay manager's signature.
__NDBG_HOOK__ dd NullHook ; the debugger's "hook" into the ovl mgr
dw __NDBG_HANDLER__
BPChain dw 0 ; set by __NOVLLDR__ and __OVLRETTRAP__
SaveWord dw 0 ; used by __NOVLLDR__ and __OVLRETTRAP__
__OVLAREALIST__ dw 0 ; head of the list of areas
__OVLROVER__ dw 0 ; used for 2nd chance cyclic algorithm
__OVLSTARTPARA__ dw 0 ; start_para for non-PRELOAD sections
__OVLDBGINFO__ OVL_DBG_INFO <?>
around:
mov __OVLPSP__,ES ; save segment address of PSP
mov BPChain,SS ; save actual SS:SP
mov SaveWord,SP ; . . .
mov AX,__OVLTAB__.ov_prolog.ovp_delta
add AX,__OVLTAB__.ov_entries.ove_start_para
cli ; set SS:SP to temporary stack
mov SS,AX ; . . .
mov SP,1024 ; linker guarantees at least 1024
sti ; . . .
; initialize __OVLFLAGS__
_guess ; determine which CPU we are using
mov AX,0FFFFh ; do the shift trick
mov CL,33 ; shift right 33 times
shr AX,CL ; AX will be 0 for 8088/8086 types
_quif e ; quit if 808x processor
xor AX,AX ; set up return value.
push SP ; do the stack trick
pop CX ; . . .
cmp CX,SP ; quit if stack value was post dec value
_quif ne ; quit if 8018x processor
pushf ; save flags
mov CX,0f000H ; try to turn on top bits in flags
push CX ; . . .
popf ; . . .
pushf ; see if any turned on
pop CX ; . . .
popf ; restore flags
test CX,0f000H ; are any bits on?
_quif e ; if not, it's a 286
inc AX ; it's a 386!
_endguess
mov __OVLFLAGS__,AX ; store result.
mov ax,3000h ; get dos version number
int 21h ; ...
cmp al,3 ; check if version 3 or greater
_if ae ; ...
or __OVLFLAGS__,2 ; set OVL_DOS3 flag
_endif
; initialize overlay loader
call __NOVLTINIT__ ; initialize overlays
cli ; set SS:SP to actual stack
mov SS,BPChain ; . . .
mov SP,SaveWord ; . . .
sti ; . . .
push DX ; push actual start segment
push AX ; push actual start offset
; We can't setup the initial area before the temporary stack
; has been moved out of the overlay area.
mov AX,__OVLAREALIST__
mov DX,__OVLTAB__.ov_prolog.ovp_ovl_size
call __OVLINITAREA__ ; . . .
assume DS:DGROUP
mov AX,seg DGROUP ; get dgroup
mov DS,AX ; now set up setjmp/longjmp vbls
mov word ptr __get_ovl_stack,offset __FINDOVLADDR__
mov word ptr __restore_ovl_stack,offset longjmp_wrap
mov word ptr __close_ovl_file,offset __CloseOvl__
mov word ptr __pcode_ret_trap,offset pcode_ret_trap
mov word ptr __get_ovl_stack+2,CS
mov word ptr __restore_ovl_stack+2,CS
mov word ptr __close_ovl_file+2,CS
mov word ptr __pcode_ret_trap+2,CS
assume DS:nothing
mov DS,__OVLPSP__ ; restore DS
_guess death
mov AX,word ptr __NDBG_HOOK__+2; get segment of hook
mov DX,CS ; get CS value
cmp AX,DX ; is it in our code segment?
_if ne ; . . .
call __OVLMAXSECT__ ; get size of largest section.
mov DX,AX ; save this for later.
mov BX,AX ; allocate memory block
mov AH,48H ; . . .
int 21H ; . . .
_if c ; check if we got it
mov ES,__OVLPSP__ ; get PSP segment again
mov BX,ES:[2] ; get end of allocation
mov AX,ES ; get psp value (start of alloc.)
sub BX,AX ; subtract start..
dec BX ; fix "off by 1"
dec BX ; give DOS an extra paragraph
sub BX,DX ; remove size of largest overlay
mov AH,4AH ; resize memory block
int 21H ; . . .
_quif c,death ; die if there was a problem
mov BX,DX ; get max section size.
mov AH,48H ; allocate memory block
int 21H ; . . .
_quif c,death ; die if there was a problem
_endif
mov __OVLDBGINFO__.location,AX; save debugger area
_endif
jmp __NDBG_HOOK__ ; hook into debugger if it's there
; otherwise, start program
_endguess
mov AX,3 ; out of memory message
jmp __OvlExit__ ; write message and end program.
__NOVLINIT__ endp
;
; unsigned near __WhichArea__( unsigned seg )
;
public "C",__WhichArea__
__WhichArea__ proc near
;
; Determine the overlay area that seg belongs to. Return 0 if it
; doesn't belong to any area. Assumes that AX != 0 and that there
; is at least one overlay area.
;
; We also return carry=1 if it is in an area, carry=0 otherwise.
;
push DS ; save registers
push DX ; . . .
mov DX,__OVLAREALIST__; get head of area list
_loop
mov DS,DX ; get segment of area
sub AX,DX ; check if ax in bounds
cmp AX,DS:[al_size] ; . . .
_quif c ; carry set if in bounds
add AX,DX ; restore ax
mov DX,DS:[al_next] ;get next segment
test DX,DX ; check if end of list (carry set to 0)
_until e
mov AX,DX ; DON'T MODIFY CARRY FROM HERE . . .
pop DX ; . . .
pop DS ; . . .
ret ; . . . TO HERE!!
__WhichArea__ endp
;
; unsigned near __OVLSCANCALLCHAIN__( void )
;
public "C",__OVLSCANCALLCHAIN__
__OVLSCANCALLCHAIN__ proc near
;
; This function modifies all start_paras in the ovltab so that they are
; either: zero ==> indicates the overlay is not in call chain
; or: non-zero ==> part of a linked list of sections which are in
; the call chain
; returns the head of the linked list. 0xffff terminates the linked list.
; The list is in the order highest-on-stack to lowest-on-stack. The
; list entries are actually (size OVLTAB_ENTRY) * overlay number.
;
push BX
push CX
push DX
push SI
push BP
push ES
push DS
ifdef OVL_MULTITHREAD
mov BP,Context_list ; get list before switching DS
endif
mov AX,CS ; set ds == cs for speed (& size)
mov BX,offset __OVLTAB__.ov_entries.ove_start_para - size OVLTAB_ENTRY
mov DS,AX ; (pipelined) set ds == cs
assume DS:_TEXT
mov DX,0ffffh ; DX is head of linked list
ifdef OVL_MULTITHREAD
_loop
push BP ; save context
mov BP,[bp+tl_saved_bp]; get bp
test BP,BP ; is it valid?
jne sc_beg ; yes
mov BP,BPChain ; active task - use start of bp chain
else
mov BP,BPChain ; start of bp chain
endif
jmp short sc_beg
EVEN
_loop
shl BP,1 ; restore bp and test if non-zero
_quif z ; if zero then done
sc_beg: mov SI,[BP+4] ; get possible segment
mov BP,[BP] ; get bp link
shr BP,1 ; test if near call
_loopif nc ; continue if it's a near call
mov AX,SI ; check if in an overlay area
call __WhichArea__ ; . . .
_loopif nc ; continue if not in overlay area
dec SI ; get overlay number from descriptor
mov ES,SI ; . . .
mov CL,4 ; (pipelined) for shifting
mov SI,ES:[0eH] ;. . .
shl SI,CL ; multiply by size OVLTAB_ENTRY
mov CX,[BX+SI] ; get start_para for this overlay
test CX,CX ; if non-zero then already in call-chain
_loopif ne ; continue if already in call-chain
mov [BX+SI],DX ; store the linked list head
mov DX,SI ; change the head
_endloop ; continue looping
ifdef OVL_MULTITHREAD
pop BP ; get context
mov BP,[BP+tl_next]
test BP,BP ; at end of list?
_until e ; loop if not
endif
mov AX,DX ; get return value
pop DS
assume DS:nothing
pop ES
pop BP
pop SI
pop DX
pop CX
pop BX
ret
__OVLSCANCALLCHAIN__ endp
;
; void near __OVLBUILDRETTRAP__( unsigned old_handle, unsigned rt_seg );
;
public "C",__OVLBUILDRETTRAP__
__OVLBUILDRETTRAP__ proc near
;
; This function constructs a return trap in rt_seg. It only initializes
; the ret_offset, ret_list, and stack_trap fields. See novlldr.c for
; more info on what a return trap looks like.
;
; We assume that old_handle is actually in the call chain at least once...
;
push BP
push DS
push CX
ifdef OVL_MULTITHREAD
push BX
mov BP,Context_list ; get list of contexts
endif
mov DS,DX ; set ds to rt_seg
ifdef OVL_MULTITHREAD
mov BX,rt_traps ; initialize to point to first trap
mov byte ptr DS:[rt_call_far],CALL_FAR
mov word ptr DS:[rt_entry],offset __OVLRETTRAP__
mov word ptr DS:[rt_entry+2],seg __OVLRETTRAP__
mov word ptr DS:[rt_old_code_handle],AX
_loop ; extra loop for each context
mov [BX+te_context],BP; assume this thread needs trap
push BP ; save context
mov BP,[BP+tl_saved_bp]; get saved bp
test BP,BP ; is it the active task?
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?