obj2supp.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,658 行 · 第 1/4 页

C
1,658
字号
        if( fix.imported ) {
            /*
                Under PE, the imported symbol address is set to the
                transfer code (JMP [xxxxx]) that is generated by the linker.
            */
            fix.tgt_addr = targ->u.sym->addr;
            fix.imported = FALSE;
        }
    }

    Relocate( save, &fix, targ );
}

extern unsigned IncExecRelocs( void *_save )
/******************************************/
{
    save_fixup *save = _save;
    segdata *   sdata;
    frame_spec  targ;
    frame_spec  frame;

    if( save->flags & FIX_CHANGE_SEG ) {
        sdata = (segdata *)( save->flags & ~FIX_CHANGE_SEG );
        if( LinkFlags & INC_LINK_FLAG ) {
            save->flags = (unsigned_32) CarveGetIndex( CarveSegData, sdata );
            save->flags |= FIX_CHANGE_SEG;
        }
        if( !sdata->isdead ) {
            LoadObj( sdata );
            LastSegData = sdata;
        } else {
            LastSegData = NULL;
        }
    } else {
        targ.type = FIX_GET_TARGET( save->flags );
        targ.u.ptr = save->target;
        frame.type = FIX_GET_FRAME( save->flags );
        if( FRAME_HAS_DATA( frame.type ) ) {
            frame.u.ptr = *((void **)( save + 1 ));
        }
        UpdateFramePtr( &targ );
        UpdateFramePtr( &frame );
        if( LastSegData != NULL ) {
            BuildReloc( save, &targ, &frame );
        }
        if( LinkFlags & INC_LINK_FLAG ) {
            MapFramePtr( &targ, &save->target );
            MapFramePtr( &frame, (void **)( save + 1 ) );
        }
    }
    return( CalcSavedFixSize( save->flags ) );
}

static void FixFrameValue( frame_type type, void **target )
/*********************************************************/
{
    switch( type ) {
    case FIX_FRAME_SEG:
        *target = CarveMapIndex( CarveSegData, *target );
        break;
    case FIX_FRAME_EXT:
        *target = CarveMapIndex( CarveSymbol, *target );
        break;
    }
}

extern unsigned RelocMarkSyms( void *_fix )
/*****************************************/
{
    save_fixup *fix = _fix;
    segdata *   sdata;
    frame_type  frame;
    symbol *    sym;

    if( fix->flags & FIX_CHANGE_SEG ) {
        sdata = CarveMapIndex( CarveSegData,
                                (void *)( fix->flags & ~FIX_CHANGE_SEG ) );
        fix->flags = (unsigned_32) sdata | FIX_CHANGE_SEG;
    } else {
        frame = FIX_GET_FRAME( fix->flags );
        if( FRAME_HAS_DATA( frame ) ) {
            FixFrameValue( frame, (void **)( fix + 1 ) );
        }
        frame = FIX_GET_TARGET( fix->flags );
        FixFrameValue( frame, &fix->target );
        if( frame == FIX_FRAME_EXT ) {
            sym = (symbol *)fix->target;
            sym->info |= SYM_RELOC_REFD;
            sym = UnaliasSym( ST_FIND, sym );
            sym->info |= SYM_RELOC_REFD;
        }
    }
    return( CalcSavedFixSize( fix->flags ) );
}

static bool MemIsZero( char *mem, unsigned size )
/***********************************************/
{
    while( size > 0 ) {
        if( *mem != '\0' )
            return( FALSE );
        mem++;
        size--;
    }
    return( TRUE );
}

extern void StoreFixup( offset off, fix_type type, frame_spec *frame,
                        frame_spec *targ, offset addend )
/*******************************************************************/
{
    save_fixup  save;
    fix_data    fix;
    unsigned    size;
    char        buff[2 * sizeof( unsigned_32 )];

    if( LastSegData != CurrRec.seg ) {
        DbgAssert( CurrRec.seg != NULL );
        LastSegData = CurrRec.seg;
        save.flags = (unsigned_32) CurrRec.seg;
        save.flags |= FIX_CHANGE_SEG;   // DANGER! assume pointers word aligned
        PermSaveFixup( &save, sizeof( unsigned_32 ) );
    }
    save.flags = type;
    save.flags |= (unsigned_32)targ->type << FIX_TARGET_SHIFT;
    save.flags |= (unsigned_32)frame->type << FIX_FRAME_SHIFT;
    save.off = off + CurrRec.obj_offset;
    save.target = targ->u.ptr;
    if( ObjFormat & FMT_UNSAFE_FIXUPP ) {
        save.flags |= FIX_UNSAFE;
    }
    size = CalcFixupSize( type );
    if( CurrRec.data != NULL ) {
        memcpy( buff, CurrRec.data + off, size );
    } else {
        ReadInfo( CurrRec.seg->data + save.off, buff, size );
    }
    fix.type = type;
    fix.data = buff;
    if( ( type & ( FIX_OFFSET_MASK | FIX_HIGH ) ) == FIX_HIGH_OFFSET_16 ) {
        addend += FixupOverflow << 16;
    }
    PatchOffset( &fix, addend, TRUE );
    if( MemIsZero( buff, size ) ) {
        save.flags |= FIX_ADDEND_ZERO;
    }
    PermSaveFixup( &save, sizeof( save_fixup ) );
    if( FRAME_HAS_DATA( frame->type ) ) {
        PermSaveFixup( &frame->u.abs, sizeof( unsigned_32 ) );
    }
    if( !( save.flags & FIX_ADDEND_ZERO ) )  {
        PermSaveFixup( buff, CalcAddendSize( save.flags ) );
    }
    TraceFixup( save.flags, targ );
    if( CurrRec.data != NULL ) {
        memcpy( CurrRec.data + off, buff, size );
    } else {
        PutInfo( CurrRec.seg->data + save.off, buff, size );
    }
}

extern unsigned IncSaveRelocs( void *_save )
/******************************************/
{
    save_fixup *save = _save;
    segdata *   sdata;
    frame_spec  targ;
    unsigned    fixsize;
    unsigned    datasize;
    char *      data;

    fixsize = CalcSavedFixSize( save->flags );
    if( save->flags & FIX_CHANGE_SEG ) {
        sdata = (segdata *)( save->flags & ~FIX_CHANGE_SEG );
        if( !sdata->isdead ) {
            LastSegData = sdata;
        } else {
            LastSegData = NULL;
        }
    } else if( LastSegData != NULL ) {
        targ.type = FIX_GET_TARGET( save->flags );
        targ.u.ptr = save->target;
        datasize = CalcFixupSize( save->flags );
        if( save->flags & FIX_ADDEND_ZERO ) {
            PutNulls( LastSegData->data + save->off, datasize  );
        } else {
            data = (char *)save + ( fixsize - CalcAddendSize( save->flags ) );
            PutInfo( LastSegData->data + save->off, data, datasize  );
        }
        TraceFixup( save->flags, &targ );
    }
    PermSaveFixup( save, fixsize );
    return( fixsize );
}

static void DumpReloc( base_reloc *curr )
/***************************************/
{
    if( curr->isfloat ) {
        FloatReloc( &curr->item );
    } else if( curr->isqnxlinear ) {
        QNXLinearReloc( CurrRec.seg->u.leader->group, &curr->item );
    } else {
        WriteReloc( CurrRec.seg->u.leader->group, curr->fix_off,
                    &curr->item, curr->rel_size );
        if( FmtData.type & MK_OS2_FLAT ) {
            if( OSF_PAGE_SIZE - ( curr->fix_off & OSF_PAGE_MASK ) < curr->fix_size ) {
                /* stupid relocation has been split across two
                    pages, have to duplicate the entry */
                curr->item.os2f.fmt.r32_soff -= OSF_PAGE_SIZE;
                WriteReloc( CurrRec.seg->u.leader->group,
                            curr->fix_off + OSF_PAGE_SIZE, &curr->item,
                            curr->rel_size );
            }
        }
    }
}

static void InitReloc( base_reloc *reloc )
/****************************************/
{
    reloc->isfloat = FALSE;
    reloc->isqnxlinear = FALSE;
    reloc->rel_size = FmtRelocSize;
}

static unsigned FindGroupIdx( segment seg )
/******************************************/
{
    group_entry *group;
    unsigned    index;

    index = 1;
    for( group = Groups; group != NULL; group = group->next_group ) {
        if( group->grp_addr.seg == seg ) {
            return( index );
        }
        index++;
    }
    return( 0 );
}

static void PatchOffset( fix_data *fix, unsigned_32 val, bool isdelta )
/*********************************************************************/
/* patch offsets into the loaded object */
{
    byte *      code;
    unsigned_32 oldval;
    signed_32   sval;

    FixupOverflow = 0;
    if( val == 0 )
        return;
    code = fix->data;
    if( fix->type & FIX_SHIFT ) {
        if( val & 3 ) {
            LnkMsg( LOC+WRN+MSG_REL_NOT_ALIGNED, "a", &fix->loc_addr );
        }
        val >>= 2;
    }
    switch( fix->type & FIX_OFFSET_MASK ) {
    case FIX_OFFSET_8:
        if( fix->type & FIX_HIGH ) {
            val >>= 8;
        }
        PUT_U8( code, GET_U8( code ) + val );
        break;
    case FIX_OFFSET_16:
        if( fix->type & FIX_HIGH ) {
            val >>= 16;
        }                       // NOTE the fall through
    case FIX_NO_OFFSET:         // used for FIX_BASE
        if( fix->type & FIX_SIGNED ) {
            if( isdelta ) {
                sval = (signed_32)GET_S16( code ) + val;
                val = sval;
                if( sval > 0x7FFF ) {
                    val = val & 0xFFFF;
                    if( val > 0x7FFF ) {
                        FixupOverflow = 1;
                        val -= 0x10000;
                    }
                }
            } else {
                oldval = val;
                sval = (signed_32)GET_S16( code );
                val += sval;
                if( ( oldval >> 16 ) < ( val >> 16 ) ) {
                    FixupOverflow = 1;
                } else if( ( fix->type & FIX_SIGNED )
                    && ( oldval >> 16 ) == ( val >> 16 )
                    && ( (signed_16)( val & 0xFFFF ) < 0 ) ) {
                    FixupOverflow = 1;
                }
            }
        } else {
            val += GET_U16( code );
        }
        PUT_U16( code, val );
        break;
    case FIX_OFFSET_21:
        oldval = GET_U32( code );
        val += oldval;
        oldval &= 0xFFE00000;
        val &= 0x001FFFFF;
        PUT_U32( code, oldval | val );
        break;
    case FIX_OFFSET_26:     // Processing is the same, except FIX_OFFSET_26
    case FIX_OFFSET_24:     // uses FIX_SHIFT (it's really a 28-bit offset)
        oldval = GET_U32( code );
        val += oldval;
        oldval &= 0xFC000000;
        val &= 0x03FFFFFF;
        PUT_U32( code, oldval | val );
        break;
    case FIX_OFFSET_32:
        PUT_U32( code, GET_U32( code ) + val );
        break;
    default:
        LnkMsg( LOC+ERR+MSG_BAD_RELOC_TYPE, NULL );
    }
}

static void MakeQNXFloatReloc( fix_data *fix )
/********************************************/
{
    base_reloc  new_reloc;

    if( FmtData.u.qnx.gen_seg_relocs ) {
        InitReloc( &new_reloc );
        new_reloc.isfloat = TRUE;
        new_reloc.item.qnx.reloc_offset = fix->loc_addr.off
                               | ( (unsigned_32)fix->ffix << 28 );
        new_reloc.item.qnx.segment = ToQNXIndex( fix->loc_addr.seg );
        DumpReloc( &new_reloc );
    }
}

static byte WinFFixMap[] = {
    0,
    WIN_FFIX_WR_SYMBOL,
    WIN_FFIX_DR_SYMBOL,
    WIN_FFIX_ES_OVERRIDE,
    WIN_FFIX_CS_OVERRIDE,
    WIN_FFIX_SS_OVERRIDE,
    WIN_FFIX_DS_OVERRIDE
};

static void MakeWindowsFloatReloc( fix_data *fix )
/************************************************/
{
    base_reloc          new_reloc;
    os2_reloc_item *    os2item;

    InitReloc( &new_reloc );
    os2item = &new_reloc.item.os2;
    os2item->addr_type = MapOS2FixType( fix->type );
    os2item->reloc_offset = fix->loc_addr.off
                        - CurrRec.seg->u.leader->group->grp_addr.off;
    os2item->reloc_type = OSFIXUP | ADDITIVE;
    os2item->put.fltpt = WinFFixMap[ fix->ffix ];
    DumpReloc( &new_reloc );
}

static offset GetSegOff( segdata *sdata )
/***************************************/
{
    return( sdata->a.delta + sdata->u.leader->seg_addr.off );
}

static void CheckPartialRange( fix_data *fix, signed_32 off,
                               unsigned_32 mask, unsigned_32 topbit )
/*******************************************************************/
{
    unsigned_32 utemp;
    signed_32   temp;

    utemp = GET_U32( fix->data ) & mask;
    if( utemp & topbit ) {      // it is negative
        utemp |= ~mask; // do a bogus sign extension
    }
    temp = utemp;
    if( fix->type & FIX_SHIFT ) {
        temp += off / 4;
    } else {
        temp += off;
    }
    if( ( temp < -topbit ) || ( temp >= topbit ) ) {
        LnkMsg( LOC+ERR+MSG_FIXUP_OFF_RANGE, "a", &fix->loc_addr );
    }
}

static bool CheckSpecials( fix_data *fix, frame_spec *targ )
/**********************************************************/
{
    signed_32   off;
    unsigned_32 uoff;
    signed_32   temp;
    signed_32   pos;
    unsigned    fixsize;
    group_entry *group;
    segdata  *  sdata;
    fix_type    special;

    if( FmtData.type & MK_ELF ) {
        if( !( fix->type & FIX_REL ) )
            return( FALSE );
#if 0
    XXX: this is not the right thing to do for elf-i386
        if( fix->loc_addr.seg != fix->tgt_addr.seg )
            return( FALSE );
#endif
    }
    if( ( FmtData.type & ( MK_QNX | MK_WINDOWS ) )
        && ( fix->ffix != FFIX_NOT_A_FLOAT ) ) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?