int directive( int i, long direct ) /* Handle all directives */ { int ret; /* no expansion on the following */ switch( direct ) { case T_MASM: Options.mode &= ~MODE_IDEAL; return( NOT_ERROR ); case T_IDEAL: Options.mode |= MODE_IDEAL; return( NOT_ERROR ); case T_DOT_286C: direct = T_DOT_286; case T_DOT_8086: case T_DOT_186: case T_DOT_286: case T_DOT_286P: case T_DOT_386: case T_DOT_386P: case T_DOT_486: case T_DOT_486P: case T_DOT_586: case T_DOT_586P: case T_DOT_686: case T_DOT_686P: case T_DOT_8087: case T_DOT_287: case T_DOT_387: case T_DOT_NO87: case T_DOT_K3D: case T_DOT_MMX: case T_DOT_XMM: case T_DOT_XMM2: case T_DOT_XMM3: if( Options.mode & MODE_IDEAL ) { AsmError( UNKNOWN_DIRECTIVE ); return( ERROR ); } else { ret = cpu_directive(direct); if( Parse_Pass != PASS_1 ) ret = NOT_ERROR; return( ret ); } case T_P286N: direct = T_P286; case T_P8086: case T_P186: case T_P286: case T_P286P: case T_P386: case T_P386P: case T_P486: case T_P486P: case T_P586: case T_P586P: case T_P686: case T_P686P: case T_P8087: case T_P287: case T_P387: case T_PK3D: case T_PMMX: case T_PXMM: case T_PXMM2: case T_PXMM3: ret = cpu_directive(direct); if( Parse_Pass != PASS_1 ) ret = NOT_ERROR; return( ret ); case T_DOT_DOSSEG: if( Options.mode & MODE_IDEAL ) { AsmError( UNKNOWN_DIRECTIVE ); return( ERROR ); } case T_DOSSEG: Globals.dosseg = TRUE; return( NOT_ERROR ); case T_PUBLIC: /* special case - expanded inside iff it is an EQU to a symbol */ return( Parse_Pass == PASS_1 ? PubDef(i+1) : NOT_ERROR ); case T_ELSE: case T_ELSEIF: case T_ELSEIF1: case T_ELSEIF2: case T_ELSEIFB: case T_ELSEIFDEF: case T_ELSEIFE: case T_ELSEIFNB: case T_ELSEIFNDEF: case T_ELSEIFDIF: case T_ELSEIFDIFI: case T_ELSEIFIDN: case T_ELSEIFIDNI: case T_ENDIF: case T_IF: case T_IF1: case T_IF2: case T_IFB: case T_IFDEF: case T_IFE: case T_IFNB: case T_IFNDEF: case T_IFDIF: case T_IFDIFI: case T_IFIDN: case T_IFIDNI: return( conditional_assembly_directive( i ) ); case T_DOT_ERR: case T_DOT_ERRB: case T_DOT_ERRDEF: case T_DOT_ERRDIF: case T_DOT_ERRDIFI: case T_DOT_ERRE: case T_DOT_ERRIDN: case T_DOT_ERRIDNI: case T_DOT_ERRNB: case T_DOT_ERRNDEF: case T_DOT_ERRNZ: if( Options.mode & MODE_IDEAL ) { AsmError( UNKNOWN_DIRECTIVE ); return( ERROR ); } case T_ERR: case T_ERRIFB: case T_ERRIFDEF: case T_ERRIFDIF: case T_ERRIFDIFI: case T_ERRIFE: case T_ERRIFIDN: case T_ERRIFIDNI: case T_ERRIFNDEF: return( conditional_error_directive( i ) ); case T_ENDS: if( Definition.struct_depth != 0 ) return( StructDef( i ) ); // else fall through to T_SEGMENT case T_SEGMENT: return( Parse_Pass == PASS_1 ? SegDef(i) : SetCurrSeg(i) ); case T_GROUP: return( Parse_Pass == PASS_1 ? GrpDef(i) : NOT_ERROR ); case T_PROC: return( ProcDef( i, TRUE ) ); case T_ENDP: return( ProcEnd(i) ); case T_ENUM: return( EnumDef( i ) ); case T_DOT_CODE: case T_DOT_STACK: case T_DOT_DATA: case T_DOT_DATA_UN: case T_DOT_FARDATA: case T_DOT_FARDATA_UN: case T_DOT_CONST: if( Options.mode & MODE_IDEAL ) { AsmError( UNKNOWN_DIRECTIVE ); return( ERROR ); } case T_CODESEG: case T_STACK: case T_DATASEG: case T_UDATASEG: case T_FARDATA: case T_UFARDATA: case T_CONST: return( SimSeg(i) ); case T_WARN: case T_NOWARN: return( NOT_ERROR ); /* Not implemented yet */ case T_DOT_ALPHA: case T_DOT_SEQ: case T_DOT_LIST: case T_DOT_LISTALL: case T_DOT_LISTIF: case T_DOT_LISTMACRO: case T_DOT_LISTMACROALL: case T_DOT_NOLIST: case T_DOT_XLIST: case T_DOT_TFCOND: case T_DOT_SFCOND: case T_DOT_LFCOND: case T_DOT_CREF: case T_DOT_XCREF: case T_DOT_NOCREF: case T_DOT_SALL: case T_PAGE: case T_TITLE: case T_SUBTITLE: case T_SUBTTL: if( Options.mode & MODE_IDEAL ) { AsmError( UNKNOWN_DIRECTIVE ); return( ERROR ); } AsmWarn( 4, IGNORING_DIRECTIVE ); return( NOT_ERROR ); case T_DOT_BREAK: case T_DOT_CONTINUE: case T_DOT_ELSE: case T_DOT_ENDIF: case T_DOT_ENDW: case T_DOT_IF: case T_DOT_RADIX: case T_DOT_REPEAT: case T_DOT_UNTIL: case T_DOT_WHILE: if( Options.mode & MODE_IDEAL ) { AsmError( UNKNOWN_DIRECTIVE ); return( ERROR ); } case T_ECHO: case T_HIGH: case T_HIGHWORD: case T_LOW: case T_LOWWORD: case T_ADDR: case T_BOUND: case T_CASEMAP: case T_INVOKE: case T_LROFFSET: case T_OPATTR: case T_OPTION: case T_POPCONTEXT: case T_PUSHCONTEXT: case T_PROTO: case T_THIS: case T_WIDTH: if( Options.mode & MODE_IDEAL ) { AsmError( UNKNOWN_DIRECTIVE ); return( ERROR ); } case T_CATSTR: case T_MASK: case T_PURGE: case T_RECORD: case T_TYPEDEF: case T_UNION: AsmError( NOT_SUPPORTED ); return( ERROR ); case T_ORG: ExpandTheWorld( 0, FALSE, TRUE ); break; case T_TEXTEQU: /* TEXTEQU */ if( Options.mode & MODE_IDEAL ) { AsmError( UNKNOWN_DIRECTIVE ); return( ERROR ); } case T_EQU2: /* = */ case T_EQU: /* EQU */ /* expand any constants and simplify any expressions */ ExpandTheConstant( 0, FALSE, TRUE ); break; case T_NAME: /* no expand parameters */ break; case T_DOT_STARTUP: case T_DOT_EXIT: if( Options.mode & MODE_IDEAL ) { AsmError( UNKNOWN_DIRECTIVE ); return( ERROR ); } case T_STARTUPCODE: case T_EXITCODE: default: /* expand any constants in all other directives */ ExpandAllConsts( 0, FALSE ); break; } switch( direct ) { case T_ALIAS: if( Parse_Pass == PASS_1 ) return( AddAlias( i ) ); return( NOT_ERROR ); case T_EXTERN: if( Options.mode & MODE_IDEAL ) { break; } case T_EXTRN: return( Parse_Pass == PASS_1 ? ExtDef( i+1, FALSE ) : NOT_ERROR ); case T_COMM: return( Parse_Pass == PASS_1 ? CommDef(i+1) : NOT_ERROR ); case T_EXTERNDEF: if( Options.mode & MODE_IDEAL ) { break; } case T_GLOBAL: return( Parse_Pass == PASS_1 ? ExtDef( i+1, TRUE ) : NOT_ERROR ); case T_DOT_MODEL: if( Options.mode & MODE_IDEAL ) { break; } case T_MODEL: return( Model(i) ); case T_INCLUDE: return( Include(i+1) ); case T_INCLUDELIB: return( Parse_Pass == PASS_1 ? IncludeLib(i+1) : NOT_ERROR ); case T_ASSUME: return( SetAssume(i) ); case T_END: return( ModuleEnd(Token_Count) ); case T_EQU: return( DefineConstant( i-1, FALSE, FALSE ) ); case T_EQU2: return( DefineConstant( i-1, TRUE, FALSE ) ); case T_TEXTEQU: return( DefineConstant( i-1, TRUE, TRUE ) ); case T_MACRO: return( MacroDef(i, FALSE ) ); case T_ENDM: return( MacroEnd( FALSE ) ); case T_EXITM: return( MacroEnd( TRUE ) ); case T_ARG: return( Parse_Pass == PASS_1 ? ArgDef(i) : NOT_ERROR ); case T_USES: return( Parse_Pass == PASS_1 ? UsesDef(i) : NOT_ERROR ); case T_LOCAL: return( Parse_Pass == PASS_1 ? LocalDef(i) : NOT_ERROR ); case T_COMMENT: if( Options.mode & MODE_IDEAL ) break; return( Comment( START_COMMENT, i ) ); case T_STRUCT: if( Options.mode & MODE_IDEAL ) { break; } case T_STRUC: return( StructDef( i ) ); case T_NAME: return( Parse_Pass == PASS_1 ? NameDirective(i) : NOT_ERROR ); case T_LABEL: return( LabelDirective( i ) ); case T_ORG: return( OrgDirective( i ) ); case T_ALIGN: case T_EVEN: return( AlignDirective( direct, i ) ); case T_FOR: if( Options.mode & MODE_IDEAL ) { break; } case T_IRP: return( ForDirective ( i+1, IRP_WORD ) ); case T_FORC: if( Options.mode & MODE_IDEAL ) { break; } case T_IRPC: return( ForDirective ( i+1, IRP_CHAR ) ); case T_REPEAT: if( Options.mode & MODE_IDEAL ) { break; } case T_REPT: return( ForDirective ( i+1, IRP_REPEAT ) ); case T_DOT_STARTUP: case T_DOT_EXIT: case T_STARTUPCODE: case T_EXITCODE: return( Startup ( i ) ); case T_LOCALS: case T_NOLOCALS: return( Locals( i ) ); } AsmError( UNKNOWN_DIRECTIVE ); return( ERROR ); }
ret_code SegmentDir( int i, struct asm_tok tokenarray[] ) /*******************************************************/ { char is_old; char *token; int typeidx; const struct typeinfo *type; /* type of option */ int temp; int temp2; uint initstate = 0; /* flags for attribute initialization */ unsigned char oldreadonly; /* readonly value of a defined segment */ //unsigned char oldsegtype; unsigned char oldOfssize; char oldalign; char oldcombine; uint oldclassidx; uint_8 oldcharacteristics; struct dsym *dir; char *name; struct asym *sym; struct expr opndx; if ( Parse_Pass != PASS_1 ) return( SetCurrSeg( i, tokenarray ) ); if( i != 1 ) { EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ); return( ERROR ); } name = tokenarray[0].string_ptr; DebugMsg1(("SegmentDir(%s) enter: ModuleInfo.Ofssize=%u, num_seg=%u\n", name, ModuleInfo.Ofssize, ModuleInfo.g.num_segs )); /* See if the segment is already defined */ sym = SymSearch( name ); if( sym == NULL || sym->state == SYM_UNDEFINED ) { /* segment is not defined (yet) */ sym = (struct asym *)CreateSegment( (struct dsym *)sym, name, TRUE ); sym->list = TRUE; /* always list segments */ dir = (struct dsym *)sym; dir->e.seginfo->seg_idx = ++ModuleInfo.g.num_segs; is_old = FALSE; /* * initialize segment with values from the one without suffix */ #if COFF_SUPPORT || ELF_SUPPORT if (Options.output_format == OFORMAT_COFF #if ELF_SUPPORT || Options.output_format == OFORMAT_ELF #endif ) { char *p; if ( p = strchr(sym->name, '$') ) { char buffer[MAX_ID_LEN+1]; struct dsym *dir2; memcpy(buffer, sym->name, p - sym->name); buffer[p - sym->name] = NULLC; if ((dir2 = (struct dsym *)SymSearch(buffer)) && dir2->sym.state == SYM_SEG) { dir->e.seginfo->readonly = dir2->e.seginfo->readonly; dir->e.seginfo->segtype = dir2->e.seginfo->segtype; dir->e.seginfo->Ofssize = dir2->e.seginfo->Ofssize; dir->e.seginfo->alignment= dir2->e.seginfo->alignment; dir->e.seginfo->characteristics = dir2->e.seginfo->characteristics; dir->e.seginfo->combine = dir2->e.seginfo->combine; dir->e.seginfo->class_name_idx = dir2->e.seginfo->class_name_idx; } } } #endif } else if ( sym->state == SYM_SEG ) { /* segment already defined */ dir = (struct dsym *)sym; is_old = TRUE; oldreadonly = dir->e.seginfo->readonly; //oldsegtype = dir->e.seginfo->segtype; oldOfssize = dir->e.seginfo->Ofssize; oldalign = dir->e.seginfo->alignment; oldcharacteristics = dir->e.seginfo->characteristics; oldcombine = dir->e.seginfo->combine; oldclassidx = dir->e.seginfo->class_name_idx; if( dir->e.seginfo->lname_idx == 0 ) { /* segment was mentioned in a group statement, but not really set up */ is_old = FALSE; /* the segment list is to be sorted. * So unlink the segment and add it at the end. */ UnlinkSeg( dir ); dir->e.seginfo->seg_idx = ++ModuleInfo.g.num_segs; dir->next = NULL; if ( SymTables[TAB_SEG].head == NULL ) SymTables[TAB_SEG].head = SymTables[TAB_SEG].tail = dir; else { SymTables[TAB_SEG].tail->next = dir; SymTables[TAB_SEG].tail = dir; } } } else { /* symbol is different kind, error */ DebugMsg(("SegmentDir(%s): symbol redefinition\n", name )); EmitErr( SYMBOL_REDEFINITION, name ); return( ERROR ); } i++; /* go past SEGMENT */ for( ; i < Token_Count; i++ ) { token = tokenarray[i].string_ptr; DebugMsg1(("SegmentDir(%s): i=%u, string=%s token=%X\n", name, i, token, tokenarray[i].token )); if( tokenarray[i].token == T_STRING ) { /* the class name - the only token which is of type STRING */ /* string must be delimited by [double]quotes */ if ( tokenarray[i].string_delim != '"' && tokenarray[i].string_delim != '\'' ) { EmitErr( SYNTAX_ERROR_EX, token ); continue; } /* remove the quote delimiters */ token++; *(token+tokenarray[i].stringlen) = NULLC; SetSegmentClass( &dir->sym, token ); DebugMsg1(("SegmentDir(%s): class found: %s\n", name, token )); continue; } /* check the rest of segment attributes. */ typeidx = FindToken( token, SegAttrToken, sizeof( SegAttrToken )/sizeof( SegAttrToken[0] ) ); if( typeidx < 0 ) { EmitErr( UNKNOWN_SEGMENT_ATTRIBUTE, token ); continue; } type = &SegAttrValue[typeidx]; /* initstate is used to check if any field is already * initialized */ if( initstate & INIT_EXCL_MASK & type->init ) { EmitErr( SEGMENT_ATTRIBUTE_DEFINED_ALREADY, token ); continue; } else { initstate |= type->init; /* mark it initialized */ } switch ( type->init ) { case INIT_ATTR: dir->e.seginfo->readonly = TRUE; break; case INIT_ALIGN: DebugMsg1(("SegmentDir(%s): align attribute found\n", name )); dir->e.seginfo->alignment = type->value; break; case INIT_ALIGN_PARAM: DebugMsg1(("SegmentDir(%s): ALIGN() found\n", name )); if ( Options.output_format == OFORMAT_OMF ) { EmitErr( NOT_SUPPORTED_WITH_OMF_FORMAT, tokenarray[i].string_ptr ); i = Token_Count; /* stop further parsing of this line */ break; } i++; if ( tokenarray[i].token != T_OP_BRACKET ) { EmitErr( EXPECTED, "(" ); break; } i++; if ( EvalOperand( &i, tokenarray, Token_Count, &opndx, 0 ) == ERROR ) break; if ( tokenarray[i].token != T_CL_BRACKET ) { EmitErr( EXPECTED, ")" ); break; } if ( opndx.kind != EXPR_CONST ) { EmitError( CONSTANT_EXPECTED ); break; } /* COFF allows alignment values 1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192 */ for( temp = 1, temp2 = 0; temp < opndx.value && temp < 8192 ; temp <<= 1, temp2++ ); if( temp != opndx.value ) { EmitError( POWER_OF_2 ); } dir->e.seginfo->alignment = temp2; break; case INIT_COMBINE: DebugMsg1(("SegmentDir(%s): combine attribute found\n", name )); dir->e.seginfo->combine = type->value; break; case INIT_COMBINE_AT: DebugMsg1(("SegmentDir(%s): AT found\n", name )); dir->e.seginfo->combine = type->value; /* v2.05: always use MAX_SEGALIGNMENT */ //dir->e.seginfo->alignment = -1; dir->e.seginfo->alignment = MAX_SEGALIGNMENT; i++; if ( EvalOperand( &i, tokenarray, Token_Count, &opndx, 0 ) != ERROR ) { if ( opndx.kind == EXPR_CONST ) { dir->e.seginfo->abs_frame = opndx.value; dir->e.seginfo->abs_offset = 0; } else { EmitError( CONSTANT_EXPECTED ); } } break; #if COMDATSUPP case INIT_COMBINE_COMDAT: DebugMsg1(("SegmentDir(%s): COMDAT found\n", name )); if ( Options.output_format != OFORMAT_COFF ) { EmitErr( NOT_SUPPORTED_WITH_CURR_FORMAT, tokenarray[i].string_ptr ); i = Token_Count; /* stop further parsing of this line */ break; } i++; if ( tokenarray[i].token != T_OP_BRACKET ) { EmitErr( EXPECTED, "(" ); break; } i++; if ( EvalOperand( &i, tokenarray, Token_Count, &opndx, 0 ) == ERROR ) break; if ( opndx.kind != EXPR_CONST ) { EmitError( CONSTANT_EXPECTED ); i = Token_Count; /* stop further parsing of this line */ break; } if ( opndx.value < 1 || opndx.value > 6 ) { EmitErr( VALUE_NOT_WITHIN_ALLOWED_RANGE, "1-6" ); } else { /* if value is IMAGE_COMDAT_SELECT_ASSOCIATIVE, * get the associated segment name argument. */ if ( opndx.value == 5 ) { struct asym *sym2; if ( tokenarray[i].token != T_COMMA ) { EmitError( EXPECTING_COMMA ); i = Token_Count; /* stop further parsing of this line */ break; } i++; if ( tokenarray[i].token != T_ID ) { EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ); i = Token_Count; /* stop further parsing of this line */ break; } /* associated segment must be COMDAT, but not associative */ sym2 = SymSearch( tokenarray[i].string_ptr ); if ( sym2 == NULL || sym2->state != SYM_SEG || ((struct dsym *)sym2)->e.seginfo->comdat_selection == 0 || ((struct dsym *)sym2)->e.seginfo->comdat_selection == 5 ) EmitErr( INVALID_ASSOCIATED_SEGMENT, tokenarray[i].string_ptr ); else dir->e.seginfo->comdat_number = ((struct dsym *)sym2)->e.seginfo->seg_idx; i++; } } if ( tokenarray[i].token != T_CL_BRACKET ) { EmitErr( EXPECTED, ")" ); break; } dir->e.seginfo->comdat_selection = opndx.value; dir->e.seginfo->combine = type->value; break; #endif case INIT_OFSSIZE: case INIT_OFSSIZE_FLAT: /* v2.07: check for compatible cpu mode */ if ( type->value == USE32 && ( ( ModuleInfo.curr_cpu & P_CPU_MASK ) < P_386 ) #if AMD64_SUPPORT || type->value == USE64 && ( ( ModuleInfo.curr_cpu & P_CPU_MASK ) < P_64 ) #endif ) { EmitError( INSTRUCTION_OR_REGISTER_NOT_ACCEPTED_IN_CURRENT_CPU_MODE ); break; } if ( type->init == INIT_OFSSIZE_FLAT ) { DefineFlatGroup(); #if AMD64_SUPPORT dir->e.seginfo->Ofssize = ModuleInfo.defOfssize; #else dir->e.seginfo->Ofssize = USE32; #endif /* put the segment into the FLAT group. * this is not quite Masm-compatible, because trying to put * the segment into another group will cause an error. */ dir->e.seginfo->group = &ModuleInfo.flat_grp->sym; } else dir->e.seginfo->Ofssize = type->value; break; #if COFF_SUPPORT || ELF_SUPPORT case INIT_CHAR_INFO: dir->e.seginfo->info = TRUE; break; case INIT_CHAR: DebugMsg1(("SegmentDir(%s): characteristics found\n", name )); ; /* characteristics are restricted to COFF/ELF */ if ( Options.output_format == OFORMAT_OMF || Options.output_format == OFORMAT_BIN ) { EmitErr( NOT_SUPPORTED_WITH_CURR_FORMAT, tokenarray[i].string_ptr ); } else dir->e.seginfo->characteristics |= type->value; break; case INIT_ALIAS: DebugMsg1(("SegmentDir(%s): ALIAS found\n", name )); if ( Options.output_format != OFORMAT_COFF && Options.output_format != OFORMAT_ELF ) { EmitErr( NOT_SUPPORTED_WITH_CURR_FORMAT, tokenarray[i].string_ptr ); i = Token_Count; /* stop further parsing of this line */ break; } i++; if ( tokenarray[i].token != T_OP_BRACKET ) { EmitErr( EXPECTED, "(" ); break; } i++; if ( tokenarray[i].token != T_STRING || ( tokenarray[i].string_delim != '"' && tokenarray[i].string_delim != '\'' ) ) { EmitErr( SYNTAX_ERROR_EX, token ); i = Token_Count; /* stop further parsing of this line */ break; } temp = i; i++; if ( tokenarray[i].token != T_CL_BRACKET ) { EmitErr( EXPECTED, ")" ); break; } dir->e.seginfo->aliasname = LclAlloc( tokenarray[temp].stringlen ); memcpy( dir->e.seginfo->aliasname, tokenarray[temp].string_ptr+1, tokenarray[temp].stringlen ); *(dir->e.seginfo->aliasname+tokenarray[temp].stringlen) = NULLC; break; #endif #ifdef DEBUG_OUT default: /* shouldn't happen */ myassert( 0 ); break; #endif } } /* end for */ /* make a guess about the segment's type */ if( dir->e.seginfo->segtype != SEGTYPE_CODE ) { enum seg_type res; token = GetLname( dir->e.seginfo->class_name_idx ); res = TypeFromClassName( dir, token ); if( res != SEGTYPE_UNDEF ) { dir->e.seginfo->segtype = res; } #if 0 /* v2.03: removed */ else { res = TypeFromSegmentName( name ); dir->e.seginfo->segtype = res; } #endif } if( is_old ) { int txt = 0; /* Check if new definition is different from previous one */ // oldobj = dir->e.seginfo->segrec; if( oldreadonly != dir->e.seginfo->readonly ) txt = TXT_READONLY; else if ( oldalign != dir->e.seginfo->alignment ) txt = TXT_ALIGNMENT; else if ( oldcombine != dir->e.seginfo->combine ) txt = TXT_COMBINE; else if ( oldOfssize != dir->e.seginfo->Ofssize ) txt = TXT_SEG_WORD_SIZE; else if ( oldclassidx != dir->e.seginfo->class_name_idx ) txt = TXT_CLASS; /* Masm warns only! */ else if ( oldcharacteristics != dir->e.seginfo->characteristics ) txt = TXT_CHARACTERISTICS; if ( txt ) { EmitErr( SEGDEF_CHANGED, dir->sym.name, MsgGetEx( txt ) ); //return( ERROR ); /* v2: display error, but continue */ } } else { /* A new definition */ sym = &dir->sym; sym->isdefined = TRUE; sym->segment = sym; sym->offset = 0; if( dir->e.seginfo->lname_idx == 0 ) { dir->e.seginfo->lname_idx = ++LnamesIdx; AddLnameData( sym ); } } push_seg( dir ); /* set CurrSeg */ if ( ModuleInfo.list ) LstWrite( LSTTYPE_LABEL, 0, NULL ); return( SetOfssize() ); }