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