fixup.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 436 行
C
436 行
/****************************************************************************
*
* 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: WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
* DESCRIBE IT HERE!
*
****************************************************************************/
#include <stddef.h>
#include <watcom.h>
#include <pcobj.h>
#include "womp.h"
#include "memutil.h"
#include "fixup.h"
#include "myassert.h"
#include "genutil.h"
#include "carve.h"
STATIC carve_t myCarver;
void FixInit( void ) {
/******************/
myCarver = CarveCreate( sizeof( fixup ), 64 );
}
void FixFini( void ) {
/******************/
CarveDestroy( myCarver );
}
fixup *FixNew( void ) {
/*******************/
return( CarveAlloc( myCarver ) );
}
fixup *FixDup( const fixup *fix ) {
/*********************************/
fixup *new;
if( fix == NULL ) {
return( NULL );
}
new = CarveAlloc( myCarver );
*new = *fix;
return( new );
}
void FixKill( fixup *fix ) {
/************************/
CarveFree( myCarver, fix );
}
#if _WOMP_OPT & _WOMP_READ
fixinfo *FixBegin( void ) {
/***********************/
fixinfo *new;
new = MemAlloc( sizeof( *new ) );
return( new );
}
void FixEnd( fixinfo *info ) {
/**************************/
MemFree( info );
}
STATIC uint_16 frameDatum( obj_rec *objr, uint_8 method ) {
/**/myassert( objr != NULL );
switch( method ) {
case FRAME_SEG:
case FRAME_GRP:
case FRAME_EXT:
return( ObjGetIndex( objr ) );
case FRAME_ABS:
return( ObjGet16( objr ) );
}
/* for FRAME_LOC, FRAME_TARG, and FRAME_NONE we return 0 */
return( 0 );
}
STATIC uint_16 targetDatum( obj_rec *objr, uint_8 method ) {
/**/myassert( objr != NULL );
if( ( method & 0x03 ) == TARGET_ABSWD ) {
return( ObjGet16( objr ) );
}
return( ObjGetIndex( objr ) );
}
void FixGetLRef( fixinfo *info, obj_rec *objr, logref *log ) {
/**********************************************************/
/*
Get a logical reference. i.e., a fix_dat, frame_datum, targ_datum,
and targ_offset... or from MODEND the end_dat, frame_datum, etc...
*/
uint_8 dat;
uint_8 method;
uint_8 trd_num;
/**/myassert( info != NULL );
/**/myassert( objr != NULL );
/**/myassert( log != NULL );
dat = ObjGet8( objr );
method = ( dat >> 4 ) & 0x07;
if( dat & 0x80 ) { /* F bit set */
trd_num = method | 0x04;
log->frame = info->trd[ trd_num ].method;
log->frame_datum = info->trd[ trd_num ].datum;
} else {
log->frame = method;
log->frame_datum = frameDatum( objr, method );
}
method = dat & 0x07;
if( dat & 0x08 ) { /* T bit set */
trd_num = method & 0x03;
log->target = info->trd[ trd_num ].method & 0x03;
log->target_datum = info->trd[ trd_num ].datum;
} else {
log->target = method & 0x03; /* always has displacement */
log->target_datum = targetDatum( objr, method );
}
if( method & 0x04 ) {
log->target_offset = 0;
log->is_secondary = 1;
} else {
if( objr->is_32 || objr->is_phar ) {
log->target_offset = (int_32)ObjGet32( objr );
} else {
log->target_offset = (int_32)ObjGet16( objr );
}
log->is_secondary = 0;
}
}
fixup *FixGetFix( fixinfo *info, obj_rec *objr ) {
/**********************************************/
uint_8 byte;
uint_8 method;
uint_8 trd_num;
fixup *fix;
/**/myassert( info != NULL );
/**/myassert( objr != NULL );
byte = ObjGet8( objr );
if( byte & 0x80 ) { /* is explicit fixup */
fix = FixNew();
fix->next = NULL;
fix->loader_resolved = 0;
fix->self_relative = ( byte & 0x40 ) == 0;
method = ( byte >> 2 ) & 0x0f;
switch( method ) {
case LOC_OFFSET_LO: /* note fall through */
case LOC_OFFSET:
case LOC_BASE:
case LOC_BASE_OFFSET:
case LOC_OFFSET_HI:
fix->loc_method = method;
break;
case LOC_MS_LINK_OFFSET:
if( objr->is_phar ) {
fix->loc_method = FIX_OFFSET386;
} else {
fix->loc_method = FIX_OFFSET;
fix->loader_resolved = 1;
}
break;
case LOC_BASE_OFFSET_32:
if( objr->is_phar == 0 ) {
Fatal( MSG_INVALID_FIXUP );
}
fix->loc_method = FIX_POINTER386;
break;
case LOC_MS_OFFSET_32:
/* FIXME we assume that the file is a Microsoft object file */
fix->loc_method = FIX_OFFSET386;
break;
case LOC_MS_BASE_OFFSET_32:
/* FIXME we assume that the file is a Microsoft object file */
fix->loc_method = FIX_POINTER386;
break;
case LOC_MS_LINK_OFFSET_32:
/* FIXME we assume that the file is a Microsoft object file */
fix->loc_method = FIX_OFFSET386;
fix->loader_resolved = 1;
break;
default:
Fatal( MSG_INVALID_FIXUP );
}
fix->loc_offset = ( (uint_16)( byte & 0x03 ) << 8 ) | ObjGet8( objr );
FixGetLRef( info, objr, &fix->lr );
return( fix );
}
/* is thread fixup */
trd_num = ( byte & 0x03 ) | ( ( byte & 0x40 ) ? 0x04 : 0 );
method = ( byte >> 2 ) & 0x07;
info->trd[ trd_num ].method = method;
info->trd[ trd_num ].datum = ( trd_num & 0x04 ) ?
targetDatum( objr, method ) : frameDatum( objr, method );
return( NULL );
}
void FixGetPRef( fixinfo *info, obj_rec *objr, physref *phys ) {
/************************************************************/
/**/myassert( info != NULL );
/**/myassert( objr != NULL );
/**/myassert( phys != NULL );
info = info;
phys->frame = ObjGet16( objr );
if( objr->is_phar ) {
phys->offset = ObjGet32( objr );
} else {
phys->offset = ObjGet16( objr );
}
}
void FixGetRef( fixinfo *info, obj_rec *objr, logphys *ref, int is_logical ) {
/**************************************************************************/
/**/myassert( info != NULL );
/**/myassert( objr != NULL );
/**/myassert( ref != NULL );
if( is_logical ) {
FixGetLRef( info, objr, &ref->log );
} else {
FixGetPRef( info, objr, &ref->phys );
}
}
#endif
#if _WOMP_OPT & _WOMP_WRITE
STATIC char *putIndex( char *p, uint_16 index ) {
if( index > 0x7f ) {
*p++ = 0x80 | ( index >> 8 );
}
*p++ = index;
return( p );
}
STATIC char *put16( char *p, uint_16 word ) {
WriteU16( p, word );
return( p + 2 );
}
STATIC char *put32( char *p, uint_32 dword ) {
WriteU32( p, dword );
return( p + 4 );
}
STATIC char *putFrameDatum( char *p, uint_8 method, uint_16 datum ) {
/**/myassert( p != NULL );
switch( method ) {
case FRAME_SEG:
case FRAME_GRP:
case FRAME_EXT:
return( putIndex( p, datum ) );
case FRAME_ABS:
return( put16( p, datum ) );
}
/* for FRAME_LOC, FRAME_TARG, and FRAME_NONE there is nothing to output */
return( p );
}
STATIC char *putTargetDatum( char *p, uint_8 method, uint_16 datum ) {
/**/myassert( p != NULL );
if( ( method & 0x03 ) == TARGET_ABSWD ) {
return( put16( p, datum ) );
}
return( putIndex( p, datum ) );
}
size_t FixGenLRef( logref *log, char *buf, int type ) {
/***************************************************/
char *p;
uint_8 target;
/**/myassert( log != NULL );
/**/myassert( buf != NULL );
/**/myassert( type == FIX_GEN_INTEL || type == FIX_GEN_PHARLAP ||
type == FIX_GEN_MS386 );
/*
According to the discussion on p102 of the Intel OMF document, we
cannot just arbitrarily write fixups without a displacment if their
displacement field is 0. So we use the is_secondary field.
*/
target = log->target;
if( log->target_offset == 0 && log->is_secondary ) {
target |= 0x04;
}
p = buf;
*p++ = ( log->frame << 4 ) | ( target );
p = putFrameDatum( p, log->frame, log->frame_datum );
p = putTargetDatum( p, target, log->target_datum );
if( ( target & 0x04 ) == 0 ) {
if( type == FIX_GEN_MS386 || type == FIX_GEN_PHARLAP ) {
p = put32( p, (uint_32)log->target_offset );
} else {
p = put16( p, (uint_16)log->target_offset );
}
}
return( p - buf );
}
size_t FixGenPRef( physref *ref, char *buf, int type ) {
/****************************************************/
char *p;
/**/myassert( ref != NULL );
/**/myassert( buf != NULL );
/**/myassert( type == FIX_GEN_INTEL || type == FIX_GEN_PHARLAP ||
type == FIX_GEN_MS386 );
p = put16( buf, ref->frame );
if( type == FIX_GEN_PHARLAP ) {
p = put32( p, ref->offset );
} else {
p = put16( p, ref->offset );
}
return( p - buf );
}
size_t FixGenRef( logphys *ref, int is_logical, char *buf, int type ) {
/*******************************************************************/
/**/myassert( ref != NULL );
/**/myassert( buf != NULL );
/**/myassert( type == FIX_GEN_INTEL || type == FIX_GEN_PHARLAP ||
type == FIX_GEN_MS386 );
if( is_logical ) {
return( FixGenLRef( &ref->log, buf, type ) );
}
return( FixGenPRef( &ref->phys, buf, type ) );
}
size_t FixGenFix( fixup *fix, char *buf, int type ) {
/*************************************************/
char *p;
uint_8 byte;
uint_16 data_rec_offset;
/**/myassert( fix != NULL );
/**/myassert( buf != NULL );
/**/myassert( type == FIX_GEN_INTEL || type == FIX_GEN_PHARLAP ||
type == FIX_GEN_MS386 );
p = buf;
byte = fix->self_relative ? 0x80 : 0xc0; /* explicit fixup */
switch( fix->loc_method ) {
case FIX_LO_BYTE: byte |= ( LOC_OFFSET_LO << 2 ); break;
case FIX_OFFSET:
if( fix->loader_resolved ) {
if( type == FIX_GEN_PHARLAP ) {
#if _WOMP_OPT & _WOMP_EXTRAS
PrtMsg( WRN|MSG_NO_LRO_PHARLAP );
#endif
byte |= ( LOC_OFFSET << 2 );
} else {
/**/ myassert( type == FIX_GEN_INTEL || type == FIX_GEN_MS386 );
byte |= ( LOC_MS_LINK_OFFSET << 2 );
}
} else {
byte |= ( LOC_OFFSET << 2 );
}
break;
case FIX_BASE: byte |= ( LOC_BASE << 2 ); break;
case FIX_POINTER: byte |= ( LOC_BASE_OFFSET << 2 ); break;
case FIX_HI_BYTE: byte |= ( LOC_OFFSET_HI << 2 ); break;
case FIX_OFFSET386:
if( type == FIX_GEN_PHARLAP ) {
#if _WOMP_OPT & _WOMP_EXTRAS
if( fix->loader_resolved ) {
PrtMsg( WRN|MSG_NO_LRO_PHARLAP );
}
#endif
byte |= ( LOC_OFFSET_32 ) << 2;
} else {
if( fix->loader_resolved ) {
byte |= ( LOC_MS_LINK_OFFSET_32 << 2 );
} else {
byte |= ( LOC_MS_OFFSET_32 << 2 );
}
}
break;
case FIX_POINTER386:
if( type == FIX_GEN_PHARLAP ) {
byte |= ( LOC_BASE_OFFSET_32 << 2 );
} else {
byte |= ( LOC_MS_BASE_OFFSET_32 << 2 );
}
break;
default:
/**/ never_reach();
}
/**/myassert( fix->loc_offset < 1024 );
data_rec_offset = fix->loc_offset;
byte |= data_rec_offset >> 8;
*p++ = byte;
*p++ = (uint_8)data_rec_offset;
p += FixGenLRef( &fix->lr, p, type );
return( p - buf );
}
#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?