mirror of
https://github.com/NishiOwO/JWasm.git
synced 2025-04-21 16:54:39 +00:00
559 lines
19 KiB
C
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 );
|
|
}
|
|
|