novlldr.c

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

C
937
字号

static int near UnloadChained( unsigned amount, unsigned_16 far *call_chain )
/****************************************************************************/
/* Unload sections that are in the call chain.  We also unlink the sections
 * from the call_chain linked list.  Returns NULL_SEG if it didn't make enough
 * room in any area; otherwise returns an area seg with enough room. */
{
    ovltab_entry_ptr    ovl;
    unsigned            ovl_num;
    area_list_ptr       area;

    area = MK_FP( __OVLAREALIST__, 0 );
    while( *call_chain != 0xFFFF ) {
        ovl_num = *call_chain >> 4;
        ovl = &__OVLTAB__.entries[ ovl_num - 1 ];
        if( OVL_ACCESSES( ovl ) != 0 ) {
#ifdef OVL_MULTITHREAD
            OVL_ACCESSES( ovl ) -= 1;
#else
            OVL_ACCESSES( ovl ) = 0;
#endif
            call_chain = &ovl->start_para;      /* advance pointer */
        } else {
            *call_chain = ovl->start_para;      /* unlink from call chain */
            if( ( ovl->flags_anc & FLAG_RET_TRAP ) == 0 ) {
                area = MK_FP( UnloadSection( ovl, ovl_num ), 0 );
                ovl->start_para = 0;
                if( area->free_paras >= amount ) {
                    return( FP_SEG( area ) );
                }
            }
            ovl->start_para = 0;
        }
    }
    return( NULL_SEG );
}


static void near redoRelocs( ovltab_entry_ptr ovl, unsigned startseg )
/********************************************************************/
/* Relocate self-referential code. Assumes that ovl->code_handle points
 * to new location of code. */
{
    tiny_ret_t          status;
    tiny_handle_t       fp;
    unsigned            save_delta;
    unsigned            save_start_para;

    status = __OpenOvl__( ovl->fname );
    if( TINY_ERROR( status ) )
        __OvlExit__( OVL_OPEN_ERR );
    fp = TINY_INFO( status );
    status = __OvlSeek__( fp, ovl->disk_addr+((unsigned_32)ovl->num_paras<<4));
    if( TINY_ERROR( status ) )
        __OvlExit__( OVL_IO_ERR );
    /*
        Fool __OvlRelocLoad__ into relocating section for us by making it
        look like the linker linked things at the current load address.
    */
    save_delta = __OVLTAB__.prolog.delta;
    save_start_para = ovl->start_para;
    ovl->start_para = startseg;
    __OVLTAB__.prolog.delta = 0;
    __OvlRelocLoad__( ovl, fp );
    __OVLTAB__.prolog.delta = save_delta;
    ovl->start_para = save_start_para;
}


static void near MoveSection( unsigned destseg, ovltab_entry_ptr ovl )
/********************************************************************/
/* this moves a section to the address in destseg, and fixes the vectors.
 * note this assumes that destseg is less than the current address.
*/
{
    unsigned            startseg;
    lvector_ptr         vect;

    ovl->flags_anc |= FLAG_CHANGED;
    startseg = ovl->code_handle;
    ovl->code_handle = destseg;
    *(desc_ptr)MK_FP( destseg - 1, 0xE ) = *(desc_ptr)MK_FP( startseg-1, 0xE );
    __OVLFIXCALLCHAIN__( startseg, destseg );
    /* copy the code */
    DoFastCopyPara( destseg, startseg, ovl->num_paras );
    /* possibly relocate */
    if( ovl->flags_anc & FLAG_SELF_REF ) {
        redoRelocs( ovl, startseg );
    }
    /* modify the vectors */
    vect = &__OVLSTARTVEC__;
    while( vect < &__OVLENDVEC__ ) {
        if( vect->u.i.cs_over == OVV_CS_OVERRIDE &&
                                vect->u.i.tab_addr == FP_OFF( ovl ) ) {
            vect->target.seg = destseg;
        }
        ++vect;
    }
}


static void near MoveRetTrap( unsigned to_seg, ovltab_entry_ptr ovl )
/*******************************************************************/
{
    unsigned_16 far *           stkptr;
    ret_trap_ptr                rt;
    ret_trap_ptr                rt_new;
#ifdef OVL_MULTITHREAD
    unsigned                    i;
#endif

    rt = MK_FP( ovl->code_handle - 1, 0x10 );
    rt_new = MK_FP( to_seg - 1, 0x10 );
    *((desc_ptr)rt_new - 1) = *((desc_ptr)rt - 1);      /* copy ovl_num */
    rt_new->call_far = CALL_FAR_INSTRUCTION;            /* standard stuff */
    rt_new->rt_entry.off = FP_OFF( __OVLRETTRAP__ );
    rt_new->rt_entry.seg = FP_SEG( __OVLRETTRAP__ );
#ifdef OVL_MULTITHREAD
    rt_new->old_code_handle = rt->old_code_handle;
    for( i = 0; rt->traps[i].stack_trap != 0; ++i ) {
        rt_new->traps[i].ret_offset = rt->traps[i].ret_offset;
        rt_new->traps[i].ret_list = rt->traps[i].ret_list;
        rt_new->traps[i].stack_trap = rt->traps[i].stack_trap;
        rt_new->traps[i].context = rt->traps[i].context;
        if( !(ovl->flags_anc & FLAG_ACTIVE_TRAP) ) {
            stkptr = MK_FP( FP_SEG( &stkptr ), rt->traps[i].stack_trap + 4 );
            /* fix the stack up */
            *stkptr = to_seg;
        }
    }
    rt_new->traps[i].stack_trap = 0;
#else
    rt_new->ret_offset = rt->ret_offset;                /* copy the trap */
    rt_new->ret_list = rt->ret_list;
    rt_new->stack_trap = rt->stack_trap;
    stkptr = MK_FP( FP_SEG( &stkptr ), rt->stack_trap + 4 );/* fix the stack up */
    *stkptr = to_seg;
#endif
    ovl->code_handle = to_seg;
    ovl->flags_anc |= FLAG_CHANGED;
}


static unsigned near DefragmentMem( unsigned amount, unsigned area_seg )
/**********************************************************************/
/* Try to defragment an area of memory.  We assume that the area has
 * free_paras >= amount. If this assumption is met, this routine is
 * guaranteed to return a non-NULL_SEG segment of size amount. */
{
    area_list_ptr       area;
    unsigned_16         to_seg;
    free_block_ptr      to_block; /* free block to be filled in */
    ovltab_entry_ptr    ovl;
    desc_ptr            descptr;
    unsigned_16         to_block_paras;
    unsigned            to_block_next;
    unsigned            num_paras;

    /* check if we can just allocate a large enough block */
    to_seg = AllocFromArea( amount, area_seg );
    if( to_seg != NULL_SEG ) {
        return( to_seg );
    }
    area = MK_FP( area_seg, 0 );
    /* there is enough room, so we move used blocks until we get a
     * free block large enough */
    to_seg = area->fblk.next;
    for(;;) {
        to_block = MK_FP( to_seg, 0 );
        to_block_paras = to_block->num_paras;
        to_block_next = to_block->next;
        AllocSeg( to_seg, to_block_paras, FP_SEG( area ) );
        if( to_block_paras >= amount ) { /* can quit early */
            if( to_block_paras != amount ) {
                    /* put back what we don't need */
                FreeWithNext( to_seg + amount, to_block_paras - amount,
                        FP_SEG( area ), to_block_next );
            }
            return( to_seg );
        }
        /* note we cannot be at last free block since we know there is
         * enough free space in this area, and we abort before now when
         * we collect a large enough free block. */
        descptr = MK_FP( to_seg - 1 + to_block_paras, 0xE );
#ifdef OVL_DEBUG
        __OvlMsg__( OVL_SECTION );
        __OvlNum__( *descptr );
        __OvlMsg__( OVL_MOVED );
#endif
        ovl = &__OVLTAB__.entries[ *descptr - 1 ];
        if( ovl->flags_anc & FLAG_RET_TRAP ) {
            MoveRetTrap( to_seg, ovl );
#ifdef OVL_MULTITHREAD
            num_paras = RET_TRAP_PARA;
#else
            num_paras = 1;
#endif
        } else {
            MoveSection( to_seg, ovl );
            num_paras = ovl->num_paras;
        }
        to_seg += num_paras;
        FreeWithNext( to_seg, to_block_paras, FP_SEG( area ), to_block_next );
        /* next free block is the one we have just added */
    }
/*  return( NULL_SEG ); unreachable */
}


static unsigned near ForceAllocate( unsigned amount )
/***************************************************/
/* Always returns a segment of size amount... throws out anything necessary
 * to do so. */
{
    unsigned            seg;
    unsigned_16         call_chain;
    unsigned            rover_save;
    unsigned            area_seg;
    ovltab_entry_ptr    ovl;

    seg = Allocate( amount );
    if( seg != NULL_SEG ) return( seg );
    /*
        Since the linker ensures that our dynamic area has as least as
        many paragraphs as (sizeof largest section) + (number of sections) + 1.
        This way every section can be ret trapped and we can still load the
        largest section into memory.  Therefore, this loop will terminate... :>

        Oh yeah, we rely on UnloadNonChained & UnloadChained to set the
        OVL_ACCESSES field to zero for every overlay scanned.
    */
    call_chain = __OVLSCANCALLCHAIN__();
    rover_save = __OVLROVER__;
    for(;;) {
        area_seg = UnloadNonChained( amount, rover_save );
        if( area_seg != NULL_SEG ) {
            seg = DefragmentMem( amount, area_seg );
            break;
        }
        area_seg = UnloadChained( amount, &call_chain );
        if( area_seg != NULL_SEG ) {
            seg = DefragmentMem( amount, area_seg );
            break;
        }
    }
    /* we are responsible for zeroing the start_paras */
    while( call_chain != 0xFFFF ) {
        /*ovl = &__OVLTAB__.entries[ ( call_chain >> 4 ) - 1 ];*/
        /* a kludge 'cause codegen doesn't catch it if we do it properly */
        ovl = (ovltab_entry_ptr)
                        ((char far *)&__OVLTAB__.entries[ -1 ] + call_chain );
        call_chain = ovl->start_para;
        ovl->start_para = 0;
    }
    return( seg );
}


void near __LoadSectionCode__( ovltab_entry_ptr ovl )
/**************************************************/
/* Load the code & do the relocations for a specified overlay.  Loads code
 * into ovl->code_handle.  Caller is responsible for putting the overlay
 * number into the descriptor byte. */
{
    tiny_ret_t          status;
    tiny_handle_t       fp;
    desc_ptr            descptr;
    desc                tmp;

    status = __OpenOvl__( ovl->fname );
    if( TINY_ERROR( status ) )
        __OvlExit__( OVL_OPEN_ERR );
    fp = TINY_INFO( status );
    status = __OvlSeek__( fp, ovl->disk_addr );
    if( TINY_ERROR( status ) ) {
        __OvlExit__( OVL_IO_ERR );
    }
    descptr = MK_FP( ovl->code_handle + ovl->num_paras - 1, 0xE );
    tmp = *descptr;             /* save the descriptor across call */
    __OvlCodeLoad__( ovl, fp );
    *descptr = tmp;
    if( __OvlRelocLoad__( ovl, fp ) ) {
        ovl->flags_anc |= FLAG_SELF_REF;
    }
    ovl->flags_anc |= FLAG_INMEM;
}


unsigned near __LoadNewOverlay__( unsigned ovl_num )
/**************************************************/
/* Load the overlay into memory.  Removes the return trap if one exists. */
{
    ovltab_entry_ptr    ovl;
    unsigned            segment;
#ifdef OVL_MULTITHREAD
    unsigned            rt_seg;
#else
    unsigned            stack_trap;
    unsigned            ret_offset;
    unsigned            ret_list;
    ret_trap_ptr        rt;
#endif

    ovl = &__OVLTAB__.entries[ ovl_num - 1 ];
    if( !(ovl->flags_anc & FLAG_INMEM) ) {
        if( ovl->flags_anc & FLAG_RET_TRAP ) {
#ifdef OVL_MULTITHREAD
            // Prevent fixups of the return trap for this overlay
            ovl->flags_anc |= FLAG_ACTIVE_TRAP;
#else
            rt = MK_FP( ovl->code_handle, 0 );
            stack_trap = rt->stack_trap;
            ret_offset = rt->ret_offset;

⌨️ 快捷键说明

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