mirror of
https://github.com/NishiOwO/JWasm.git
synced 2025-04-21 16:54:39 +00:00
437 lines
16 KiB
C
437 lines
16 KiB
C
/****************************************************************************
|
|
*
|
|
* 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: handle OMF fixups
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include <stddef.h>
|
|
|
|
#include "globals.h"
|
|
#include "parser.h"
|
|
#include "segment.h"
|
|
#include "fixup.h"
|
|
#include "omfint.h"
|
|
#include "omfspec.h"
|
|
#include "myassert.h"
|
|
|
|
extern const char szNull[];
|
|
extern unsigned omf_GetGrpIdx( struct asym *sym );
|
|
|
|
/* logical data for fixup subrecord creation */
|
|
struct logref {
|
|
uint_8 frame; /* see enum frame_methods in omfspec.h */
|
|
uint_16 frame_datum; /* datum for certain frame methods */
|
|
uint_8 is_secondary; /* can write target in a secondary manner */
|
|
uint_8 target; /* see enum target_methods in omfspec.h */
|
|
uint_16 target_datum; /* datum for certain target methods */
|
|
int_32 target_offset; /* offset of target for target method */
|
|
};
|
|
|
|
static uint_8 *putIndex( uint_8 *p, uint_16 index )
|
|
/*************************************************/
|
|
{
|
|
if( index > 0x7f ) {
|
|
*p++ = 0x80 | ( index >> 8 );
|
|
}
|
|
*p++ = index;
|
|
return( p );
|
|
}
|
|
|
|
static uint_8 *put16( uint_8 *p, uint_16 value )
|
|
/**********************************************/
|
|
{
|
|
WriteU16( p, value );
|
|
return( p + sizeof( uint_16 ) );
|
|
}
|
|
|
|
static uint_8 *put32( uint_8 *p, uint_32 value )
|
|
/**********************************************/
|
|
{
|
|
WriteU32( p, value );
|
|
return( p + sizeof( uint_32 ) );
|
|
}
|
|
|
|
static uint_8 *putFrameDatum( uint_8 *p, uint_8 method, uint_16 datum )
|
|
/*********************************************************************/
|
|
{
|
|
switch( method ) {
|
|
case FRAME_SEG:
|
|
case FRAME_GRP:
|
|
case FRAME_EXT:
|
|
return( putIndex( p, datum ) );
|
|
#if 0 /* v2.12: FRAME_ABS is invalid according to TIS OMF docs. */
|
|
case FRAME_ABS:
|
|
return( put16( p, datum ) );
|
|
#endif
|
|
}
|
|
/* for FRAME_LOC & FRAME_TARG ( & FRAME_NONE ) there's no datum to write. */
|
|
return( p );
|
|
}
|
|
|
|
static uint_8 *putTargetDatum( uint_8 *p, uint_8 method, uint_16 datum )
|
|
/**********************************************************************/
|
|
{
|
|
#if 0 /* v2.12: JWasm won't use TARGE_ABSxx; also, it's not defined for FIXUP sub-records */
|
|
if( ( method & 0x03 ) == TARGET_ABSWD ) {
|
|
return( put16( p, datum ) );
|
|
}
|
|
#endif
|
|
return( putIndex( p, datum ) );
|
|
}
|
|
|
|
/* translate logref to FIXUP subrecord ( without Locat field ).
|
|
* fields written to buf:
|
|
* - uint_8 Fix Data (type of frame and target)
|
|
* - index Frame Datum (optional, index of a SEGDEF, GRPDEF or EXTDEF)
|
|
* - index Target Datum (index of a SEGDEF, GRPDEF or EXTDEF)
|
|
* - uint_16/32 Target Displacement (optional)
|
|
*
|
|
* type is FIX_GEN_INTEL or FIX_GEN_MS386
|
|
* v2.12: new function OmfFixGetFixModend() replaced code in writeModend(),
|
|
* TranslateLogref() has become static.
|
|
*/
|
|
|
|
static unsigned TranslateLogref( const struct logref *lr, uint_8 *buf, enum fixgen_types type )
|
|
/*********************************************************************************************/
|
|
{
|
|
uint_8 *p;
|
|
uint_8 target;
|
|
|
|
/**/myassert( lr != NULL );
|
|
/**/myassert( buf != NULL );
|
|
/**/myassert( type == FIX_GEN_INTEL || 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 = lr->target;
|
|
if( lr->target_offset == 0 && lr->is_secondary ) {
|
|
target |= 0x04; /* P=1 -> no displacement field */
|
|
}
|
|
p = buf;
|
|
/* write the "Fix Data" field, FfffTPtt:
|
|
* F : 0 = frame method is defined in fff field ( F0-F5)
|
|
* 1 = frame is defined by a thread ( won't occur here )
|
|
* fff: frame method
|
|
* T : 0 = target is defined by tt
|
|
* 1 = target is defined by thread# in tt, P is used as bit 2 for method
|
|
* P : 0 = target displacement field is present
|
|
* 1 = no displacement field
|
|
* tt : target method
|
|
*/
|
|
*p++ = ( lr->frame << 4 ) | ( target );
|
|
p = putFrameDatum( p, lr->frame, lr->frame_datum );
|
|
p = putTargetDatum( p, target, lr->target_datum );
|
|
if( ( target & 0x04 ) == 0 ) {
|
|
if( type == FIX_GEN_MS386 ) {
|
|
p = put32( p, (uint_32)lr->target_offset );
|
|
} else {
|
|
p = put16( p, (uint_16)lr->target_offset );
|
|
}
|
|
}
|
|
return( p - buf );
|
|
}
|
|
|
|
#if 0 /* v2.11: obsolete */
|
|
|
|
static uint TranslatePhysref( const struct physref *ref, uint_8 *buf, enum fixgen_types type )
|
|
/********************************************************************************************/
|
|
{
|
|
uint_8 *p;
|
|
|
|
/**/myassert( ref != NULL );
|
|
/**/myassert( buf != NULL );
|
|
/**/myassert( type == FIX_GEN_INTEL || type == FIX_GEN_MS386 );
|
|
|
|
p = put16( buf, ref->frame );
|
|
p = put16( p, ref->offset );
|
|
return( p - buf );
|
|
}
|
|
|
|
/* used when the MODEND record is written.
|
|
* is_logical is always 1 then.
|
|
* v2.11: obsolete. TranslateLogref() is now called directly by writeModend() in omfint.c
|
|
*/
|
|
|
|
unsigned TranslateRef( const union logphys *ref, int is_logical, uint_8 *buf, enum fixgen_types type )
|
|
/****************************************************************************************************/
|
|
{
|
|
return( is_logical ? TranslateLogref( &ref->log, buf, type ) : TranslatePhysref( &ref->phys, buf, type ) );
|
|
}
|
|
|
|
#endif
|
|
|
|
/* generate start address subfield for MODEND */
|
|
|
|
unsigned OmfFixGenFixModend( const struct fixup *fixup, uint_8 *buf, uint_32 displ, enum fixgen_types type )
|
|
/**********************************************************************************************************/
|
|
{
|
|
struct asym *sym = fixup->sym;
|
|
struct logref lr;
|
|
|
|
lr.is_secondary = FALSE;
|
|
lr.target_offset = sym->offset + displ;
|
|
|
|
lr.frame_datum = fixup->frame_datum;
|
|
|
|
/* symbol is always a code label (near or far), internal or external */
|
|
/* now set Target and Frame */
|
|
|
|
if( sym->state == SYM_EXTERNAL ) {
|
|
DebugMsg(("omf_write_modend(%p): fixup->frame_type/datum=%u/%u, EXTERNAL sym=%s\n",
|
|
fixup, fixup->frame_type, fixup->frame_datum, sym->name));
|
|
|
|
lr.target = TARGET_EXT & TARGET_WITH_DISPL;
|
|
lr.target_datum = sym->ext_idx1;
|
|
|
|
if( fixup->frame_type == FRAME_GRP && fixup->frame_datum == 0 ) {
|
|
/* set the frame to the frame of the corresponding segment */
|
|
lr.frame_datum = omf_GetGrpIdx( sym );
|
|
}
|
|
} else { /* SYM_INTERNAL */
|
|
DebugMsg(("OmfFixGenFixModend(%p): fixup->frame_type/datum=%u/%u sym->name=%s state=%X segm=%s\n",
|
|
fixup, fixup->frame_type, fixup->frame_datum, sym->name, sym->state, sym->segment ? sym->segment->name : "NULL" ));
|
|
/**/myassert( sym->state == SYM_INTERNAL );
|
|
|
|
lr.target = TARGET_SEG & TARGET_WITH_DISPL;
|
|
lr.target_datum = GetSegIdx( sym->segment );
|
|
}
|
|
|
|
if( fixup->frame_type != FRAME_NONE && fixup->frame_type != FRAME_SEG ) {
|
|
lr.frame = (uint_8)fixup->frame_type;
|
|
} else {
|
|
lr.frame = FRAME_TARG;
|
|
}
|
|
return( TranslateLogref( &lr, buf, type ) );
|
|
}
|
|
|
|
/* fill a logref from a fixup's info */
|
|
|
|
static int omf_fill_logref( const struct fixup *fixup, struct logref *lr )
|
|
/************************************************************************/
|
|
{
|
|
struct asym *sym;
|
|
|
|
sym = fixup->sym; /* may be NULL! */
|
|
|
|
DebugMsg1(("omf_fill_logref: sym=%s, state=%d, fixup->type=%u\n",
|
|
sym ? sym->name : "NULL", sym ? sym->state : -1, fixup->type ));
|
|
|
|
/*------------------------------------*/
|
|
/* Determine the Target and the Frame */
|
|
/*------------------------------------*/
|
|
|
|
if( sym == NULL ) {
|
|
|
|
DebugMsg(("omf_fill_logref: sym is NULL, frame_type=%u\n", fixup->frame_type ));
|
|
if ( fixup->frame_type == FRAME_NONE ) /* v1.96: nothing to do without a frame */
|
|
return( 0 );
|
|
lr->target = fixup->frame_type;
|
|
lr->target_datum = fixup->frame_datum;
|
|
lr->frame = FRAME_TARG;
|
|
|
|
} else if( sym->state == SYM_UNDEFINED ) { /* shouldn't happen */
|
|
|
|
DebugMsg(("omf_fill_logref: sym->state is SYM_UNDEFINED\n" ));
|
|
EmitErr( SYMBOL_NOT_DEFINED, sym->name );
|
|
return( 0 );
|
|
|
|
} else if( sym->state == SYM_GRP ) {
|
|
|
|
DebugMsg1(("omf_fill_logref: sym->state is SYM_GRP\n" ));
|
|
lr->target = TARGET_GRP;
|
|
lr->target_datum = ((struct dsym *)sym)->e.grpinfo->grp_idx;
|
|
if( fixup->frame_type != FRAME_NONE ) {
|
|
lr->frame = fixup->frame_type;
|
|
lr->frame_datum = fixup->frame_datum;
|
|
} else {
|
|
lr->frame = FRAME_GRP;
|
|
lr->frame_datum = lr->target_datum;
|
|
}
|
|
|
|
} else if( sym->state == SYM_SEG ) {
|
|
|
|
DebugMsg1(("omf_fill_logref: sym->state is SYM_SEG %s\n" ));
|
|
lr->target = TARGET_SEG;
|
|
lr->target_datum = GetSegIdx( sym );
|
|
if( fixup->frame_type != FRAME_NONE ) {
|
|
lr->frame = fixup->frame_type;
|
|
lr->frame_datum = fixup->frame_datum;
|
|
} else {
|
|
lr->frame = FRAME_SEG;
|
|
lr->frame_datum = lr->target_datum;
|
|
}
|
|
|
|
} else {
|
|
|
|
/* symbol is a label */
|
|
|
|
lr->frame_datum = fixup->frame_datum;
|
|
if( sym->state == SYM_EXTERNAL ) {
|
|
DebugMsg1(("omf_fill_logref: sym->state is SYM_EXTERNAL, fixup->frame_type/datum=%u/%u\n",
|
|
fixup->frame_type, fixup->frame_datum ));
|
|
lr->target = TARGET_EXT;
|
|
lr->target_datum = sym->ext_idx1;
|
|
|
|
if( fixup->frame_type == FRAME_GRP && fixup->frame_datum == 0 ) {
|
|
/* set the frame to the frame of the corresponding segment */
|
|
lr->frame_datum = omf_GetGrpIdx( sym );
|
|
}
|
|
} else {
|
|
/* must be SYM_INTERNAL */
|
|
/**/myassert( sym->state == SYM_INTERNAL );
|
|
DebugMsg1(("omf_fill_logref: sym->state is SYM_INTERNAL, sym->segment=%s, fixup->frame/datum=%u/%u\n",
|
|
sym->segment ? sym->segment->name : "NULL", fixup->frame_type, fixup->frame_datum ));
|
|
/* v2.08: don't use info from assembly-time variables */
|
|
if ( sym->variable ) {
|
|
lr->target = ( fixup->frame_type == FRAME_GRP ? TARGET_GRP : TARGET_SEG );
|
|
lr->target_datum = fixup->frame_datum;
|
|
} else if ( sym->segment == NULL ) { /* shouldn't happen */
|
|
EmitErr( SEGMENT_MISSING_FOR_FIXUP, sym->name );
|
|
return ( 0 );
|
|
#if COMDATSUPP
|
|
} else if ( ( (struct dsym *)sym->segment)->e.seginfo->comdat_selection ) {
|
|
lr->target = TARGET_EXT;
|
|
lr->target_datum = ((struct dsym *)sym->segment)->e.seginfo->seg_idx;
|
|
lr->frame = FRAME_TARG;
|
|
return( 1 );
|
|
#endif
|
|
} else {
|
|
lr->target = TARGET_SEG;
|
|
lr->target_datum = GetSegIdx( sym->segment );
|
|
}
|
|
}
|
|
|
|
if( fixup->frame_type != FRAME_NONE ) {
|
|
lr->frame = (uint_8)fixup->frame_type;
|
|
} else {
|
|
lr->frame = FRAME_TARG;
|
|
}
|
|
}
|
|
|
|
/*--------------------*/
|
|
/* Optimize the fixup */
|
|
/*--------------------*/
|
|
|
|
if( lr->frame == ( lr->target - TARGET_SEG ) ) {
|
|
lr->frame = FRAME_TARG;
|
|
}
|
|
|
|
return( 1 );
|
|
}
|
|
|
|
/* translate a fixup into its binary representation,
|
|
* which is a "FIXUPP subrecord" according to OMF docs.
|
|
* structure:
|
|
* - WORD, Locat: 1MLLLLDD DDDDDDDD, is
|
|
* 1 = indicates FIXUP, no THREAD subrecord
|
|
* M = mode: 1=segment relative, 0=self relative
|
|
* L = location, see LOC_ entries in omfspec.h
|
|
* D = data record offset, 10 bits for range 0-3FFh
|
|
* - BYTE, Fix Data: FRRRTPGG, is
|
|
* F = 0=frame defined in fixup, 1=frame defined in frame thread
|
|
* R = Frame
|
|
* T = 0=target defined in fixup, 1=Target defined in target thread
|
|
* P = 0=target displacement is present
|
|
* G = lower bits of target method (F=0), target thread number (F=1)
|
|
* - void/BYTE/WORD, Frame Datum
|
|
* - BYTE/WORD, Target Datum
|
|
* - WORD/DWORD, Target Displacement
|
|
*/
|
|
|
|
unsigned OmfFixGenFix( const struct fixup *fixup, uint_32 start_loc, uint_8 *buf, enum fixgen_types type )
|
|
/********************************************************************************************************/
|
|
{
|
|
uint_8 locat1;
|
|
uint_8 self_relative = FALSE;
|
|
unsigned data_rec_offset;
|
|
struct logref lr;
|
|
|
|
/**/myassert( fixup != NULL );
|
|
/**/myassert( buf != NULL );
|
|
/**/myassert( type == FIX_GEN_INTEL || type == FIX_GEN_MS386 );
|
|
|
|
lr.is_secondary = TRUE;
|
|
lr.target_offset = 0;
|
|
|
|
switch( fixup->type ) {
|
|
case FIX_RELOFF8:
|
|
self_relative = TRUE;
|
|
/* no break */
|
|
case FIX_OFF8:
|
|
locat1 = ( LOC_OFFSET_LO << 2 );
|
|
break;
|
|
case FIX_RELOFF16:
|
|
self_relative = TRUE;
|
|
/* no break */
|
|
case FIX_OFF16:
|
|
locat1 = ( fixup->loader_resolved ? LOC_MS_LINK_OFFSET << 2 : LOC_OFFSET << 2 );
|
|
break;
|
|
case FIX_RELOFF32:
|
|
self_relative = TRUE;
|
|
/* no break */
|
|
case FIX_OFF32:
|
|
locat1 = ( fixup->loader_resolved ? LOC_MS_LINK_OFFSET_32 << 2 : LOC_MS_OFFSET_32 << 2 );
|
|
break;
|
|
case FIX_HIBYTE:
|
|
locat1 = ( LOC_OFFSET_HI << 2 );
|
|
break;
|
|
case FIX_SEG:
|
|
locat1 = ( LOC_BASE << 2 );
|
|
break;
|
|
case FIX_PTR16:
|
|
locat1 = ( LOC_BASE_OFFSET << 2 );
|
|
break;
|
|
case FIX_PTR32:
|
|
locat1 = ( LOC_MS_BASE_OFFSET_32 << 2 );
|
|
break;
|
|
default: /* shouldn't happen. Check for valid fixup has already happened */
|
|
EmitErr( UNSUPPORTED_FIXUP_TYPE,
|
|
ModuleInfo.fmtopt->formatname,
|
|
fixup->sym ? fixup->sym->name : szNull );
|
|
return( 0 );
|
|
}
|
|
locat1 |= self_relative ? 0x80 : 0xc0; /* bit 7: 1=is a fixup subrecord */
|
|
|
|
if ( omf_fill_logref( fixup, &lr ) == 0 )
|
|
return( 0 );
|
|
|
|
/* magnitude of fixup's position is 10! */
|
|
/**/myassert( fixup->locofs - start_loc < 1024 );
|
|
|
|
/* calculate the fixup's position in current LEDATA */
|
|
data_rec_offset = fixup->locofs - start_loc;
|
|
|
|
locat1 |= data_rec_offset >> 8;
|
|
*buf = locat1;
|
|
*(buf+1) = (uint_8)data_rec_offset;
|
|
return( 2 + TranslateLogref( &lr, buf+2, type ) );
|
|
}
|
|
|