/*****************************************************************************/
/* */
-/* symtab.c */
+/* symtab.c */
/* */
-/* Symbol table for the ca65 macroassembler */
+/* Symbol table for the ca65 macroassembler */
/* */
/* */
/* */
-/* (C) 1998-2003 Ullrich von Bassewitz */
-/* Römerstraße 52 */
-/* D-70794 Filderstadt */
-/* EMail: uz@cc65.org */
+/* (C) 1998-2014, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* common */
#include "addrsize.h"
#include "check.h"
-#include "hashstr.h"
+#include "hashfunc.h"
+#include "mmodel.h"
+#include "scopedefs.h"
#include "symdefs.h"
#include "xmalloc.h"
/* ca65 */
-#include "global.h"
+#include "dbginfo.h"
#include "error.h"
#include "expr.h"
+#include "global.h"
#include "objfile.h"
#include "scanner.h"
#include "segment.h"
+#include "sizeof.h"
+#include "span.h"
#include "spool.h"
+#include "studyexpr.h"
#include "symtab.h"
/*****************************************************************************/
-/* Data */
+/* Data */
/*****************************************************************************/
/* Combined symbol entry flags used within this module */
-#define SF_UNDEFMASK (SF_REFERENCED | SF_DEFINED | SF_IMPORT)
-#define SF_UNDEFVAL (SF_REFERENCED)
-#define SF_EXPMASK (SF_TRAMPOLINE | SF_EXPORT)
-#define SF_EXPVAL (SF_EXPORT)
-#define SF_DBGINFOMASK (SF_TRAMPOLINE | SF_DEFINED | SF_EXPORT | SF_IMPORT)
-#define SF_DBGINFOVAL (SF_DEFINED)
+#define SF_UNDEFMASK (SF_REFERENCED | SF_DEFINED | SF_IMPORT)
+#define SF_UNDEFVAL (SF_REFERENCED)
/* Symbol tables */
-SymTable* CurrentScope = 0; /* Pointer to current symbol table */
-SymTable* RootScope = 0; /* Root symbol table */
+SymTable* CurrentScope = 0; /* Pointer to current symbol table */
+SymTable* RootScope = 0; /* Root symbol table */
+static SymTable* LastScope = 0; /* Pointer to last scope in list */
+static unsigned ScopeCount = 0; /* Number of scopes */
/* Symbol table variables */
-static unsigned ImportCount = 0;/* Counter for import symbols */
-static unsigned ExportCount = 0;/* Counter for export symbols */
+static unsigned ImportCount = 0; /* Counter for import symbols */
+static unsigned ExportCount = 0; /* Counter for export symbols */
/*****************************************************************************/
-/* Internally used functions */
+/* Internally used functions */
/*****************************************************************************/
+static int IsDbgSym (const SymEntry* S)
+/* Return true if this is a debug symbol */
+{
+ if ((S->Flags & (SF_DEFINED | SF_UNUSED)) == SF_DEFINED) {
+ /* Defined symbols are debug symbols if they aren't sizes */
+ return !IsSizeOfSymbol (S);
+ } else {
+ /* Others are debug symbols if they're referenced imports */
+ return ((S->Flags & SF_REFIMP) == SF_REFIMP);
+ }
+}
+
+
+
static unsigned ScopeTableSize (unsigned Level)
/* Get the size of a table for the given lexical level */
{
-static SymTable* NewSymTable (SymTable* Parent, const char* Name)
+static SymTable* NewSymTable (SymTable* Parent, const StrBuf* Name)
/* Allocate a symbol table on the heap and return it */
{
/* Determine the lexical level and the number of table slots */
SymTable* S = xmalloc (sizeof (SymTable) + (Slots-1) * sizeof (SymEntry*));
/* Set variables and clear hash table entries */
+ S->Next = 0;
S->Left = 0;
S->Right = 0;
S->Childs = 0;
+ S->Label = 0;
+ S->Spans = AUTO_COLLECTION_INITIALIZER;
+ S->Id = ScopeCount++;
S->Flags = ST_NONE;
S->AddrSize = ADDR_SIZE_DEFAULT;
- S->Type = ST_UNDEF;
+ S->Type = SCOPE_UNDEF;
S->Level = Level;
S->TableSlots = Slots;
S->TableEntries = 0;
S->Parent = Parent;
- S->Name = GetStringId (Name);
+ S->Name = GetStrBufId (Name);
while (Slots--) {
- S->Table[Slots] = 0;
+ S->Table[Slots] = 0;
+ }
+
+ /* Insert the symbol table into the list of all symbol tables */
+ if (RootScope == 0) {
+ RootScope = S;
+ } else {
+ LastScope->Next = S;
}
+ LastScope = S;
/* Insert the symbol table into the child tree of the parent */
if (Parent) {
} else {
while (1) {
/* Choose next entry */
- int Cmp = strcmp (Name, GetString (T->Name));
+ int Cmp = SB_Compare (Name, GetStrBuf (T->Name));
if (Cmp < 0) {
if (T->Left) {
T = T->Left;
}
} else {
/* Duplicate scope name */
- Internal ("Duplicate scope name: `%s'", Name);
+ Internal ("Duplicate scope name: `%m%p'", Name);
}
}
}
-static int SearchSymTree (SymEntry* T, const char* Name, SymEntry** E)
-/* Search in the given tree for a name. If we find the symbol, the function
- * will return 0 and put the entry pointer into E. If we did not find the
- * symbol, and the tree is empty, E is set to NULL. If the tree is not empty,
- * E will be set to the last entry, and the result of the function is <0 if
- * the entry should be inserted on the left side, and >0 if it should get
- * inserted on the right side.
- */
-{
- /* Is there a tree? */
- if (T == 0) {
- *E = 0;
- return 1;
- }
-
- /* We have a table, search it */
- while (1) {
-
- /* Get the symbol name */
- const char* SymName = GetString (T->Name);
-
- /* Choose next entry */
- int Cmp = strcmp (Name, SymName);
- if (Cmp < 0 && T->Left) {
- T = T->Left;
- } else if (Cmp > 0&& T->Right) {
- T = T->Right;
- } else {
- /* Found or end of search, return the result */
- *E = T;
- return Cmp;
- }
- }
-}
-
-
-
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
-void SymEnterLevel (const char* ScopeName, unsigned char Type, unsigned char AddrSize)
+void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type,
+ unsigned char AddrSize, SymEntry* ScopeLabel)
/* Enter a new lexical level */
{
/* Map a default address size to something real */
}
/* If we have a current scope, search for the given name and create a
- * new one if it doesn't exist. If this is the root scope, just create it.
- */
+ ** new one if it doesn't exist. If this is the root scope, just create it.
+ */
if (CurrentScope) {
/* Search for the scope, create a new one */
/* Check if the scope has been defined before */
if (CurrentScope->Flags & ST_DEFINED) {
- Error ("Duplicate scope `%s'", ScopeName);
+ Error ("Duplicate scope `%m%p'", ScopeName);
}
} else {
CurrentScope = RootScope = NewSymTable (0, ScopeName);
}
- /* Mark the scope as defined and set type and address size */
+ /* Mark the scope as defined and set type, address size and owner symbol */
CurrentScope->Flags |= ST_DEFINED;
CurrentScope->AddrSize = AddrSize;
CurrentScope->Type = Type;
+ CurrentScope->Label = ScopeLabel;
+
+ /* If this is a scope that allows to emit data into segments, add spans
+ ** for all currently existing segments. Doing this for just a few scope
+ ** types is not really necessary but an optimization, because it does not
+ ** allocate memory for useless data (unhandled types here don't occupy
+ ** space in any segment).
+ */
+ if (CurrentScope->Type <= SCOPE_HAS_DATA) {
+ OpenSpanList (&CurrentScope->Spans);
+ }
}
void SymLeaveLevel (void)
/* Leave the current lexical level */
{
+ /* If this is a scope that allows to emit data into segments, close the
+ ** open the spans.
+ */
+ if (CurrentScope->Type <= SCOPE_HAS_DATA) {
+ CloseSpanList (&CurrentScope->Spans);
+ }
+
+ /* If we have spans, the first one is the segment that was active, when the
+ ** scope was opened. Set the size of the scope to the number of data bytes
+ ** emitted into this segment. If we have an owner symbol set the size of
+ ** this symbol, too.
+ */
+ if (CollCount (&CurrentScope->Spans) > 0) {
+ const Span* S = CollAtUnchecked (&CurrentScope->Spans, 0);
+ unsigned long Size = GetSpanSize (S);
+ DefSizeOfScope (CurrentScope, Size);
+ if (CurrentScope->Label) {
+ DefSizeOfSymbol (CurrentScope->Label, Size);
+ }
+ }
+
+ /* Mark the scope as closed */
+ CurrentScope->Flags |= ST_CLOSED;
+
+ /* Leave the scope */
CurrentScope = CurrentScope->Parent;
}
-SymTable* SymFindScope (SymTable* Parent, const char* Name, int AllocNew)
+SymTable* SymFindScope (SymTable* Parent, const StrBuf* Name, SymFindAction Action)
/* Find a scope in the given enclosing scope */
{
SymTable** T = &Parent->Childs;
while (*T) {
- int Cmp = strcmp (Name, GetString ((*T)->Name));
+ int Cmp = SB_Compare (Name, GetStrBuf ((*T)->Name));
if (Cmp < 0) {
T = &(*T)->Left;
} else if (Cmp > 0) {
}
/* Create a new scope if requested and we didn't find one */
- if (*T == 0 && AllocNew) {
+ if (*T == 0 && (Action & SYM_ALLOC_NEW) != 0) {
*T = NewSymTable (Parent, Name);
}
-SymEntry* SymFind (SymTable* Scope, const char* Name, int AllocNew)
-/* Find a new symbol table entry in the given table. If AllocNew is given and
- * the entry is not found, create a new one. Return the entry found, or the
- * new entry created, or - in case AllocNew is zero - return 0.
- */
+SymTable* SymFindAnyScope (SymTable* Parent, const StrBuf* Name)
+/* Find a scope in the given or any of its parent scopes. The function will
+** never create a new symbol, since this can only be done in one specific
+** scope.
+*/
+{
+ SymTable* Scope;
+ do {
+ /* Search in the current table */
+ Scope = SymFindScope (Parent, Name, SYM_FIND_EXISTING);
+ if (Scope == 0) {
+ /* Not found, search in the parent scope, if we have one */
+ Parent = Parent->Parent;
+ }
+ } while (Scope == 0 && Parent != 0);
+
+ return Scope;
+}
+
+
+
+SymEntry* SymFindLocal (SymEntry* Parent, const StrBuf* Name, SymFindAction Action)
+/* Find a cheap local symbol. If Action contains SYM_ALLOC_NEW and the entry is
+** not found, create a new one. Return the entry found, or the new entry
+** created, or - in case Action is SYM_FIND_EXISTING - return 0.
+*/
+
{
SymEntry* S;
int Cmp;
- if (IsLocalName (Name)) {
-
- /* Local symbol, get the table */
- if (!SymLast) {
- /* No last global, so there's no local table */
- Error ("No preceeding global symbol");
- if (AllocNew) {
- return NewSymEntry (Name);
- } else {
- return 0;
- }
- }
-
- /* Search for the symbol if we have a table */
- Cmp = SearchSymTree (SymLast->Locals, Name, &S);
-
- /* If we found an entry, return it */
- if (Cmp == 0) {
- return S;
- }
-
- if (AllocNew) {
-
- /* Otherwise create a new entry, insert and return it */
- SymEntry* N = NewSymEntry (Name);
- if (S == 0) {
- SymLast->Locals = N;
- } else if (Cmp < 0) {
- S->Left = N;
- } else {
- S->Right = N;
- }
- return N;
- }
+ /* Local symbol, get the table */
+ if (!Parent) {
+ /* No last global, so there's no local table */
+ Error ("No preceeding global symbol");
+ if (Action & SYM_ALLOC_NEW) {
+ return NewSymEntry (Name, SF_LOCAL);
+ } else {
+ return 0;
+ }
+ }
- } else {
+ /* Search for the symbol if we have a table */
+ Cmp = SymSearchTree (Parent->Locals, Name, &S);
- /* Global symbol: Get the hash value for the name */
- unsigned Hash = HashStr (Name) % Scope->TableSlots;
-
- /* Search for the entry */
- Cmp = SearchSymTree (Scope->Table[Hash], Name, &S);
-
- /* If we found an entry, return it */
- if (Cmp == 0) {
- /* Check for a trampoline entry, in this case return the real
- * symbol.
- */
- while (S->Flags & SF_TRAMPOLINE) {
- S = S->V.Sym;
- }
- return S;
- }
-
- if (AllocNew) {
-
- /* Otherwise create a new entry, insert and return it */
- SymEntry* N = NewSymEntry (Name);
- if (S == 0) {
- Scope->Table[Hash] = N;
- } else if (Cmp < 0) {
- S->Left = N;
- } else {
- S->Right = N;
- }
- N->SymTab = Scope;
- ++Scope->TableEntries;
- return N;
-
- }
+ /* If we found an entry, return it */
+ if (Cmp == 0) {
+ return S;
+ }
+
+ if (Action & SYM_ALLOC_NEW) {
+
+ /* Otherwise create a new entry, insert and return it */
+ SymEntry* N = NewSymEntry (Name, SF_LOCAL);
+ N->Sym.Entry = Parent;
+ if (S == 0) {
+ Parent->Locals = N;
+ } else if (Cmp < 0) {
+ S->Left = N;
+ } else {
+ S->Right = N;
+ }
+ return N;
}
/* We did not find the entry and AllocNew is false. */
-static SymEntry* SymFindAny (SymTable* Scope, const char* Name)
-/* Find a symbol in the given or any of its parent scopes. The function will
- * never create a new symbol, since this can only be done in one specific
- * scope.
- */
+SymEntry* SymFind (SymTable* Scope, const StrBuf* Name, SymFindAction Action)
+/* Find a new symbol table entry in the given table. If Action contains
+** SYM_ALLOC_NEW and the entry is not found, create a new one. Return the
+** entry found, or the new entry created, or - in case Action is
+** SYM_FIND_EXISTING - return 0.
+*/
{
- SymEntry* Sym;
- do {
- /* Search in the current table */
- Sym = SymFind (Scope, Name, SYM_FIND_EXISTING);
- if (Sym) {
- /* Found, return it */
- return Sym;
- } else {
- /* Not found, search in the parent scope, if we have one */
- Scope = Scope->Parent;
- }
- } while (Sym == 0 && Scope != 0);
-
- /* Not found */
- return 0;
-}
+ SymEntry* S;
+ /* Global symbol: Get the hash value for the name */
+ unsigned Hash = HashBuf (Name) % Scope->TableSlots;
+ /* Search for the entry */
+ int Cmp = SymSearchTree (Scope->Table[Hash], Name, &S);
-int SymIsZP (SymEntry* S)
-/* Return true if the symbol is explicitly marked as zeropage symbol */
-{
- /* Resolve trampoline entries */
- if (S->Flags & SF_TRAMPOLINE) {
- S = S->V.Sym;
+ /* If we found an entry, return it */
+ if (Cmp == 0) {
+ if ((Action & SYM_CHECK_ONLY) == 0 && SymTabIsClosed (Scope)) {
+ S->Flags |= SF_FIXED;
+ }
+ return S;
}
- /* If the symbol is not a global symbol, was not defined before, check the
- * enclosing scope for a symbol with the same name, and return the ZP
- * attribute of this symbol if we find one.
- */
- if (!IsLocalNameId (S->Name) && (S->Flags & (SF_DEFINED | SF_IMPORT)) == 0 &&
- S->SymTab->Parent != 0) {
+ if (Action & SYM_ALLOC_NEW) {
- /* Try to find a symbol with the same name in the enclosing scope */
- SymEntry* E = SymFindAny (S->SymTab->Parent, GetString (S->Name));
+ /* Otherwise create a new entry, insert and return it. If the scope is
+ ** already closed, mark the symbol as fixed so it won't be resolved
+ ** by a symbol in the enclosing scopes later.
+ */
+ SymEntry* N = NewSymEntry (Name, SF_NONE);
+ if (SymTabIsClosed (Scope)) {
+ N->Flags |= SF_FIXED;
+ }
+ N->Sym.Tab = Scope;
+ if (S == 0) {
+ Scope->Table[Hash] = N;
+ } else if (Cmp < 0) {
+ S->Left = N;
+ } else {
+ S->Right = N;
+ }
+ ++Scope->TableEntries;
+ return N;
- /* If we found one, use the ZP flag */
- if (E && E->AddrSize == ADDR_SIZE_ZP) {
- S->AddrSize = ADDR_SIZE_ZP;
- }
}
- /* Check the ZP flag */
- return (S->AddrSize == ADDR_SIZE_ZP);
+ /* We did not find the entry and AllocNew is false. */
+ return 0;
}
-unsigned char GetCurrentSymTabType ()
-/* Return the type of the current symbol table */
+SymEntry* SymFindAny (SymTable* Scope, const StrBuf* Name)
+/* Find a symbol in the given or any of its parent scopes. The function will
+** never create a new symbol, since this can only be done in one specific
+** scope.
+*/
{
- CHECK (CurrentScope != 0);
- return CurrentScope->Type;
+ /* Generate the name hash */
+ unsigned Hash = HashBuf (Name);
+
+ /* Search for the symbol */
+ SymEntry* Sym;
+ do {
+ /* Search in the current table. Ignore entries flagged with SF_UNUSED,
+ ** because for such symbols there is a real entry in one of the parent
+ ** scopes.
+ */
+ if (SymSearchTree (Scope->Table[Hash % Scope->TableSlots], Name, &Sym) == 0) {
+ if (Sym->Flags & SF_UNUSED) {
+ Sym = 0;
+ } else {
+ /* Found, return it */
+ break;
+ }
+ } else {
+ Sym = 0;
+ }
+
+ /* Not found, search in the parent scope, if we have one */
+ Scope = Scope->Parent;
+
+ } while (Sym == 0 && Scope != 0);
+
+ /* Return the result */
+ return Sym;
}
/* Handle an undefined symbol */
{
/* Undefined symbol. It may be...
- *
- * - An undefined symbol in a nested lexical level. In this
- * case, search for the symbol in the higher levels and
- * make the entry a trampoline entry if we find one.
- *
- * - If the symbol is not found, it is a real undefined symbol.
- * If the AutoImport flag is set, make it an import. If the
- * AutoImport flag is not set, it's an error.
- */
+ **
+ ** - An undefined symbol in a nested lexical level. If the symbol is not
+ ** fixed to this level, search for the symbol in the higher levels and
+ ** make the entry a trampoline entry if we find one.
+ **
+ ** - If the symbol is not found, it is a real undefined symbol. If the
+ ** AutoImport flag is set, make it an import. If the AutoImport flag is
+ ** not set, it's an error.
+ */
SymEntry* Sym = 0;
- if (S->SymTab) {
- /* It's a global symbol, get the higher level table */
- SymTable* Tab = S->SymTab->Parent;
- while (Tab) {
- Sym = SymFindAny (Tab, GetString (S->Name));
- if (Sym) {
- if (Sym->Flags & (SF_DEFINED | SF_IMPORT)) {
- /* We've found a symbol in a higher level that is
- * either defined in the source, or an import.
- */
- break;
- } else {
- /* The symbol found is undefined itself. Look further */
- Tab = Sym->SymTab->Parent;
- }
- } else {
- /* No symbol found */
- break;
- }
- }
+ if ((S->Flags & SF_FIXED) == 0) {
+ SymTable* Tab = GetSymParentScope (S);
+ while (Tab) {
+ Sym = SymFind (Tab, GetStrBuf (S->Name), SYM_FIND_EXISTING | SYM_CHECK_ONLY);
+ if (Sym && (Sym->Flags & (SF_DEFINED | SF_IMPORT)) != 0) {
+ /* We've found a symbol in a higher level that is
+ ** either defined in the source, or an import.
+ */
+ break;
+ }
+ /* No matching symbol found in this level. Look further */
+ Tab = Tab->Parent;
+ }
}
+
if (Sym) {
- /* We found the symbol in a higher level. Make S a trampoline
- * symbol. Beware: We have to transfer the symbol attributes to
- * the real symbol and check for any conflicts.
- */
- S->Flags |= SF_TRAMPOLINE;
- S->V.Sym = Sym;
-
- /* Transfer the flags. Note: S may not be imported, since in that
- * case it wouldn't be undefined.
- */
- if (S->Flags & SF_EXPORT) {
- if (Sym->Flags & SF_IMPORT) {
- /* The symbol is already marked as imported external symbol */
- PError (&S->Pos, "Symbol `%s' is already an import", GetString (S->Name));
- }
- Sym->Flags |= (S->Flags & SF_EXPORT);
- Sym->ExportSize = S->ExportSize;
- }
-
- /* Transfer the referenced flag */
- Sym->Flags |= (S->Flags & SF_REFERENCED);
+
+ /* We found the symbol in a higher level. Transfer the flags and
+ ** address size from the local symbol to that in the higher level
+ ** and check for problems.
+ */
+ if (S->Flags & SF_EXPORT) {
+ if (Sym->Flags & SF_IMPORT) {
+ /* The symbol is already marked as import */
+ LIError (&S->RefLines,
+ "Symbol `%s' is already an import",
+ GetString (Sym->Name));
+ }
+ if ((Sym->Flags & SF_EXPORT) == 0) {
+ /* Mark the symbol as an export */
+ Sym->Flags |= SF_EXPORT;
+ Sym->ExportSize = S->ExportSize;
+ if (Sym->ExportSize == ADDR_SIZE_DEFAULT) {
+ /* Use the actual size of the symbol */
+ Sym->ExportSize = Sym->AddrSize;
+ }
+ if (Sym->AddrSize > Sym->ExportSize) {
+ /* We're exporting a symbol smaller than it actually is */
+ LIWarning (&Sym->DefLines, 1,
+ "Symbol `%m%p' is %s but exported %s",
+ GetSymName (Sym),
+ AddrSizeToStr (Sym->AddrSize),
+ AddrSizeToStr (Sym->ExportSize));
+ }
+ }
+ }
+ if (S->Flags & SF_REFERENCED) {
+ /* Mark as referenced and move the line info */
+ Sym->Flags |= SF_REFERENCED;
+ CollTransfer (&Sym->RefLines, &S->RefLines);
+ CollDeleteAll (&S->RefLines);
+ }
+
+ /* Transfer all expression references */
+ SymTransferExprRefs (S, Sym);
+
+ /* Mark the symbol as unused removing all other flags */
+ S->Flags = SF_UNUSED;
} else {
- /* The symbol is definitely undefined */
- if (S->Flags & SF_EXPORT) {
- /* We will not auto-import an export */
- PError (&S->Pos, "Exported symbol `%s' was never defined",
- GetString (S->Name));
- } else {
- if (AutoImport) {
- /* Mark as import, will be indexed later */
- S->Flags |= SF_IMPORT;
- } else {
- /* Error */
- PError (&S->Pos, "Symbol `%s' is undefined", GetString (S->Name));
- }
- }
+ /* The symbol is definitely undefined */
+ if (S->Flags & SF_EXPORT) {
+ /* We will not auto-import an export */
+ LIError (&S->RefLines,
+ "Exported symbol `%m%p' was never defined",
+ GetSymName (S));
+ } else {
+ if (AutoImport) {
+ /* Mark as import, will be indexed later */
+ S->Flags |= SF_IMPORT;
+ /* Use the address size for code */
+ S->AddrSize = CodeAddrSize;
+ /* Mark point of import */
+ GetFullLineInfo (&S->DefLines);
+ } else {
+ /* Error */
+ LIError (&S->RefLines,
+ "Symbol `%m%p' is undefined",
+ GetSymName (S));
+ }
+ }
}
}
/* Check for open scopes */
if (CurrentScope->Parent != 0) {
- Error ("Local scope was not closed");
+ Error ("Local scope was not closed");
}
/* First pass: Walk through all symbols, checking for undefined's and
- * changing them to trampoline symbols or make them imports.
- */
+ ** changing them to trampoline symbols or make them imports.
+ */
S = SymList;
while (S) {
- /* If the symbol is marked as global, mark it as export, if it is
- * already defined, otherwise mark it as import.
- */
- if (S->Flags & SF_GLOBAL) {
- S->Flags &= ~SF_GLOBAL;
- if (S->Flags & SF_DEFINED) {
- S->Flags |= SF_EXPORT;
- } else {
- S->Flags |= SF_IMPORT;
- }
- }
-
- /* Handle undefined symbols */
- if ((S->Flags & SF_UNDEFMASK) == SF_UNDEFVAL) {
- /* This is an undefined symbol. Handle it. */
- SymCheckUndefined (S);
- }
-
- /* Next symbol */
- S = S->List;
+ /* If the symbol is marked as global, mark it as export, if it is
+ ** already defined, otherwise mark it as import.
+ */
+ if (S->Flags & SF_GLOBAL) {
+ if (S->Flags & SF_DEFINED) {
+ SymExportFromGlobal (S);
+ } else {
+ SymImportFromGlobal (S);
+ }
+ }
+
+ /* Handle undefined symbols */
+ if ((S->Flags & SF_UNDEFMASK) == SF_UNDEFVAL) {
+ /* This is an undefined symbol. Handle it. */
+ SymCheckUndefined (S);
+ }
+
+ /* Next symbol */
+ S = S->List;
}
- /* Second pass: Walk again through the symbols. Ignore undefined's, since
- * we handled them in the last pass, and ignore trampoline symbols, since
- * we handled them in the last pass, too.
- */
+ /* Second pass: Walk again through the symbols. Count exports and imports
+ ** and set address sizes where this has not happened before. Ignore
+ ** undefined's, since we handled them in the last pass, and ignore unused
+ ** symbols, since we handled them in the last pass, too.
+ */
S = SymList;
while (S) {
- if ((S->Flags & SF_TRAMPOLINE) == 0 &&
- (S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) {
- if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) {
- /* Symbol was defined but never referenced */
- PWarning (&S->Pos, 2,
- "Symbol `%s' is defined but never used",
- GetString (S->Name));
- }
- if (S->Flags & SF_IMPORT) {
- if ((S->Flags & (SF_REFERENCED | SF_FORCED)) == SF_NONE) {
- /* Imported symbol is not referenced */
- PWarning (&S->Pos, 2,
- "Symbol `%s' is imported but never used",
- GetString (S->Name));
- } else {
- /* Give the import an index, count imports */
- S->Index = ImportCount++;
- S->Flags |= SF_INDEXED;
- }
- }
- if (S->Flags & SF_EXPORT) {
- /* Give the export an index, count exports */
- S->Index = ExportCount++;
- S->Flags |= SF_INDEXED;
- }
- }
-
- /* Next symbol */
- S = S->List;
+ if ((S->Flags & SF_UNUSED) == 0 &&
+ (S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) {
+
+ /* Check for defined symbols that were never referenced */
+ if (IsSizeOfSymbol (S)) {
+ /* Remove line infos, we don't need them any longer */
+ ReleaseFullLineInfo (&S->DefLines);
+ ReleaseFullLineInfo (&S->RefLines);
+ } else if ((S->Flags & SF_DEFINED) != 0 && (S->Flags & SF_REFERENCED) == 0) {
+ LIWarning (&S->DefLines, 2,
+ "Symbol `%m%p' is defined but never used",
+ GetSymName (S));
+ }
+
+ /* Assign an index to all imports */
+ if (S->Flags & SF_IMPORT) {
+ if ((S->Flags & (SF_REFERENCED | SF_FORCED)) == SF_NONE) {
+ /* Imported symbol is not referenced */
+ LIWarning (&S->DefLines, 2,
+ "Symbol `%m%p' is imported but never used",
+ GetSymName (S));
+ } else {
+ /* Give the import an id, count imports */
+ S->ImportId = ImportCount++;
+ }
+ }
+
+ /* Count exports, assign the export ID */
+ if (S->Flags & SF_EXPORT) {
+ S->ExportId = ExportCount++;
+ }
+
+ /* If the symbol is defined but has an unknown address size,
+ ** recalculate it.
+ */
+ if (SymHasExpr (S) && S->AddrSize == ADDR_SIZE_DEFAULT) {
+ ExprDesc ED;
+ ED_Init (&ED);
+ StudyExpr (S->Expr, &ED);
+ S->AddrSize = ED.AddrSize;
+ if (SymIsExport (S)) {
+ if (S->ExportSize == ADDR_SIZE_DEFAULT) {
+ /* Use the real export size */
+ S->ExportSize = S->AddrSize;
+ } else if (S->AddrSize > S->ExportSize) {
+ /* We're exporting a symbol smaller than it actually is */
+ LIWarning (&S->DefLines, 1,
+ "Symbol `%m%p' is %s but exported %s",
+ GetSymName (S),
+ AddrSizeToStr (S->AddrSize),
+ AddrSizeToStr (S->ExportSize));
+ }
+ }
+ ED_Done (&ED);
+ }
+
+ /* If the address size of the symbol was guessed, check the guess
+ ** against the actual address size and print a warning if the two
+ ** differ.
+ */
+ if (S->AddrSize != ADDR_SIZE_DEFAULT) {
+ /* Do we have data for this address size? */
+ if (S->AddrSize <= sizeof (S->GuessedUse) / sizeof (S->GuessedUse[0])) {
+ /* Get the file position where the symbol was used */
+ const FilePos* P = S->GuessedUse[S->AddrSize - 1];
+ if (P) {
+ PWarning (P, 0,
+ "Didn't use %s addressing for `%m%p'",
+ AddrSizeToStr (S->AddrSize),
+ GetSymName (S));
+ }
+ }
+ }
+
+ }
+
+ /* Next symbol */
+ S = S->List;
}
}
SymEntry* S = SymList;
while (S) {
- /* Ignore trampoline symbols */
- if ((S->Flags & SF_TRAMPOLINE) != 0) {
- fprintf (F,
- "%-24s %s %s %s %s %s\n",
- GetString (S->Name),
- (S->Flags & SF_DEFINED)? "DEF" : "---",
- (S->Flags & SF_REFERENCED)? "REF" : "---",
- (S->Flags & SF_IMPORT)? "IMP" : "---",
- (S->Flags & SF_EXPORT)? "EXP" : "---",
+ /* Ignore unused symbols */
+ if ((S->Flags & SF_UNUSED) == 0) {
+ fprintf (F,
+ "%-24s %s %s %s %s %s\n",
+ SB_GetConstBuf (GetSymName (S)),
+ (S->Flags & SF_DEFINED)? "DEF" : "---",
+ (S->Flags & SF_REFERENCED)? "REF" : "---",
+ (S->Flags & SF_IMPORT)? "IMP" : "---",
+ (S->Flags & SF_EXPORT)? "EXP" : "---",
AddrSizeToStr (S->AddrSize));
- }
- /* Next symbol */
- S = S->List;
+ }
+ /* Next symbol */
+ S = S->List;
}
}
ObjWriteVar (ImportCount);
/* Walk throught list and write all valid imports to the file. An import
- * is considered valid, if it is either referenced, or the forced bit is
- * set. Otherwise, the import is ignored (no need to link in something
- * that isn't used).
- */
+ ** is considered valid, if it is either referenced, or the forced bit is
+ ** set. Otherwise, the import is ignored (no need to link in something
+ ** that isn't used).
+ */
S = SymList;
while (S) {
- if ((S->Flags & (SF_TRAMPOLINE | SF_IMPORT)) == SF_IMPORT &&
+ if ((S->Flags & (SF_UNUSED | SF_IMPORT)) == SF_IMPORT &&
(S->Flags & (SF_REFERENCED | SF_FORCED)) != 0) {
- if (S->AddrSize == ADDR_SIZE_ZP) {
- ObjWrite8 (IMP_ZP);
- } else {
- ObjWrite8 (IMP_ABS);
- }
- ObjWriteVar (S->Name);
- ObjWritePos (&S->Pos);
- }
- S = S->List;
+ ObjWrite8 (S->AddrSize);
+ ObjWriteVar (S->Name);
+ WriteLineInfo (&S->DefLines);
+ WriteLineInfo (&S->RefLines);
+ }
+ S = S->List;
}
/* Done writing imports */
/* Walk throught list and write all exports to the file */
S = SymList;
while (S) {
- if ((S->Flags & SF_EXPMASK) == SF_EXPVAL) {
+ if ((S->Flags & (SF_UNUSED | SF_EXPORT)) == SF_EXPORT) {
+ /* Get the expression bits and the value */
long ConstVal;
+ unsigned SymFlags = GetSymInfoFlags (S, &ConstVal);
+
+ /* Check if this symbol has a size. If so, remember it in the
+ ** flags.
+ */
+ long Size;
+ SymEntry* SizeSym = FindSizeOfSymbol (S);
+ if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) {
+ SymFlags |= SYM_SIZE;
+ }
- /* Get the expression bits */
- unsigned char ExprMask = SymIsConst (S, &ConstVal)? EXP_CONST : EXP_EXPR;
- ExprMask |= (S->ExportSize == ADDR_SIZE_ZP)? EXP_ZP : EXP_ABS;
- ExprMask |= (S->Flags & SF_LABEL)? EXP_LABEL : EXP_EQUATE;
-
- /* Count the number of ConDes types */
- for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
- if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
- INC_EXP_CONDES_COUNT (ExprMask);
- }
- }
-
- /* Write the type */
- ObjWrite8 (ExprMask);
-
- /* Write any ConDes declarations */
- if (GET_EXP_CONDES_COUNT (ExprMask) > 0) {
- for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
- unsigned char Prio = S->ConDesPrio[Type];
- if (Prio != CD_PRIO_NONE) {
- ObjWrite8 (CD_BUILD (Type, Prio));
- }
- }
- }
-
- /* Write the name */
- ObjWriteVar (S->Name);
-
- /* Write the value */
- if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) {
- /* Constant value */
- ObjWrite32 (ConstVal);
- } else {
- /* Expression involved */
- WriteExpr (S->V.Expr);
+ /* Count the number of ConDes types */
+ for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
+ if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
+ SYM_INC_CONDES_COUNT (SymFlags);
+ }
+ }
+
+ /* Write the type and the export size */
+ ObjWriteVar (SymFlags);
+ ObjWrite8 (S->ExportSize);
+
+ /* Write any ConDes declarations */
+ if (SYM_GET_CONDES_COUNT (SymFlags) > 0) {
+ for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
+ unsigned char Prio = S->ConDesPrio[Type];
+ if (Prio != CD_PRIO_NONE) {
+ ObjWrite8 (CD_BUILD (Type, Prio));
+ }
+ }
}
- /* Write the source file position */
- ObjWritePos (&S->Pos);
- }
- S = S->List;
+ /* Write the name */
+ ObjWriteVar (S->Name);
+
+ /* Write the value */
+ if (SYM_IS_CONST (SymFlags)) {
+ /* Constant value */
+ ObjWrite32 (ConstVal);
+ } else {
+ /* Expression involved */
+ WriteExpr (S->Expr);
+ }
+
+ /* If the symbol has a size, write it to the file */
+ if (SYM_HAS_SIZE (SymFlags)) {
+ ObjWriteVar (Size);
+ }
+
+ /* Write the line infos */
+ WriteLineInfo (&S->DefLines);
+ WriteLineInfo (&S->RefLines);
+ }
+ S = S->List;
}
/* Done writing exports */
/* Check if debug info is requested */
if (DbgSyms) {
- /* Walk through the list and count the symbols */
- Count = 0;
- S = SymList;
- while (S) {
- if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
- ++Count;
- }
- S = S->List;
- }
+ /* Walk through the list, give each symbol an id and count them */
+ Count = 0;
+ S = SymList;
+ while (S) {
+ if (IsDbgSym (S)) {
+ S->DebugSymId = Count++;
+ }
+ S = S->List;
+ }
- /* Write the symbol count to the list */
- ObjWriteVar (Count);
+ /* Write the symbol count to the list */
+ ObjWriteVar (Count);
- /* Walk through list and write all symbols to the file */
- S = SymList;
- while (S) {
- if ((S->Flags & SF_DBGINFOMASK) == SF_DBGINFOVAL) {
+ /* Walk through list and write all symbols to the file. Ignore size
+ ** symbols.
+ */
+ S = SymList;
+ while (S) {
+ if (IsDbgSym (S)) {
+ /* Get the expression bits and the value */
long ConstVal;
+ unsigned SymFlags = GetSymInfoFlags (S, &ConstVal);
+
+ /* Check if this symbol has a size. If so, remember it in the
+ ** flags.
+ */
+ long Size;
+ SymEntry* SizeSym = FindSizeOfSymbol (S);
+ if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) {
+ SymFlags |= SYM_SIZE;
+ }
- /* Get the expression bits */
- unsigned char ExprMask = (SymIsConst (S, &ConstVal))? EXP_CONST : EXP_EXPR;
- ExprMask |= (S->AddrSize == ADDR_SIZE_ZP)? EXP_ZP : EXP_ABS;
- ExprMask |= (S->Flags & SF_LABEL)? EXP_LABEL : EXP_EQUATE;
+ /* Write the type */
+ ObjWriteVar (SymFlags);
- /* Write the type */
- ObjWrite8 (ExprMask);
+ /* Write the address size */
+ ObjWrite8 (S->AddrSize);
- /* Write the name */
- ObjWriteVar (S->Name);
+ /* Write the id of the parent. For normal symbols, this is a
+ ** scope (symbol table), for cheap locals, it's a symbol.
+ */
+ if (SYM_IS_STD (SymFlags)) {
+ ObjWriteVar (S->Sym.Tab->Id);
+ } else {
+ ObjWriteVar (S->Sym.Entry->DebugSymId);
+ }
+
+ /* Write the name */
+ ObjWriteVar (S->Name);
+
+ /* Write the value */
+ if (SYM_IS_CONST (SymFlags)) {
+ /* Constant value */
+ ObjWrite32 (ConstVal);
+ } else {
+ /* Expression involved */
+ WriteExpr (S->Expr);
+ }
- /* Write the value */
- if ((ExprMask & EXP_MASK_VAL) == EXP_CONST) {
- /* Constant value */
- ObjWrite32 (ConstVal);
- } else {
- /* Expression involved */
- WriteExpr (S->V.Expr);
- }
+ /* If the symbol has a size, write it to the file */
+ if (SYM_HAS_SIZE (SymFlags)) {
+ ObjWriteVar (Size);
+ }
- /* Write the source file position */
- ObjWritePos (&S->Pos);
- }
- S = S->List;
- }
+ /* If the symbol is an im- or export, write out the ids */
+ if (SYM_IS_IMPORT (SymFlags)) {
+ ObjWriteVar (GetSymImportId (S));
+ }
+ if (SYM_IS_EXPORT (SymFlags)) {
+ ObjWriteVar (GetSymExportId (S));
+ }
+
+ /* Write the line infos */
+ WriteLineInfo (&S->DefLines);
+ WriteLineInfo (&S->RefLines);
+ }
+ S = S->List;
+ }
} else {
- /* No debug symbols */
- ObjWriteVar (0);
+ /* No debug symbols */
+ ObjWriteVar (0);
}
+ /* Write the high level symbols */
+ WriteHLLDbgSyms ();
+
/* Done writing debug symbols */
ObjEndDbgSyms ();
}
+void WriteScopes (void)
+/* Write the scope table to the object file */
+{
+ /* Tell the object file module that we're about to start the scopes */
+ ObjStartScopes ();
+
+ /* We will write scopes only if debug symbols are requested */
+ if (DbgSyms) {
+
+ /* Get head of list */
+ SymTable* S = RootScope;
+
+ /* Write the scope count to the file */
+ ObjWriteVar (ScopeCount);
+
+ /* Walk through all scopes and write them to the file */
+ while (S) {
+
+ /* Flags for this scope */
+ unsigned Flags = 0;
+
+ /* Check if this scope has a size. If so, remember it in the
+ ** flags.
+ */
+ long Size;
+ SymEntry* SizeSym = FindSizeOfScope (S);
+ if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) {
+ Flags |= SCOPE_SIZE;
+ }
+
+ /* Check if the scope has a label */
+ if (S->Label) {
+ Flags |= SCOPE_LABELED;
+ }
+
+ /* Scope must be defined */
+ CHECK (S->Type != SCOPE_UNDEF);
+
+ /* Id of parent scope */
+ if (S->Parent) {
+ ObjWriteVar (S->Parent->Id);
+ } else {
+ ObjWriteVar (0);
+ }
+
+ /* Lexical level */
+ ObjWriteVar (S->Level);
+ /* Scope flags */
+ ObjWriteVar (Flags);
+ /* Type of scope */
+ ObjWriteVar (S->Type);
+
+ /* Name of the scope */
+ ObjWriteVar (S->Name);
+
+ /* If the scope has a size, write it to the file */
+ if (SCOPE_HAS_SIZE (Flags)) {
+ ObjWriteVar (Size);
+ }
+
+ /* If the scope has a label, write its id to the file */
+ if (SCOPE_HAS_LABEL (Flags)) {
+ ObjWriteVar (S->Label->DebugSymId);
+ }
+
+ /* Spans for this scope */
+ WriteSpanList (&S->Spans);
+
+ /* Next scope */
+ S = S->Next;
+ }
+
+ } else {
+
+ /* No debug info requested */
+ ObjWriteVar (0);
+
+ }
+
+ /* Done writing the scopes */
+ ObjEndScopes ();
+}