jwasm/segment.c
2014-06-18 19:16:56 +04:00

1603 lines
55 KiB
C

/****************************************************************************
*
* 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 <ctype.h>
#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 <FLAT> 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