jwasm/assume.c
2014-06-18 19:16:56 +04:00

559 lines
19 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: handles ASSUME
*
****************************************************************************/
#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
/* prototypes */
/* todo: move static variables to ModuleInfo */
/* table SegAssume is for the segment registers;
* for order see enum assume_segreg.
*/
struct assume_info SegAssumeTable[NUM_SEGREGS];
/* table StdAssume is for the standard registers;
* order does match regno in special.h:
* (R|E)AX=0, (R|E)CX=1, (R|E)DX=2, (R|E)BX=3
* (R|E)SP=4, (R|E)BP=5, (R|E)SI=6, (R|E)DI=7
* R8 .. R15.
*/
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];
/* v2.05: saved type info content */
static struct stdassume_typeinfo saved_StdTypeInfo[NUM_STDREGS];
#endif
/* order to use for assume searches */
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) );
}
/* unlike the segment register assumes, the
* register assumes need more work to save/restore the
* current status, because they have their own
* type symbols, which may be reused.
* this functions is also called by context.c, ContextDirective()!
*/
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 ) /* pass may be -1 here! */
/*************************/
{
int reg;
for( reg = 0; reg < NUM_SEGREGS; reg++ ) {
SegAssumeTable[reg].symbol = NULL;
SegAssumeTable[reg].error = FALSE;
SegAssumeTable[reg].is_flat = FALSE;
}
/* the GPR assumes are handled somewhat special by masm.
* they aren't reset for each pass - instead they keep their value.
*/
if ( pass <= PASS_1 ) { /* v2.10: just reset assumes in pass one */
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
/* v2.10: this is a weird Masm feature:
* if a GPR is assumed to be a pointer to a struct,
* it isn't reset when a new pass starts.
* see assume11.asm and assume12.asm
*/
if ( pass == PASS_2 ) {
struct assume_info *psaved = &saved_StdAssumeTable;
struct stdassume_typeinfo *ptype = &saved_StdTypeInfo;
for ( reg = 0; reg < NUM_STDREGS; reg++, psaved++, ptype++ )
if ( psaved->symbol == NULL && StdAssumeTable[reg].symbol && StdAssumeTable[reg].symbol->target_type ) {
psaved->symbol = StdAssumeTable[reg].symbol;
ptype->type = psaved->symbol->type;
ptype->target_type = psaved->symbol->target_type;
ptype->mem_type = psaved->symbol->mem_type;
ptype->ptr_memtype = psaved->symbol->ptr_memtype;
ptype->is_ptr = psaved->symbol->is_ptr;
}
}
#endif
SetStdAssumeTable( &saved_StdAssumeTable, saved_StdTypeInfo );
}
#endif
}
/* generate assume lines after .MODEL directive
* model is in ModuleInfo.model, it can't be MODEL_NONE.
*/
void ModelAssumeInit( void )
/**************************/
{
const char *pCS;
const char *pFSassume = szError;
const char *pGSassume = szError;
const char *pFmt;
/* Generates codes for assume */
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:
/* v2.03: no DGROUP for COFF/ELF */
#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;
}
}
/* used by INVOKE directive */
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 );
}
/* v2.05: new, used by
* expression evaluator if a register is used for indirect addressing
*/
struct asym *GetStdAssumeEx( int reg )
/************************************/
{
return( StdAssumeTable[reg].symbol );
}
ret_code AssumeDirective( int i, struct asm_tok tokenarray[] )
/************************************************************/
/* Handles ASSUME
* syntax is :
* - ASSUME
* - ASSUME NOTHING
* - ASSUME segregister : seglocation [, segregister : seglocation ]
* - ASSUME dataregister : qualified type [, dataregister : qualified type ]
* - ASSUME register : ERROR | NOTHING | FLAT
*/
{
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;
}
/*---- get the info ptr for the register ----*/
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++; /* go past register */
if( tokenarray[i].token != T_COLON ) {
return( EmitError( COLON_EXPECTED ) );
}
i++;
if( tokenarray[i].token == T_FINAL ) {
return( EmitError( SYNTAX_ERROR ) );
}
/* check for ERROR and NOTHING */
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 ) {
/* v2.05: changed to use new GetQualifiedType() function */
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 );
/* v2.04: check size of argument! */
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; /* added v2.05 rc13 */
if ( ti.mem_type == MT_TYPE )
stdsym[j]->type = ti.symtype;
else
stdsym[j]->target_type = ti.symtype;
info->symbol = stdsym[j];
} else { /* segment register */
struct expr opnd;
/* v2.08: read expression with standard evaluator */
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 ) {
/* ensure that directive is rerun in pass 2
* so an error msg can be emitted.
*/
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;
}
/* comma expected */
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 );
}
/* for a symbol, search segment register which holds segment
* part of symbol's address in assume table.
* - sym: segment of symbol for which to search segment register
* - def: prefered default register (or ASSUME_NOTHING )
* - search_grps: if TRUE, check groups as well
*
* for data items, Masm checks assumes in this order:
* DS, SS, ES, FS, GS, CS
*/
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 );
/* first check the default segment register */
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 );
}
}
/* now check all segment registers */
for( def = 0; def < NUM_SEGREGS; def++ ) {
if( SegAssumeTable[searchtab[def]].symbol == sym ) {
return( searchtab[def] );
}
}
/* now check the groups */
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 );
}
/*
called by the parser's seg_override() function if
a segment register override has been detected.
- override: segment register override (0,1,2,3,4,5)
*/
struct asym *GetOverrideAssume( enum assume_segreg override )
/***********************************************************/
{
if( SegAssumeTable[override].is_flat ) {
return( (struct asym *)ModuleInfo.flat_grp );
}
return( SegAssumeTable[override].symbol);
}
/*
* GetAssume():
* called by check_assume() in parser.c
* in:
* - override: SegOverride
* - sym: symbol in current memory operand
* - def: default segment assume value
* to be fixed: check if symbols with state==SYM_STACK are handled correctly.
*/
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 /* v2.10: added */
} else if ( sym->state == SYM_STACK ) {
/* stack symbols don't have a segment part.
* In case [R|E]BP is used as base, it doesn't matter.
* However, if option -Zg is set, this isn't true.
*/
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 );
}