#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 );
struct logref {
uint_8 frame;
uint_16 frame_datum;
uint_8 is_secondary;
uint_8 target;
uint_16 target_datum;
int_32 target_offset;
};
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#endif
}
return( p );
}
static uint_8 *putTargetDatum( uint_8 *p, uint_8 method, uint_16 datum )
{
#if 0#endif
return( putIndex( p, datum ) );
}
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 );
target = lr->target;
if( lr->target_offset == 0 && lr->is_secondary ) {
target |= 0x04;
}
p = buf;
*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#endif
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;
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 ) {
lr.frame_datum = omf_GetGrpIdx( sym );
}
} else {
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 ) );
}
static int omf_fill_logref( const struct fixup *fixup, struct logref *lr )
{
struct asym *sym;
sym = fixup->sym;
DebugMsg1(("omf_fill_logref: sym=%s, state=%d, fixup->type=%u\n",
sym ? sym->name : "NULL", sym ? sym->state : -1, fixup->type ));
if( sym == NULL ) {
DebugMsg(("omf_fill_logref: sym is NULL, frame_type=%u\n", fixup->frame_type ));
if ( fixup->frame_type == FRAME_NONE )
return( 0 );
lr->target = fixup->frame_type;
lr->target_datum = fixup->frame_datum;
lr->frame = FRAME_TARG;
} else if( sym->state == SYM_UNDEFINED ) {
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 {
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 ) {
lr->frame_datum = omf_GetGrpIdx( sym );
}
} else {
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 ));
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 ) {
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;
}
}
if( lr->frame == ( lr->target - TARGET_SEG ) ) {
lr->frame = FRAME_TARG;
}
return( 1 );
}
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;
case FIX_OFF8:
locat1 = ( LOC_OFFSET_LO << 2 );
break;
case FIX_RELOFF16:
self_relative = TRUE;
case FIX_OFF16:
locat1 = ( fixup->loader_resolved ? LOC_MS_LINK_OFFSET << 2 : LOC_OFFSET << 2 );
break;
case FIX_RELOFF32:
self_relative = TRUE;
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:
EmitErr( UNSUPPORTED_FIXUP_TYPE,
ModuleInfo.fmtopt->formatname,
fixup->sym ? fixup->sym->name : szNull );
return( 0 );
}
locat1 |= self_relative ? 0x80 : 0xc0;
if ( omf_fill_logref( fixup, &lr ) == 0 )
return( 0 );
myassert( fixup->locofs - start_loc < 1024 );
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 ) );
}