mirror of
https://github.com/NishiOwO/JWasm.git
synced 2025-04-21 16:54:39 +00:00
854 lines
26 KiB
C
854 lines
26 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: symbol table access
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include <time.h>
|
|
|
|
#include "globals.h"
|
|
#include "memalloc.h"
|
|
#include "parser.h"
|
|
#include "segment.h"
|
|
#include "extern.h"
|
|
#include "fixup.h"
|
|
#include "fastpass.h"
|
|
#include "myassert.h"
|
|
#include "macro.h"
|
|
#include "types.h"
|
|
#include "proc.h"
|
|
#include "input.h"
|
|
|
|
#if defined(__WATCOMC__) && !defined(__FLAT__)
|
|
#define HASH_MAGNITUDE 12 /* for 16bit model */
|
|
#else
|
|
#define HASH_MAGNITUDE 15 /* is 15 since v1.94, previously 12 */
|
|
#endif
|
|
|
|
/* size of global hash table for symbol table searches. This affects
|
|
* assembly speed.
|
|
*/
|
|
#if HASH_MAGNITUDE==12
|
|
#define GHASH_TABLE_SIZE 2003
|
|
#else
|
|
#define GHASH_TABLE_SIZE 8009
|
|
#endif
|
|
|
|
/* size of local hash table */
|
|
#define LHASH_TABLE_SIZE 127
|
|
|
|
/* use memcpy()/memcmpi() directly?
|
|
* this may speed-up things, but not with OW.
|
|
* MSVC is a bit faster then.
|
|
*/
|
|
#define USEFIXSYMCMP 0 /* 1=don't use a function pointer for string compare */
|
|
#define USESTRFTIME 0 /* 1=use strftime() */
|
|
|
|
#if USEFIXSYMCMP
|
|
#define SYMCMP( x, y, z ) ( ModuleInfo.case_sensitive ? memcmp( x, y, z ) : _memicmp( x, y, z ) )
|
|
#else
|
|
#define SYMCMP( x, y, z ) SymCmpFunc( x, y, z )
|
|
#endif
|
|
|
|
extern struct asym *FileCur; /* @FileCur symbol */
|
|
extern struct asym *LineCur; /* @Line symbol */
|
|
extern struct asym *symCurSeg;/* @CurSeg symbol */
|
|
|
|
extern void UpdateLineNumber( struct asym *, void * );
|
|
extern void UpdateWordSize( struct asym *, void * );
|
|
extern void UpdateCurPC( struct asym *sym, void *p );
|
|
|
|
static struct asym *gsym_table[ GHASH_TABLE_SIZE ];
|
|
static struct asym *lsym_table[ LHASH_TABLE_SIZE ];
|
|
|
|
StrCmpFunc SymCmpFunc;
|
|
|
|
static struct asym **gsym; /* pointer into global hash table */
|
|
static struct asym **lsym; /* pointer into local hash table */
|
|
static unsigned SymCount; /* Number of symbols in global table */
|
|
static char szDate[12]; /* value of @Date symbol */
|
|
static char szTime[12]; /* value of @Time symbol */
|
|
|
|
#if USESTRFTIME
|
|
#if defined(__WATCOMC__) || defined(__UNIX__) || defined(__CYGWIN__) || defined(__DJGPP__)
|
|
static const char szDateFmt[] = "%D"; /* POSIX date (mm/dd/yy) */
|
|
static const char szTimeFmt[] = "%T"; /* POSIX time (HH:MM:SS) */
|
|
#else
|
|
/* v2.04: MS VC won't understand POSIX formats */
|
|
static const char szDateFmt[] = "%x"; /* locale's date */
|
|
static const char szTimeFmt[] = "%X"; /* locale's time */
|
|
#endif
|
|
#endif
|
|
|
|
static struct asym *symPC; /* the $ symbol */
|
|
|
|
struct tmitem {
|
|
const char *name;
|
|
char *value;
|
|
struct asym **store;
|
|
};
|
|
|
|
/* table of predefined text macros */
|
|
static const struct tmitem tmtab[] = {
|
|
/* @Version contains the Masm compatible version */
|
|
/* v2.06: value of @Version changed to 800 */
|
|
//{"@Version", "615", NULL },
|
|
{"@Version", "800", NULL },
|
|
{"@Date", szDate, NULL },
|
|
{"@Time", szTime, NULL },
|
|
{"@FileName", ModuleInfo.name, NULL },
|
|
{"@FileCur", NULL, &FileCur },
|
|
/* v2.09: @CurSeg value is never set if no segment is ever opened.
|
|
* this may have caused an access error if a listing was written.
|
|
*/
|
|
{"@CurSeg", "", &symCurSeg }
|
|
};
|
|
|
|
struct eqitem {
|
|
const char *name;
|
|
uint_32 value;
|
|
void (* sfunc_ptr)( struct asym *, void * );
|
|
struct asym **store;
|
|
};
|
|
|
|
/* table of predefined numeric equates */
|
|
static const struct eqitem eqtab[] = {
|
|
{ "__JWASM__", _JWASM_VERSION_INT_, NULL, NULL },
|
|
{ "$", 0, UpdateCurPC, &symPC },
|
|
{ "@Line", 0, UpdateLineNumber, &LineCur },
|
|
{ "@WordSize", 0, UpdateWordSize, NULL }, /* must be last (see SymInit()) */
|
|
};
|
|
|
|
static unsigned int hashpjw( const char *s )
|
|
/******************************************/
|
|
{
|
|
unsigned h;
|
|
unsigned g;
|
|
|
|
#if HASH_MAGNITUDE==12
|
|
for( h = 0; *s; ++s ) {
|
|
h = (h << 4) + (*s | ' ');
|
|
g = h & ~0x0fff;
|
|
h ^= g;
|
|
h ^= g >> 12;
|
|
}
|
|
#else
|
|
for( h = 0; *s; ++s ) {
|
|
h = (h << 5) + (*s | ' ');
|
|
g = h & ~0x7fff;
|
|
h ^= g;
|
|
h ^= g >> 15;
|
|
}
|
|
#endif
|
|
return( h );
|
|
}
|
|
|
|
void SymSetCmpFunc( void )
|
|
/************************/
|
|
{
|
|
SymCmpFunc = ( ModuleInfo.case_sensitive == TRUE ? memcmp : (StrCmpFunc)_memicmp );
|
|
return;
|
|
}
|
|
|
|
/* reset local hash table */
|
|
|
|
void SymClearLocal( void )
|
|
/************************/
|
|
{
|
|
memset( &lsym_table, 0, sizeof( lsym_table ) );
|
|
return;
|
|
}
|
|
|
|
/* store local hash table in proc's list of local symbols */
|
|
|
|
void SymGetLocal( struct asym *proc )
|
|
/***********************************/
|
|
{
|
|
int i;
|
|
struct dsym **l = &((struct dsym *)proc)->e.procinfo->labellist;
|
|
|
|
for ( i = 0; i < LHASH_TABLE_SIZE; i++ ) {
|
|
if ( lsym_table[i] ) {
|
|
*l = (struct dsym *)lsym_table[i];
|
|
l = &(*l)->e.nextll;
|
|
}
|
|
}
|
|
*l = NULL;
|
|
|
|
return;
|
|
}
|
|
|
|
/* restore local hash table.
|
|
* - proc: procedure which will become active.
|
|
* fixme: It might be necessary to reset the "defined" flag
|
|
* for local labels (not for params and locals!). Low priority!
|
|
*/
|
|
|
|
void SymSetLocal( struct asym *proc )
|
|
/***********************************/
|
|
{
|
|
int i;
|
|
struct dsym *l;
|
|
|
|
SymClearLocal();
|
|
for ( l = ((struct dsym *)proc)->e.procinfo->labellist; l; l = l->e.nextll ) {
|
|
DebugMsg1(("SymSetLocal(%s): label=%s\n", proc->name, l->sym.name ));
|
|
i = hashpjw( l->sym.name ) % LHASH_TABLE_SIZE;
|
|
lsym_table[i] = &l->sym;
|
|
}
|
|
return;
|
|
}
|
|
|
|
struct asym *SymAlloc( const char *name )
|
|
/***************************************/
|
|
{
|
|
int len = strlen( name );
|
|
struct asym *sym;
|
|
|
|
sym = LclAlloc( sizeof( struct dsym ) );
|
|
memset( sym, 0, sizeof( struct dsym ) );
|
|
#if 1
|
|
/* the tokenizer ensures that identifiers are within limits, so
|
|
* this check probably is redundant */
|
|
if( len > MAX_ID_LEN ) {
|
|
EmitError( IDENTIFIER_TOO_LONG );
|
|
len = MAX_ID_LEN;
|
|
}
|
|
#endif
|
|
sym->name_size = len;
|
|
sym->list = ModuleInfo.cref;
|
|
sym->mem_type = MT_EMPTY;
|
|
if ( len ) {
|
|
sym->name = LclAlloc( len + 1 );
|
|
memcpy( sym->name, name, len );
|
|
sym->name[len] = NULLC;
|
|
} else
|
|
sym->name = "";
|
|
return( sym );
|
|
}
|
|
|
|
struct asym *SymFind( const char *name )
|
|
/**************************************/
|
|
/* find a symbol in the local/global symbol table,
|
|
* return ptr to next free entry in global table if not found.
|
|
* Note: lsym must be global, thus if the symbol isn't
|
|
* found and is to be added to the local table, there's no
|
|
* second scan necessary.
|
|
*/
|
|
{
|
|
int i;
|
|
int len;
|
|
|
|
len = strlen( name );
|
|
i = hashpjw( name );
|
|
|
|
if ( CurrProc ) {
|
|
for( lsym = &lsym_table[ i % LHASH_TABLE_SIZE ]; *lsym; lsym = &((*lsym)->nextitem ) ) {
|
|
if ( len == (*lsym)->name_size && SYMCMP( name, (*lsym)->name, len ) == 0 ) {
|
|
DebugMsg1(("SymFind(%s): found in local table, state=%u, local=%u\n", name, (*lsym)->state, (*lsym)->scoped ));
|
|
return( *lsym );
|
|
}
|
|
}
|
|
}
|
|
|
|
for( gsym = &gsym_table[ i % GHASH_TABLE_SIZE ]; *gsym; gsym = &((*gsym)->nextitem ) ) {
|
|
if ( len == (*gsym)->name_size && SYMCMP( name, (*gsym)->name, len ) == 0 ) {
|
|
DebugMsg1(("SymFind(%s): found, state=%u memtype=%X lang=%u\n", name, (*gsym)->state, (*gsym)->mem_type, (*gsym)->langtype ));
|
|
return( *gsym );
|
|
}
|
|
}
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
#if 0
|
|
/* Search a symbol */
|
|
|
|
struct asym *SymSearch( const char *name )
|
|
/****************************************/
|
|
{
|
|
return( *SymFind( name ) );
|
|
}
|
|
#endif
|
|
|
|
/* SymLookup() creates a global label if it isn't defined yet */
|
|
|
|
struct asym *SymLookup( const char *name )
|
|
/****************************************/
|
|
{
|
|
struct asym *sym;
|
|
|
|
sym = SymFind( name );
|
|
if( sym == NULL ) {
|
|
sym = SymAlloc( name );
|
|
DebugMsg1(("SymLookup(%s): created new symbol, CurrProc=%s\n", name, CurrProc ? CurrProc->sym.name : "NULL" ));
|
|
//sym->next = *gsym;
|
|
*gsym = sym;
|
|
++SymCount;
|
|
}
|
|
|
|
DebugMsg1(("SymLookup(%s): found, state=%u, defined=%u\n", name, sym->state, sym->isdefined));
|
|
|
|
return( sym );
|
|
}
|
|
|
|
/* SymLookupLocal() creates a local label if it isn't defined yet.
|
|
* called by LabelCreate() [see labels.c]
|
|
*/
|
|
struct asym *SymLookupLocal( const char *name )
|
|
/*********************************************/
|
|
{
|
|
//struct asym **sym_ptr;
|
|
struct asym *sym;
|
|
|
|
sym = SymFind( name );
|
|
if ( sym == NULL ) {
|
|
sym = SymAlloc( name );
|
|
sym->scoped = TRUE;
|
|
/* add the label to the local hash table */
|
|
//sym->next = *lsym;
|
|
*lsym = sym;
|
|
DebugMsg1(("SymLookupLocal(%s): local symbol created in %s\n", name, CurrProc->sym.name));
|
|
} else if( sym->state == SYM_UNDEFINED && sym->scoped == FALSE ) {
|
|
/* if the label was defined due to a FORWARD reference,
|
|
* its scope is to be changed from global to local.
|
|
*/
|
|
/* remove the label from the global hash table */
|
|
*gsym = sym->nextitem;
|
|
SymCount--;
|
|
sym->scoped = TRUE;
|
|
/* add the label to the local hash table */
|
|
//sym->next = *lsym;
|
|
sym->nextitem = NULL;
|
|
*lsym = sym;
|
|
DebugMsg1(("SymLookupLocal(%s): label moved into %s's local namespace\n", sym->name, CurrProc->sym.name ));
|
|
}
|
|
|
|
DebugMsg1(("SymLookupLocal(%s): found, state=%u, defined=%u\n", name, sym->state, sym->isdefined));
|
|
return( sym );
|
|
}
|
|
|
|
/* free state-specific info of a symbol */
|
|
|
|
static void free_ext( struct asym *sym )
|
|
/**************************************/
|
|
{
|
|
DebugMsg(("free_ext: item=%p name=%s state=%u\n", sym, sym->name, sym->state ));
|
|
switch( sym->state ) {
|
|
case SYM_INTERNAL:
|
|
if ( sym->isproc )
|
|
DeleteProc( (struct dsym *)sym );
|
|
break;
|
|
case SYM_EXTERNAL:
|
|
if ( sym->isproc )
|
|
DeleteProc( (struct dsym *)sym );
|
|
sym->first_size = 0;
|
|
/* The altname field may contain a symbol (if weak == FALSE).
|
|
* However, this is an independant item and must not be released here
|
|
*/
|
|
#ifdef DEBUG_OUT /* to be removed, this can't happen anymore. */
|
|
if ( sym->mem_type == MT_TYPE && *sym->type->name == NULLC ) {
|
|
DebugMsg(( "free_ext: external with private type: %s\n", sym->name ));
|
|
SymFree( sym->type );
|
|
}
|
|
#endif
|
|
break;
|
|
case SYM_SEG:
|
|
if ( ((struct dsym *)sym)->e.seginfo->internal )
|
|
LclFree( ((struct dsym *)sym)->e.seginfo->CodeBuffer );
|
|
LclFree( ((struct dsym *)sym)->e.seginfo );
|
|
break;
|
|
case SYM_GRP:
|
|
DeleteGroup( (struct dsym *)sym );
|
|
break;
|
|
case SYM_TYPE:
|
|
DeleteType( (struct dsym *)sym );
|
|
break;
|
|
case SYM_MACRO:
|
|
ReleaseMacroData( (struct dsym *)sym );
|
|
LclFree( ((struct dsym *)sym)->e.macroinfo );
|
|
break;
|
|
case SYM_TMACRO:
|
|
if ( sym->predefined == FALSE )
|
|
LclFree( sym->string_ptr );
|
|
break;
|
|
#ifdef DEBUG_OUT
|
|
case SYM_STACK:
|
|
/* to be removed, this can't happen anymore. */
|
|
if ( sym->mem_type == MT_TYPE && *sym->type->name == NULLC ) {
|
|
DebugMsg(( "free_ext: case SYM_STACK, sym=%s with private type\n", sym->name ));
|
|
/* symbol has a "private" type */
|
|
SymFree( sym->type );
|
|
}
|
|
break;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* free a symbol.
|
|
* the symbol is no unlinked from hash tables chains,
|
|
* hence it is assumed that this is either not needed
|
|
* or done by the caller.
|
|
*/
|
|
|
|
void SymFree( struct asym *sym )
|
|
/******************************/
|
|
{
|
|
//DebugMsg(("SymFree: free %X, name=%s, state=%X\n", sym, sym->name, sym->state));
|
|
free_ext( sym );
|
|
#if FASTMEM==0
|
|
if ( sym->state != SYM_EXTERNAL ) {
|
|
struct fixup *fix;
|
|
for( fix = sym->bp_fixup ; fix; ) {
|
|
struct fixup *next = fix->nextbp;
|
|
DebugMsg(("SymFree: free bp fixup %p\n", fix ));
|
|
LclFree( fix );
|
|
fix = next;
|
|
}
|
|
}
|
|
if ( sym->name_size ) LclFree( sym->name );
|
|
#endif
|
|
LclFree( sym );
|
|
return;
|
|
}
|
|
|
|
/* add a symbol to local table and set the symbol's name.
|
|
* the previous name was "", the symbol wasn't in a symbol table.
|
|
* Called by:
|
|
* - ParseParams() in proc.c for procedure parameters.
|
|
*/
|
|
struct asym *SymAddLocal( struct asym *sym, const char *name )
|
|
/************************************************************/
|
|
{
|
|
struct asym *sym2;
|
|
/* v2.10: ignore symbols with state SYM_UNDEFINED! */
|
|
//if( SymFind( name ) ) {
|
|
if( ( sym2 = SymFind( name ) ) && sym2->state != SYM_UNDEFINED ) {
|
|
/* shouldn't happen */
|
|
EmitErr( SYMBOL_ALREADY_DEFINED, name );
|
|
return( NULL );
|
|
}
|
|
#if FASTMEM==0
|
|
if ( sym->name_size ) LclFree( sym->name );
|
|
#endif
|
|
sym->name_size = strlen( name );
|
|
sym->name = LclAlloc( sym->name_size + 1 );
|
|
memcpy( sym->name, name, sym->name_size + 1 );
|
|
sym->nextitem = NULL;
|
|
*lsym = sym;
|
|
return( sym );
|
|
}
|
|
|
|
/* add a symbol to the global symbol table.
|
|
* Called by:
|
|
* - RecordDirective() in types.c to add bitfield fields (which have global scope).
|
|
*/
|
|
|
|
struct asym *SymAddGlobal( struct asym *sym )
|
|
/*******************************************/
|
|
{
|
|
if( SymFind( sym->name ) ) {
|
|
EmitErr( SYMBOL_ALREADY_DEFINED, sym->name );
|
|
return( NULL );
|
|
}
|
|
sym->nextitem = NULL;
|
|
*gsym = sym;
|
|
SymCount++;
|
|
return( sym );
|
|
}
|
|
|
|
struct asym *SymCreate( const char *name )
|
|
/****************************************/
|
|
/* Create symbol and optionally insert it into the symbol table */
|
|
{
|
|
struct asym *sym;
|
|
|
|
if( SymFind( name ) ) {
|
|
EmitErr( SYMBOL_ALREADY_DEFINED, name );
|
|
return( NULL );
|
|
}
|
|
sym = SymAlloc( name );
|
|
*gsym = sym;
|
|
SymCount++;
|
|
return( sym );
|
|
}
|
|
|
|
struct asym *SymLCreate( const char *name )
|
|
/*****************************************/
|
|
/* Create symbol and insert it into the local symbol table.
|
|
* This function is called by LocalDir() and ParseParams()
|
|
* in proc.c ( for LOCAL directive and PROC parameters ).
|
|
*/
|
|
{
|
|
struct asym *sym;
|
|
|
|
/* v2.10: ignore symbols with state SYM_UNDEFINED */
|
|
//if( SymFind( name ) ) {
|
|
if( ( sym = SymFind( name ) ) && sym->state != SYM_UNDEFINED ) {
|
|
EmitErr( SYMBOL_ALREADY_DEFINED, name );
|
|
return( NULL );
|
|
}
|
|
sym = SymAlloc( name );
|
|
*lsym = sym;
|
|
return( sym );
|
|
}
|
|
|
|
void SymMakeAllSymbolsPublic( void )
|
|
/**********************************/
|
|
{
|
|
int i;
|
|
struct asym *sym;
|
|
|
|
for( i = 0; i < GHASH_TABLE_SIZE; i++ ) {
|
|
for( sym = gsym_table[i]; sym; sym = sym->nextitem ) {
|
|
if ( sym->state == SYM_INTERNAL &&
|
|
/* v2.07: MT_ABS is obsolete */
|
|
//sym->mem_type != MT_ABS && /* no EQU or '=' constants */
|
|
sym->isequate == FALSE && /* no EQU or '=' constants */
|
|
sym->predefined == FALSE && /* no predefined symbols ($) */
|
|
sym->included == FALSE && /* v2.09: symbol already added to public queue? */
|
|
//sym->scoped == FALSE && /* v2.09: no procs that are marked as "private" */
|
|
sym->name[1] != '&' && /* v2.10: no @@ code labels */
|
|
sym->ispublic == FALSE ) {
|
|
sym->ispublic = TRUE;
|
|
AddPublicData( sym );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG_OUT
|
|
static void DumpSymbols( void );
|
|
#endif
|
|
|
|
void SymFini( void )
|
|
/******************/
|
|
{
|
|
#if FASTMEM==0 || defined( DEBUG_OUT )
|
|
unsigned i;
|
|
#endif
|
|
|
|
#ifdef DEBUG_OUT
|
|
if ( Options.dump_symbols_hash ) {
|
|
for( i = 0; i < GHASH_TABLE_SIZE; i++ ) {
|
|
struct asym *sym = gsym_table[i];
|
|
if ( sym ) {
|
|
printf("%4u ", i );
|
|
for( ; sym; sym = sym->nextitem ) {
|
|
printf("%-16s ", sym->name );
|
|
}
|
|
printf("\n" );
|
|
}
|
|
}
|
|
}
|
|
DumpSymbols();
|
|
#endif
|
|
|
|
#if FASTMEM==0 || defined( DEBUG_OUT )
|
|
/* free the symbol table */
|
|
for( i = 0; i < GHASH_TABLE_SIZE; i++ ) {
|
|
struct asym *sym;
|
|
struct asym *next;
|
|
for( sym = gsym_table[i]; sym; ) {
|
|
next = sym->nextitem;
|
|
SymFree( sym );
|
|
SymCount--;
|
|
sym = next;
|
|
}
|
|
}
|
|
/**/myassert( SymCount == 0 );
|
|
#endif
|
|
|
|
}
|
|
|
|
/* initialize global symbol table */
|
|
|
|
void SymInit( void )
|
|
/******************/
|
|
{
|
|
struct asym *sym;
|
|
int i;
|
|
time_t time_of_day;
|
|
struct tm *now;
|
|
|
|
DebugMsg(("SymInit() enter\n"));
|
|
SymCount = 0;
|
|
|
|
/* v2.11: ensure CurrProc is NULL - might be a problem if multiple files are assembled */
|
|
CurrProc = NULL;
|
|
|
|
memset( gsym_table, 0, sizeof(gsym_table) );
|
|
|
|
time_of_day = time( NULL );
|
|
now = localtime( &time_of_day );
|
|
#if USESTRFTIME
|
|
strftime( szDate, 9, szDateFmt, now );
|
|
strftime( szTime, 9, szTimeFmt, now );
|
|
#else
|
|
sprintf( szDate, "%02u/%02u/%02u", now->tm_mon + 1, now->tm_mday, now->tm_year % 100 );
|
|
sprintf( szTime, "%02u:%02u:%02u", now->tm_hour, now->tm_min, now->tm_sec );
|
|
#endif
|
|
|
|
for( i = 0; i < sizeof(tmtab) / sizeof(tmtab[0]); i++ ) {
|
|
sym = SymCreate( tmtab[i].name );
|
|
sym->state = SYM_TMACRO;
|
|
sym->isdefined = TRUE;
|
|
sym->predefined = TRUE;
|
|
sym->string_ptr = tmtab[i].value;
|
|
if ( tmtab[i].store )
|
|
*tmtab[i].store = sym;
|
|
}
|
|
|
|
for( i = 0; i < sizeof(eqtab) / sizeof(eqtab[0]); i++ ) {
|
|
sym = SymCreate( eqtab[i].name );
|
|
sym->state = SYM_INTERNAL;
|
|
/* v2.07: MT_ABS is obsolete */
|
|
//sym->mem_type = MT_ABS;
|
|
sym->isdefined = TRUE;
|
|
sym->predefined = TRUE;
|
|
sym->offset = eqtab[i].value;
|
|
sym->sfunc_ptr = eqtab[i].sfunc_ptr;
|
|
//sym->variable = TRUE; /* if fixup must be created */
|
|
if ( eqtab[i].store )
|
|
*eqtab[i].store = sym;
|
|
}
|
|
sym->list = FALSE; /* @WordSize should not be listed */
|
|
/* $ is an address (usually). Also, don't add it to the list */
|
|
symPC->variable = TRUE;
|
|
symPC->list = FALSE;
|
|
LineCur->list = FALSE;
|
|
|
|
DebugMsg(("SymInit() exit\n"));
|
|
return;
|
|
|
|
}
|
|
|
|
void SymPassInit( int pass )
|
|
/**************************/
|
|
{
|
|
unsigned i;
|
|
|
|
if ( pass == PASS_1 )
|
|
return;
|
|
|
|
#if FASTPASS
|
|
/* No need to reset the "defined" flag if FASTPASS is on.
|
|
* Because then the source lines will come from the line store,
|
|
* where inactive conditional lines are NOT contained.
|
|
*/
|
|
if ( UseSavedState )
|
|
return;
|
|
#endif
|
|
/* mark as "undefined":
|
|
* - SYM_INTERNAL - internals
|
|
* - SYM_MACRO - macros
|
|
* - SYM_TMACRO - text macros
|
|
*/
|
|
for( i = 0; i < GHASH_TABLE_SIZE; i++ ) {
|
|
struct asym *sym;
|
|
for( sym = gsym_table[i]; sym; sym = sym->nextitem ) {
|
|
if ( sym->predefined == FALSE ) {
|
|
/* v2.04: all symbol's "defined" flag is now reset. */
|
|
// if ( sym->state == SYM_TMACRO ||
|
|
// sym->state == SYM_MACRO ||
|
|
// sym->state == SYM_INTERNAL ) {
|
|
sym->isdefined = FALSE;
|
|
//}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
uint_32 SymGetCount( void )
|
|
/*************************/
|
|
{
|
|
return( SymCount );
|
|
}
|
|
|
|
/* get all symbols in global hash table */
|
|
|
|
void SymGetAll( struct asym **syms )
|
|
/**********************************/
|
|
{
|
|
struct asym *sym;
|
|
unsigned i, j;
|
|
|
|
/* copy symbols to table */
|
|
for( i = j = 0; i < GHASH_TABLE_SIZE; i++ ) {
|
|
for( sym = gsym_table[i]; sym; sym = sym->nextitem ) {
|
|
syms[j++] = sym;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* enum symbols in global hash table.
|
|
* used for codeview symbolic debug output.
|
|
*/
|
|
|
|
struct asym *SymEnum( struct asym *sym, int *pi )
|
|
/***********************************************/
|
|
{
|
|
if ( sym == NULL ) {
|
|
*pi = 0;
|
|
sym = gsym_table[*pi];
|
|
} else {
|
|
sym = sym->nextitem;
|
|
}
|
|
|
|
/* v2.10: changed from for() to while() */
|
|
while( sym == NULL && *pi < GHASH_TABLE_SIZE - 1 )
|
|
sym = gsym_table[++(*pi)];
|
|
|
|
//printf("sym=%X, i=%u\n", sym, *pi );
|
|
return( sym );
|
|
}
|
|
|
|
#ifdef DEBUG_OUT
|
|
|
|
static void DumpSymbol( struct asym *sym )
|
|
/****************************************/
|
|
{
|
|
struct dsym *dir = (struct dsym *)sym;
|
|
char *type;
|
|
uint_64 value = sym->uvalue;
|
|
//const char *langtype;
|
|
|
|
switch( sym->state ) {
|
|
case SYM_UNDEFINED:
|
|
type = "Undefined";
|
|
break;
|
|
case SYM_INTERNAL:
|
|
if ( sym->isproc )
|
|
type = "Procedure";
|
|
//else if ( sym->mem_type == MT_ABS )
|
|
else if ( sym->segment == NULL ) {
|
|
type = "Number";
|
|
value += ((uint_64)(uint_32)sym->value3264) << 32;
|
|
} else if ( sym->mem_type == MT_NEAR || sym->mem_type == MT_FAR )
|
|
type = "Code Label";
|
|
else
|
|
type = "Data Label";
|
|
break;
|
|
case SYM_EXTERNAL:
|
|
if ( sym->isproc )
|
|
type = "Proto";
|
|
else if ( sym->iscomm )
|
|
type = "Communal";
|
|
else if ( sym->mem_type == MT_EMPTY )
|
|
type = "Number (ext)";
|
|
else if ( sym->mem_type == MT_NEAR || sym->mem_type == MT_FAR )
|
|
type = "Code (ext)";
|
|
else
|
|
type = "Data (ext)";
|
|
break;
|
|
case SYM_SEG:
|
|
type = "Segment";
|
|
break;
|
|
case SYM_GRP:
|
|
type = "Group";
|
|
break;
|
|
case SYM_STACK: /* should never be found in global table */
|
|
type = "Stack Var";
|
|
break;
|
|
case SYM_STRUCT_FIELD: /* record bitfields are in global namespace! */
|
|
type = "Struct Field";
|
|
break;
|
|
case SYM_TYPE:
|
|
switch ( sym->typekind ) {
|
|
case TYPE_STRUCT: type = "Structure"; break;
|
|
case TYPE_UNION: type = "Union"; break;
|
|
case TYPE_TYPEDEF: type = "Typedef"; break;
|
|
case TYPE_RECORD: type = "Record"; break;
|
|
default: type = "Undef Type";break;
|
|
}
|
|
break;
|
|
case SYM_ALIAS:
|
|
type = "Alias";
|
|
break;
|
|
case SYM_MACRO:
|
|
type = "Macro";
|
|
break;
|
|
case SYM_TMACRO:
|
|
type = "Text";
|
|
break;
|
|
//case SYM_CLASS_LNAME: /* never stored in global or local table */
|
|
// type = "CLASS";
|
|
// break;
|
|
default:
|
|
type = "Unknown";
|
|
break;
|
|
}
|
|
printf( "%-12s %16" I64_SPEC "X %02X %8p %c %8p %s\n", type, value, sym->mem_type, dir->e, sym->ispublic ? 'X' : ' ', sym->name, sym->name );
|
|
}
|
|
|
|
static void DumpSymbols( void )
|
|
/*****************************/
|
|
{
|
|
struct asym *sym;
|
|
unsigned i;
|
|
unsigned count = 0;
|
|
unsigned max = 0;
|
|
unsigned num0 = 0;
|
|
unsigned num1 = 0;
|
|
unsigned num5 = 0;
|
|
unsigned num10 = 0;
|
|
unsigned curr = 0;
|
|
|
|
DebugMsg(("DumpSymbols enter\n"));
|
|
if ( Options.dump_symbols ) {
|
|
printf( " # Addr Type Value MT Ext P pName Name\n" );
|
|
printf( "--------------------------------------------------------------------------------\n" );
|
|
}
|
|
for( i = 0; i < GHASH_TABLE_SIZE; i++ ) {
|
|
for( sym = gsym_table[i], curr = 0; sym; sym = sym->nextitem ) {
|
|
curr++;
|
|
if ( Options.dump_symbols ) {
|
|
printf("%4u %8p ", i, sym );
|
|
DumpSymbol( sym );
|
|
}
|
|
}
|
|
count += curr;
|
|
if ( curr == 0 )
|
|
num0++;
|
|
else if ( curr == 1 )
|
|
num1++;
|
|
else if ( curr <= 5 )
|
|
num5++;
|
|
else if ( curr <= 10 )
|
|
num10++;
|
|
if ( max < curr )
|
|
max = curr;
|
|
}
|
|
if ( Options.quiet == FALSE ) {
|
|
printf( "%u items in symbol table, expected %u\n", count, SymCount );
|
|
printf( "max items in a line=%u, lines with 0/1/<=5/<=10 items=%u/%u/%u/%u, \n", max, num0, num1, num5, num10 );
|
|
}
|
|
}
|
|
#endif
|
|
|