obj2supp.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,658 行 · 第 1/4 页
C
1,658 行
/****************************************************************************
*
* 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: Utilities for wlink specific parts of objpass2.
*
****************************************************************************/
#include <string.h>
#include "linkstd.h"
#include "reloc.h"
#include "pcobj.h"
#include "newmem.h"
#include "msg.h"
#include "alloc.h"
#include "mapio.h"
#include "exeos2.h"
#include "exeqnx.h"
#include "exeelf.h"
#include "loadfile.h"
#include "loados2.h"
#include "loadnov.h"
#include "loadqnx.h"
#include "loadelf.h"
#include "wlnkmsg.h"
#include "virtmem.h"
#include "objpass2.h"
#include "objstrip.h"
#include "objcalc.h"
#include "impexp.h"
#include "overlays.h"
#include "strtab.h"
#include "carve.h"
#include "permdata.h"
#include "dbgcv.h"
#include "dbgall.h"
#include "toc.h"
#include "ring.h"
#include "obj2supp.h"
typedef struct fix_data {
byte * data;
unsigned_32 value; /* value at location being patched */
targ_addr loc_addr;
targ_addr tgt_addr;
fix_type type;
unsigned ffix : 3;
unsigned additive : 1;
unsigned done : 1;
unsigned imported : 1;
unsigned os2_selfrel : 1;
} fix_data;
static offset LastOptimized; // offset last optimized.
static fix_type LastOptType;
static segdata * LastSegData;
static offset FixupOverflow;
static unsigned MapOS2FixType( unsigned type );
static void PatchOffset( fix_data *fix, unsigned_32 val,
bool isdelta );
static void Relocate( save_fixup *save, fix_data *fix, frame_spec *targ );
#define MAX_ADDEND_SIZE ( 2 * sizeof( unsigned_32 ) )
#define GET_S16( P ) (*(signed_16 *)(P))
#define FIX_POINTER_MASK ( FIX_BASE | FIX_HIGH | FIX_OFFSET_MASK )
extern void ResetObj2Supp( void )
/*******************************/
{
FixupOverflow = 0;
LastOptType = 0;
LastOptimized = 0xFFFFFFFF;
}
static void DCERelocRef( symbol *sym, bool isdata )
/*************************************************/
{
if( isdata ) {
if( !( sym->info & SYM_VF_REFS_DONE ) ) {
DataRef( sym );
}
} else {
if( CurrRec.seg->ispdata || CurrRec.seg->isreldata ) {
if( !IsTocSym( sym ) ) { // make sure that if symbol goes,
AddSymSegEdge( sym, CurrRec.seg ); // .pdata and .reldata go too
}
} else {
AddEdge( CurrRec.seg, sym );
}
}
}
static void TraceFixup( fix_type type, frame_spec *targ )
/*******************************************************/
{
bool isovldata; // TRUE if data and overlaying.
bool overlay; // TRUE if doing overlays;
overlay = ( ( FmtData.type & MK_OVERLAYS ) && !FmtData.u.dos.noindirect );
if( ( LinkFlags & STRIP_CODE ) || overlay ) {
isovldata = !( CurrRec.seg->u.leader->info & SEG_OVERLAYED );
if( ObjFormat & FMT_UNSAFE_FIXUPP )
isovldata = TRUE;
if( targ->type == FIX_FRAME_SEG ) {
if( LinkFlags & STRIP_CODE ) {
if( targ->u.sdata->iscode && targ->u.sdata != CurrRec.seg ) {
RefSeg( targ->u.sdata );
}
}
} else if( targ->type == FIX_FRAME_EXT ) {
if( LinkFlags & STRIP_CODE ) {
DCERelocRef( targ->u.sym, !CurrRec.seg->iscode );
}
if( !( type & FIX_REL ) && overlay ) {
switch( type & FIX_POINTER_MASK ) {
case FIX_OFFSET_16:
if( FmtData.u.dos.ovl_short ) {
IndirectCall( targ->u.sym );
}
break;
case FIX_BASE:
IndirectCall( targ->u.sym );
break;
case FIX_BASE_OFFSET_16:
if( isovldata ) {
IndirectCall( targ->u.sym );
}
break;
}
} /* end if (notrelative && overlay) */
} /* end if (a symbol/segment) */
}
}
extern void RelocStartMod( void )
/*******************************/
{
LastSegData = NULL;
}
static byte OffsetSizes[] = { 0, 1, 2, 4, 4, 4, 4 };
static unsigned CalcFixupSize( fix_type type )
/********************************************/
{
unsigned value;
value = OffsetSizes[ FIX_GET_OFFSET( type ) ];
if( type & FIX_BASE ) {
value += sizeof( unsigned_16 );
}
return( value );
}
static unsigned CalcAddendSize( fix_type fixtype )
/************************************************/
{
if( fixtype & FIX_ADDEND_ZERO ) {
return( 0 );
} else if( ( fixtype & FIX_BASE )
&& ( ( fixtype & FIX_OFFSET_MASK ) == FIX_OFFSET_32 ) ) {
return( MAX_ADDEND_SIZE );
}
return( sizeof( unsigned_32 ) );
}
static unsigned CalcSavedFixSize( fix_type fixtype )
/**************************************************/
{
unsigned retval;
if( fixtype & FIX_CHANGE_SEG ) {
retval = sizeof( unsigned_32 );
} else {
retval = sizeof( save_fixup ) + CalcAddendSize( fixtype );
if( FRAME_HAS_DATA( FIX_GET_FRAME( fixtype ) ) ) {
retval += sizeof( unsigned_32 );
}
}
return( retval );
}
static void UpdateFramePtr( frame_spec *frame )
/*********************************************/
/* do any necessary work to get frame pointing to the right place */
{
switch( frame->type ) {
case FIX_FRAME_GRP:
if( IS_FMT_INCREMENTAL( CurrMod->modinfo ) ) {
DbgAssert( frame->u.val != 0 );
frame->u.group = IncGroups[frame->u.val - 1];
}
break;
case FIX_FRAME_EXT:
frame->u.sym = UnaliasSym( ST_FIND, frame->u.sym );
DbgAssert( frame->u.sym != NULL );
break;
}
}
static void GetFrameAddr( frame_spec *frame, targ_addr *addr,
targ_addr *tgt_addr, unsigned_32 off )
/**************************************************************/
{
switch( frame->type ) {
case FIX_FRAME_SEG:
*addr = frame->u.sdata->u.leader->seg_addr;
addr->off += frame->u.sdata->a.delta;
break;
case FIX_FRAME_GRP:
*addr = frame->u.group->grp_addr;
break;
case FIX_FRAME_EXT:
*addr = frame->u.sym->addr;
break;
case FIX_FRAME_ABS:
addr->seg = frame->u.abs;
break;
case FIX_FRAME_LOC:
*addr = CurrRec.addr;
addr->off += off;
break;
case FIX_FRAME_TARG:
case FIX_FRAME_FLAT:
*addr = *tgt_addr;
break;
}
}
static void MapFramePtr( frame_spec *frame, void **targ )
/*******************************************************/
{
switch( frame->type ) {
case FIX_FRAME_SEG:
*targ = CarveGetIndex( CarveSegData, *targ );
break;
case FIX_FRAME_GRP:
*targ = (void *)frame->u.group->num;
break;
case FIX_FRAME_EXT:
*targ = CarveGetIndex( CarveSymbol, *targ );
break;
}
}
static segdata * GetFrameSegData( frame_spec *targ )
/**************************************************/
{
segdata * sdata;
seg_leader *leader;
sdata = NULL;
switch( targ->type ) {
case FIX_FRAME_SEG:
sdata = targ->u.sdata;
break;
case FIX_FRAME_GRP:
leader = Ring2First( targ->u.group->leaders );
if( leader != NULL ) {
sdata = Ring2First( leader->pieces );
}
break;
case FIX_FRAME_EXT:
sdata = targ->u.sym->p.seg;
break;
}
return( sdata );
}
static bool IsReadOnly( segdata *sdata )
/**************************************/
{
return( sdata->iscode
|| ( sdata->u.leader->group != NULL )
&& ( sdata->u.leader->group->segflags & SEG_READ_ONLY ) );
}
static void CheckRWData( frame_spec *targ, targ_addr *addr )
/**********************************************************/
{
symbol sym;
if( ( FmtData.type & MK_WINDOWS )
&& FmtData.u.os2.chk_seg_relocs
&& IsReadOnly( LastSegData ) ) {
if( ( !IS_SYM_IMPORTED( targ->u.sym ) )
&& ( !IsReadOnly( GetFrameSegData( targ ) ) ) ) {
if( CurrRec.seg->u.leader->dbgtype == NOT_DEBUGGING_INFO ) {
if( targ->type == TARGET_SEGWD ) {
sym.name = targ->u.sdata->u.leader->segname;
LnkMsg( LOC+WRN+MSG_RELOC_TO_RWDATA_SEG, "aS", addr, &sym );
} else if( targ->type == TARGET_EXTWD ) {
LnkMsg( LOC+WRN+MSG_RELOC_TO_RWDATA_SEG, "aS", addr, targ->u.sym );
}
}
}
}
}
static bool IsTargAbsolute( frame_spec *targ )
/********************************************/
{
return( ( targ->type == FIX_FRAME_SEG ) && targ->u.sdata->isabs
|| ( targ->type == FIX_FRAME_EXT ) && ( targ->u.sym->info & SYM_ABSOLUTE ) );
}
static void BuildReloc( save_fixup *save, frame_spec *targ, frame_spec *frame )
/*****************************************************************************/
{
fix_data fix;
targ_addr faddr;
memset( &fix, 0, sizeof( fix_data ) ); // to get all bitfields 0
GetFrameAddr( targ, &fix.tgt_addr, NULL, save->off );
GetFrameAddr( frame, &faddr, &fix.tgt_addr, save->off );
fix.type = save->flags;
fix.loc_addr = CurrRec.addr;
fix.loc_addr.off += save->off;
if( targ->type == FIX_FRAME_EXT ) {
if( targ->u.sym->info & SYM_TRACE ) {
RecordTracedSym( targ->u.sym );
}
if( !( targ->u.sym->info & SYM_DEFINED ) ) {
ProcUndefined( targ->u.sym );
return;
}
fix.ffix = GET_FFIX_VALUE( targ->u.sym );
if( IS_SYM_IMPORTED( targ->u.sym ) ) {
if( ( frame->type < FIX_FRAME_LOC )
&& ( targ->u.sym != frame->u.sym ) ) {
if( FmtData.type & ( MK_NOVELL | MK_OS2_FLAT | MK_PE ) ) {
fix.tgt_addr.seg = faddr.seg;
fix.tgt_addr.off = 0;
} else {
LnkMsg( LOC+ERR+MSG_FRAME_EQ_TARGET, "a", &fix.loc_addr );
}
}
fix.imported = TRUE;
}
}
if( save->flags & FIX_BASE ) {
if( FmtData.type & ( MK_PROT_MODE & ~( MK_OS2_FLAT | MK_PE ) ) ) {
if( faddr.seg != fix.tgt_addr.seg ) {
if( FmtData.type & MK_ID_SPLIT ) {
LnkMsg( LOC+ERR+MSG_NOV_NO_CODE_DATA_RELOC, "a",
&fix.loc_addr );
} else {
LnkMsg( LOC+ERR+MSG_FRAME_EQ_TARGET, "a", &fix.loc_addr );
}
}
}
if( !fix.imported ) {
CheckRWData( targ, &fix.loc_addr );
}
}
if( !fix.imported ) {
if( ( (save->flags & FIX_OFFSET_MASK) > FIX_OFFSET_16 )
|| ( fix.ffix != FFIX_NOT_A_FLOAT ) ) {
/***************************************************************/
/* fix bug #630 fixup is applied to non first segment of grp */
/* recalculate offset from start of group */
/***************************************************************/
if( faddr.seg < fix.tgt_addr.seg ) {
ConvertToFrame( &fix.tgt_addr, faddr.seg );
}
fix.tgt_addr.seg = faddr.seg;
} else {
ConvertToFrame( &fix.tgt_addr, faddr.seg );
}
}
if( (save->flags & (FIX_OFFSET_MASK | FIX_HIGH)) == FIX_HIGH_OFFSET_16 ) {
fix.tgt_addr.off += FixupOverflow << 16;
}
if( IsTargAbsolute( targ ) ) {
fix.type |= FIX_ABS;
}
if( FmtData.type & MK_OVERLAYS ) {
if( ( (fix.type & FIX_REL) == 0 )
&& ( targ->type == FIX_FRAME_EXT )
&& targ->u.sym->u.d.ovlref
&& ( (targ->u.sym->u.d.ovlstate & OVL_VEC_MASK) == OVL_MAKE_VECTOR ) ) {
// redirect target to appropriate vector entry
GetVecAddr( targ->u.sym->u.d.ovlref, &fix.tgt_addr );
}
} else if( FmtData.type & MK_PE ) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?