static ret_code SubStrFunc( struct macro_instance *mi, char *buffer, struct asm_tok tokenarray[] ) /************************************************************************************************/ { int pos; int size; char *src = mi->parm_array[0]; DebugMsg1(("@SubStr( %s, %s, %s)\n", src ? src : "", mi->parm_array[1] ? mi->parm_array[1] : "", mi->parm_array[2] ? mi->parm_array[2] : "" )); if ( GetNumber( mi->parm_array[1], &pos, tokenarray ) == ERROR ) return( ERROR ); if ( pos <= 0 ) { /* Masm doesn't check if index is < 0; * might cause an "internal assembler error". * v2.09: negative index no longer silently changed to 1. */ if ( pos ) { return( EmitErr( INDEX_VALUE_PAST_END_OF_STRING, pos ) ); } DebugMsg(( "@SubStr(): index value 0 changed to 1\n", pos )); pos = 1; } size = strlen( src ); if ( pos > size ) { return( EmitErr( INDEX_VALUE_PAST_END_OF_STRING, pos ) ); } size = size - pos + 1; if ( mi->parm_array[2] ) { int sizereq; if ( GetNumber( mi->parm_array[2], &sizereq, tokenarray ) == ERROR ) return( ERROR ); if ( sizereq < 0 ) { return( EmitError( COUNT_MUST_BE_POSITIVE_OR_ZERO ) ); } if ( sizereq > size ) { return( EmitError( COUNT_VALUE_TOO_LARGE ) ); } size = sizereq; } #if 1 memcpy( buffer, src + pos - 1, size ); *(buffer+size) = NULLC; #else for( src += pos - 1; size; size-- ) *buffer++ = *src++; *buffer = NULLC; #endif return( NOT_ERROR ); }
static struct asym *CreateProto( int i, struct asm_tok tokenarray[], const char *name, enum lang_type langtype ) /**************************************************************************************************************/ { struct asym *sym; struct dsym *dir; DebugMsg1(("CreateProto( i=%u, name=%s, lang=%u )\n", i, name ? name : "NULL", langtype )); sym = SymSearch( name ); /* the symbol must be either NULL or state * - SYM_UNDEFINED * - SYM_EXTERNAL + isproc == FALSE ( previous EXTERNDEF ) * - SYM_EXTERNAL + isproc == TRUE ( previous PROTO ) * - SYM_INTERNAL + isproc == TRUE ( previous PROC ) */ if( sym == NULL || sym->state == SYM_UNDEFINED || ( sym->state == SYM_EXTERNAL && sym->weak == TRUE && sym->isproc == FALSE )) { if ( NULL == ( sym = CreateProc( sym, name, SYM_EXTERNAL ) ) ) return( NULL ); /* name was probably invalid */ } else if ( sym->isproc == FALSE ) { EmitErr( SYMBOL_REDEFINITION, sym->name ); return( NULL ); } dir = (struct dsym *)sym; /* a PROTO typedef may be used */ if ( tokenarray[i].token == T_ID ) { struct asym * sym2; sym2 = SymSearch( tokenarray[i].string_ptr ); if ( sym2 && sym2->state == SYM_TYPE && sym2->mem_type == MT_PROC ) { i++; if ( tokenarray[i].token != T_FINAL ) { EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ); return( NULL ); } CopyPrototype( dir, (struct dsym *)sym2->target_type ); return( sym ); } } /* sym->isproc is set inside ParseProc() */ //sym->isproc = TRUE; if ( Parse_Pass == PASS_1 ) { if ( ParseProc( dir, i, tokenarray, FALSE, langtype ) == ERROR ) return( NULL ); #if DLLIMPORT sym->dll = ModuleInfo.CurrDll; #endif } else { sym->isdefined = TRUE; } return( sym ); }
struct asym *CreateIntSegment( const char *name, const char *classname, uint_8 alignment, uint_8 Ofssize, bool add_global ) /*************************************************************************************************************************/ { struct dsym *seg; if ( add_global ) { seg = (struct dsym *)SymSearch( name ); if ( seg == NULL || seg->sym.state == SYM_UNDEFINED ) seg = CreateSegment( seg, name, add_global ); else if ( seg->sym.state != SYM_SEG ) { EmitErr( SYMBOL_REDEFINITION, name ); return( NULL ); } } else seg = CreateSegment( NULL, name, FALSE ); if ( seg ) { if( seg->e.seginfo->lname_idx == 0 ) { seg->e.seginfo->seg_idx = ++ModuleInfo.g.num_segs; seg->e.seginfo->lname_idx = ++LnamesIdx; AddLnameData( &seg->sym ); } seg->sym.segment = &seg->sym; seg->e.seginfo->alignment = alignment; seg->e.seginfo->Ofssize = Ofssize; SetSegmentClass( (struct asym *)seg, classname ); return( &seg->sym ); } return( NULL ); }
static ret_code SetCurrSeg( int i, struct asm_tok tokenarray[] ) /**************************************************************/ { struct asym *sym; sym = SymSearch( tokenarray[0].string_ptr ); DebugMsg1(("SetCurrSeg(%s) sym=%p\n", tokenarray[0].string_ptr, sym)); if ( sym == NULL || sym->state != SYM_SEG ) { EmitErr( SEG_NOT_DEFINED, tokenarray[0].string_ptr ); return( ERROR ); } /* v2.04: added */ sym->isdefined = TRUE; if ( CurrSeg && Options.output_format == OFORMAT_OMF ) { omf_FlushCurrSeg(); if ( Options.no_comment_data_in_code_records == FALSE ) omf_OutSelect( FALSE ); } push_seg( (struct dsym *)sym ); if ( ModuleInfo.list ) LstWrite( LSTTYPE_LABEL, 0, NULL ); return( SetOfssize() ); }
static ret_code CloseSeg( const char *name ) /******************************************/ { //struct asym *sym; DebugMsg1(("CloseSeg(%s) enter\n", name)); if( CurrSeg == NULL || ( SymCmpFunc( CurrSeg->sym.name, name, CurrSeg->sym.name_size ) != 0 ) ) { DebugMsg(("CloseSeg(%s): nesting error, CurrSeg=%s\n", name, CurrSeg ? CurrSeg->sym.name : "(null)" )); EmitErr( BLOCK_NESTING_ERROR, name ); return( ERROR ); } DebugMsg1(("CloseSeg(%s): current ofs=%" FX32 "\n", name, CurrSeg->e.seginfo->current_loc)); if ( write_to_file && ( Options.output_format == OFORMAT_OMF ) ) { //if ( !omf_FlushCurrSeg() ) /* v2: error check is obsolete */ // EmitErr( INTERNAL_ERROR, "CloseSeg", 1 ); /* coding error! */ omf_FlushCurrSeg(); if ( Options.no_comment_data_in_code_records == FALSE ) omf_OutSelect( FALSE ); } pop_seg(); return( NOT_ERROR ); }
static struct dsym *CreateGroup( const char *name ) /*************************************************/ { struct dsym *grp; grp = (struct dsym *)SymSearch( name ); if( grp == NULL || grp->sym.state == SYM_UNDEFINED ) { if ( grp == NULL ) grp = (struct dsym *)SymCreate( name ); else sym_remove_table( &SymTables[TAB_UNDEF], grp ); grp->sym.state = SYM_GRP; grp->e.grpinfo = LclAlloc( sizeof( struct grp_info ) ); grp->e.grpinfo->seglist = NULL; //grp->e.grpinfo->grp_idx = 0; //grp->e.grpinfo->lname_idx = 0; grp->e.grpinfo->numseg = 0; sym_add_table( &SymTables[TAB_GRP], grp ); grp->sym.list = TRUE; grp->e.grpinfo->grp_idx = ++grpdefidx; grp->e.grpinfo->lname_idx = ++LnamesIdx; AddLnameData( &grp->sym ); } else if( grp->sym.state != SYM_GRP ) { EmitErr( SYMBOL_REDEFINITION, name ); return( NULL ); } grp->sym.isdefined = TRUE; return( grp ); }
/* preprocessor directive or macro procedure is preceded * by a code label. */ ret_code WriteCodeLabel( char *line, struct asm_tok tokenarray[] ) /****************************************************************/ { int oldcnt; int oldtoken; char oldchar; if ( tokenarray[0].token != T_ID ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[0].string_ptr ) ); } /* ensure the listing is written with the FULL source line */ if ( CurrFile[LST] ) LstWrite( LSTTYPE_LABEL, 0, NULL ); /* v2.04: call ParseLine() to parse the "label" part of the line */ oldcnt = Token_Count; oldtoken = tokenarray[2].token; oldchar = *tokenarray[2].tokpos; Token_Count = 2; tokenarray[2].token = T_FINAL; *tokenarray[2].tokpos = NULLC; ParseLine( tokenarray ); if ( Options.preprocessor_stdout == TRUE ) WritePreprocessedLine( line ); Token_Count = oldcnt; tokenarray[2].token = oldtoken; *tokenarray[2].tokpos = oldchar; return( NOT_ERROR ); }
ret_code ListMacroDirective( int i, struct asm_tok tokenarray[] ) /***************************************************************/ { if ( tokenarray[i+1].token != T_FINAL ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i+1].string_ptr ) ); } ModuleInfo.list_macro = GetSflagsSp( tokenarray[i].tokval ); return( NOT_ERROR ); }
ret_code SegmentModuleExit( void ) /********************************/ { if ( ModuleInfo.model != MODEL_NONE ) ModelSimSegmExit(); /* if there's still an open segment, it's an error */ if ( CurrSeg ) { EmitErr( BLOCK_NESTING_ERROR, CurrSeg->sym.name ); /* but close the still open segments anyway */ while( CurrSeg && ( CloseSeg( CurrSeg->sym.name ) == NOT_ERROR ) ); } return( NOT_ERROR ); }
ret_code EndsDir( int i, struct asm_tok tokenarray[] ) /****************************************************/ { if( CurrStruct != NULL ) { return( EndstructDirective( i, tokenarray ) ); } /* a label must precede ENDS */ if( i != 1 ) { EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ); return( ERROR ); } if ( Parse_Pass != PASS_1 ) { if ( ModuleInfo.list ) LstWrite( LSTTYPE_LABEL, 0, NULL ); } if ( CloseSeg( tokenarray[0].string_ptr ) == ERROR ) return( ERROR ); i++; if ( tokenarray[i].token != T_FINAL ) { EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ); } return( SetOfssize() ); }
/* SizeStr() * defines a numeric variable which contains size of a string */ ret_code SizeStrDir( int i, struct asm_tok tokenarray[] ) /*******************************************************/ { struct asym *sym; int sizestr; DebugMsg1(("SizeStrDir entry\n")); DebugCmd( sizstrcnt++ ); if ( i != 1 ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } #if 0 /* this is checked in ParseLine() */ if ( tokenarray[0].token != T_ID ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[0].string_ptr ) ); } #endif if ( tokenarray[2].token != T_STRING || tokenarray[2].string_delim != '<' ) { return( TextItemError( &tokenarray[2] ) ); } if ( Token_Count > 3 ) { DebugMsg(("SizeStrDir: syntax error, name=%s, Token_Count=%u\n", tokenarray[0].string_ptr, Token_Count)); return( EmitErr( SYNTAX_ERROR_EX, tokenarray[3].string_ptr ) ); } //sizestr = GetLiteralValue( StringBufferEnd, tokenarray[2].string_ptr ); sizestr = tokenarray[2].stringlen; if ( sym = CreateVariable( tokenarray[0].string_ptr, sizestr ) ) { DebugMsg1(("SizeStrDir(%s) exit, value=%u\n", tokenarray[0].string_ptr, sizestr)); LstWrite( LSTTYPE_EQUATE, 0, sym ); return( NOT_ERROR ); } return( ERROR ); }
int TextItemError( struct asm_tok *item ) /***************************************/ { if ( item->token == T_STRING && *item->string_ptr == '<' ) { return( EmitError( MISSING_ANGLE_BRACKET_OR_BRACE_IN_LITERAL ) ); } /* v2.05: better error msg if (text) symbol isn't defined */ if ( item->token == T_ID ) { struct asym *sym = SymSearch( item->string_ptr ); if ( sym == NULL || sym->state == SYM_UNDEFINED ) { return( EmitErr( SYMBOL_NOT_DEFINED, item->string_ptr ) ); } } return( EmitError( TEXT_ITEM_REQUIRED ) ); }
ret_code ProtoDirective( int i, struct asm_tok tokenarray[] ) /***********************************************************/ { if( Parse_Pass != PASS_1 ) { struct asym *sym; /* v2.04: set the "defined" flag */ if ( ( sym = SymSearch( tokenarray[0].string_ptr ) ) && sym->isproc == TRUE ) sym->isdefined = TRUE; return( NOT_ERROR ); } if( i != 1 ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } return( CreateProto( 2, tokenarray, tokenarray[0].string_ptr, ModuleInfo.langtype ) ? NOT_ERROR : ERROR ); }
/* internal @InStr macro function * syntax: @InStr( [num], literal, literal ) * the result is returned as string in current radix */ static ret_code InStrFunc( struct macro_instance *mi, char *buffer, struct asm_tok tokenarray[] ) /***********************************************************************************************/ { int pos = 1; char *p; uint_32 found; DebugMsg1(("@InStr( %s, %s, %s)\n", mi->parm_array[0] ? mi->parm_array[0] : "", mi->parm_array[1] ? mi->parm_array[1] : "", mi->parm_array[2] ? mi->parm_array[2] : "" )); /* init buffer with "0" */ *buffer = '0'; *(buffer+1) = NULLC; if ( mi->parm_array[0] ) { if ( GetNumber( mi->parm_array[0], &pos, tokenarray ) == ERROR ) return( ERROR ); if ( pos == 0 ) { /* adjust index 0. Masm also accepts 0 (and any negative index), * but the result will always be 0 then */ DebugMsg(( "@InStr(): index value is 0, changed to 1\n" )); pos++; } } if ( pos > strlen( mi->parm_array[1] ) ) { return( EmitErr( INDEX_VALUE_PAST_END_OF_STRING, pos ) ); } /* v2.08: if() added, empty searchstr is to return 0 */ if ( *(mi->parm_array[2]) != NULLC ) { p = strstr( mi->parm_array[1] + pos - 1, mi->parm_array[2] ); if ( p ) { found = p - mi->parm_array[1] + 1; myltoa( found, buffer, ModuleInfo.radix, FALSE, TRUE ); } } DebugMsg1(( "@InStr()=>%s<\n", buffer )); return( NOT_ERROR ); }
static ret_code GetNumber( char *string, int *pi, struct asm_tok tokenarray[] ) /*****************************************************************************/ { struct expr opndx; int i; int last; last = Tokenize( string, Token_Count+1, tokenarray, TOK_RESCAN ); i = Token_Count+1; if( EvalOperand( &i, tokenarray, last, &opndx, EXPF_NOUNDEF ) == ERROR ) { return( ERROR ); } /* v2.11: string constants are accepted ( although hardly useful ) */ //if( opndx.kind != EXPR_CONST || opndx.quoted_string != NULL || tokenarray[i].token != T_FINAL ) { if( opndx.kind != EXPR_CONST || tokenarray[i].token != T_FINAL ) { return( EmitErr( SYNTAX_ERROR_EX, string ) ); } *pi = opndx.value; return( NOT_ERROR ); }
static direct_idx SetSegmentClass( struct asym *seg, const char *classname ) /**************************************************************************/ { direct_idx classidx; classidx = FindLnameIdx( classname ); if( classidx == LNAME_NULL ) { classidx = InsertClassLname( classname ); if( classidx == LNAME_NULL ) { return( ERROR ); } } /* default class name index is 1, which is the NULL class name */ if ( ((struct dsym *)seg)->e.seginfo->class_name_idx == 1 ) ((struct dsym *)seg)->e.seginfo->class_name_idx = classidx; else if ( ((struct dsym *)seg)->e.seginfo->class_name_idx != classidx ) { EmitErr( SEGDEF_CHANGED, seg->name, MsgGetEx( TXT_CLASS ) ); return( ERROR ); } return( classidx ); }
/* read one line from current source file. * returns NULL if EOF has been detected and no char stored in buffer * v2.08: 00 in the stream no longer causes an exit. Hence if the * char occurs in the comment part, everything is ok. */ static char *my_fgets( char *buffer, int max, FILE *fp ) /******************************************************/ { char *ptr = buffer; char *last = buffer + max; int c; c = getc( fp ); while( ptr < last ) { switch ( c ) { case '\r': break; /* don't store CR */ case '\n': /* fall through */ //case '\0': /* v2.08: */ #ifdef DEBUG_OUT if ( Parse_Pass == PASS_1 ) cntflines++; #endif *ptr = NULLC; return( buffer ); #if DETECTCTRLZ case 0x1a: /* since source files are opened in binary mode, ctrl-z * handling must be done here. */ /* no break */ #endif case EOF: *ptr = NULLC; return( ptr > buffer ? buffer : NULL ); default: *ptr++ = c; } c = getc( fp ); } EmitErr( LINE_TOO_LONG ); *(ptr-1) = NULLC; return( buffer ); }
ret_code PublicDirective( int i, struct asm_tok tokenarray[] ) /************************************************************/ { #if MANGLERSUPP char *mangle_type = NULL; #endif char *token; struct asym *sym; //struct dsym *dir; char skipitem; enum lang_type langtype; DebugMsg1(("PublicDirective(%u) enter\n", i)); i++; /* skip PUBLIC directive */ #if MANGLERSUPP mangle_type = Check4Mangler( &i, tokenarray ); #endif do { /* read the optional language type */ langtype = ModuleInfo.langtype; GetLangType( &i, tokenarray, &langtype ); if ( tokenarray[i].token != T_ID ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } /* get the symbol name */ token = tokenarray[i++].string_ptr; DebugMsg1(("PublicDirective: sym=%s\n", token )); /* Add the public name */ sym = SymSearch( token ); if ( Parse_Pass == PASS_1 ) { if ( sym == NULL ) { if ( sym = SymCreate( token ) ) { sym_add_table( &SymTables[TAB_UNDEF], (struct dsym *)sym ); DebugMsg1(("PublicDirective(%s): new symbol\n", sym->name )); } else return( ERROR ); /* name was too long */ } skipitem = FALSE; } else { if ( sym == NULL || sym->state == SYM_UNDEFINED ) { EmitErr( SYMBOL_NOT_DEFINED, token ); //return( ERROR ); /* v2.04: dont exit */ } } if ( sym ) { switch ( sym->state ) { case SYM_UNDEFINED: break; case SYM_INTERNAL: if ( sym->scoped == TRUE ) { EmitErr( CANNOT_DECLARE_SCOPED_CODE_LABEL_AS_PUBLIC, sym->name ); skipitem = TRUE; //return( ERROR ); } break; case SYM_EXTERNAL: if ( sym->iscomm == TRUE ) { EmitErr( CANNOT_DEFINE_AS_PUBLIC_OR_EXTERNAL, sym->name ); skipitem = TRUE; //return( ERROR ); } else if ( sym->weak == FALSE ) { /* for EXTERNs, emit a different error msg */ EmitErr( SYMBOL_REDEFINITION, sym->name ); skipitem = TRUE; //return( ERROR ); } break; default: EmitErr( CANNOT_DEFINE_AS_PUBLIC_OR_EXTERNAL, sym->name ); skipitem = TRUE; //return( ERROR ); } if( Parse_Pass == PASS_1 && skipitem == FALSE ) { if ( sym->ispublic == FALSE ) { sym->ispublic = TRUE; AddPublicData( sym ); /* put it into the public table */ } SetMangler( sym, langtype, mangle_type ); } } if ( tokenarray[i].token != T_FINAL ) if ( tokenarray[i].token == T_COMMA ) { if ( (i + 1) < Token_Count ) i++; } else { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].tokpos ) ); } } while ( i < Token_Count ); return( NOT_ERROR ); }
/* .[NO|X]LIST, .[NO|X]CREF, .LISTALL, * .[NO]LISTIF, .[LF|SF|TF]COND, * PAGE, TITLE, SUBTITLE, SUBTTL directives */ ret_code ListingDirective( int i, struct asm_tok tokenarray[] ) /*************************************************************/ { int directive = tokenarray[i].tokval; i++; switch ( directive ) { case T_DOT_LIST: if ( CurrFile[LST] ) ModuleInfo.list = TRUE; break; case T_DOT_CREF: ModuleInfo.cref = TRUE; break; case T_DOT_NOLIST: case T_DOT_XLIST: ModuleInfo.list = FALSE; break; case T_DOT_NOCREF: case T_DOT_XCREF: if ( i == Token_Count ) { ModuleInfo.cref = FALSE; break; } do { struct asym *sym; if ( tokenarray[i].token != T_ID ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].tokpos ) ); } /* the name may be a forward reference. In this case it will * be created here. * v2.11: function call cannot fail. no need for checks. */ sym = SymLookup( tokenarray[i].string_ptr ); sym->list = FALSE; i++; if ( i < Token_Count ) { if ( tokenarray[i].token != T_COMMA ) return( EmitErr( EXPECTING_COMMA, tokenarray[i].tokpos ) ); /* if there's nothing after the comma, don't increment */ if ( i < ( Token_Count - 1 ) ) i++; } } while ( i < Token_Count ); break; case T_DOT_LISTALL: /* list false conditionals and generated code */ if ( CurrFile[LST] ) ModuleInfo.list = TRUE; ModuleInfo.list_generated_code = TRUE; /* fall through */ case T_DOT_LISTIF: case T_DOT_LFCOND: /* .LFCOND is synonym for .LISTIF */ ModuleInfo.listif = TRUE; break; case T_DOT_NOLISTIF: case T_DOT_SFCOND: /* .SFCOND is synonym for .NOLISTIF */ ModuleInfo.listif = FALSE; break; case T_DOT_TFCOND: /* .TFCOND toggles .LFCOND, .SFCOND */ ModuleInfo.listif = !ModuleInfo.listif; break; case T_PAGE: default: /* TITLE, SUBTITLE, SUBTTL */ /* tiny checks to ensure that these directives aren't used as code labels or struct fields */ if ( tokenarray[i].token == T_COLON ) break; /* this isn't really Masm-compatible, but ensures we don't get * struct fields with names page, title, subtitle, subttl. */ if( CurrStruct ) { return( EmitError( STATEMENT_NOT_ALLOWED_INSIDE_STRUCTURE_DEFINITION ) ); } if ( Parse_Pass == PASS_1 ) EmitWarn( 4, DIRECTIVE_IGNORED, tokenarray[i-1].string_ptr ); while ( tokenarray[i].token != T_FINAL) i++; } if ( tokenarray[i].token != T_FINAL ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } return( NOT_ERROR ); }
ret_code ExternDirective( int i, struct asm_tok tokenarray[] ) /************************************************************/ { char *token; #if MANGLERSUPP char *mangle_type = NULL; #endif char *altname; struct asym *sym; enum lang_type langtype; struct qualified_type ti; DebugMsg1(("ExternDirective(%u) enter\n", i)); i++; /* skip EXT[E]RN token */ #if MANGLERSUPP mangle_type = Check4Mangler( &i, tokenarray ); #endif do { altname = NULL; /* get the symbol language type if present */ langtype = ModuleInfo.langtype; GetLangType( &i, tokenarray, &langtype ); /* get the symbol name */ if( tokenarray[i].token != T_ID ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } token = tokenarray[i++].string_ptr; /* go past the optional alternative name (weak ext, default resolution) */ if( tokenarray[i].token == T_OP_BRACKET ) { i++; if ( tokenarray[i].token != T_ID ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } altname = tokenarray[i].string_ptr; i++; if( tokenarray[i].token != T_CL_BRACKET ) { return( EmitErr( EXPECTED, ")" ) ); } i++; } /* go past the colon */ if( tokenarray[i].token != T_COLON ) { return( EmitError( COLON_EXPECTED ) ); } i++; sym = SymSearch( token ); ti.mem_type = MT_EMPTY; ti.size = 0; ti.is_ptr = 0; ti.is_far = FALSE; ti.ptr_memtype = MT_EMPTY; ti.symtype = NULL; ti.Ofssize = ModuleInfo.Ofssize; if ( tokenarray[i].token == T_ID && ( 0 == _stricmp( tokenarray[i].string_ptr, "ABS" ) ) ) { //ti.mem_type = MT_ABS; i++; } else if ( tokenarray[i].token == T_DIRECTIVE && tokenarray[i].tokval == T_PROTO ) { /* dont scan this line further */ /* CreateProto() will define a SYM_EXTERNAL */ sym = CreateProto( i + 1, tokenarray, token, langtype ); DebugMsg1(("ExternDirective(%s): CreateProto()=%X\n", token, sym)); if ( sym == NULL ) return( ERROR ); if ( sym->state == SYM_EXTERNAL ) { sym->weak = FALSE; return( HandleAltname( altname, sym ) ); } else { /* unlike EXTERNDEF, EXTERN doesn't allow a PROC for the same name */ return( EmitErr( SYMBOL_REDEFINITION, sym->name ) ); } } else if ( tokenarray[i].token != T_FINAL && tokenarray[i].token != T_COMMA ) { if ( GetQualifiedType( &i, tokenarray, &ti ) == ERROR ) return( ERROR ); } DebugMsg1(("ExternDirective(%s): mem_type=%Xh\n", token, ti.mem_type )); if( sym == NULL || sym->state == SYM_UNDEFINED ) { /* v2.04: emit the error at the PUBLIC directive */ //if ( sym && sym->public == TRUE ) { // EmitErr( CANNOT_DEFINE_AS_PUBLIC_OR_EXTERNAL, sym->name ); // return( ERROR ); //} if(( sym = MakeExtern( token, ti.mem_type, ti.mem_type == MT_TYPE ? ti.symtype : NULL, sym, ti.is_ptr ? ModuleInfo.Ofssize : ti.Ofssize )) == NULL ) return( ERROR ); /* v2.05: added to accept type prototypes */ if ( ti.is_ptr == 0 && ti.symtype && ti.symtype->isproc ) { CreateProc( sym, NULL, SYM_EXTERNAL ); sym->weak = FALSE; /* v2.09: reset the weak bit that has been set inside CreateProc() */ CopyPrototype( (struct dsym *)sym, (struct dsym *)ti.symtype ); ti.mem_type = ti.symtype->mem_type; ti.symtype = NULL; DebugMsg1(("ExternDirective(%s): prototype copied, memtype=%X\n", token, ti.mem_type )); } } else { #if MASM_EXTCOND /* allow internal AND external definitions for equates */ //if ( sym->state == SYM_INTERNAL && sym->mem_type == MT_ABS ) if ( sym->state == SYM_INTERNAL && sym->mem_type == MT_EMPTY ) ; else #endif if ( sym->state != SYM_EXTERNAL ) { DebugMsg(("ExternDirective: symbol %s redefinition, state=%u\n", token, sym->state )); return( EmitErr( SYMBOL_REDEFINITION, token ) ); } /* v2.05: added to accept type prototypes */ if ( ti.is_ptr == 0 && ti.symtype && ti.symtype->isproc ) { ti.mem_type = ti.symtype->mem_type; ti.symtype = NULL; } if( sym->mem_type != ti.mem_type || sym->is_ptr != ti.is_ptr || sym->isfar != ti.is_far || ( sym->is_ptr && sym->ptr_memtype != ti.ptr_memtype ) || ((sym->mem_type == MT_TYPE) ? sym->type : sym->target_type) != ti.symtype || ( langtype != LANG_NONE && sym->langtype != LANG_NONE && sym->langtype != langtype )) { DebugMsg(("ExternDirective: memtype:%X-%X ptr=%X-%X far=%X-%X ptr_memtype=%X-%X lang=%u-%u\n", sym->mem_type, ti.mem_type, sym->is_ptr, ti.is_ptr, sym->isfar, ti.is_far, sym->ptr_memtype, ti.ptr_memtype, sym->langtype, langtype )); return( EmitErr( SYMBOL_TYPE_CONFLICT, token ) ); } } sym->isdefined = TRUE; sym->Ofssize = ti.Ofssize; if ( ti.is_ptr == 0 && ti.Ofssize != ModuleInfo.Ofssize ) { sym->seg_ofssize = ti.Ofssize; if ( sym->segment && ((struct dsym *)sym->segment)->e.seginfo->Ofssize != sym->seg_ofssize ) sym->segment = NULL; } sym->mem_type = ti.mem_type; sym->is_ptr = ti.is_ptr; sym->isfar = ti.is_far; sym->ptr_memtype = ti.ptr_memtype; if ( ti.mem_type == MT_TYPE ) sym->type = ti.symtype; else sym->target_type = ti.symtype; HandleAltname( altname, sym ); SetMangler( sym, langtype, mangle_type ); if ( tokenarray[i].token != T_FINAL ) if ( tokenarray[i].token == T_COMMA && ( (i + 1) < Token_Count ) ) { i++; } else { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } } while ( i < Token_Count ); return( NOT_ERROR ); }
ret_code CommDirective( int i, struct asm_tok tokenarray[] ) /**********************************************************/ { char *token; #if MANGLERSUPP char *mangle_type = NULL; #endif bool isfar; //int distance; int tmp; uint_32 size; /* v2.12: changed from 'int' to 'uint_32' */ uint_32 count; /* v2.12: changed from 'int' to 'uint_32' */ struct asym *sym; struct expr opndx; enum lang_type langtype; DebugMsg1(("CommDirective(%u) enter\n", i)); i++; /* skip COMM token */ for( ; i < Token_Count; i++ ) { #if MANGLERSUPP mangle_type = Check4Mangler( &i, tokenarray ); #endif /* get the symbol language type if present */ langtype = ModuleInfo.langtype; GetLangType( &i, tokenarray, &langtype ); /* get the -optional- distance ( near or far ) */ isfar = FALSE; if ( tokenarray[i].token == T_STYPE ) switch ( tokenarray[i].tokval ) { case T_FAR: case T_FAR16: case T_FAR32: if ( ModuleInfo.model == MODEL_FLAT ) { EmitError( FAR_NOT_ALLOWED_IN_FLAT_MODEL_COMM_VARIABLES ); } else isfar = TRUE; /* no break */ case T_NEAR: case T_NEAR16: case T_NEAR32: i++; } /* v2.08: ensure token is a valid id */ if( tokenarray[i].token != T_ID ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } /* get the symbol name */ token = tokenarray[i++].string_ptr; /* go past the colon */ if( tokenarray[i].token != T_COLON ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } i++; /* the evaluator cannot handle a ':' so scan for one first */ for ( tmp = i; tmp < Token_Count;tmp++ ) if ( tokenarray[tmp].token == T_COLON ) break; /* v2.10: expression evaluator isn't to accept forward references */ //if ( EvalOperand( &i, tokenarray, tmp, &opndx, 0 ) == ERROR ) if ( EvalOperand( &i, tokenarray, tmp, &opndx, EXPF_NOUNDEF ) == ERROR ) return( ERROR ); /* v2.03: a string constant is accepted by Masm */ /* v2.11: don't accept NEAR or FAR */ /* v2.12: check for too large value added */ //if ( opndx.kind != EXPR_CONST || opndx.string != NULL ) { if ( opndx.kind != EXPR_CONST ) EmitError( CONSTANT_EXPECTED ); else if ( ( opndx.mem_type & MT_SPECIAL_MASK) == MT_ADDRESS ) EmitErr( INVALID_TYPE_FOR_DATA_DECLARATION, token ); else if ( opndx.hvalue != 0 && opndx.hvalue != -1 ) EmitConstError( &opndx ); else if ( opndx.uvalue == 0 ) EmitError( POSITIVE_VALUE_EXPECTED ); size = opndx.uvalue; count = 1; if( tokenarray[i].token == T_COLON ) { i++; /* get optional count argument */ /* v2.10: expression evaluator isn't to accept forward references */ //if ( EvalOperand( &i, tokenarray, Token_Count, &opndx, 0 ) == ERROR ) if ( EvalOperand( &i, tokenarray, Token_Count, &opndx, EXPF_NOUNDEF ) == ERROR ) return( ERROR ); /* v2.03: a string constant is acceptable! */ /* v2.12: check for too large value added */ //if ( opndx.kind != EXPR_CONST || opndx.string != NULL ) { if ( opndx.kind != EXPR_CONST ) EmitError( CONSTANT_EXPECTED ); else if ( opndx.hvalue != 0 && opndx.hvalue != -1 ) EmitConstError( &opndx ); else if ( opndx.uvalue == 0 ) EmitError( POSITIVE_VALUE_EXPECTED ); count = opndx.uvalue; } sym = SymSearch( token ); if( sym == NULL || sym->state == SYM_UNDEFINED ) { sym = MakeComm( token, sym, size, count, isfar ); if ( sym == NULL ) return( ERROR ); } else if ( sym->state != SYM_EXTERNAL || sym->iscomm != TRUE ) { return( EmitErr( SYMBOL_REDEFINITION, sym->name ) ); } else { tmp = sym->total_size / sym->total_length; if( count != sym->total_length || size != tmp ) { return( EmitErr( NON_BENIGN_XXX_REDEFINITION, szCOMM, sym->name ) ); } } sym->isdefined = TRUE; SetMangler( sym, langtype, mangle_type ); if ( tokenarray[i].token != T_FINAL && tokenarray[i].token != T_COMMA ) { return( EmitErr( EXPECTING_COMMA, tokenarray[i].tokpos ) ); } } return( NOT_ERROR ); }
static ret_code DoPatch( struct asym *sym, struct fixup *fixup ) /**************************************************************/ { long disp; long max_disp; unsigned size; struct dsym *seg; #if LABELOPT struct asym *sym2; struct fixup *fixup2; #endif /* all relative fixups should occure only at first pass and they signal forward references * they must be removed after patching or skiped ( next processed as normal fixup ) */ DebugMsg(("DoPatch(%u, %s): fixup sym=%s type=%u ofs=%" FX32 "h loc=%" FX32 "h opt=%u def_seg=%s\n", Parse_Pass + 1, sym->name, fixup->sym ? fixup->sym->name : "NULL", fixup->type, fixup->offset, fixup->location, fixup->option, fixup->def_seg ? fixup->def_seg->sym.name : "NULL" )); seg = GetSegm( sym ); if( seg == NULL || fixup->def_seg != seg ) { /* if fixup location is in another segment, backpatch is possible, but * complicated and it's a pretty rare case, so nothing's done. */ DebugMsg(("DoPatch: skipped due to seg incompat: %s - %s\n", fixup->def_seg ? fixup->def_seg->sym.name : "NULL", seg ? seg->sym.name : "NULL" )); SkipFixup(); return( NOT_ERROR ); } if( Parse_Pass == PASS_1 ) { if( sym->mem_type == MT_FAR && fixup->option == OPTJ_CALL ) { /* convert near call to push cs + near call, * (only at first pass) */ DebugMsg(("DoPatch: Phase error! caused by far call optimization\n")); ModuleInfo.PhaseError = TRUE; sym->offset++; /* a PUSH CS will be added */ /* todo: insert LABELOPT block here */ OutputByte( 0 ); /* it's pass one, nothing is written */ FreeFixup( fixup ); return( NOT_ERROR ); //} else if( sym->mem_type == MT_NEAR ) { } else { /* forward reference, only at first pass */ switch( fixup->type ) { case FIX_RELOFF32: case FIX_RELOFF16: FreeFixup( fixup ); DebugMsg(("DoPatch: FIX_RELOFF32/FIX_RELOFF16, return\n")); return( NOT_ERROR ); case FIX_OFF8: /* push <forward reference> */ if ( fixup->option == OPTJ_PUSH ) { size = 1; /* size increases from 2 to 3/5 */ DebugMsg(("DoPatch: FIX_OFF8\n")); goto patch; } } } } size = 0; switch( fixup->type ) { case FIX_RELOFF32: size = 2; /* will be 4 finally */ /* fall through */ case FIX_RELOFF16: size++; /* will be 2 finally */ /* fall through */ case FIX_RELOFF8: size++; /* calculate the displacement */ // disp = fixup->offset + GetCurrOffset() - fixup->location - size; disp = fixup->offset + fixup->sym->offset - fixup->location - size - 1; max_disp = (1UL << ((size * 8)-1)) - 1; if( disp > max_disp || disp < (-max_disp-1) ) { patch: DebugMsg(("DoPatch(%u): Phase error, disp=%X, fixup=%s(%X), loc=%X!\n", Parse_Pass + 1, disp, fixup->sym->name, fixup->sym->offset, fixup->location )); ModuleInfo.PhaseError = TRUE; /* ok, the standard case is: there's a forward jump which * was assumed to be SHORT, but it must be NEAR instead. */ switch( size ) { case 1: size = 0; switch( fixup->option ) { case OPTJ_EXPLICIT: #if 0 /* don't display the error at the destination line! */ sym->fixup = NULL; DebugMsg(("DoPatch: jump out of range, disp=%d\n", disp )); EmitErr( JUMP_OUT_OF_RANGE, disp - max_disp ); return( ERROR ); #else return( NOT_ERROR ); /* nothing to do */ #endif case OPTJ_EXTEND: /* Jxx for 8086 */ size++; /* will be 3/5 finally */ /* fall through */ case OPTJ_JXX: /* Jxx for 386 */ size++; /* fall through */ default: /* normal JMP (and PUSH) */ // if( CodeInfo->Ofssize ) /* v1.96: don't use CodeInfo here! */ if( seg->e.seginfo->Ofssize ) size += 2; /* NEAR32 instead of NEAR16 */ size++; #if LABELOPT /* v2.04: if there's an ORG between src and dst, skip * the optimization! */ if ( Parse_Pass == PASS_1 ) { for ( fixup2 = seg->e.seginfo->FixupListHead; fixup2; fixup2 = fixup2->nextrlc ) { if ( fixup2->orgoccured ) { DebugMsg(("DoPatch: ORG/ALIGN detected, optimization canceled\n" )); return( NOT_ERROR ); } /* do this check after the check for ORG! */ if ( fixup2->location <= fixup->location ) break; } } /* scan the segment's label list and adjust all labels * which are between the fixup loc and the current sym. * ( PROCs are NOT contained in this list because they * use the <next>-field of dsym already!) */ for ( sym2 = seg->e.seginfo->labels; sym2; sym2 = (struct asym *)((struct dsym *)sym2)->next ) { //if ( sym2 == sym ) // continue; /* v2.0: location is at least 1 byte too low, so * use the "<=" operator instead of "<"! */ //if ( sym2->offset < fixup->location ) if ( sym2->offset <= fixup->location ) break; sym2->offset += size; DebugMsg(("DoPatch(loc=%" FX32 "): sym %s, offset changed %" FX32 " -> %" FX32 "\n", fixup->location, sym2->name, sym2->offset - size, sym2->offset)); } /* v2.03: also adjust fixup locations located between the * label reference and the label. This should reduce the * number of passes to 2 for not too complex sources. */ if ( Parse_Pass == PASS_1 ) /* v2.04: added, just to be safe */ for ( fixup2 = seg->e.seginfo->FixupListHead; fixup2; fixup2 = fixup2->nextrlc ) { if ( fixup2->sym == sym ) continue; if ( fixup2->location <= fixup->location ) break; fixup2->location += size; DebugMsg(("for sym=%s fixup loc %" FX32 " changed to %" FX32 "\n", fixup2->sym->name, fixup2->location - size, fixup2->location )); } #else DebugMsg(("DoPatch: sym %s, offset changed %" FX32 " -> %" FX32 "\n", sym->name, sym->offset, sym->offset + size)); sym->offset += size; #endif /* it doesn't matter what's actually "written" */ for ( ; size; size-- ) OutputByte( 0xCC ); break; } break; case 2: case 4: DebugMsg(("DoPatch: jump out of range, disp=%d\n", disp )); EmitWarn( 4, JUMP_OUT_OF_RANGE, disp - max_disp ); break; } } #ifdef DEBUG_OUT else DebugMsg(("DoPatch, loc=%" FX32 ": displacement still short: %Xh\n", fixup->location, disp )); #endif /* v2.04: fixme: is it ok to remove the fixup? * it might still be needed in a later backpatch. */ FreeFixup( fixup ); break; default: DebugMsg(("DoPatch: default branch, unhandled fixup type=%u\n", fixup->type )); SkipFixup(); break; } return( NOT_ERROR ); }
static ret_code HandleAltname( char *altname, struct asym *sym ) /**************************************************************/ { struct asym *symalt; if ( altname && sym->state == SYM_EXTERNAL ) { symalt = SymSearch( altname ); /* altname symbol changed? */ if ( sym->altname && sym->altname != symalt ) { return( EmitErr( SYMBOL_REDEFINITION, sym->name ) ); } if ( Parse_Pass > PASS_1 ) { if ( symalt->state == SYM_UNDEFINED ) { EmitErr( SYMBOL_NOT_DEFINED, altname ); } else if (symalt->state != SYM_INTERNAL && symalt->state != SYM_EXTERNAL ) { EmitErr( SYMBOL_TYPE_CONFLICT, altname ); } else { #if COFF_SUPPORT || ELF_SUPPORT if ( symalt->state == SYM_INTERNAL && symalt->ispublic == FALSE ) if ( Options.output_format == OFORMAT_COFF #if ELF_SUPPORT || Options.output_format == OFORMAT_ELF #endif ) { EmitErr( MUST_BE_PUBLIC_OR_EXTERNAL, altname ); } #endif if ( sym->mem_type != symalt->mem_type ) EmitErr( SYMBOL_TYPE_CONFLICT, altname ); } } else { if ( symalt ) { DebugMsg(("HandleAltname: symbol '%s' found, state=%u\n", altname, symalt->state )); if ( symalt->state != SYM_INTERNAL && symalt->state != SYM_EXTERNAL && symalt->state != SYM_UNDEFINED ) { return( EmitErr( SYMBOL_TYPE_CONFLICT, altname ) ); } } else { symalt = SymCreate( altname ); sym_add_table( &SymTables[TAB_UNDEF], (struct dsym *)symalt ); } /* make sure the alt symbol becomes strong if it is an external * v2.11: don't do this for OMF ( maybe neither for COFF/ELF? ) */ if ( Options.output_format != OFORMAT_OMF ) symalt->used = TRUE; /* symbol inserted in the "weak external" queue? * currently needed for OMF only. */ if ( sym->altname == NULL ) { sym->altname = symalt; #if 0 /* v2.11: removed. Member nextext wasn't free to use */ DebugMsg1(("HandleAltname: symbol '%s' added to AltQueue\n", sym->name )); ((struct dsym *)sym)->nextext = NULL; if ( ModuleInfo.g.AltQueue.head == NULL ) ModuleInfo.g.AltQueue.head = ModuleInfo.g.AltQueue.tail = (struct dsym *)sym; else { ((struct dsym *)ModuleInfo.g.AltQueue.tail)->nextext = (struct dsym *)sym; ModuleInfo.g.AltQueue.tail = (struct dsym *)sym; } #endif } } } return( NOT_ERROR ); }
ret_code ExterndefDirective( int i, struct asm_tok tokenarray[] ) /***************************************************************/ { char *token; #if MANGLERSUPP char *mangle_type = NULL; #endif struct asym *sym; enum lang_type langtype; char isnew; struct qualified_type ti; DebugMsg1(("ExterndefDirective(%u) enter\n", i)); i++; /* skip EXTERNDEF token */ #if MANGLERSUPP mangle_type = Check4Mangler( &i, tokenarray ); #endif do { ti.Ofssize = ModuleInfo.Ofssize; /* get the symbol language type if present */ langtype = ModuleInfo.langtype; GetLangType( &i, tokenarray, &langtype ); /* get the symbol name */ if( tokenarray[i].token != T_ID ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } token = tokenarray[i++].string_ptr; /* go past the colon */ if( tokenarray[i].token != T_COLON ) { return( EmitError( COLON_EXPECTED ) ); } i++; sym = SymSearch( token ); //typetoken = tokenarray[i].string_ptr; ti.mem_type = MT_EMPTY; ti.size = 0; ti.is_ptr = 0; ti.is_far = FALSE; ti.ptr_memtype = MT_EMPTY; ti.symtype = NULL; ti.Ofssize = ModuleInfo.Ofssize; if ( tokenarray[i].token == T_ID && ( 0 == _stricmp( tokenarray[i].string_ptr, "ABS" ) ) ) { /* v2.07: MT_ABS is obsolete */ //ti.mem_type = MT_ABS; i++; } else if ( tokenarray[i].token == T_DIRECTIVE && tokenarray[i].tokval == T_PROTO ) { /* dont scan this line further! * CreateProto() will either define a SYM_EXTERNAL or fail * if there's a syntax error or symbol redefinition. */ sym = CreateProto( i + 1, tokenarray, token, langtype ); #if 0 /* global queue is obsolete */ if ( sym && sym->isglobal == FALSE ) { sym->isglobal = TRUE; QAddItem( &ModuleInfo.g.GlobalQueue, sym ); } #endif return( sym ? NOT_ERROR : ERROR ); } else if ( tokenarray[i].token != T_FINAL && tokenarray[i].token != T_COMMA ) { if ( GetQualifiedType( &i, tokenarray, &ti ) == ERROR ) return( ERROR ); } isnew = FALSE; if ( sym == NULL || sym->state == SYM_UNDEFINED ) { sym = CreateExternal( sym, token, TRUE ); isnew = TRUE; } /* new symbol? */ if ( isnew ) { DebugMsg1(("ExterndefDirective(%s): memtype=%X set, ofssize=%X\n", token, ti.mem_type, ti.Ofssize )); /* v2.05: added to accept type prototypes */ if ( ti.is_ptr == 0 && ti.symtype && ti.symtype->isproc ) { CreateProc( sym, NULL, SYM_EXTERNAL ); CopyPrototype( (struct dsym *)sym, (struct dsym *)ti.symtype ); ti.mem_type = ti.symtype->mem_type; ti.symtype = NULL; } switch ( ti.mem_type ) { //case MT_ABS: case MT_EMPTY: /* v2.04: hack no longer necessary */ //if ( sym->weak == TRUE ) // sym->equate = TRUE; /* allow redefinition by EQU, = */ break; case MT_FAR: /* v2.04: don't inherit current segment for FAR externals * if -Zg is set. */ if ( Options.masm_compat_gencode ) break; /* fall through */ default: //SetSymSegOfs( sym ); sym->segment = &CurrSeg->sym; } sym->Ofssize = ti.Ofssize; if ( ti.is_ptr == 0 && ti.Ofssize != ModuleInfo.Ofssize ) { sym->seg_ofssize = ti.Ofssize; if ( sym->segment && ((struct dsym *)sym->segment)->e.seginfo->Ofssize != sym->seg_ofssize ) sym->segment = NULL; } sym->mem_type = ti.mem_type; sym->is_ptr = ti.is_ptr; sym->isfar = ti.is_far; sym->ptr_memtype = ti.ptr_memtype; if ( ti.mem_type == MT_TYPE ) sym->type = ti.symtype; else sym->target_type = ti.symtype; /* v2.04: only set language if there was no previous definition */ SetMangler( sym, langtype, mangle_type ); } else if ( Parse_Pass == PASS_1 ) { /* v2.05: added to accept type prototypes */ if ( ti.is_ptr == 0 && ti.symtype && ti.symtype->isproc ) { ti.mem_type = ti.symtype->mem_type; ti.symtype = NULL; } /* ensure that the type of the symbol won't change */ if ( sym->mem_type != ti.mem_type ) { /* if the symbol is already defined (as SYM_INTERNAL), Masm won't display an error. The other way, first externdef and then the definition, will make Masm complain, however */ DebugMsg(("ExterndefDirective: type conflict for %s. mem_types old-new: %X-%X\n", sym->name, sym->mem_type, ti.mem_type)); EmitWarn( 1, SYMBOL_TYPE_CONFLICT, sym->name ); } else if ( sym->mem_type == MT_TYPE && sym->type != ti.symtype ) { struct asym *sym2 = sym; /* skip alias types and compare the base types */ DebugMsg(("ExterndefDirective(%s): types differ: %X (%s) - %X (%s)\n", sym->name, sym->type, sym->type->name, ti.symtype, ti.symtype->name)); while ( sym2->type ) sym2 = sym2->type; while ( ti.symtype->type ) ti.symtype = ti.symtype->type; if ( sym2 != ti.symtype ) { DebugMsg(("ExterndefDirective(%s): type conflict old-new: %X (%s) - %X (%s)\n", sym->name, sym2, sym2->name, ti.symtype, ti.symtype->name)); EmitWarn( 1, SYMBOL_TYPE_CONFLICT, sym->name ); } } /* v2.04: emit a - weak - warning if language differs. * Masm doesn't warn. */ if ( langtype != LANG_NONE && sym->langtype != langtype ) EmitWarn( 3, LANGUAGE_ATTRIBUTE_CONFLICT, sym->name ); } sym->isdefined = TRUE; #if 0 /* write a global entry if none has been written yet */ if ( sym->state == SYM_EXTERNAL && sym->weak == FALSE ) ;/* skip EXTERNDEF if a real EXTERN/COMM was done */ else if ( sym->isglobal == FALSE ) { sym->isglobal = TRUE; DebugMsg1(("ExterndefDirective(%s): writing a global entry\n", sym->name)); QAddItem( &ModuleInfo.g.GlobalQueue, sym ); } #else if ( sym->state == SYM_INTERNAL && sym->ispublic == FALSE ) { sym->ispublic = TRUE; AddPublicData( sym ); } #endif if ( tokenarray[i].token != T_FINAL ) if ( tokenarray[i].token == T_COMMA ) { if ( (i + 1) < Token_Count ) i++; } else { return( EmitErr( EXPECTING_COMMA, tokenarray[i].tokpos ) ); } } while ( i < Token_Count ); return( NOT_ERROR ); }
int main( int argc, char **argv ) /*******************************/ { char *pEnv; int numArgs = 0; int numFiles = 0; int rc = 0; #if WILDCARDS long fh; /* _findfirst/next/close() handle, must be long! */ struct _finddata_t finfo; char drv[_MAX_DRIVE]; char dir[_MAX_DIR]; char fname[_MAX_PATH]; #endif #if 0 //def DEBUG_OUT /* DebugMsg() cannot be used that early */ int i; for ( i = 1; i < argc; i++ ) { printf("argv[%u]=>%s<\n", i, argv[i] ); } #endif pEnv = getenv( "JWASM" ); if ( pEnv == NULL ) pEnv = ""; argv[0] = pEnv; #ifndef DEBUG_OUT signal(SIGSEGV, genfailure); #endif #if CATCHBREAK signal(SIGBREAK, genfailure); #else signal(SIGTERM, genfailure); #endif MsgInit(); while ( 1 ) { if ( ParseCmdline( (const char **)argv, &numArgs ) == NULL ) break; /* exit if no source file name supplied */ numFiles++; write_logo(); #if WILDCARDS if ((fh = _findfirst( Options.names[ASM], &finfo )) == -1 ) { DebugMsg(("main: _findfirst(%s) failed\n", Options.names[ASM] )); EmitErr( CANNOT_OPEN_FILE, Options.names[ASM], ErrnoStr() ); break; } _splitpath( Options.names[ASM], drv, dir, NULL, NULL ); DebugMsg(("main: _splitpath(%s): drv=\"%s\" dir=\"%s\"\n", Options.names[ASM], drv, dir )); do { _makepath( fname, drv, dir, finfo.name, NULL ); DebugMsg(("main: _makepath(\"%s\", \"%s\", \"%s\")=\"%s\"\n", drv, dir, finfo.name, fname )); rc = AssembleModule( fname ); /* assemble 1 module */ } while ( ( _findnext( fh, &finfo ) != -1 ) ); _findclose( fh ); #else rc = AssembleModule( Options.names[ASM] ); #endif }; CmdlineFini(); if ( numArgs == 0 ) { write_logo(); printf( MsgGetEx( MSG_USAGE ) ); } else if ( numFiles == 0 ) EmitError( NO_FILENAME_SPECIFIED ); MsgFini(); return( 1 - rc ); /* zero if no errors */ }
/* handle .model directive * syntax: .MODEL <FLAT|TINY|SMALL...> [,<C|PASCAL|STDCALL...>][,<NEARSTACK|FARSTACK>][,<OS_DOS|OS_OS2>] * sets fields * - ModuleInfo.model * - ModuleInfo.language * - ModuleInfo.distance * - ModuleInfo.ostype * if model is FLAT, defines FLAT pseudo-group * set default segment names for code and data */ ret_code ModelDirective( int i, struct asm_tok tokenarray[] ) /***********************************************************/ { enum model_type model; enum lang_type language; enum dist_type distance; enum os_type ostype; int index; uint_8 init; uint_8 initv; DebugMsg1(("ModelDirective enter\n")); /* v2.03: it may occur that "code" is defined BEFORE the MODEL * directive (i.e. DB directives in AT-segments). For FASTPASS, * this may have caused errors because contents of the ModuleInfo * structure was saved before the .MODEL directive. */ //if( Parse_Pass != PASS_1 ) { if( Parse_Pass != PASS_1 && ModuleInfo.model != MODEL_NONE ) { /* just set the model with SetModel() if pass is != 1. * This won't set the language ( which can be modified by * OPTION LANGUAGE directive ), but the language in ModuleInfo * isn't needed anymore once pass one is done. */ SetModel(); return( NOT_ERROR ); } i++; if ( tokenarray[i].token == T_FINAL ) { EmitError( EXPECTED_MEMORY_MODEL ); return( ERROR ); } /* get the model argument */ index = FindToken( tokenarray[i].string_ptr, ModelToken, sizeof( ModelToken )/sizeof( ModelToken[0] ) ); if( index >= 0 ) { if( ModuleInfo.model != MODEL_NONE ) { EmitWarn( 2, MODEL_DECLARED_ALREADY ); return( NOT_ERROR ); } model = index + 1; i++; } else { EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ); return( ERROR ); } /* get the optional arguments: language, stack distance, os */ init = 0; while ( i < ( Token_Count - 1 ) && tokenarray[i].token == T_COMMA ) { i++; if ( tokenarray[i].token != T_COMMA ) { if ( GetLangType( &i, tokenarray, &language ) == NOT_ERROR ) { initv = INIT_LANG; } else { index = FindToken( tokenarray[i].string_ptr, ModelAttr, sizeof( ModelAttr )/sizeof( ModelAttr[0] ) ); if ( index < 0 ) break; initv = ModelAttrValue[index].init; switch ( initv ) { case INIT_STACK: if ( model == MODEL_FLAT ) { EmitError( INVALID_MODEL_PARAM_FOR_FLAT ); return( ERROR ); } distance = ModelAttrValue[index].value; break; case INIT_OS: ostype = ModelAttrValue[index].value; break; } i++; } /* attribute set already? */ if ( initv & init ) { i--; break; } init |= initv; } } /* everything parsed successfully? */ if ( tokenarray[i].token != T_FINAL ) { EmitErr( SYNTAX_ERROR_EX, tokenarray[i].tokpos ); return( ERROR ); } if ( model == MODEL_FLAT ) { if ( ( ModuleInfo.curr_cpu & P_CPU_MASK) < P_386 ) { EmitError( INSTRUCTION_OR_REGISTER_NOT_ACCEPTED_IN_CURRENT_CPU_MODE ); return( ERROR ); } DefineFlatGroup(); } ModuleInfo.model = model; if ( init & INIT_LANG ) { ModuleInfo.langtype = language; #if AMD64_SUPPORT /* v2.03: set header and fastcall type to win64 if x64 is active. * This is rather hackish, but currently there's no other possibility * to enable the win64 ABI from the source. */ if ( ( ModuleInfo.curr_cpu & P_CPU_MASK ) == P_64 ) if ( language == LANG_FASTCALL && model == MODEL_FLAT && Options.output_format != OFORMAT_ELF ) { DebugMsg(("ModelDirective: FASTCALL type set to WIN64\n")); ModuleInfo.header_format = HFORMAT_WIN64; ModuleInfo.fctype = FCT_WIN64; } #endif } if ( init & INIT_STACK ) ModuleInfo.distance = distance; if ( init & INIT_OS ) ModuleInfo.ostype = ostype; SetModelDefaultSegNames(); SetModel(); return( NOT_ERROR ); }
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(); 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 ) { EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ); return( ERROR ); } if( ( ModuleInfo.curr_cpu & P_CPU_MASK ) < GetCpuSp( reg ) ) { EmitError( INSTRUCTION_OR_REGISTER_NOT_ACCEPTED_IN_CURRENT_CPU_MODE ); return( ERROR ); } i++; /* go past register */ if( tokenarray[i].token != T_COLON ) { EmitError( COLON_EXPECTED ); return( ERROR ); } i++; if( tokenarray[i].token == T_FINAL ) { EmitError( SYNTAX_ERROR ); return( ERROR ); } /* check for ERROR and NOTHING */ if( 0 == _stricmp( tokenarray[i].string_ptr, szError )) { if ( segtable ) { info->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->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 ) ) { EmitError( TYPE_IS_WRONG_SIZE_FOR_REGISTER ); return( ERROR ); } 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 ) { EmitError( SEGMENT_GROUP_OR_SEGREG_EXPECTED ); return( ERROR ); } 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 { EmitError( SEGMENT_GROUP_OR_SEGREG_EXPECTED ); return( ERROR ); } info->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->flat = SegAssumeTable[ GetRegNo( opnd.base_reg->tokval ) ].flat; break; } default: EmitError( SEGMENT_GROUP_OR_SEGREG_EXPECTED ); return( ERROR ); } info->error = FALSE; } /* comma expected */ if( i < Token_Count && tokenarray[i].token != T_COMMA ) break; } if ( i < Token_Count ) { EmitErr( SYNTAX_ERROR_EX, tokenarray[i].tokpos ); return( ERROR ); } return( NOT_ERROR ); }
/* handle .model directive * syntax: .MODEL <FLAT|TINY|SMALL...> [,<C|PASCAL|STDCALL...>][,<NEARSTACK|FARSTACK>][,<OS_DOS|OS_OS2>] * sets fields * - ModuleInfo.model * - ModuleInfo.language * - ModuleInfo.distance * - ModuleInfo.ostype * if model is FLAT, defines FLAT pseudo-group * set default segment names for code and data */ ret_code ModelDirective( int i, struct asm_tok tokenarray[] ) /***********************************************************/ { enum model_type model; enum lang_type language; enum dist_type distance; enum os_type ostype; int index; uint_8 init; uint_8 initv; DebugMsg1(("ModelDirective enter\n")); /* v2.03: it may occur that "code" is defined BEFORE the MODEL * directive (i.e. DB directives in AT-segments). For FASTPASS, * this may have caused errors because contents of the ModuleInfo * structure was saved before the .MODEL directive. */ //if( Parse_Pass != PASS_1 ) { if( Parse_Pass != PASS_1 && ModuleInfo.model != MODEL_NONE ) { /* just set the model with SetModel() if pass is != 1. * This won't set the language ( which can be modified by * OPTION LANGUAGE directive ), but the language in ModuleInfo * isn't needed anymore once pass one is done. */ SetModel(); return( NOT_ERROR ); } i++; if ( tokenarray[i].token == T_FINAL ) { return( EmitError( EXPECTED_MEMORY_MODEL ) ); } /* get the model argument */ index = FindToken( tokenarray[i].string_ptr, ModelToken, sizeof( ModelToken )/sizeof( ModelToken[0] ) ); if( index >= 0 ) { if( ModuleInfo.model != MODEL_NONE ) { //if ( Parse_Pass == PASS_1 ) /* not needed, this code runs in pass one only */ EmitWarn( 2, MODEL_DECLARED_ALREADY ); } model = index + 1; /* model is one-base ( 0 is MODEL_NONE ) */ i++; } else { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } /* get the optional arguments: language, stack distance, os */ init = 0; while ( i < ( Token_Count - 1 ) && tokenarray[i].token == T_COMMA ) { i++; if ( tokenarray[i].token != T_COMMA ) { if ( GetLangType( &i, tokenarray, &language ) == NOT_ERROR ) { initv = INIT_LANG; } else { index = FindToken( tokenarray[i].string_ptr, ModelAttr, sizeof( ModelAttr )/sizeof( ModelAttr[0] ) ); if ( index < 0 ) break; initv = ModelAttrValue[index].init; switch ( initv ) { case INIT_STACK: if ( model == MODEL_FLAT ) { return( EmitError( INVALID_MODEL_PARAM_FOR_FLAT ) ); } distance = ModelAttrValue[index].value; break; case INIT_OS: ostype = ModelAttrValue[index].value; break; } i++; } /* attribute set already? */ if ( initv & init ) { i--; break; } init |= initv; } } /* everything parsed successfully? */ if ( tokenarray[i].token != T_FINAL ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].tokpos ) ); } if ( model == MODEL_FLAT ) { if ( ( ModuleInfo.curr_cpu & P_CPU_MASK) < P_386 ) { return( EmitError( INSTRUCTION_OR_REGISTER_NOT_ACCEPTED_IN_CURRENT_CPU_MODE ) ); } #if AMD64_SUPPORT if ( ( ModuleInfo.curr_cpu & P_CPU_MASK ) >= P_64 ) /* cpu 64-bit? */ switch ( Options.output_format ) { case OFORMAT_COFF: ModuleInfo.fmtopt = &coff64_fmtopt; break; case OFORMAT_ELF: ModuleInfo.fmtopt = &elf64_fmtopt; break; }; #endif /* v2.11: define FLAT symbol is to early here, because defOfssize isn't set yet */ //DefineFlatGroup(); } ModuleInfo.model = model; if ( init & INIT_LANG ) ModuleInfo.langtype = language; if ( init & INIT_STACK ) ModuleInfo.distance = distance; if ( init & INIT_OS ) ModuleInfo.ostype = ostype; SetModelDefaultSegNames(); SetModel(); return( NOT_ERROR ); }
ret_code SafeSEHDirective( int i, struct asm_tok tokenarray[] ) /*************************************************************/ { struct asym *sym; struct qnode *node; if ( Options.output_format != OFORMAT_COFF ) { if ( Parse_Pass == PASS_1) EmitWarn( 2, DIRECTIVE_IGNORED_WITHOUT_X, "coff" ); return( NOT_ERROR ); } if ( Options.safeseh == FALSE ) { if ( Parse_Pass == PASS_1) EmitWarn( 2, DIRECTIVE_IGNORED_WITHOUT_X, "safeseh" ); return( NOT_ERROR ); } i++; if ( tokenarray[i].token != T_ID ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } sym = SymSearch( tokenarray[i].string_ptr ); /* make sure the argument is a true PROC */ if ( sym == NULL || sym->state == SYM_UNDEFINED ) { if ( Parse_Pass != PASS_1 ) { return( EmitErr( SYMBOL_NOT_DEFINED, tokenarray[i].string_ptr ) ); } } else if ( sym->isproc == FALSE ) { return( EmitErr( SAFESEH_ARGUMENT_MUST_BE_A_PROC, tokenarray[i].string_ptr ) ); } if ( Parse_Pass == PASS_1 ) { if ( sym ) { for ( node = ModuleInfo.g.SafeSEHQueue.head; node; node = node->next ) if ( node->elmt == sym ) break; } else { sym = SymCreate( tokenarray[i].string_ptr ); node = NULL; } if ( node == NULL ) { sym->used = TRUE; /* make sure an external reference will become strong */ #if 0 /* v2.11: use QAddItem() */ node = LclAlloc( sizeof( struct qnode ) ); node->elmt = sym; node->next = NULL; if ( ModuleInfo.g.SafeSEHQueue.head == 0 ) ModuleInfo.g.SafeSEHQueue.head = ModuleInfo.g.SafeSEHQueue.tail = node; else { ((struct qnode *)ModuleInfo.g.SafeSEHQueue.tail)->next = node; ModuleInfo.g.SafeSEHQueue.tail = node; } #else QAddItem( &ModuleInfo.g.SafeSEHQueue, sym ); #endif } } i++; if ( tokenarray[i].token != T_FINAL ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } return( NOT_ERROR ); }
FILE *SearchFile( const char *path, bool queue ) /**********************************************/ { FILE *file = NULL; struct src_item *fl; const char *fn; bool isabs; char fullpath[FILENAME_MAX]; DebugMsg1(("SearchFile(%s) enter\n", path )); //_splitpath( path, drive, dir, fname, ext ); //DebugMsg1(("SearchFile(): drive=%s, dir=%s, fname=%s, ext=%s\n", drive, dir, fname, ext )); fn = GetFNamePart( path ); /* if no absolute path is given, then search in the directory * of the current source file first! * v2.11: various changes because field fullpath has been removed. */ isabs = ISABS( path ); //if ( dir[0] != '\\' && dir[0] != '/' ) { if ( !isabs ) { for ( fl = src_stack; fl ; fl = fl->next ) { if ( fl->type == SIT_FILE ) { const char *fn2; char *src; //_splitpath( GetFName( fl->srcfile )->fname, drive2, dir2, NULL, NULL ); //DebugMsg1(("SearchFile(): curr src=%s, split into drive=%s, dir=%s\n", GetFName( fl->srcfile)->fname, drive2, dir2 )); src = GetFName( fl->srcfile )->fname; fn2 = GetFNamePart( src ); if ( fn2 != src ) { int i = fn2 - src; /* v2.10: if there's a directory part, add it to the directory part of the current file. * fixme: check that both parts won't exceed FILENAME_MAX! * fixme: 'path' is relative, but it may contain a drive letter! */ memcpy( fullpath, src, i ); strcpy( fullpath + i, path ); if ( (file = fopen( fullpath, "rb" )) != NULL ) { DebugMsg1(("SearchFile(): file found, fopen(%s)=%X\n", fullpath, file )); path = fullpath; } #ifdef DEBUG_OUT else DebugMsg1(("SearchFile(): fopen(%s) failed\n", fullpath )); #endif } break; } } } if ( file == NULL ) { fullpath[0] = NULLC; file = fopen( path, "rb" ); DebugMsg1(("SearchFile(): fopen(%s)=%X\n", path, file )); /* if the file isn't found yet and include paths have been set, * and NO absolute path is given, then search include dirs */ if( file == NULL && ModuleInfo.g.IncludePath != NULL && !isabs ) { if ( (file = open_file_in_include_path( path, fullpath )) != NULL ) { DebugMsg1(("SearchFile(): open_file_in_include_path(%s)=%X [%s]\n", path, file, fullpath )); path = fullpath; } #ifdef DEBUG_OUT else DebugMsg1(("SearchFile(): open_file_in_include_path(%s)=NULL\n", path )); #endif } if( file == NULL ) { EmitErr( CANNOT_OPEN_FILE, path, ErrnoStr() ); return( NULL ); } } /* is the file to be added to the file stack? * assembly files usually are, but binary files ( INCBIN ) aren't. */ if ( queue ) { fl = PushSrcItem( SIT_FILE, file ); fl->srcfile = AddFile( path ); FileCur->string_ptr = GetFName( fl->srcfile )->fname; #if FILESEQ if ( Options.line_numbers && Parse_Pass == PASS_1 ) AddFileSeq( fl->srcfile ); #endif } return( file ); }