static struct asym *MakeComm( char *name, struct asym *sym, uint_32 size, uint_32 count, bool isfar ) /***************************************************************************************************/ { sym = CreateComm( sym, name ); if( sym == NULL ) return( NULL ); sym->total_length = count; sym->isfar = isfar; /* v2.04: don't set segment if communal is far and -Zg is set */ if ( Options.masm_compat_gencode == FALSE || isfar == FALSE ) sym->segment = &CurrSeg->sym; MemtypeFromSize( size, &sym->mem_type ); /* v2.04: warning added ( Masm emits an error ) */ /* v2.05: code active for 16-bit only */ if ( ModuleInfo.Ofssize == USE16 ) if ( ( count * size ) > 0x10000UL ) EmitWarn( 2, COMM_VAR_EXCEEDS_64K, sym->name ); sym->total_size = count * size; return( sym ); }
/* The "mangler" has been inherited from Wasm. * By default it's not active in HJWasm (see MANGLERSUPP in globals.h) * It allows some fine tuning of the external's name in the object module, * but is relevant for mixing with OW code only. * Syntax: * EXTERN|EXTERNDEF [ [ mangle_type, ] lang_type ] name : type * PUBLIC [ [ mangle_type, ] lang_type ] name * COMM [ [ mangle_type, ] langtype] [NEAR|FAR] name: ... * mangle_type must be a 'string'. */ static char *Check4Mangler( int *i, struct asm_tok tokenarray[] ) /***************************************************************/ { char *mangle_type = NULL; if( tokenarray[*i].token == T_STRING ) { mangle_type = tokenarray[*i].string_ptr; (*i)++; if( tokenarray[*i].token != T_COMMA ) { EmitWarn( 2, EXPECTING_COMMA, tokenarray[*i].tokpos ); } else { (*i)++; } } return( mangle_type ); }
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 ); }
/* .[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 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 ); }
void AddLinnumDataRef( unsigned srcfile, uint_32 line_num ) /*********************************************************/ { struct line_num_info *curr; #if COFF_SUPPORT /* COFF line number info is related to functions/procedures. Since * assembly allows code lines outside of procs, "dummy" procs must * be generated. A dummy proc lasts until * - a true PROC is detected or * - the source file changes or * - the segment/section changes ( added in v2.11 ) */ if ( Options.output_format == OFORMAT_COFF && CurrProc == NULL && ( dmyproc == NULL || dmyproc->debuginfo->file != srcfile || dmyproc->segment != (struct asym *)CurrSeg ) ) { char procname[12]; if ( dmyproc ) { /**/myassert( dmyproc->segment ); dmyproc->total_size = ((struct dsym *)dmyproc->segment)->e.seginfo->current_loc - dmyproc->offset; } sprintf( procname, "$$$%05u", procidx ); DebugMsg1(("AddLinnumDataRef(src=%u.%u): CurrProc==NULL, dmyproc=%s searching proc=%s\n", srcfile, line_num, dmyproc ? dmyproc->name : "NULL", procname )); dmyproc = SymSearch( procname ); /* in pass 1, create the proc */ if ( dmyproc == NULL ) { dmyproc = CreateProc( NULL, procname, SYM_INTERNAL ); DebugMsg1(("AddLinnumDataRef: new proc %s created\n", procname )); dmyproc->isproc = TRUE; /* flag is usually set inside ParseProc() */ dmyproc->included = TRUE; AddPublicData( dmyproc ); } else procidx++; /* for passes > 1, adjust procidx */ /* if the symbols isn't a PROC, the symbol name has been used * by the user - bad! A warning should be displayed */ if ( dmyproc->isproc == TRUE ) { SetSymSegOfs( dmyproc ); dmyproc->Ofssize = ModuleInfo.Ofssize; dmyproc->langtype = ModuleInfo.langtype; if ( write_to_file == TRUE ) { curr = LclAlloc( sizeof( struct line_num_info ) ); curr->sym = dmyproc; curr->line_number = GetLineNumber(); curr->file = srcfile; curr->number = 0; DebugMsg1(("AddLinnumDataRef: CURRPROC=NULL, sym=%s, calling AddLinnumData(src=%u.%u)\n", curr->sym->name, curr->file, curr->line_number )); AddLinnumData( curr ); } } } #endif if( line_num && ( write_to_file == FALSE || lastLineNumber == line_num )) { #ifdef DEBUG_OUT if ( write_to_file == TRUE ) DebugMsg1(("AddLinnumDataRef(src=%u.%u) line skipped, lastline=%u\n", srcfile, line_num, lastLineNumber )); #endif return; } DebugMsg1(("AddLinnumDataRef(src=%u.%u): currofs=%Xh, CurrProc=%s, GeneratedCode=%u\n", srcfile, line_num, GetCurrOffset(), CurrProc ? CurrProc->sym.name : "NULL", ModuleInfo.GeneratedCode )); curr = LclAlloc( sizeof( struct line_num_info ) ); curr->number = line_num; #if COFF_SUPPORT if ( line_num == 0 ) { /* happens for COFF only */ /* changed v2.03 (CurrProc might have been NULL) */ /* if ( Options.output_format == OFORMAT_COFF && CurrProc->sym.public == FALSE ) { */ /* v2.09: avoid duplicates, check for pass 1 */ //if ( Options.output_format == OFORMAT_COFF && CurrProc && CurrProc->sym.public == FALSE ) { if ( Parse_Pass == PASS_1 && Options.output_format == OFORMAT_COFF && CurrProc && CurrProc->sym.ispublic == FALSE ) { CurrProc->sym.included = TRUE; AddPublicData( (struct asym *)CurrProc ); } /* changed v2.03 */ /* curr->sym = (struct asym *)CurrProc; */ curr->sym = ( CurrProc ? (struct asym *)CurrProc : dmyproc ); curr->line_number = GetLineNumber(); curr->file = srcfile; /* set the function's size! */ if ( dmyproc ) { /**/myassert( dmyproc->segment ); dmyproc->total_size = ((struct dsym *)dmyproc->segment)->e.seginfo->current_loc - dmyproc->offset; dmyproc = NULL; } /* v2.11: write a 0x7fff line item if prologue exists */ if ( CurrProc && CurrProc->e.procinfo->size_prolog ) { DebugMsg1(("AddLinnumDataRef: calling AddLinnumData(src=%u.%u) sym=%s\n", curr->file, curr->line_number, curr->sym->name )); AddLinnumData( curr ); curr = LclAlloc( sizeof( struct line_num_info ) ); curr->number = GetLineNumber(); curr->offset = GetCurrOffset(); curr->srcfile = srcfile; } } else { #endif curr->offset = GetCurrOffset(); curr->srcfile = srcfile; #if COFF_SUPPORT } #endif lastLineNumber = line_num; /* v2.11: added, improved multi source support for CV. * Also, the size of line number info could have become > 1024, * ( even > 4096, thus causing an "internal error in omfint.c" ) */ if ( Options.output_format == OFORMAT_OMF ) omf_check_flush( curr ); /* v2.10: warning if line-numbers for segments without class code! */ if ( CurrSeg->e.seginfo->linnum_init == FALSE ) { CurrSeg->e.seginfo->linnum_init = TRUE; if ( TypeFromClassName( CurrSeg, CurrSeg->e.seginfo->clsym ) != SEGTYPE_CODE ) { EmitWarn( 2, LINNUM_INFO_FOR_SEGMENT_WITHOUT_CLASS_CODE, CurrSeg->sym.name ); } } DebugMsg1(("AddLinnumDataRef: calling AddLinnumData(src=%u.%u ofs=%X)\n", curr->number == 0 ? curr->file : curr->srcfile, curr->number, curr->offset )); AddLinnumData( curr ); return; }
/* 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 ); }
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 ); }
/* 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 ); }
static void CalcOffset( struct dsym *curr, bool firstseg ) /********************************************************/ { uint_32 align; uint_32 alignbytes; uint_32 offset; struct dsym *grp; if ( curr->e.seginfo->segtype == SEGTYPE_ABS ) { curr->e.seginfo->start_offset = curr->e.seginfo->abs_frame << 4; DebugMsg(("CalcOffset(%s): abs seg, offset=%" FX32 "h\n", curr->sym.name, curr->e.seginfo->start_offset )); return; } grp = (struct dsym *)curr->e.seginfo->group; align = 1 << curr->e.seginfo->alignment; //alignbytes = ((offset + (align - 1)) & (-align)) - offset; alignbytes = ((fileoffset + (align - 1)) & (-align)) - fileoffset; fileoffset += alignbytes; if ( grp == NULL ) { offset = fileoffset - sizehdr; // + alignbytes; DebugMsg(("CalcOffset(%s): fileofs=%" FX32 "h, ofs=%" FX32 "h\n", curr->sym.name, fileoffset, offset )); } else { if ( grp->sym.total_size == 0 ) { grp->sym.offset = fileoffset - sizehdr; offset = 0; } else offset = grp->sym.total_size + alignbytes; DebugMsg(("CalcOffset(%s): fileofs=%" FX32 "h, alignbytes=%lu, ofs=%" FX32 "h, group=%s, grp.ofs=%" FX32 "h\n", curr->sym.name, fileoffset, alignbytes, offset, grp->sym.name, grp->sym.offset )); } /* v2.04: added */ /* v2.05: this addition did mess sample Win32_5.asm, because the * "empty" alignment sections are now added to <fileoffset>. * todo: VA in binary map is displayed wrong. */ if ( firstseg == FALSE ) { /* v2.05: do the reset more carefully. * Do reset start_loc only if * - segment is in a group and * - group isn't FLAT or segment's name contains '$' */ if ( grp && ( grp != ModuleInfo.flat_grp || strchr( curr->sym.name, '$' ) ) ) curr->e.seginfo->start_loc = 0; } curr->e.seginfo->fileoffset = fileoffset; //if ( firstseg && ModuleInfo.header_format == HFORMAT_NONE ) { if ( ModuleInfo.header_format == HFORMAT_NONE ) { fileoffset += curr->sym.max_offset - curr->e.seginfo->start_loc; if ( firstseg ) imagestart = curr->e.seginfo->start_loc; } else { /* v2.05: changed, removed */ //curr->e.seginfo->fileoffset += curr->e.seginfo->start_loc; //fileoffset += curr->sym.max_offset; fileoffset += curr->sym.max_offset - curr->e.seginfo->start_loc; } curr->e.seginfo->start_offset = offset; /* there's no real entry address for BIN, therefore the start label must be at the very beginning of the file */ if (entryoffset == -1) { entryoffset = offset; entryseg = (struct asym *)curr; } //offset += curr->sym.max_offset - curr->e.seginfo->start_loc; offset += curr->sym.max_offset; if ( grp ) { //grp->sym.total_size = offset + curr->e.seginfo->start_loc; grp->sym.total_size = offset; /* v2.07: for 16-bit groups, ensure that it fits in 64 kB */ if ( grp->sym.total_size > 0x10000 && grp->sym.Ofssize == USE16 ) { EmitWarn( 2, GROUP_EXCEEDS_64K, grp->sym.name ); } } DebugMsg(("CalcOffset(%s) exit: seg.fileofs=%" FX32 "h, seg.start_offset=%" FX32 "h, endofs=%" FX32 "h fileoffset=%" FX32 "h\n", curr->sym.name, curr->e.seginfo->fileoffset, curr->e.seginfo->start_offset, offset, fileoffset )); return; }
ret_code CatStrDir( int i, struct asm_tok tokenarray[] ) /******************************************************/ { struct asym *sym; int count; char *p; /* struct expr opndx; */ DebugMsg1(("CatStrDir(%u) enter\n", i )); DebugCmd( catstrcnt++ ); #if 0 /* can't happen */ /* syntax must be <id> CATSTR textitem[,textitem,...] */ if ( i != 1 ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } if ( tokenarray[0].token != T_ID ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[0].string_ptr ) ); } #endif i++; /* go past CATSTR/TEXTEQU */ /* v2.08: don't copy to temp buffer */ //*StringBufferEnd = NULLC; /* check correct syntax and length of items */ for ( count = 0; i < Token_Count; ) { DebugMsg1(("CatStrDir(%s): item[%u]=%s delim=0x%x\n", tokenarray[0].string_ptr, i, tokenarray[i].string_ptr, tokenarray[i].string_delim )); if ( tokenarray[i].token != T_STRING || tokenarray[i].string_delim != '<' ) { DebugMsg(("CatStrDir: error, not a <>-literal: %s\n", tokenarray[i].tokpos )); return( TextItemError( &tokenarray[i] ) ); } /* v2.08: using tokenarray.stringlen is not quite correct, since some chars * are stored in 2 bytes (!) */ if ( ( count + tokenarray[i].stringlen ) >= MAX_LINE_LEN ) { DebugMsg(("CatStrDir: error, literal too long: %u + %u >= %u\n", count, tokenarray[i].stringlen, MAX_LINE_LEN )); return( EmitError( STRING_OR_TEXT_LITERAL_TOO_LONG ) ); } /* v2.08: don't copy to temp buffer */ //strcpy( StringBufferEnd + count, tokenarray[i].string_ptr ); count = count + tokenarray[i].stringlen; i++; if ( ( tokenarray[i].token != T_COMMA ) && ( tokenarray[i].token != T_FINAL ) ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } i++; } sym = SymSearch( tokenarray[0].string_ptr ); if ( sym == NULL ) { sym = SymCreate( tokenarray[0].string_ptr ); DebugMsg1(( "CatStrDir: new symbol %s created\n", sym->name)); } else if( sym->state == SYM_UNDEFINED ) { /* v2.01: symbol has been used already. Using * a textmacro before it has been defined is * somewhat problematic. */ sym_remove_table( &SymTables[TAB_UNDEF], (struct dsym *)sym ); #if FASTPASS SkipSavedState(); /* further passes must be FULL! */ #endif EmitWarn( 2, TEXT_MACRO_USED_PRIOR_TO_DEFINITION, sym->name ); } else if( sym->state != SYM_TMACRO ) { /* it is defined as something else, get out */ DebugMsg(( "CatStrDir(%s) exit, symbol redefinition\n", sym->name)); return( EmitErr( SYMBOL_REDEFINITION, sym->name ) ); } sym->state = SYM_TMACRO; sym->isdefined = TRUE; #if FASTMEM==0 if ( sym->string_ptr ) LclFree( sym->string_ptr ); sym->string_ptr = (char *)LclAlloc( count + 1 ); #else /* v2.08: reuse string space if fastmem is on */ if ( sym->total_size < ( count+1 ) ) { LclFree( sym->string_ptr ); /* is a noop if fastmem is on */ sym->string_ptr = (char *)LclAlloc( count + 1 ); sym->total_size = count + 1; } #endif /* v2.08: don't use temp buffer */ //memcpy( sym->string_ptr, StringBufferEnd, count + 1 ); for ( i = 2, p = sym->string_ptr; i < Token_Count; i += 2 ) { memcpy( p, tokenarray[i].string_ptr, tokenarray[i].stringlen ); p += tokenarray[i].stringlen; } *p = NULLC; DebugMsg1(("CatStrDir(%s) (new) value: >%s<\n", sym->name, sym->string_ptr )); if ( ModuleInfo.list ) LstWrite( LSTTYPE_TMACRO, 0, sym ); return( NOT_ERROR ); }
/* InStr() * defines a numeric variable which contains position of substring. * syntax: * name INSTR [pos,]string, substr */ ret_code InStrDir( int i, struct asm_tok tokenarray[] ) /*****************************************************/ { struct asym *sym; int sizestr; int j; /* int commas; */ char *src; char *p; char *q; char *string1; struct expr opndx; int start = 1; int strpos; DebugMsg1(("InStrDir entry\n")); DebugCmd( instrcnt++ ); 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 i++; /* go past INSTR */ if ( tokenarray[i].token != T_STRING || tokenarray[i].string_delim != '<' ) { /* v2.11: flag NOUNDEF added - no forward reference accepted */ if ( EvalOperand( &i, tokenarray, Token_Count, &opndx, EXPF_NOUNDEF ) == ERROR ) return( ERROR ); if ( opndx.kind != EXPR_CONST ) { return( EmitError( CONSTANT_EXPECTED ) ); } start = opndx.value; if ( start <= 0 ) { /* v2.05: don't change the value. if it's invalid, the result * is to be 0. Emit a level 3 warning instead. */ //start = 1; EmitWarn( 3, POSITIVE_VALUE_EXPECTED ); } if ( tokenarray[i].token != T_COMMA ) { return( EmitErr( EXPECTING_COMMA, tokenarray[i].tokpos ) ); } i++; /* skip comma */ } if ( tokenarray[i].token != T_STRING || tokenarray[i].string_delim != '<' ) { return( TextItemError( &tokenarray[i] ) ); } /* to compare the strings, the "visible" format is needed, since * the possible '!' operators inside the strings is optional and * must be ignored. */ //src = StringBufferEnd; //sizestr = GetLiteralValue( src, tokenarray[i].string_ptr ); src = tokenarray[i].string_ptr; sizestr = tokenarray[i].stringlen; DebugMsg1(("InStrDir: first string >%s< \n", src )); if ( start > sizestr ) { return( EmitErr( INDEX_VALUE_PAST_END_OF_STRING, start ) ); } p = src + start - 1; i++; if ( tokenarray[i].token != T_COMMA ) { return( EmitErr( EXPECTING_COMMA, tokenarray[i].tokpos ) ); } i++; if ( tokenarray[i].token != T_STRING || tokenarray[i].string_delim != '<' ) { return( TextItemError( &tokenarray[i] ) ); } //q = GetAlignedPointer( src, sizestr ); //j = GetLiteralValue( q, tokenarray[i].string_ptr ); q = tokenarray[i].string_ptr; j = tokenarray[i].stringlen; DebugMsg1(("InStrDir: second string >%s< \n", q )); i++; if ( tokenarray[i].token != T_FINAL ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } strpos = 0; /* v2.05: check for start > 0 added */ /* v2.08: check for j > 0 added */ if ( ( start > 0 ) && ( sizestr >= j ) && j && ( string1 = strstr( p, q ) )) strpos = string1 - src + 1; if ( sym = CreateVariable( tokenarray[0].string_ptr, strpos ) ) { DebugMsg1(("InStrDir(%s) exit, value=%u\n", tokenarray[0].string_ptr, strpos)); LstWrite( LSTTYPE_EQUATE, 0, sym ); return ( NOT_ERROR ); } return( ERROR ); }
/* SubStr() * defines a text equate. * syntax: name SUBSTR <string>, pos [, size] */ ret_code SubStrDir( int i, struct asm_tok tokenarray[] ) /******************************************************/ { struct asym *sym; char *name; char *p; //char *newvalue; int pos; int size; int cnt; bool chksize; struct expr opndx; DebugMsg1(("SubStrDir enter\n")); DebugCmd( substrcnt++ ); /* at least 5 items are needed * 0 1 2 3 4 5 6 * ID SUBSTR SRC_ID , POS [, LENGTH] */ #if 0 /* can't happen */ if ( i != 1 ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } if ( tokenarray[0].token != T_ID ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[0].string_ptr ) ); } #endif name = tokenarray[0].string_ptr; i++; /* go past SUBSTR */ /* third item must be a string */ if ( tokenarray[i].token != T_STRING || tokenarray[i].string_delim != '<' ) { DebugMsg(("SubStrDir: error, no text item\n")); return( TextItemError( &tokenarray[i] ) ); } p = tokenarray[i].string_ptr; cnt = tokenarray[i].stringlen; i++; DebugMsg1(("SubStrDir(%s): src=>%s<\n", name, p)); if ( tokenarray[i].token != T_COMMA ) { return( EmitErr( EXPECTING_COMMA, tokenarray[i].tokpos ) ); } i++; /* get pos, must be a numeric value and > 0 */ /* v2.11: flag NOUNDEF added - no forward ref possible */ if ( EvalOperand( &i, tokenarray, Token_Count, &opndx, EXPF_NOUNDEF ) == ERROR ) { DebugMsg(("SubStrDir(%s): invalid pos value\n", name)); return( ERROR ); } /* v2.04: "string" constant allowed as second argument */ //if ( opndx.kind != EXPR_CONST || opndx.string != NULL ) { if ( opndx.kind != EXPR_CONST ) { DebugMsg(("SubStrDir(%s): pos value is not a constant\n", name)); return( EmitError( CONSTANT_EXPECTED ) ); } /* pos is expected to be 1-based */ pos = opndx.value; if ( pos <= 0 ) { return( EmitError( POSITIVE_VALUE_EXPECTED ) ); } if ( tokenarray[i].token != T_FINAL ) { if ( tokenarray[i].token != T_COMMA ) { return( EmitErr( EXPECTING_COMMA, tokenarray[i].tokpos ) ); } i++; /* get size, must be a constant */ /* v2.11: flag NOUNDEF added - no forward ref possible */ if ( EvalOperand( &i, tokenarray, Token_Count, &opndx, EXPF_NOUNDEF ) == ERROR ) { DebugMsg(("SubStrDir(%s): invalid size value\n", name)); return( ERROR ); } /* v2.04: string constant ok */ //if ( opndx.kind != EXPR_CONST || opndx.string != NULL ) { if ( opndx.kind != EXPR_CONST ) { DebugMsg(("SubStrDir(%s): size value is not a constant\n", name)); return( EmitError( CONSTANT_EXPECTED ) ); } size = opndx.value; if ( tokenarray[i].token != T_FINAL ) { DebugMsg(("SubStrDir(%s): additional items found\n", name)); return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } if ( size < 0 ) { return( EmitError( COUNT_MUST_BE_POSITIVE_OR_ZERO ) ); } chksize = TRUE; } else { size = -1; chksize = FALSE; } #if 0 cnt = pos; /* position p to start of substring */ for ( pos--; pos > 0 && *p ; pos--, p++ ) if ( *p == '!' && *(p+1) != NULLC ) p++; if ( *p == NULLC ) { return( EmitErr( INDEX_VALUE_PAST_END_OF_STRING, cnt ) ); } if ( *p == '!' && *(p+1) != NULLC ) p++; for ( newvalue = p, cnt = size; *p && cnt; cnt--, p++ ) if ( *p == '!' && *(p+1) != NULLC ) p++; /* v2.04: check added */ if ( chksize && cnt ) { return( EmitError( COUNT_VALUE_TOO_LARGE ) ); } size = p - newvalue; p = newvalue; #else if ( pos > cnt ) { return( EmitErr( INDEX_VALUE_PAST_END_OF_STRING, pos ) ); } if ( chksize && (pos+size-1) > cnt ) { return( EmitError( COUNT_VALUE_TOO_LARGE ) ); } p += pos - 1; if ( size == -1 ) size = cnt - pos + 1; #endif sym = SymSearch( name ); /* if we've never seen it before, put it in */ if( sym == NULL ) { sym = SymCreate( name ); } else if( sym->state == SYM_UNDEFINED ) { /* it was referenced before being defined. This is * a bad idea for preprocessor text items, because it * will require a full second pass! */ sym_remove_table( &SymTables[TAB_UNDEF], (struct dsym *)sym ); #if FASTPASS SkipSavedState(); EmitWarn( 2, TEXT_MACRO_USED_PRIOR_TO_DEFINITION, sym->name ); #endif } else if( sym->state != SYM_TMACRO ) { /* it is defined as something incompatible, get out */ DebugMsg(( "SubStrDir(%s) error, incompatible type\n", sym->name)); return( EmitErr( SYMBOL_REDEFINITION, sym->name ) ); } sym->state = SYM_TMACRO; sym->isdefined = TRUE; #if FASTMEM==0 if ( sym->string_ptr ) LclFree( sym->string_ptr ); sym->string_ptr = (char *)LclAlloc( size + 1 ); #else if ( sym->total_size < ( size + 1 ) ) { LclFree( sym->string_ptr ); sym->string_ptr = LclAlloc ( size + 1 ); sym->total_size = size + 1; } #endif memcpy( sym->string_ptr, p, size ); *(sym->string_ptr + size) = NULLC; DebugMsg1(("SubStrDir(%s): result=>%s<\n", sym->name, sym->string_ptr )); LstWrite( LSTTYPE_TMACRO, 0, sym ); return( NOT_ERROR ); }
/* * used by EQU if the value to be assigned to a symbol is text. * - sym: text macro name, may be NULL * - name: identifer ( if sym == NULL ) * - value: value of text macro ( original line, BEFORE expansion ) */ struct asym *SetTextMacro( struct asm_tok tokenarray[], struct asym *sym, const char *name, const char *value ) /*************************************************************************************************************/ { int count; //char *p; DebugCmd( equcnt++ ); if ( sym == NULL ) sym = SymCreate( name ); else if ( sym->state == SYM_UNDEFINED ) { sym_remove_table( &SymTables[TAB_UNDEF], (struct dsym *)sym ); #if FASTPASS /* the text macro was referenced before being defined. * this is valid usage, but it requires a full second pass. * just simply deactivate the fastpass feature for this module! */ SkipSavedState(); #endif EmitWarn( 2, TEXT_MACRO_USED_PRIOR_TO_DEFINITION, sym->name ); } else if ( sym->state != SYM_TMACRO ) { EmitErr( SYMBOL_REDEFINITION, name ); return( NULL ); } sym->state = SYM_TMACRO; sym->isdefined = TRUE; if ( tokenarray[2].token == T_STRING && tokenarray[2].string_delim == '<' ) { /* the simplest case: value is a literal. define a text macro! */ /* just ONE literal is allowed */ if ( tokenarray[3].token != T_FINAL ) { EmitErr( SYNTAX_ERROR_EX, tokenarray[3].tokpos ); return( NULL ); } value = tokenarray[2].string_ptr; count = tokenarray[2].stringlen; } else { /* * the original source is used, since the tokenizer has * deleted some information. */ //while ( isspace( *value ) ) value++; /* probably obsolete */ count = strlen( value ); /* skip trailing spaces */ for ( ; count; count-- ) if ( isspace( *( value + count - 1 ) ) == FALSE ) break; } #if FASTMEM==0 if ( sym->string_ptr ) LclFree( sym->string_ptr ); sym->string_ptr = (char *)LclAlloc( count + 1 ); #else if ( sym->total_size < ( count + 1 ) ) { LclFree( sym->string_ptr ); /* is a noop if fastmem is on */ sym->string_ptr = (char *)LclAlloc( count + 1 ); sym->total_size = count + 1; } #endif memcpy( sym->string_ptr, value, count ); *(sym->string_ptr + count) = NULLC; DebugMsg1(( "SetTextMacro(%s): value is >%s<, exit\n", sym->name, sym->string_ptr )); return( sym ); }