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