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; }
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() ); }