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 + -
显示快捷键?