novlldr.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 937 行 · 第 1/3 页

C
937
字号
/****************************************************************************
*
*                            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:  New (Whoosh) overlay loader.
*
****************************************************************************/


#include "novlldr.h"

/*
 * Here's a nice fast inline memcpy that is used if a 386 or better is
 * detected. This is passed the length to copy in paragraphs.
*/

extern  void DoFastCopyPara( unsigned dst, unsigned src, unsigned len_in_paras );

#pragma aux DoFastCopyPara = \
        ".386" \
        "xor si,si" \
        "xor di,di" \
        "test byte ptr __OVLFLAGS__, 1 " \
        "jz   cpu86" \
        "shl cx,2" \
        "rep movsd" \
        "jmp short end" \
"cpu86:  shl cx,1" \
        "shl cx,1" \
        "shl cx,1" \
        "rep movsw" \
"end:   " \
        parm [es] [ds] [cx]               \
        modify exact [si di cx];


/**************************************************************************/

#ifdef OVL_MULTITHREAD
// Extra flag used only for the Multi-threaded overlay manager

#define FLAG_ACTIVE_TRAP        1       // Assumes flags start at 0x8000

#endif

static void near AllocSeg( unsigned seg, unsigned amount, unsigned area_seg )
/***************************************************************************/
/* Allocate amount paras from seg in area_seg */
{
    area_list_ptr       area;
    free_block_ptr      memptr;
    free_block_ptr      newptr;
    free_block_ptr      nextptr;
    free_block_ptr      prevptr;

    area = MK_FP( area_seg, 0 );
    area->free_paras -= amount;
    memptr = MK_FP( seg - 1, 0x10 );
    if( memptr->num_paras == amount ) {     /* took up entire free block */
        nextptr = MK_FP( memptr->next, 0 ); /* unlink from ring */
        nextptr->prev = memptr->prev;
        prevptr = MK_FP( memptr->prev, 0 );
        prevptr->next = memptr->next;
    } else { /* make new free block with remaining paras from this block */
        newptr = MK_FP( FP_SEG( memptr ) + amount, 0x10 );
        newptr->next = memptr->next;
        newptr->prev = memptr->prev;
        newptr->num_paras = memptr->num_paras - amount;
        *((desc_ptr)newptr - 1) = BLOCK_IS_FREE;
        nextptr = MK_FP( newptr->next, 0 );
        nextptr->prev = FP_SEG( newptr ) + 1;
        prevptr = MK_FP( newptr->prev, 0 );
        prevptr->next = FP_SEG( newptr ) + 1;
    }
}


static unsigned near AllocFromArea( unsigned amount, unsigned area_seg )
/**********************************************************************/
/* Allocate amount paras from area. */
{
    free_block_ptr      memptr;
    unsigned            seg;
    area_list_ptr       area;

    area = MK_FP( area_seg, 0 );
    memptr = MK_FP( area->fblk.next, 0 );
    while( memptr->num_paras != 0 && memptr->num_paras < amount ) {
        memptr = MK_FP( memptr->next, 0 );
    }
    seg = NULL_SEG;
    if( memptr->num_paras != 0 ) {
        seg = FP_SEG( memptr );
        AllocSeg( seg, amount, FP_SEG( area ) );
    }
    return( seg );
}


static unsigned near Allocate( unsigned amount )
/**********************************************/
/* Allocate amount paragraphs from any area */
{
    unsigned            seg;
    area_list_ptr       area;

    area = MK_FP( __OVLAREALIST__, 0 );
    while( area != NULL ) {
        if( area->free_paras >= amount ) {
            seg = AllocFromArea( amount, FP_SEG( area ) );
            if( seg != NULL_SEG ) {
                return( seg );
            }
        }
        area = MK_FP( area->next, 0 );
    }
    return( NULL_SEG );
}


static void near FreeWithNext( unsigned seg, unsigned num_paras,
                                        unsigned area_seg, unsigned next_seg )
/****************************************************************************/
/* Put seg of size num_paras onto the free list in area_seg.  next_seg must be
 * the segment of the next free block in the area. */
{
    area_list_ptr       area;
    free_block_ptr      prevptr;
    free_block_ptr      nextptr;
    free_block_ptr      memptr;

    /* add block to area */
    area = MK_FP( area_seg, 0 );
    area->free_paras += num_paras;
    memptr = MK_FP( seg, 0 );
    memptr->num_paras = num_paras;
    memptr->next = next_seg;
    nextptr = MK_FP( next_seg, 0 );
    memptr->prev = nextptr->prev;
    nextptr->prev = FP_SEG( memptr );
    prevptr = MK_FP( memptr->prev, 0 );
    prevptr->next = FP_SEG( memptr );
    /* try to coalesce forward */
    if( nextptr->num_paras != 0 &&
                FP_SEG( memptr ) + memptr->num_paras == FP_SEG( nextptr ) ) {
        memptr->num_paras += nextptr->num_paras;
        memptr->next = nextptr->next;
        nextptr = MK_FP( nextptr->next, 0 ); /* advance nextptr */
        nextptr->prev = FP_SEG( memptr );
    }
    /* try to coalesce backward */
    if( prevptr->num_paras != 0 &&
                FP_SEG( prevptr ) + prevptr->num_paras == FP_SEG( memptr ) ) {
        /* coalesce backward */
        prevptr->next = memptr->next;
        nextptr->prev = FP_SEG( prevptr );
        prevptr->num_paras += memptr->num_paras;
        memptr = prevptr;
    }
    /* set up the descriptor */
    *(desc_ptr)MK_FP( FP_SEG( memptr ) - 1, 0xE ) = BLOCK_IS_FREE;
}


static void near FreeSeg( unsigned seg, unsigned num_paras, unsigned area_seg )
/*****************************************************************************/
/* Add the seg of size num_paras to the free list in area_seg. */
{
    area_list_ptr       area;
    free_block_ptr      nextptr;
    free_block_ptr      memptr;

    area = MK_FP( area_seg, 0 );
    memptr = MK_FP( seg, 0 );
    nextptr = MK_FP( area->fblk.next, 0 );
    /* Note: Since there is a dummy block at end of list, we don't have to
     * explicitly test for it here. */
    while( FP_SEG( nextptr ) < FP_SEG( memptr ) ) {
        nextptr = MK_FP( nextptr->next, 0 );
    }
    FreeWithNext( seg, num_paras, area_seg, FP_SEG( nextptr ) );
}


static void near DeMungeVectors( unsigned tab_off, unsigned sec_num,
                                                                unsigned seg )
/****************************************************************************/
/* overlay not in memory any more, so demunge vectors.
 * NOTE: this assumes that __NOVLLDR__ and the vectors are in the same segment!
 */
{
    lvector_ptr vect;
    unsigned    loader;

    vect = &__OVLSTARTVEC__;
    loader = FP_OFF(__NOVLLDR__) - FP_OFF(&vect->u.v.ldr_addr) - 2;
    while( vect < &__OVLENDVEC__ ) {
        if(( vect->u.i.cs_over == OVV_CS_OVERRIDE ) && ( vect->u.i.tab_addr == tab_off )) {
            vect->u.v.call_op = CALL_INSTRUCTION;
            vect->u.v.ldr_addr = loader;
            vect->u.v.sec_num = sec_num;
            vect->target.seg -= seg;
        }
        ++vect;
        loader -= sizeof( lvector );
    }
}


static unsigned near UnloadSection( ovltab_entry_ptr ovl, unsigned ovl_num )
/**************************************************************************/
/* Unload a section.  Assumes that __OVLSCANCALLCHAIN__ has been called.
 * Returns the area that the section was in. */
{
    unsigned            area_seg;
    unsigned            rt_seg;

    area_seg = __WhichArea__( ovl->code_handle );
    FreeSeg( ovl->code_handle, ovl->num_paras, area_seg );
    ovl->flags_anc |= FLAG_CHANGED;
    ovl->flags_anc &= ~FLAG_INMEM;
    DeMungeVectors( FP_OFF( ovl ), ovl_num, ovl->code_handle );
    if( ovl->start_para != 0 ) {
        /* was in call chain - build a ret trap */
#ifdef OVL_MULTITHREAD
        rt_seg = Allocate( RET_TRAP_PARA );
#else
        rt_seg = Allocate( 1 );
#endif
        __OVLBUILDRETTRAP__( ovl->code_handle, rt_seg );
        ovl->code_handle = rt_seg;
        ovl->flags_anc |= FLAG_RET_TRAP;
        *(desc_ptr)MK_FP( rt_seg - 1, 0xE ) = ovl_num;
#ifdef OVL_DEBUG
        __OvlMsg__( OVL_SECTION );
        __OvlNum__( ovl_num );
        __OvlMsg__( OVL_RET_TRAPPED );
    } else {
        __OvlMsg__( OVL_SECTION );
        __OvlNum__( ovl_num );
        __OvlMsg__( OVL_UNLOADED );
#endif
    }
    return( area_seg );
}


static unsigned near UnloadNonChained( unsigned amount, unsigned start_ovl )
/**************************************************************************/
/* Toss overlays that are not in call chain.  Assumes __OVLSCANCALLCHAIN__
 * has been called.  Returns NULL_SEG if it was unable to make enough room in
 * any area.  Otherwise it returns the area seg.
 */
{
    unsigned            curr_ovl;
    ovltab_entry_ptr    ovl;
    area_list_ptr       area;

    curr_ovl = start_ovl;
    area = MK_FP( __OVLAREALIST__, 0 );
    ovl = &__OVLTAB__.entries[ curr_ovl - 1 ];
    for(;;) {
        ++ovl;
        ++curr_ovl;
        if( FP_OFF( ovl ) == FP_OFF( &__OVLTABEND__ ) ) {
            curr_ovl = 1;
            ovl = __OVLTAB__.entries;
        }
        if( ( ovl->flags_anc & FLAG_INMEM ) && ( ovl->start_para == 0 ) ) {
            if( OVL_ACCESSES( ovl ) != 0 ) {
#ifdef OVL_MULTITHREAD
                OVL_ACCESSES( ovl ) -= 1;
#else
                OVL_ACCESSES( ovl ) = 0;
#endif
            } else {
                area = MK_FP( UnloadSection( ovl, curr_ovl ), 0 );
                if( area->free_paras >= amount ) {
                    __OVLROVER__ = curr_ovl;
                    return( FP_SEG( area ) );
                }
            }
        }
        if( curr_ovl == start_ovl ) {
            break;
        }
    }
    __OVLROVER__ = curr_ovl;
    return( NULL_SEG );
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?