#include <ctype.h>
#include "globals.h"
#include "memalloc.h"
#include "parser.h"
#include "segment.h"
#include "assume.h"
#include "types.h"
#include "label.h"
#include "lqueue.h"
#include "expreval.h"
#include "fastpass.h"
#include "tokenize.h"
#include "listing.h"
#if AMD64_SUPPORT
#define NUM_STDREGS 16
#else
#define NUM_STDREGS 8
#endif
struct assume_info SegAssumeTable[NUM_SEGREGS];
struct assume_info StdAssumeTable[NUM_STDREGS];
static struct asym *stdsym[NUM_STDREGS];
#if FASTPASS
static struct assume_info saved_SegAssumeTable[NUM_SEGREGS];
static struct assume_info saved_StdAssumeTable[NUM_STDREGS];
static struct stdassume_typeinfo saved_StdTypeInfo[NUM_STDREGS];
#endif
static const enum assume_segreg searchtab[] = {
ASSUME_DS, ASSUME_SS, ASSUME_ES, ASSUME_FS, ASSUME_GS, ASSUME_CS
};
static const char szError[] = { "ERROR" };
static const char szNothing[] = { "NOTHING" };
const char szDgroup[] = { "DGROUP" };
void SetSegAssumeTable( void *savedstate )
{
DebugMsg(("SetSegAssumeTable\n" ));
memcpy( &SegAssumeTable, savedstate, sizeof(SegAssumeTable) );
}
void GetSegAssumeTable( void *savedstate )
{
DebugMsg(("GetSegAssumeTable\n" ));
memcpy( savedstate, &SegAssumeTable, sizeof(SegAssumeTable) );
}
void SetStdAssumeTable( void *savedstate, struct stdassume_typeinfo *ti )
{
int i;
DebugMsg(("SetStdAssumeTable enter\n" ));
memcpy( &StdAssumeTable, savedstate, sizeof(StdAssumeTable) );
for ( i = 0; i < NUM_STDREGS; i++, ti++ ) {
if ( StdAssumeTable[i].symbol ) {
StdAssumeTable[i].symbol->type = ti->type;
StdAssumeTable[i].symbol->target_type = ti->target_type;
StdAssumeTable[i].symbol->mem_type = ti->mem_type;
StdAssumeTable[i].symbol->ptr_memtype = ti->ptr_memtype;
StdAssumeTable[i].symbol->is_ptr = ti->is_ptr;
}
}
}
void GetStdAssumeTable( void *savedstate, struct stdassume_typeinfo *ti )
{
int i;
DebugMsg(("GetStdAssumeTable\n" ));
memcpy( savedstate, &StdAssumeTable, sizeof(StdAssumeTable) );
for ( i = 0; i < NUM_STDREGS; i++, ti++ ) {
if ( StdAssumeTable[i].symbol ) {
ti->type = StdAssumeTable[i].symbol->type;
ti->target_type = StdAssumeTable[i].symbol->target_type;
ti->mem_type = StdAssumeTable[i].symbol->mem_type;
ti->ptr_memtype = StdAssumeTable[i].symbol->ptr_memtype;
ti->is_ptr = StdAssumeTable[i].symbol->is_ptr;
}
}
}
#if FASTPASS
void AssumeSaveState( void )
{
GetSegAssumeTable( &saved_SegAssumeTable );
GetStdAssumeTable( &saved_StdAssumeTable, saved_StdTypeInfo );
}
#endif
void AssumeInit( int pass )
{
int reg;
for( reg = 0; reg < NUM_SEGREGS; reg++ ) {
SegAssumeTable[reg].symbol = NULL;
SegAssumeTable[reg].error = FALSE;
SegAssumeTable[reg].is_flat = FALSE;
}
if ( pass <= PASS_1 ) {
for( reg = 0; reg < NUM_STDREGS; reg++ ) {
StdAssumeTable[reg].symbol = NULL;
StdAssumeTable[reg].error = 0;
}
if ( pass == PASS_1 )
memset( &stdsym, 0, sizeof( stdsym ) );
}
#if FASTPASS
if ( pass > PASS_1 && UseSavedState ) {
SetSegAssumeTable( &saved_SegAssumeTable );
#if 0#endif
SetStdAssumeTable( &saved_StdAssumeTable, saved_StdTypeInfo );
}
#endif
}
void ModelAssumeInit( void )
{
const char *pCS;
const char *pFSassume = szError;
const char *pGSassume = szError;
const char *pFmt;
switch( ModuleInfo.model ) {
case MODEL_FLAT:
#if AMD64_SUPPORT
if ( ModuleInfo.fctype == FCT_WIN64 )
pGSassume = szNothing;
#endif
AddLineQueueX( "%r %r:%r,%r:%r,%r:%r,%r:%r,%r:%s,%r:%s",
T_ASSUME, T_CS, T_FLAT, T_DS, T_FLAT, T_SS, T_FLAT, T_ES, T_FLAT, T_FS, pFSassume, T_GS, pGSassume );
break;
case MODEL_TINY:
case MODEL_SMALL:
case MODEL_COMPACT:
case MODEL_MEDIUM:
case MODEL_LARGE:
case MODEL_HUGE:
#if COFF_SUPPORT || ELF_SUPPORT
if( Options.output_format == OFORMAT_COFF
#if ELF_SUPPORT
|| Options.output_format == OFORMAT_ELF
#endif
)
break;
#endif
if ( ModuleInfo.model == MODEL_TINY )
pCS = szDgroup;
else
pCS = SimGetSegName( SIM_CODE );
if ( ModuleInfo.distance != STACK_FAR )
pFmt = "%r %r:%s,%r:%s,%r:%s";
else
pFmt = "%r %r:%s,%r:%s";
AddLineQueueX( pFmt, T_ASSUME, T_CS, pCS, T_DS, szDgroup, T_SS, szDgroup );
break;
}
}
struct asym *GetStdAssume( int reg )
{
if ( StdAssumeTable[reg].symbol )
if ( StdAssumeTable[reg].symbol->mem_type == MT_TYPE )
return( StdAssumeTable[reg].symbol->type );
else
return( StdAssumeTable[reg].symbol->target_type );
return ( NULL );
}
struct asym *GetStdAssumeEx(int reg)
{
if (reg >= NUM_STDREGS)
return NULL;
return(StdAssumeTable[reg].symbol);
}
ret_code AssumeDirective( int i, struct asm_tok tokenarray[] )
{
int reg;
int j;
int size;
uint_32 flags;
struct assume_info *info;
bool segtable;
struct qualified_type ti;
DebugMsg1(( "AssumeDirective enter, pass=%u\n", Parse_Pass+1 ));
for( i++; i < Token_Count; i++ ) {
if( ( tokenarray[i].token == T_ID )
&& (0 == _stricmp( tokenarray[i].string_ptr, szNothing )) ) {
AssumeInit( -1 );
i++;
break;
}
info = NULL;
if ( tokenarray[i].token == T_REG ) {
reg = tokenarray[i].tokval;
j = GetRegNo( reg );
flags = GetValueSp( reg );
if ( flags & OP_SR ) {
info = &SegAssumeTable[j];
segtable = TRUE;
} else if ( flags & OP_R ) {
info = &StdAssumeTable[j];
segtable = FALSE;
}
}
if ( info == NULL ) {
return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) );
}
if( ( ModuleInfo.curr_cpu & P_CPU_MASK ) < GetCpuSp( reg ) ) {
return( EmitError( INSTRUCTION_OR_REGISTER_NOT_ACCEPTED_IN_CURRENT_CPU_MODE ) );
}
i++;
if( tokenarray[i].token != T_COLON ) {
return( EmitError( COLON_EXPECTED ) );
}
i++;
if( tokenarray[i].token == T_FINAL ) {
return( EmitError( SYNTAX_ERROR ) );
}
if( 0 == _stricmp( tokenarray[i].string_ptr, szError )) {
if ( segtable ) {
info->is_flat = FALSE;
info->error = TRUE;
} else
info->error |= (( reg >= T_AH && reg <= T_BH ) ? RH_ERROR : ( flags & OP_R ));
info->symbol = NULL;
i++;
} else if( 0 == _stricmp( tokenarray[i].string_ptr, szNothing )) {
if ( segtable ) {
info->is_flat = FALSE;
info->error = FALSE;
} else
info->error &= ~(( reg >= T_AH && reg <= T_BH ) ? RH_ERROR : ( flags & OP_R ));
info->symbol = NULL;
i++;
} else if ( segtable == FALSE ) {
ti.size = 0;
ti.is_ptr = 0;
ti.is_far = FALSE;
ti.mem_type = MT_EMPTY;
ti.ptr_memtype = MT_EMPTY;
ti.symtype = NULL;
ti.Ofssize = ModuleInfo.Ofssize;
if ( GetQualifiedType( &i, tokenarray, &ti ) == ERROR )
return( ERROR );
size = OperandSize( flags, NULL );
if ( ( ti.is_ptr == 0 && size != ti.size ) ||
( ti.is_ptr > 0 && size < CurrWordSize ) ) {
return( EmitError( TYPE_IS_WRONG_SIZE_FOR_REGISTER ) );
}
info->error &= ~(( reg >= T_AH && reg <= T_BH ) ? RH_ERROR : ( flags & OP_R ));
if ( stdsym[j] == NULL ) {
stdsym[j] = CreateTypeSymbol( NULL, "", FALSE );
stdsym[j]->typekind = TYPE_TYPEDEF;
}
stdsym[j]->total_size = ti.size;
stdsym[j]->mem_type = ti.mem_type;
stdsym[j]->is_ptr = ti.is_ptr;
stdsym[j]->isfar = ti.is_far;
stdsym[j]->Ofssize = ti.Ofssize;
stdsym[j]->ptr_memtype = ti.ptr_memtype;
if ( ti.mem_type == MT_TYPE )
stdsym[j]->type = ti.symtype;
else
stdsym[j]->target_type = ti.symtype;
info->symbol = stdsym[j];
} else {
struct expr opnd;
if( EvalOperand( &i, tokenarray, Token_Count, &opnd, 0 ) == ERROR )
return( ERROR );
switch ( opnd.kind ) {
case EXPR_ADDR:
if ( opnd.sym == NULL || opnd.indirect == TRUE || opnd.value ) {
return( EmitError( SEGMENT_GROUP_OR_SEGREG_EXPECTED ) );
} else if ( opnd.sym->state == SYM_UNDEFINED ) {
FStoreLine( 0 );
info->symbol = opnd.sym;
} else if ( ( opnd.sym->state == SYM_SEG || opnd.sym->state == SYM_GRP ) && opnd.instr == EMPTY ) {
info->symbol = opnd.sym;
} else if ( opnd.instr == T_SEG ) {
info->symbol = opnd.sym->segment;
} else {
return( EmitError( SEGMENT_GROUP_OR_SEGREG_EXPECTED ) );
}
info->is_flat = ( info->symbol == &ModuleInfo.flat_grp->sym );
break;
case EXPR_REG:
if ( GetValueSp( opnd.base_reg->tokval ) & OP_SR ) {
info->symbol = SegAssumeTable[ GetRegNo( opnd.base_reg->tokval ) ].symbol;
info->is_flat = SegAssumeTable[ GetRegNo( opnd.base_reg->tokval ) ].is_flat;
break;
}
default:
return( EmitError( SEGMENT_GROUP_OR_SEGREG_EXPECTED ) );
}
info->error = FALSE;
}
if( i < Token_Count && tokenarray[i].token != T_COMMA )
break;
}
if ( i < Token_Count ) {
return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].tokpos ) );
}
return( NOT_ERROR );
}
enum assume_segreg search_assume( const struct asym *sym,
enum assume_segreg def, bool search_grps )
{
struct asym *grp;
if( sym == NULL )
return( ASSUME_NOTHING );
grp = GetGroup( sym );
if( def != ASSUME_NOTHING ) {
if( SegAssumeTable[def].symbol == sym )
return( def );
if( search_grps && grp ) {
if( SegAssumeTable[def].is_flat && grp == &ModuleInfo.flat_grp->sym )
return( def );
if( SegAssumeTable[def].symbol == grp )
return( def );
}
}
for( def = 0; def < NUM_SEGREGS; def++ ) {
if( SegAssumeTable[searchtab[def]].symbol == sym ) {
return( searchtab[def] );
}
}
if( search_grps && grp )
for( def = 0; def < NUM_SEGREGS; def++ ) {
if( SegAssumeTable[searchtab[def]].is_flat && grp == &ModuleInfo.flat_grp->sym )
return( searchtab[def] );
if( SegAssumeTable[searchtab[def]].symbol == grp ) {
return( searchtab[def] );
}
}
return( ASSUME_NOTHING );
}
struct asym *GetOverrideAssume( enum assume_segreg override )
{
if( SegAssumeTable[override].is_flat ) {
return( (struct asym *)ModuleInfo.flat_grp );
}
return( SegAssumeTable[override].symbol);
}
enum assume_segreg GetAssume( const struct asym *override, const struct asym *sym, enum assume_segreg def, struct asym * *passume )
{
enum assume_segreg reg;
if( ( def != ASSUME_NOTHING ) && SegAssumeTable[def].is_flat ) {
*passume = (struct asym *)ModuleInfo.flat_grp;
return( def );
}
if( override != NULL ) {
reg = search_assume( override, def, FALSE );
#if 1
} else if ( sym->state == SYM_STACK ) {
reg = ASSUME_SS;
#endif
} else {
reg = search_assume( sym->segment, def, TRUE );
}
if( reg == ASSUME_NOTHING ) {
if( sym && sym->state == SYM_EXTERNAL && sym->segment == NULL ) {
reg = def;
}
}
if( reg != ASSUME_NOTHING ) {
*passume = SegAssumeTable[reg].symbol;
return( reg );
}
*passume = NULL;
return( ASSUME_NOTHING );
}