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