/**************************************************************************** * * Open Watcom Project * * Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved. * * ======================================================================== * * This file contains Original Code and/or Modifications of Original * Code as defined in and that are subject to the Sybase Open Watcom * Public License version 1.0 (the 'License'). You may not use this file * except in compliance with the License. BY USING THIS FILE YOU AGREE TO * ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is * provided with the Original Code and Modifications, and is also * available at www.sybase.com/developer/opensource. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR * NON-INFRINGEMENT. Please see the License for the specific language * governing rights and limitations under the License. * * ======================================================================== * * Description: Processing of segment and group related directives: * - SEGMENT, ENDS, GROUP ****************************************************************************/ #include #include "globals.h" #include "memalloc.h" #include "parser.h" #include "reswords.h" #include "segment.h" #include "expreval.h" #include "omf.h" #include "omfspec.h" #include "fastpass.h" #include "coffspec.h" #include "assume.h" #include "listing.h" #include "msgtext.h" #include "types.h" #include "fixup.h" #include "myassert.h" extern ret_code EndstructDirective( int, struct asm_tok tokenarray[] ); //struct asym symPC = { NULL,"$", 0 }; /* the '$' symbol */ struct asym *symCurSeg; /* @CurSeg symbol */ #define INIT_ATTR 0x01 /* READONLY attribute */ #define INIT_ALIGN 0x02 /* BYTE, WORD, PARA, DWORD, ... */ #define INIT_ALIGN_PARAM (0x80 | INIT_ALIGN) /* ALIGN(x) */ #define INIT_COMBINE 0x04 /* PRIVATE, PUBLIC, STACK, COMMON */ #define INIT_COMBINE_AT (0x80 | INIT_COMBINE) /* AT */ #if COMDATSUPP #define INIT_COMBINE_COMDAT (0xC0 | INIT_COMBINE) /* COMDAT */ #endif #define INIT_OFSSIZE 0x08 /* USE16, USE32, ... */ #define INIT_OFSSIZE_FLAT (0x80 | INIT_OFSSIZE) /* FLAT */ #define INIT_ALIAS 0x10 /* ALIAS(x) */ #define INIT_CHAR 0x20 /* DISCARD, SHARED, EXECUTE, ... */ #define INIT_CHAR_INFO (0x80 | INIT_CHAR) /* INFO */ #define INIT_EXCL_MASK 0x1F /* exclusive bits */ struct typeinfo { uint_8 value; /* value assigned to the token */ uint_8 init; /* kind of token */ }; static const char * const SegAttrToken[] = { #define sitem( text, value, init ) text, #include "segattr.h" #undef sitem }; static const struct typeinfo SegAttrValue[] = { #define sitem( text, value, init ) { value, init }, #include "segattr.h" #undef sitem }; static unsigned grpdefidx; /* Number of group definitions */ /* v2.12: obsolete, lnames are OMF only */ //static unsigned LnamesIdx; /* Number of LNAMES definitions */ static struct dsym *SegStack[MAX_SEG_NESTING]; /* stack of open segments */ static int stkindex; /* current top of stack */ #if FASTPASS /* saved state */ static struct dsym *saved_CurrSeg; static struct dsym **saved_SegStack; static int saved_stkindex; #endif /* generic byte buffer, used for OMF LEDATA records only */ static uint_8 codebuf[ 1024 ]; static uint_32 buffer_size; /* total size of code buffer */ /* min cpu for USE16, USE32 and USE64 */ static const uint_16 min_cpu[] = { P_86, P_386, #if AMD64_SUPPORT P_64 #endif }; /* find token in a string table */ static int FindToken( const char *token, const char * const *table, int size ) /****************************************************************************/ { int i; for( i = 0; i < size; i++, table++ ) { if( _stricmp( *table, token ) == 0 ) { return( i ); } } return( -1 ); /* Not found */ } /* set value of $ symbol */ void UpdateCurPC( struct asym *sym, void *p ) /*******************************************/ { if( CurrStruct ) { //symPC.segment = NULL; //symPC.mem_type = MT_ABS; sym->mem_type = MT_EMPTY; sym->segment = NULL; /* v2.07: needed again */ sym->offset = CurrStruct->sym.offset + (CurrStruct->next ? CurrStruct->next->sym.offset : 0); } else if ( CurrSeg ) { /* v2.10: check for CurrSeg != NULL */ sym->mem_type = MT_NEAR; sym->segment = (struct asym *)CurrSeg; sym->offset = GetCurrOffset(); } else EmitErr( MUST_BE_IN_SEGMENT_BLOCK ); /* v2.10: added */ DebugMsg1(("UpdateCurPC: curr value=%" I32_SPEC "Xh\n", sym->offset )); } #if 0 /* value of text macros can't be set by internal function call yet! */ void SetCurSeg( struct asym *sym ) /********************************/ { symCurSeg->string_ptr = CurrSeg ? CurrSeg->sym.name : ""; DebugMsg1(("SetCurSeg: curr value=>%s<\n", symCurSeg->string_ptr )); } #endif #if 0 /* v2.09: obsolete */ /* find a class name. * those names aren't in the symbol table! */ char *GetLname( int idx ) /***********************/ { struct qnode *node; struct asym *sym; for( node = ModuleInfo.g.LnameQueue.head; node != NULL; node = node->next ) { sym = node->sym; if( sym->state == SYM_CLASS_LNAME && sym->class_lname_idx == idx ) { return( sym->name ); } } return( "" ); } #endif static void AddLnameItem( struct asym *sym ) /******************************************/ { QAddItem( &ModuleInfo.g.LnameQueue, sym ); //return( ++LnamesIdx ); return; } /* what's inserted into the LNAMES queue: * SYM_SEG: segment names * SYM_GRP: group names * SYM_CLASS_LNAME : class names */ static void FreeLnameQueue( void ) /********************************/ { struct qnode *curr; struct qnode *next; DebugMsg(("FreeLnameQueue enter\n" )); for( curr = ModuleInfo.g.LnameQueue.head; curr; curr = next ) { next = curr->next; /* the class name symbols are not part of the * symbol table and hence must be freed now. */ if( curr->sym->state == SYM_CLASS_LNAME ) { SymFree( curr->sym ); } LclFree( curr ); } DebugMsg(("FreeLnameQueue exit\n" )); } /* set CS assume entry whenever current segment is changed. * Also updates values of text macro @CurSeg. */ static void UpdateCurrSegVars( void ) /***********************************/ { struct assume_info *info; DebugMsg1(("UpdateCurrSegVars(%s)\n", CurrSeg ? CurrSeg->sym.name : "NULL" )); info = &(SegAssumeTable[ ASSUME_CS ]); if( CurrSeg == NULL ) { info->symbol = NULL; info->is_flat = FALSE; info->error = TRUE; symCurSeg->string_ptr = ""; //symPC.segment = NULL; /* v2.05: removed */ } else { info->is_flat = FALSE; info->error = FALSE; /* fixme: OPTION OFFSET:SEGMENT? */ if( CurrSeg->e.seginfo->group != NULL ) { info->symbol = CurrSeg->e.seginfo->group; if ( info->symbol == &ModuleInfo.flat_grp->sym ) info->is_flat = TRUE; } else { info->symbol = &CurrSeg->sym; } symCurSeg->string_ptr = CurrSeg->sym.name; //symPC.segment = &CurrSeg->sym; /* v2.05: removed */ } return; } static void push_seg( struct dsym *seg ) /**************************************/ /* Push a segment into the current segment stack */ { //pushitem( &CurrSeg, seg ); /* changed in v1.96 */ if ( stkindex >= MAX_SEG_NESTING ) { EmitError( NESTING_LEVEL_TOO_DEEP ); return; } SegStack[stkindex] = CurrSeg; stkindex++; CurrSeg = seg; UpdateCurrSegVars(); return; } static void pop_seg( void ) /*************************/ /* Pop a segment out of the current segment stack */ { //seg = popitem( &CurrSeg ); /* changed in v1.96 */ /* it's already checked that CurrSeg is != NULL, so * stkindex must be > 0, but anyway ... */ if ( stkindex ) { stkindex--; CurrSeg = SegStack[stkindex]; UpdateCurrSegVars(); } return; } uint_32 GetCurrOffset( void ) /***************************/ { return( CurrSeg ? CurrSeg->e.seginfo->current_loc : 0 ); } #if 0 struct dsym *GetCurrSeg( void ) /*****************************/ { return( CurrSeg ); } #endif #if 0 int GetCurrClass( void ) /***********************/ { if( CurrSeg == NULL ) return( 0 ); return( CurrSeg->e.seginfo->segrec->d.segdef.class_name_idx ); } #endif uint_32 GetCurrSegAlign( void ) /*****************************/ { if( CurrSeg == NULL ) return( 0 ); if ( CurrSeg->e.seginfo->alignment == MAX_SEGALIGNMENT ) /* ABS? */ return( 0x10 ); /* assume PARA alignment for AT segments */ return( 1 << CurrSeg->e.seginfo->alignment ); } 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 = */ AddLnameItem( &grp->sym ); } else if( grp->sym.state != SYM_GRP ) { EmitErr( SYMBOL_REDEFINITION, name ); return( NULL ); } grp->sym.isdefined = TRUE; return( grp ); } static struct dsym *CreateSegment( struct dsym *seg, const char *name, bool add_global ) /**************************************************************************************/ { if ( seg == NULL ) seg = ( add_global ? (struct dsym *)SymCreate( name ) : (struct dsym *)SymAlloc( name ) ); else if ( seg->sym.state == SYM_UNDEFINED ) sym_remove_table( &SymTables[TAB_UNDEF], seg ); if ( seg ) { seg->sym.state = SYM_SEG; seg->e.seginfo = LclAlloc( sizeof( struct seg_info ) ); memset( seg->e.seginfo, 0, sizeof( struct seg_info ) ); seg->e.seginfo->Ofssize = ModuleInfo.defOfssize; seg->e.seginfo->alignment = 4; /* this is PARA (2^4) */ seg->e.seginfo->combine = COMB_INVALID; /* null class name, in case none is mentioned */ //seg->e.seginfo->clsym = NULL; seg->next = NULL; /* don't use sym_add_table(). Thus the "prev" member * becomes free for another use. */ if ( SymTables[TAB_SEG].head == NULL ) SymTables[TAB_SEG].head = SymTables[TAB_SEG].tail = seg; else { SymTables[TAB_SEG].tail->next = seg; SymTables[TAB_SEG].tail = seg; } } return( seg ); } void DeleteGroup( struct dsym *dir ) /**********************************/ { #if FASTMEM==0 || defined(DEBUG_OUT) struct seg_item *curr; struct seg_item *next; for( curr = dir->e.grpinfo->seglist; curr; curr = next ) { next = curr->next; DebugMsg(("DeleteGroup(%s): free seg_item=%p\n", dir->sym.name, curr )); LclFree( curr ); } #endif DebugMsg(("DeleteGroup(%s): extension %p will be freed\n", dir->sym.name, dir->e.grpinfo )); LclFree( dir->e.grpinfo ); return; } /* handle GROUP directive */ ret_code GrpDir( int i, struct asm_tok tokenarray[] ) /***************************************************/ { char *name; struct dsym *grp; struct dsym *seg; /* GROUP directive must be at pos 1, needs a name at pos 0 */ if( i != 1 ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } /* GROUP isn't valid for COFF/ELF/BIN-PE */ #if COFF_SUPPORT || ELF_SUPPORT || PE_SUPPORT if ( Options.output_format == OFORMAT_COFF #if ELF_SUPPORT || Options.output_format == OFORMAT_ELF #endif #if PE_SUPPORT || ( Options.output_format == OFORMAT_BIN && ModuleInfo.sub_format == SFORMAT_PE ) #endif ) { return( EmitErr( NOT_SUPPORTED_WITH_CURR_FORMAT, _strupr( tokenarray[i].string_ptr ) ) ); } #endif grp = CreateGroup( tokenarray[0].string_ptr ); if( grp == NULL ) return( ERROR ); i++; /* go past GROUP */ do { /* get segment name */ if ( tokenarray[i].token != T_ID ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } name = tokenarray[i].string_ptr; i++; seg = (struct dsym *)SymSearch( name ); if ( Parse_Pass == PASS_1 ) { if( seg == NULL || seg->sym.state == SYM_UNDEFINED ) { seg = CreateSegment( seg, name, TRUE ); /* inherit the offset magnitude from the group */ if ( grp->e.grpinfo->seglist ) seg->e.seginfo->Ofssize = grp->sym.Ofssize; } else if( seg->sym.state != SYM_SEG ) { return( EmitErr( SEGMENT_EXPECTED, name ) ); } else if( seg->e.seginfo->group != NULL && /* v2.09: allow segments in FLAT magic group be moved to a "real" group */ seg->e.seginfo->group != &ModuleInfo.flat_grp->sym && seg->e.seginfo->group != &grp->sym ) { /* segment is in another group */ DebugMsg(("GrpDir: segment >%s< is in group >%s< already\n", name, seg->e.seginfo->group->name)); return( EmitErr( SEGMENT_IN_ANOTHER_GROUP, name ) ); } /* the first segment will define the group's word size */ if( grp->e.grpinfo->seglist == NULL ) { grp->sym.Ofssize = seg->e.seginfo->Ofssize; } else if ( grp->sym.Ofssize != seg->e.seginfo->Ofssize ) { return( EmitErr( GROUP_SEGMENT_SIZE_CONFLICT, grp->sym.name, seg->sym.name ) ); } } else { /* v2.04: don't check the "defined" flag in passes > 1. It's for IFDEF only! */ //if( seg == NULL || seg->sym.state != SYM_SEG || seg->sym.defined == FALSE ) { /* v2.07: check the "segment" field instead of "defined" flag! */ //if( seg == NULL || seg->sym.state != SYM_SEG ) { if( seg == NULL || seg->sym.state != SYM_SEG || seg->sym.segment == NULL ) { return( EmitErr( SEGMENT_NOT_DEFINED, name ) ); } } /* insert segment in group if it's not there already */ if ( seg->e.seginfo->group == NULL ) { struct seg_item *si; /* set the segment's grp */ seg->e.seginfo->group = &grp->sym; si = LclAlloc( sizeof( struct seg_item ) ); si->seg = seg; si->next = NULL; grp->e.grpinfo->numseg++; /* insert the segment at the end of linked list */ if( grp->e.grpinfo->seglist == NULL ) { grp->e.grpinfo->seglist = si; } else { struct seg_item *curr; curr = grp->e.grpinfo->seglist; while( curr->next != NULL ) { curr = curr->next; } curr->next = si; } } if ( i < Token_Count ) { if ( tokenarray[i].token != T_COMMA || tokenarray[i+1].token == T_FINAL ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].tokpos ) ); } i++; } } while ( i < Token_Count ); return( NOT_ERROR ); } /* get/set value of predefined symbol @WordSize */ void UpdateWordSize( struct asym *sym, void *p ) /**********************************************/ { sym->value = CurrWordSize; return; } /* called by SEGMENT and ENDS directives */ ret_code SetOfssize( void ) /*************************/ { if( CurrSeg == NULL ) { ModuleInfo.Ofssize = ModuleInfo.defOfssize; } else { ModuleInfo.Ofssize = CurrSeg->e.seginfo->Ofssize; if( (uint_8)ModuleInfo.curr_cpu < min_cpu[ModuleInfo.Ofssize] ) { DebugMsg(("SetOfssize, error: CurrSeg=%s, ModuleInfo.Ofssize=%u, curr_cpu=%X, defOfssize=%u\n", CurrSeg->sym.name, ModuleInfo.Ofssize, ModuleInfo.curr_cpu, ModuleInfo.defOfssize )); return( EmitErr( INCOMPATIBLE_CPU_MODE_FOR_XXBIT_SEGMENT, 16 << ModuleInfo.Ofssize ) ); } } DebugMsg1(("SetOfssize: ModuleInfo.Ofssize=%u\n", ModuleInfo.Ofssize )); CurrWordSize = (2 << ModuleInfo.Ofssize); #if AMD64_SUPPORT Set64Bit( ModuleInfo.Ofssize == USE64 ); #endif return( NOT_ERROR ); } /* close segment */ 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)" )); return( EmitErr( BLOCK_NESTING_ERROR, name ) ); } DebugMsg1(("CloseSeg(%s): current ofs=%" I32_SPEC "X\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 ); } void DefineFlatGroup( void ) /**************************/ { if( ModuleInfo.flat_grp == NULL ) { /* can't fail because is a reserved word */ ModuleInfo.flat_grp = CreateGroup( "FLAT" ); ModuleInfo.flat_grp->sym.Ofssize = ModuleInfo.defOfssize; DebugMsg1(("DefineFlatGroup(): Ofssize=%u\n", ModuleInfo.flat_grp->sym.Ofssize )); } ModuleInfo.flat_grp->sym.isdefined = TRUE; /* v2.09 */ } unsigned GetSegIdx( const struct asym *sym ) /******************************************/ /* get idx to sym's segment */ { if( sym ) return( ((struct dsym *)sym)->e.seginfo->seg_idx ); return( 0 ); } struct asym *GetGroup( const struct asym *sym ) /*********************************************/ /* get a symbol's group */ { struct dsym *curr; curr = GetSegm( sym ); if( curr != NULL ) return( curr->e.seginfo->group ); return( NULL ); } int GetSymOfssize( const struct asym *sym ) /*****************************************/ /* get sym's offset size (64=2, 32=1, 16=0) */ { struct dsym *curr; /* v2.07: MT_ABS has been removed */ //if ( sym->mem_type == MT_ABS ) // return( USE16 ); curr = GetSegm( sym ); if( curr == NULL ) { /* v2.04: SYM_STACK added */ //if( sym->state == SYM_EXTERNAL || ( sym->state == SYM_INTERNAL && sym->isproc ) || sym->state == SYM_GRP ) if( sym->state == SYM_EXTERNAL ) return( sym->seg_ofssize ); if( sym->state == SYM_STACK || sym->state == SYM_GRP ) return( sym->Ofssize ); if( sym->state == SYM_SEG ) return( ((struct dsym *)sym)->e.seginfo->Ofssize ); /* v2.07: added */ if ( sym->mem_type == MT_EMPTY ) return( USE16 ); } else { return( curr->e.seginfo->Ofssize ); } return( ModuleInfo.Ofssize ); } void SetSymSegOfs( struct asym *sym ) /***********************************/ { sym->segment = &CurrSeg->sym; sym->offset = GetCurrOffset(); } /* get segment type from alignment, combine type or class name */ enum seg_type TypeFromClassName( const struct dsym *seg, const struct asym *clname ) /**********************************************************************************/ { int slen; char uname[MAX_ID_LEN+1]; if ( seg->e.seginfo->alignment == MAX_SEGALIGNMENT ) return( SEGTYPE_ABS ); /* v2.03: added */ if ( seg->e.seginfo->combine == COMB_STACK ) return( SEGTYPE_STACK ); if( clname == NULL ) return( SEGTYPE_UNDEF ); if( _stricmp( clname->name, GetCodeClass() ) == 0 ) return( SEGTYPE_CODE ); slen = clname->name_size; memcpy( uname, clname->name, clname->name_size + 1 ); _strupr( uname ); switch( slen ) { default: case 5: if( memcmp( uname, "CONST", 6 ) == 0 ) return( SEGTYPE_DATA ); //if( memcmp( uname, "STACK", 6 ) == 0 ) // return( SEGTYPE_DATA ); if( memcmp( uname, "DBTYP", 6 ) == 0 ) return( SEGTYPE_DATA ); if( memcmp( uname, "DBSYM", 6 ) == 0 ) return( SEGTYPE_DATA ); case 4: /* v2.03: changed */ //if( memcmp( uname , "CODE", 5 ) == 0 ) // return( SEGTYPE_CODE ); if( memcmp( uname + slen - 4, "CODE", 4 ) == 0 ) return( SEGTYPE_CODE ); if( memcmp( uname + slen - 4, "DATA", 4 ) == 0 ) return( SEGTYPE_DATA ); case 3: if( memcmp( uname + slen - 3, "BSS", 3 ) == 0 ) return( SEGTYPE_BSS ); case 2: case 1: case 0: return( SEGTYPE_UNDEF ); } } #if 0 /* v2.03: obsolete */ /* get the type of the segment by checking it's name. * this is called only if the class gives no hint */ static enum seg_type TypeFromSegmentName( const char *name ) /**********************************************************/ { int slen; char uname[MAX_ID_LEN+1]; slen = strlen( name ); strcpy( uname, name ); _strupr( uname ); switch( slen ) { default: case 5: if ( Options.output_format != OFORMAT_COFF ) { /* '..._TEXT'? */ if( memcmp( uname + slen - 5, SegmNamesDef[SIM_CODE], 5 ) == 0 ) return( SEGTYPE_CODE ); } /* '..._DATA' */ if( memcmp( uname + slen - 5, SegmNamesDef[SIM_DATA], 5 ) == 0 ) return( SEGTYPE_DATA ); /* 'CONST' */ if( memcmp( uname + slen - 5, SegmNamesDef[SIM_CONST], 5 ) == 0 ) return( SEGTYPE_DATA ); case 4: if ( Options.output_format != OFORMAT_COFF ) { /* '..._BSS' */ if( memcmp( uname + slen - 4, "_BSS", 4 ) == 0 ) return( SEGTYPE_BSS ); } case 3: case 2: case 1: case 0: return( SEGTYPE_UNDEF ); } } #endif /* search a class item by name. * the classes aren't stored in the symbol table! */ static struct asym *FindClass( const char *name, int len ) /********************************************************/ { struct qnode *node; for( node = ModuleInfo.g.LnameQueue.head; node; node = node->next ) { struct asym *sym = node->sym; /* v2.09: use SymCmpFunc (optionally case-sensitive, depending on OPTION CASEMAP) */ //if( sym->state == SYM_CLASS_LNAME && ( _stricmp( sym->name, name ) == 0 ) ) if( sym->state == SYM_CLASS_LNAME && ( SymCmpFunc( sym->name, name, len ) == 0 ) ) return( sym ); } return( NULL ); } /* add a class name to the lname queue * if it doesn't exist yet. */ static struct asym *CreateClassLname( const char *name ) /******************************************************/ { struct asym *sym; int len = strlen( name ); /* max lname is 255 - this is an OMF restriction */ if( len > MAX_LNAME ) { EmitError( CLASS_NAME_TOO_LONG ); return( NULL ); } if ( !( sym = FindClass( name, len ) ) ) { /* the classes aren't inserted into the symbol table but they are in a queue */ sym = SymAlloc( name ); sym->state = SYM_CLASS_LNAME; /* sym->class_lname_idx = */ AddLnameItem( sym ); /* index needed by OMF only */ } return( sym ); } /* set the segment's class. report an error if the class has been set * already and the new value differs. */ static ret_code SetSegmentClass( struct dsym *seg, const char *name ) /*******************************************************************/ { struct asym *clsym; clsym = CreateClassLname( name ); if( clsym == NULL ) { return( ERROR ); } #if 0 /* v2.09: Masm allows a segment's class name to change */ if ( seg->e.seginfo->clsym == NULL ) seg->e.seginfo->clsym = clsym; else if ( seg->e.seginfo->clsym != clsym ) { return( EmitErr( SEGDEF_CHANGED, seg->sym.name, MsgGetEx( TXT_CLASS ) ) ); } #else seg->e.seginfo->clsym = clsym; #endif return( NOT_ERROR ); } /* CreateIntSegment(), used for internally defined segments: * codeview debugging segments, COFF .drectve, COFF .sxdata */ 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 ) { /* v2.12: check 'isdefined' instead of 'lname_idx' */ //if( seg->e.seginfo->lname_idx == 0 ) { if( seg->sym.isdefined == FALSE ) { seg->e.seginfo->seg_idx = ++ModuleInfo.g.num_segs; /* seg->e.seginfo->lname_idx = */ AddLnameItem( &seg->sym ); seg->sym.isdefined = TRUE; /* v2.12: added */ } seg->e.seginfo->internal = TRUE; /* segment has private buffer */ seg->sym.segment = &seg->sym; seg->e.seginfo->alignment = alignment; seg->e.seginfo->Ofssize = Ofssize; SetSegmentClass( seg, classname ); return( &seg->sym ); } return( NULL ); } /* ENDS directive */ ret_code EndsDir( int i, struct asm_tok tokenarray[] ) /****************************************************/ { if( CurrStruct != NULL ) { return( EndstructDirective( i, tokenarray ) ); } /* a label must precede ENDS */ if( i != 1 ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } 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() ); } /* SEGMENT directive if pass is > 1 */ 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 ) { return( EmitErr( SEGMENT_NOT_DEFINED, tokenarray[0].string_ptr ) ); } /* 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 void UnlinkSeg( struct dsym *dir ) /***************************************/ { struct dsym *curr; struct dsym *prev; for ( curr = SymTables[TAB_SEG].head, prev = NULL; curr; prev = curr, curr = curr->next ) if ( curr == dir ) { /* if segment is first, set a new head */ if ( prev == NULL ) SymTables[TAB_SEG].head = curr->next; else prev->next = curr->next; /* if segment is last, set a new tail */ if ( curr->next == NULL ) SymTables[TAB_SEG].tail = prev; break; } return; } /* SEGMENT directive */ ret_code SegmentDir( int i, struct asm_tok tokenarray[] ) /*******************************************************/ { char is_old = FALSE; char *token; int typeidx; const struct typeinfo *type; /* type of option */ int temp; int temp2; unsigned 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; //struct asym *oldclsym; uint_8 newcharacteristics = 0; struct dsym *dir; char *name; struct asym *sym; struct expr opndx; if ( Parse_Pass != PASS_1 ) return( SetCurrSeg( i, tokenarray ) ); if( i != 1 ) { return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) ); } 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; /* v2.12: seg_idx member now set AFTER parsing is done */ //dir->e.seginfo->seg_idx = ++ModuleInfo.g.num_segs; #if 0 //COFF_SUPPORT || ELF_SUPPORT /* v2.09: removed, since not Masm-compatible */ 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; /* initialize segment with values from the one without suffix */ 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->segtype = dir2->e.seginfo->segtype; dir->e.seginfo->combine = dir2->e.seginfo->combine; dir->e.seginfo->readonly = dir2->e.seginfo->readonly; 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->clsym = dir2->e.seginfo->clsym; } } } #endif } else if ( sym->state == SYM_SEG ) { /* segment already defined? */ dir = (struct dsym *)sym; /* v2.12: check 'isdefined' instead of lname_idx */ //if( dir->e.seginfo->lname_idx == 0 ) { if( sym->isdefined == FALSE ) { /* segment was forward referenced (in a GROUP directive), but not really set up */ /* the segment list is to be sorted. * So unlink the segment and add it at the end. */ UnlinkSeg( dir ); /* v2.12: seg_idx member now set AFTER parsing is done */ //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 { is_old = TRUE; //oldreadonly = dir->e.seginfo->readonly; //oldsegtype = dir->e.seginfo->segtype; oldOfssize = dir->e.seginfo->Ofssize; oldalign = dir->e.seginfo->alignment; oldcombine = dir->e.seginfo->combine; /* v2.09: class isn't checked anymore, and characteristics is handled differently */ //oldcharacteristics = dir->e.seginfo->characteristics; //oldclsym = dir->e.seginfo->clsym; } } else { /* symbol is different kind, error */ DebugMsg(("SegmentDir(%s): symbol redefinition\n", name )); return( EmitErr( SYMBOL_REDEFINITION, name ) ); } 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, 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 ) { EmitErr( POWER_OF_2, opndx.value ); } 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 )); /* v2.12: COMDAT supported by OMF */ //if ( Options.output_format != OFORMAT_COFF ) { if ( Options.output_format != OFORMAT_COFF && Options.output_format != OFORMAT_OMF ) { 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 ) { EmitErr( EXPECTING_COMMA, tokenarray[i].tokpos ); 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: if ( type->init == INIT_OFSSIZE_FLAT ) { DefineFlatGroup(); #if AMD64_SUPPORT /* v2.09: make sure ofssize is at least USE32 for FLAT */ dir->e.seginfo->Ofssize = ( ModuleInfo.defOfssize > USE16 ? ModuleInfo.defOfssize : USE32 ); #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 || PE_SUPPORT case INIT_CHAR_INFO: dir->e.seginfo->info = TRUE; /* fixme: check that this flag isn't changed */ break; case INIT_CHAR: DebugMsg1(("SegmentDir(%s): characteristics found\n", name )); /* characteristics are restricted to COFF/ELF/BIN-PE */ if ( Options.output_format == OFORMAT_OMF #if PE_SUPPORT || ( Options.output_format == OFORMAT_BIN && ModuleInfo.sub_format != SFORMAT_PE ) #endif ) { EmitErr( NOT_SUPPORTED_WITH_CURR_FORMAT, tokenarray[i].string_ptr ); } else newcharacteristics |= type->value; break; case INIT_ALIAS: DebugMsg1(("SegmentDir(%s): ALIAS found, curr value=%s\n", name, dir->e.seginfo->aliasname ? dir->e.seginfo->aliasname : "NULL" )); /* alias() is restricted to COFF/ELF/BIN-PE */ if ( Options.output_format == OFORMAT_OMF || ( Options.output_format == OFORMAT_BIN && ModuleInfo.sub_format != SFORMAT_PE ) ) { 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; } /* v2.10: if segment already exists, check that old and new aliasname are equal */ if ( is_old ) { if ( dir->e.seginfo->aliasname == NULL || ( tokenarray[temp].stringlen != strlen( dir->e.seginfo->aliasname ) ) || memcmp( dir->e.seginfo->aliasname, tokenarray[temp].string_ptr + 1, tokenarray[temp].stringlen ) ) { EmitErr( SEGDEF_CHANGED, dir->sym.name, MsgGetEx( TXT_ALIASNAME ) ); break; } } else { /* v2.10: " + 1" was missing in next line */ dir->e.seginfo->aliasname = LclAlloc( tokenarray[temp].stringlen + 1 ); memcpy( dir->e.seginfo->aliasname, tokenarray[temp].string_ptr+1, tokenarray[temp].stringlen ); *(dir->e.seginfo->aliasname+tokenarray[temp].stringlen) = NULLC; } DebugMsg1(("SegmentDir(%s): ALIAS argument=>%s<\n", name, dir->e.seginfo->aliasname )); 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, dir->e.seginfo->clsym ); 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 ( 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; #if 0 /* v2.09: removed */ else if( oldreadonly != dir->e.seginfo->readonly ) /* readonly is not a true segment attribute */ txt = TXT_READONLY; else if ( oldclsym != dir->e.seginfo->clsym ) /* segment class check is done in SetSegmentClass() */ txt = TXT_CLASS; #endif else if ( newcharacteristics && ( newcharacteristics != 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; /* remains 0 ( =segment's local start offset ) */ #if COMDATSUPP /* no segment index for COMDAT segments in OMF! */ if ( dir->e.seginfo->comdat_selection && Options.output_format == OFORMAT_OMF ) ; else { #endif dir->e.seginfo->seg_idx = ++ModuleInfo.g.num_segs; /* dir->e.seginfo->lname_idx = */ AddLnameItem( sym ); #if COMDATSUPP } #endif } if ( newcharacteristics ) dir->e.seginfo->characteristics = newcharacteristics; push_seg( dir ); /* set CurrSeg */ if ( ModuleInfo.list ) LstWrite( LSTTYPE_LABEL, 0, NULL ); return( SetOfssize() ); } /* sort segments ( a simple bubble sort ) * type = 0: sort by fileoffset (.DOSSEG ) * type = 1: sort by name ( .ALPHA ) * type = 2: sort by segment type+name ( PE format ). member lname_idx is misused here for "type" */ void SortSegments( int type ) /***************************/ { bool changed = TRUE; bool swap; struct dsym *curr; //int index = 1; while ( changed == TRUE ) { struct dsym *prev = NULL; changed = FALSE; for( curr = SymTables[TAB_SEG].head; curr && curr->next ; prev = curr, curr = curr->next ) { swap = FALSE; switch (type ) { case 0: if ( curr->e.seginfo->fileoffset > curr->next->e.seginfo->fileoffset ) swap = TRUE; break; case 1: if ( strcmp( curr->sym.name, curr->next->sym.name ) > 0 ) swap = TRUE; break; case 2: if ( curr->e.seginfo->lname_idx > curr->next->e.seginfo->lname_idx || ( curr->e.seginfo->lname_idx == curr->next->e.seginfo->lname_idx && ( _stricmp( curr->sym.name, curr->next->sym.name ) > 0 ) ) ) swap = TRUE; break; #ifdef DEBUG_OUT default: /**/myassert( 0 ); #endif } if ( swap ) { struct dsym *tmp = curr->next; changed = TRUE; if ( prev == NULL ) { SymTables[TAB_SEG].head = tmp; } else { prev->next = tmp; } curr->next = tmp->next; tmp->next = curr; } } } /* v2.7: don't change segment indices! They're stored in fixup.frame_datum */ //for ( curr = SymTables[TAB_SEG].head; curr ; curr = curr->next ) { // curr->e.seginfo->seg_idx = index++; //} } /* END directive has been found. */ 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 ); } /* this is called once per module after the last pass is finished */ void SegmentFini( void ) /**********************/ { #if FASTMEM==0 struct dsym *curr; #endif DebugMsg(("SegmentFini() enter\n")); #if FASTMEM==0 for( curr = SymTables[TAB_SEG].head; curr; curr = curr->next ) { struct fixup *fix; DebugMsg(("SegmentFini: segment %s\n", curr->sym.name )); for ( fix = curr->e.seginfo->FixupList.head; fix ; ) { struct fixup *next = fix->nextrlc; DebugMsg(("SegmentFini: free fixup [sym=%s, loc=%" I32_SPEC "X]\n", fix->sym ? fix->sym->name : "NULL", fix->location )); LclFree( fix ); fix = next; } } #endif #if FASTPASS if ( saved_SegStack ) { LclFree( saved_SegStack ); } #endif FreeLnameQueue(); DebugMsg(("SegmentFini() exit\n")); } /* init. called for each pass */ void SegmentInit( int pass ) /**************************/ { struct dsym *curr; uint_32 i; #ifdef __I86__ char __huge *p; #else char *p; #endif //struct fixup *fix; DebugMsg(("SegmentInit(%u) enter\n", pass )); CurrSeg = NULL; stkindex = 0; if ( pass == PASS_1 ) { grpdefidx = 0; //LnamesIdx = 1; /* the first Lname is a null-string */ //pCodeBuff = NULL; buffer_size = 0; //flat_grp = NULL; #if FASTPASS #if FASTMEM==0 saved_SegStack = NULL; #endif #endif #if 0 /* v2.03: obsolete, also belongs to simplified segment handling */ /* set ModuleInfo.code_class */ if( Options.code_class ) size = strlen( Options.code_class ) + 1; else size = 4 + 1; ModuleInfo.code_class = LclAlloc( size ); if ( Options.code_class ) strcpy( ModuleInfo.code_class, Options.code_class ); else strcpy( ModuleInfo.code_class, "CODE" ); #endif } /* * alloc a buffer for the contents */ if ( ModuleInfo.pCodeBuff == NULL && Options.output_format != OFORMAT_OMF ) { for( curr = SymTables[TAB_SEG].head, buffer_size = 0; curr; curr = curr->next ) { if ( curr->e.seginfo->internal ) continue; if ( curr->e.seginfo->bytes_written ) { i = curr->sym.max_offset - curr->e.seginfo->start_loc; /* the segment can grow in step 2-n due to forward references. * for a quick solution just add 25% to the size if segment * is a code segment. (v2.02: previously if was added only if * code segment contained labels, but this isn't sufficient.) */ //if ( curr->e.seginfo->labels ) /* v2.02: changed */ if ( curr->e.seginfo->segtype == SEGTYPE_CODE ) i = i + (i >> 2); DebugMsg(("SegmentInit(%u), %s: max_ofs=%" I32_SPEC "X, alloc_size=%" I32_SPEC "Xh\n", pass, curr->sym.name, curr->sym.max_offset, i )); buffer_size += i; } } if ( buffer_size ) { ModuleInfo.pCodeBuff = LclAlloc( buffer_size ); DebugMsg(("SegmentInit(%u): total buffer size=%" I32_SPEC "X, start=%p\n", pass, buffer_size, ModuleInfo.pCodeBuff )); } } /* Reset length of all segments to zero. * set start of segment buffers. */ #if FASTMEM==0 /* fastmem clears the memory blocks, but malloc() won't */ if ( ModuleInfo.pCodeBuff ) memset( ModuleInfo.pCodeBuff, 0, buffer_size ); #endif for( curr = SymTables[TAB_SEG].head, p = ModuleInfo.pCodeBuff; curr; curr = curr->next ) { curr->e.seginfo->current_loc = 0; if ( curr->e.seginfo->internal ) continue; if ( curr->e.seginfo->bytes_written ) { if ( Options.output_format == OFORMAT_OMF ) { curr->e.seginfo->CodeBuffer = codebuf; DebugMsg(("SegmentInit(%u), %s: buffer=%p\n", pass, curr->sym.name, codebuf )); } else { curr->e.seginfo->CodeBuffer = p; i = curr->sym.max_offset - curr->e.seginfo->start_loc; DebugMsg(("SegmentInit(%u), %s: size=%" I32_SPEC "X buffer=%p\n", pass, curr->sym.name, i, p )); p += i; } } if( curr->e.seginfo->combine != COMB_STACK ) { curr->sym.max_offset = 0; } if ( Options.output_format == OFORMAT_OMF ) { /* v2.03: do this selectively */ curr->e.seginfo->start_loc = 0; curr->e.seginfo->data_in_code = FALSE; } curr->e.seginfo->bytes_written = 0; //if ( Options.output_format != OFORMAT_OMF ) { curr->e.seginfo->FixupList.head = NULL; curr->e.seginfo->FixupList.tail = NULL; //} } ModuleInfo.Ofssize = USE16; #if FASTPASS if ( pass != PASS_1 && UseSavedState == TRUE ) { CurrSeg = saved_CurrSeg; stkindex = saved_stkindex; if ( stkindex ) memcpy( &SegStack, saved_SegStack, stkindex * sizeof(struct dsym *) ); //symCurSeg->string_ptr = saved_CurSeg_name; UpdateCurrSegVars(); } #endif } #if FASTPASS void SegmentSaveState( void ) /***************************/ { //int i; //i = stkindex; saved_CurrSeg = CurrSeg; saved_stkindex = stkindex; if ( stkindex ) { saved_SegStack = LclAlloc( stkindex * sizeof(struct dsym *) ); memcpy( saved_SegStack, &SegStack, stkindex * sizeof(struct dsym *) ); DebugMsg(("SegmentSaveState: saved_segStack=%X\n", saved_SegStack )); } //saved_CurSeg_name = symCurSeg->string_ptr; } #endif