2000-05-28 13:40:48 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* */
|
2013-05-09 11:56:54 +00:00
|
|
|
/* symtab.c */
|
2000-05-28 13:40:48 +00:00
|
|
|
/* */
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Symbol table for the ca65 macroassembler */
|
2000-05-28 13:40:48 +00:00
|
|
|
/* */
|
|
|
|
/* */
|
|
|
|
/* */
|
2014-05-12 06:08:04 +00:00
|
|
|
/* (C) 1998-2014, Ullrich von Bassewitz */
|
2010-08-17 16:58:41 +00:00
|
|
|
/* Roemerstrasse 52 */
|
|
|
|
/* D-70794 Filderstadt */
|
|
|
|
/* EMail: uz@cc65.org */
|
2000-05-28 13:40:48 +00:00
|
|
|
/* */
|
|
|
|
/* */
|
|
|
|
/* This software is provided 'as-is', without any expressed or implied */
|
|
|
|
/* warranty. In no event will the authors be held liable for any damages */
|
|
|
|
/* arising from the use of this software. */
|
|
|
|
/* */
|
|
|
|
/* Permission is granted to anyone to use this software for any purpose, */
|
|
|
|
/* including commercial applications, and to alter it and redistribute it */
|
|
|
|
/* freely, subject to the following restrictions: */
|
|
|
|
/* */
|
|
|
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
|
|
|
/* claim that you wrote the original software. If you use this software */
|
|
|
|
/* in a product, an acknowledgment in the product documentation would be */
|
|
|
|
/* appreciated but is not required. */
|
|
|
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
|
|
|
/* be misrepresented as being the original software. */
|
|
|
|
/* 3. This notice may not be removed or altered from any source */
|
|
|
|
/* distribution. */
|
|
|
|
/* */
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
2000-07-30 21:27:37 +00:00
|
|
|
/* common */
|
2003-11-07 19:28:37 +00:00
|
|
|
#include "addrsize.h"
|
2000-08-01 15:17:43 +00:00
|
|
|
#include "check.h"
|
2011-08-12 16:22:28 +00:00
|
|
|
#include "hashfunc.h"
|
2003-11-28 22:12:14 +00:00
|
|
|
#include "mmodel.h"
|
2011-07-31 14:01:11 +00:00
|
|
|
#include "scopedefs.h"
|
2000-08-01 15:17:43 +00:00
|
|
|
#include "symdefs.h"
|
2000-07-30 21:27:37 +00:00
|
|
|
#include "xmalloc.h"
|
2000-08-01 15:17:43 +00:00
|
|
|
|
2000-07-30 21:27:37 +00:00
|
|
|
/* ca65 */
|
2011-08-29 20:02:06 +00:00
|
|
|
#include "dbginfo.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
#include "error.h"
|
|
|
|
#include "expr.h"
|
2011-08-29 20:02:06 +00:00
|
|
|
#include "global.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
#include "objfile.h"
|
2000-08-02 14:12:36 +00:00
|
|
|
#include "scanner.h"
|
2003-11-08 17:20:21 +00:00
|
|
|
#include "segment.h"
|
2003-12-06 14:16:27 +00:00
|
|
|
#include "sizeof.h"
|
2011-08-04 12:49:59 +00:00
|
|
|
#include "span.h"
|
2003-05-25 17:57:50 +00:00
|
|
|
#include "spool.h"
|
2003-12-13 20:56:31 +00:00
|
|
|
#include "studyexpr.h"
|
2000-05-28 13:40:48 +00:00
|
|
|
#include "symtab.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Data */
|
2000-05-28 13:40:48 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-10-22 21:24:37 +00:00
|
|
|
/* Combined symbol entry flags used within this module */
|
2013-05-09 11:56:54 +00:00
|
|
|
#define SF_UNDEFMASK (SF_REFERENCED | SF_DEFINED | SF_IMPORT)
|
|
|
|
#define SF_UNDEFVAL (SF_REFERENCED)
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2003-11-06 11:22:31 +00:00
|
|
|
/* Symbol tables */
|
2013-05-09 11:56:54 +00:00
|
|
|
SymTable* CurrentScope = 0; /* Pointer to current symbol table */
|
|
|
|
SymTable* RootScope = 0; /* Root symbol table */
|
2010-08-17 16:58:41 +00:00
|
|
|
static SymTable* LastScope = 0; /* Pointer to last scope in list */
|
2011-07-31 12:25:02 +00:00
|
|
|
static unsigned ScopeCount = 0; /* Number of scopes */
|
2000-10-30 19:30:26 +00:00
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Symbol table variables */
|
2010-08-17 16:58:41 +00:00
|
|
|
static unsigned ImportCount = 0; /* Counter for import symbols */
|
|
|
|
static unsigned ExportCount = 0; /* Counter for export symbols */
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Internally used functions */
|
2000-05-28 13:40:48 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-08-16 13:39:00 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-07 19:28:37 +00:00
|
|
|
static unsigned ScopeTableSize (unsigned Level)
|
2003-10-31 20:21:48 +00:00
|
|
|
/* Get the size of a table for the given lexical level */
|
|
|
|
{
|
|
|
|
switch (Level) {
|
|
|
|
case 0: return 213;
|
|
|
|
case 1: return 53;
|
|
|
|
default: return 29;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-03-31 20:54:45 +00:00
|
|
|
static SymTable* NewSymTable (SymTable* Parent, const StrBuf* Name)
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Allocate a symbol table on the heap and return it */
|
|
|
|
{
|
2003-10-31 20:21:48 +00:00
|
|
|
/* Determine the lexical level and the number of table slots */
|
|
|
|
unsigned Level = Parent? Parent->Level + 1 : 0;
|
2003-11-07 19:28:37 +00:00
|
|
|
unsigned Slots = ScopeTableSize (Level);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Allocate memory */
|
2003-10-31 20:21:48 +00:00
|
|
|
SymTable* S = xmalloc (sizeof (SymTable) + (Slots-1) * sizeof (SymEntry*));
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Set variables and clear hash table entries */
|
2011-07-31 15:37:51 +00:00
|
|
|
S->Next = 0;
|
2003-10-31 20:21:48 +00:00
|
|
|
S->Left = 0;
|
|
|
|
S->Right = 0;
|
|
|
|
S->Childs = 0;
|
2011-08-07 18:46:56 +00:00
|
|
|
S->Label = 0;
|
2011-08-04 12:49:59 +00:00
|
|
|
S->Spans = AUTO_COLLECTION_INITIALIZER;
|
2011-07-31 15:37:51 +00:00
|
|
|
S->Id = ScopeCount++;
|
2003-11-08 17:20:21 +00:00
|
|
|
S->Flags = ST_NONE;
|
|
|
|
S->AddrSize = ADDR_SIZE_DEFAULT;
|
2011-07-31 15:37:51 +00:00
|
|
|
S->Type = SCOPE_UNDEF;
|
2003-10-31 20:21:48 +00:00
|
|
|
S->Level = Level;
|
|
|
|
S->TableSlots = Slots;
|
2000-05-28 13:40:48 +00:00
|
|
|
S->TableEntries = 0;
|
2003-10-31 20:21:48 +00:00
|
|
|
S->Parent = Parent;
|
2008-03-31 20:54:45 +00:00
|
|
|
S->Name = GetStrBufId (Name);
|
2003-10-31 20:21:48 +00:00
|
|
|
while (Slots--) {
|
2013-05-09 11:56:54 +00:00
|
|
|
S->Table[Slots] = 0;
|
2003-10-31 20:21:48 +00:00
|
|
|
}
|
|
|
|
|
2011-07-31 15:37:51 +00:00
|
|
|
/* Insert the symbol table into the list of all symbol tables */
|
2010-08-17 16:58:41 +00:00
|
|
|
if (RootScope == 0) {
|
|
|
|
RootScope = S;
|
|
|
|
} else {
|
2011-07-31 15:37:51 +00:00
|
|
|
LastScope->Next = S;
|
2010-08-17 16:58:41 +00:00
|
|
|
}
|
|
|
|
LastScope = S;
|
|
|
|
|
2003-10-31 20:21:48 +00:00
|
|
|
/* Insert the symbol table into the child tree of the parent */
|
|
|
|
if (Parent) {
|
|
|
|
SymTable* T = Parent->Childs;
|
|
|
|
if (T == 0) {
|
|
|
|
/* First entry */
|
|
|
|
Parent->Childs = S;
|
|
|
|
} else {
|
|
|
|
while (1) {
|
|
|
|
/* Choose next entry */
|
2008-03-31 20:54:45 +00:00
|
|
|
int Cmp = SB_Compare (Name, GetStrBuf (T->Name));
|
2003-11-06 11:22:31 +00:00
|
|
|
if (Cmp < 0) {
|
2003-10-31 20:21:48 +00:00
|
|
|
if (T->Left) {
|
|
|
|
T = T->Left;
|
|
|
|
} else {
|
|
|
|
T->Left = S;
|
|
|
|
break;
|
|
|
|
}
|
2003-11-06 11:22:31 +00:00
|
|
|
} else if (Cmp > 0) {
|
2003-10-31 20:21:48 +00:00
|
|
|
if (T->Right) {
|
|
|
|
T = T->Right;
|
|
|
|
} else {
|
|
|
|
T->Right = S;
|
|
|
|
break;
|
2011-07-31 12:25:02 +00:00
|
|
|
}
|
2003-10-31 20:21:48 +00:00
|
|
|
} else {
|
|
|
|
/* Duplicate scope name */
|
2008-03-31 20:54:45 +00:00
|
|
|
Internal ("Duplicate scope name: `%m%p'", Name);
|
2003-10-31 20:21:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the prepared struct */
|
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Code */
|
2000-05-28 13:40:48 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-06-13 18:43:50 +00:00
|
|
|
void SymEnterLevel (const StrBuf* ScopeName, unsigned char Type,
|
2011-08-07 18:46:56 +00:00
|
|
|
unsigned char AddrSize, SymEntry* ScopeLabel)
|
2003-11-06 11:22:31 +00:00
|
|
|
/* Enter a new lexical level */
|
|
|
|
{
|
2003-11-07 19:28:37 +00:00
|
|
|
/* Map a default address size to something real */
|
2003-11-08 17:20:21 +00:00
|
|
|
if (AddrSize == ADDR_SIZE_DEFAULT) {
|
2003-11-07 19:28:37 +00:00
|
|
|
/* Use the segment address size */
|
|
|
|
AddrSize = GetCurrentSegAddrSize ();
|
|
|
|
}
|
|
|
|
|
2003-11-09 22:50:36 +00:00
|
|
|
/* If we have a current scope, search for the given name and create a
|
2014-06-30 09:10:35 +00:00
|
|
|
** new one if it doesn't exist. If this is the root scope, just create it.
|
|
|
|
*/
|
2003-11-08 23:13:02 +00:00
|
|
|
if (CurrentScope) {
|
2003-11-13 00:21:31 +00:00
|
|
|
|
|
|
|
/* Search for the scope, create a new one */
|
2003-11-08 23:13:02 +00:00
|
|
|
CurrentScope = SymFindScope (CurrentScope, ScopeName, SYM_ALLOC_NEW);
|
2003-11-09 22:50:36 +00:00
|
|
|
|
2003-11-08 23:13:02 +00:00
|
|
|
/* Check if the scope has been defined before */
|
|
|
|
if (CurrentScope->Flags & ST_DEFINED) {
|
2008-03-31 20:54:45 +00:00
|
|
|
Error ("Duplicate scope `%m%p'", ScopeName);
|
2003-11-08 23:13:02 +00:00
|
|
|
}
|
2003-11-13 00:21:31 +00:00
|
|
|
|
2003-11-08 23:13:02 +00:00
|
|
|
} else {
|
|
|
|
CurrentScope = RootScope = NewSymTable (0, ScopeName);
|
2003-11-08 17:20:21 +00:00
|
|
|
}
|
|
|
|
|
2011-06-13 18:43:50 +00:00
|
|
|
/* Mark the scope as defined and set type, address size and owner symbol */
|
2003-11-13 00:21:31 +00:00
|
|
|
CurrentScope->Flags |= ST_DEFINED;
|
|
|
|
CurrentScope->AddrSize = AddrSize;
|
|
|
|
CurrentScope->Type = Type;
|
2011-08-07 18:46:56 +00:00
|
|
|
CurrentScope->Label = ScopeLabel;
|
2003-12-06 14:16:27 +00:00
|
|
|
|
2011-08-04 12:49:59 +00:00
|
|
|
/* If this is a scope that allows to emit data into segments, add spans
|
2014-06-30 09:10:35 +00:00
|
|
|
** 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).
|
|
|
|
*/
|
2011-07-31 15:37:51 +00:00
|
|
|
if (CurrentScope->Type <= SCOPE_HAS_DATA) {
|
2011-08-21 19:08:23 +00:00
|
|
|
OpenSpanList (&CurrentScope->Spans);
|
2003-12-06 14:16:27 +00:00
|
|
|
}
|
2003-11-06 11:22:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SymLeaveLevel (void)
|
|
|
|
/* Leave the current lexical level */
|
|
|
|
{
|
2011-08-19 15:24:11 +00:00
|
|
|
/* If this is a scope that allows to emit data into segments, close the
|
2014-06-30 09:10:35 +00:00
|
|
|
** open the spans.
|
|
|
|
*/
|
2011-08-19 15:24:11 +00:00
|
|
|
if (CurrentScope->Type <= SCOPE_HAS_DATA) {
|
2011-08-21 19:08:23 +00:00
|
|
|
CloseSpanList (&CurrentScope->Spans);
|
2011-08-19 15:24:11 +00:00
|
|
|
}
|
2003-12-06 14:16:27 +00:00
|
|
|
|
2011-08-07 18:46:56 +00:00
|
|
|
/* If we have spans, the first one is the segment that was active, when the
|
2014-06-30 09:10:35 +00:00
|
|
|
** 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.
|
|
|
|
*/
|
2011-08-04 12:49:59 +00:00
|
|
|
if (CollCount (&CurrentScope->Spans) > 0) {
|
|
|
|
const Span* S = CollAtUnchecked (&CurrentScope->Spans, 0);
|
|
|
|
unsigned long Size = GetSpanSize (S);
|
2011-06-13 18:43:50 +00:00
|
|
|
DefSizeOfScope (CurrentScope, Size);
|
2011-08-07 18:46:56 +00:00
|
|
|
if (CurrentScope->Label) {
|
|
|
|
DefSizeOfSymbol (CurrentScope->Label, Size);
|
|
|
|
}
|
2003-12-06 14:16:27 +00:00
|
|
|
}
|
|
|
|
|
2012-10-27 11:49:37 +00:00
|
|
|
/* Mark the scope as closed */
|
|
|
|
CurrentScope->Flags |= ST_CLOSED;
|
|
|
|
|
2003-12-06 14:16:27 +00:00
|
|
|
/* Leave the scope */
|
2003-11-06 11:22:31 +00:00
|
|
|
CurrentScope = CurrentScope->Parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-10-27 19:50:49 +00:00
|
|
|
SymTable* SymFindScope (SymTable* Parent, const StrBuf* Name, SymFindAction Action)
|
2003-11-06 11:22:31 +00:00
|
|
|
/* Find a scope in the given enclosing scope */
|
|
|
|
{
|
|
|
|
SymTable** T = &Parent->Childs;
|
|
|
|
while (*T) {
|
2008-03-31 20:54:45 +00:00
|
|
|
int Cmp = SB_Compare (Name, GetStrBuf ((*T)->Name));
|
2003-11-06 11:22:31 +00:00
|
|
|
if (Cmp < 0) {
|
|
|
|
T = &(*T)->Left;
|
|
|
|
} else if (Cmp > 0) {
|
|
|
|
T = &(*T)->Right;
|
|
|
|
} else {
|
|
|
|
/* Found the scope */
|
|
|
|
return *T;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a new scope if requested and we didn't find one */
|
2012-10-27 19:50:49 +00:00
|
|
|
if (*T == 0 && (Action & SYM_ALLOC_NEW) != 0) {
|
2003-11-06 11:22:31 +00:00
|
|
|
*T = NewSymTable (Parent, Name);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the scope */
|
|
|
|
return *T;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-03-31 20:54:45 +00:00
|
|
|
SymTable* SymFindAnyScope (SymTable* Parent, const StrBuf* Name)
|
2003-11-13 22:03:24 +00:00
|
|
|
/* Find a scope in the given or any of its parent scopes. The function will
|
2014-06-30 09:10:35 +00:00
|
|
|
** never create a new symbol, since this can only be done in one specific
|
|
|
|
** scope.
|
|
|
|
*/
|
2003-11-13 22:03:24 +00:00
|
|
|
{
|
|
|
|
SymTable* Scope;
|
|
|
|
do {
|
2013-05-09 11:56:54 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
2003-11-13 22:03:24 +00:00
|
|
|
} while (Scope == 0 && Parent != 0);
|
|
|
|
|
|
|
|
return Scope;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-10-27 19:50:49 +00:00
|
|
|
SymEntry* SymFindLocal (SymEntry* Parent, const StrBuf* Name, SymFindAction Action)
|
|
|
|
/* Find a cheap local symbol. If Action contains SYM_ALLOC_NEW and the entry is
|
2014-06-30 09:10:35 +00:00
|
|
|
** 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.
|
|
|
|
*/
|
2012-10-27 19:50:49 +00:00
|
|
|
|
2003-11-29 07:53:26 +00:00
|
|
|
{
|
|
|
|
SymEntry* S;
|
|
|
|
int Cmp;
|
|
|
|
|
|
|
|
/* Local symbol, get the table */
|
2003-11-30 18:41:32 +00:00
|
|
|
if (!Parent) {
|
2003-11-29 07:53:26 +00:00
|
|
|
/* No last global, so there's no local table */
|
|
|
|
Error ("No preceeding global symbol");
|
2012-10-27 19:50:49 +00:00
|
|
|
if (Action & SYM_ALLOC_NEW) {
|
2003-12-03 09:18:31 +00:00
|
|
|
return NewSymEntry (Name, SF_LOCAL);
|
2003-11-29 07:53:26 +00:00
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Search for the symbol if we have a table */
|
2003-11-30 18:41:32 +00:00
|
|
|
Cmp = SymSearchTree (Parent->Locals, Name, &S);
|
2003-11-29 07:53:26 +00:00
|
|
|
|
|
|
|
/* If we found an entry, return it */
|
|
|
|
if (Cmp == 0) {
|
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
2012-10-27 19:50:49 +00:00
|
|
|
if (Action & SYM_ALLOC_NEW) {
|
2003-11-29 07:53:26 +00:00
|
|
|
|
|
|
|
/* Otherwise create a new entry, insert and return it */
|
2003-12-03 09:18:31 +00:00
|
|
|
SymEntry* N = NewSymEntry (Name, SF_LOCAL);
|
2010-08-17 16:58:41 +00:00
|
|
|
N->Sym.Entry = Parent;
|
2003-11-29 07:53:26 +00:00
|
|
|
if (S == 0) {
|
2003-11-30 18:41:32 +00:00
|
|
|
Parent->Locals = N;
|
2003-11-29 07:53:26 +00:00
|
|
|
} else if (Cmp < 0) {
|
|
|
|
S->Left = N;
|
|
|
|
} else {
|
|
|
|
S->Right = N;
|
|
|
|
}
|
|
|
|
return N;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We did not find the entry and AllocNew is false. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-10-27 19:50:49 +00:00
|
|
|
SymEntry* SymFind (SymTable* Scope, const StrBuf* Name, SymFindAction Action)
|
|
|
|
/* Find a new symbol table entry in the given table. If Action contains
|
2014-06-30 09:10:35 +00:00
|
|
|
** 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.
|
|
|
|
*/
|
2000-05-28 13:40:48 +00:00
|
|
|
{
|
|
|
|
SymEntry* S;
|
|
|
|
|
2003-11-29 07:53:26 +00:00
|
|
|
/* Global symbol: Get the hash value for the name */
|
2008-03-31 20:54:45 +00:00
|
|
|
unsigned Hash = HashBuf (Name) % Scope->TableSlots;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2003-11-29 07:53:26 +00:00
|
|
|
/* Search for the entry */
|
|
|
|
int Cmp = SymSearchTree (Scope->Table[Hash], Name, &S);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2003-11-29 07:53:26 +00:00
|
|
|
/* If we found an entry, return it */
|
|
|
|
if (Cmp == 0) {
|
2012-10-27 19:50:49 +00:00
|
|
|
if ((Action & SYM_CHECK_ONLY) == 0 && SymTabIsClosed (Scope)) {
|
2012-10-27 11:49:37 +00:00
|
|
|
S->Flags |= SF_FIXED;
|
|
|
|
}
|
2003-11-29 07:53:26 +00:00
|
|
|
return S;
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2012-10-27 19:50:49 +00:00
|
|
|
if (Action & SYM_ALLOC_NEW) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2012-10-27 11:49:37 +00:00
|
|
|
/* Otherwise create a new entry, insert and return it. If the scope is
|
2014-06-30 09:10:35 +00:00
|
|
|
** already closed, mark the symbol as fixed so it won't be resolved
|
|
|
|
** by a symbol in the enclosing scopes later.
|
|
|
|
*/
|
2003-12-03 09:18:31 +00:00
|
|
|
SymEntry* N = NewSymEntry (Name, SF_NONE);
|
2012-10-27 11:49:37 +00:00
|
|
|
if (SymTabIsClosed (Scope)) {
|
|
|
|
N->Flags |= SF_FIXED;
|
|
|
|
}
|
2010-08-17 16:58:41 +00:00
|
|
|
N->Sym.Tab = Scope;
|
2003-11-29 07:53:26 +00:00
|
|
|
if (S == 0) {
|
|
|
|
Scope->Table[Hash] = N;
|
|
|
|
} else if (Cmp < 0) {
|
|
|
|
S->Left = N;
|
|
|
|
} else {
|
|
|
|
S->Right = N;
|
|
|
|
}
|
|
|
|
++Scope->TableEntries;
|
|
|
|
return N;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We did not find the entry and AllocNew is false. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-03-31 20:54:45 +00:00
|
|
|
SymEntry* SymFindAny (SymTable* Scope, const StrBuf* Name)
|
2003-11-06 11:22:31 +00:00
|
|
|
/* Find a symbol in the given or any of its parent scopes. The function will
|
2014-06-30 09:10:35 +00:00
|
|
|
** never create a new symbol, since this can only be done in one specific
|
|
|
|
** scope.
|
|
|
|
*/
|
2012-10-27 19:50:49 +00:00
|
|
|
{
|
2012-10-27 19:32:42 +00:00
|
|
|
/* Generate the name hash */
|
|
|
|
unsigned Hash = HashBuf (Name);
|
|
|
|
|
|
|
|
/* Search for the symbol */
|
2000-05-28 13:40:48 +00:00
|
|
|
SymEntry* Sym;
|
|
|
|
do {
|
2011-08-30 11:42:26 +00:00
|
|
|
/* Search in the current table. Ignore entries flagged with SF_UNUSED,
|
2014-06-30 09:10:35 +00:00
|
|
|
** because for such symbols there is a real entry in one of the parent
|
|
|
|
** scopes.
|
|
|
|
*/
|
2012-10-27 19:32:42 +00:00
|
|
|
if (SymSearchTree (Scope->Table[Hash % Scope->TableSlots], Name, &Sym) == 0) {
|
2011-08-30 11:42:26 +00:00
|
|
|
if (Sym->Flags & SF_UNUSED) {
|
|
|
|
Sym = 0;
|
|
|
|
} else {
|
|
|
|
/* Found, return it */
|
|
|
|
break;
|
|
|
|
}
|
2012-10-27 15:47:49 +00:00
|
|
|
} else {
|
|
|
|
Sym = 0;
|
2011-08-30 11:42:26 +00:00
|
|
|
}
|
2003-12-13 20:56:31 +00:00
|
|
|
|
|
|
|
/* Not found, search in the parent scope, if we have one */
|
2011-08-30 11:42:26 +00:00
|
|
|
Scope = Scope->Parent;
|
2003-12-13 20:56:31 +00:00
|
|
|
|
2003-11-06 11:22:31 +00:00
|
|
|
} while (Sym == 0 && Scope != 0);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2003-12-13 20:56:31 +00:00
|
|
|
/* Return the result */
|
|
|
|
return Sym;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void SymCheckUndefined (SymEntry* S)
|
|
|
|
/* Handle an undefined symbol */
|
|
|
|
{
|
|
|
|
/* Undefined symbol. It may be...
|
2014-06-30 09:10:35 +00:00
|
|
|
**
|
|
|
|
** - 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.
|
|
|
|
*/
|
2000-05-28 13:40:48 +00:00
|
|
|
SymEntry* Sym = 0;
|
2012-10-27 11:49:37 +00:00
|
|
|
if ((S->Flags & SF_FIXED) == 0) {
|
|
|
|
SymTable* Tab = GetSymParentScope (S);
|
|
|
|
while (Tab) {
|
2012-10-27 19:50:49 +00:00
|
|
|
Sym = SymFind (Tab, GetStrBuf (S->Name), SYM_FIND_EXISTING | SYM_CHECK_ONLY);
|
2012-10-27 11:49:37 +00:00
|
|
|
if (Sym && (Sym->Flags & (SF_DEFINED | SF_IMPORT)) != 0) {
|
|
|
|
/* We've found a symbol in a higher level that is
|
2014-06-30 09:10:35 +00:00
|
|
|
** either defined in the source, or an import.
|
|
|
|
*/
|
2012-10-27 11:49:37 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* No matching symbol found in this level. Look further */
|
|
|
|
Tab = Tab->Parent;
|
2003-12-13 20:56:31 +00:00
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2003-11-29 07:53:26 +00:00
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
if (Sym) {
|
|
|
|
|
2003-11-29 07:53:26 +00:00
|
|
|
/* We found the symbol in a higher level. Transfer the flags and
|
2014-06-30 09:10:35 +00:00
|
|
|
** address size from the local symbol to that in the higher level
|
|
|
|
** and check for problems.
|
|
|
|
*/
|
2003-11-29 07:53:26 +00:00
|
|
|
if (S->Flags & SF_EXPORT) {
|
2013-05-09 11:56:54 +00:00
|
|
|
if (Sym->Flags & SF_IMPORT) {
|
|
|
|
/* The symbol is already marked as import */
|
|
|
|
LIError (&S->RefLines,
|
2011-01-25 16:27:17 +00:00
|
|
|
"Symbol `%s' is already an import",
|
|
|
|
GetString (Sym->Name));
|
2013-05-09 11:56:54 +00:00
|
|
|
}
|
2014-05-12 06:08:04 +00:00
|
|
|
if ((Sym->Flags & SF_EXPORT) == 0) {
|
2003-11-29 07:53:26 +00:00
|
|
|
/* 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 */
|
2014-05-12 06:08:04 +00:00
|
|
|
LIWarning (&Sym->DefLines, 1,
|
2011-01-25 16:27:17 +00:00
|
|
|
"Symbol `%m%p' is %s but exported %s",
|
|
|
|
GetSymName (Sym),
|
|
|
|
AddrSizeToStr (Sym->AddrSize),
|
|
|
|
AddrSizeToStr (Sym->ExportSize));
|
2003-11-29 07:53:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-08-18 16:25:58 +00:00
|
|
|
if (S->Flags & SF_REFERENCED) {
|
2011-08-19 11:06:52 +00:00
|
|
|
/* Mark as referenced and move the line info */
|
2011-08-18 16:25:58 +00:00
|
|
|
Sym->Flags |= SF_REFERENCED;
|
2011-08-19 11:06:52 +00:00
|
|
|
CollTransfer (&Sym->RefLines, &S->RefLines);
|
2011-08-18 16:25:58 +00:00
|
|
|
CollDeleteAll (&S->RefLines);
|
|
|
|
}
|
2003-11-29 07:53:26 +00:00
|
|
|
|
|
|
|
/* Transfer all expression references */
|
|
|
|
SymTransferExprRefs (S, Sym);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2003-11-29 07:53:26 +00:00
|
|
|
/* Mark the symbol as unused removing all other flags */
|
|
|
|
S->Flags = SF_UNUSED;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
} else {
|
2013-05-09 11:56:54 +00:00
|
|
|
/* The symbol is definitely undefined */
|
|
|
|
if (S->Flags & SF_EXPORT) {
|
|
|
|
/* We will not auto-import an export */
|
|
|
|
LIError (&S->RefLines,
|
2011-01-25 16:27:17 +00:00
|
|
|
"Exported symbol `%m%p' was never defined",
|
|
|
|
GetSymName (S));
|
2013-05-09 11:56:54 +00:00
|
|
|
} else {
|
|
|
|
if (AutoImport) {
|
|
|
|
/* Mark as import, will be indexed later */
|
|
|
|
S->Flags |= SF_IMPORT;
|
2003-11-28 22:12:14 +00:00
|
|
|
/* Use the address size for code */
|
|
|
|
S->AddrSize = CodeAddrSize;
|
2011-08-18 16:25:58 +00:00
|
|
|
/* Mark point of import */
|
|
|
|
GetFullLineInfo (&S->DefLines);
|
2013-05-09 11:56:54 +00:00
|
|
|
} else {
|
|
|
|
/* Error */
|
|
|
|
LIError (&S->RefLines,
|
2011-06-13 18:43:50 +00:00
|
|
|
"Symbol `%m%p' is undefined",
|
2011-01-25 16:27:17 +00:00
|
|
|
GetSymName (S));
|
2013-05-09 11:56:54 +00:00
|
|
|
}
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SymCheck (void)
|
|
|
|
/* Run through all symbols and check for anomalies and errors */
|
|
|
|
{
|
|
|
|
SymEntry* S;
|
|
|
|
|
2003-11-08 17:20:21 +00:00
|
|
|
/* Check for open scopes */
|
2003-11-06 11:22:31 +00:00
|
|
|
if (CurrentScope->Parent != 0) {
|
2013-05-09 11:56:54 +00:00
|
|
|
Error ("Local scope was not closed");
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* First pass: Walk through all symbols, checking for undefined's and
|
2014-06-30 09:10:35 +00:00
|
|
|
** changing them to trampoline symbols or make them imports.
|
|
|
|
*/
|
2000-05-28 13:40:48 +00:00
|
|
|
S = SymList;
|
|
|
|
while (S) {
|
2013-05-09 11:56:54 +00:00
|
|
|
/* If the symbol is marked as global, mark it as export, if it is
|
2014-06-30 09:10:35 +00:00
|
|
|
** already defined, otherwise mark it as import.
|
|
|
|
*/
|
2013-05-09 11:56:54 +00:00
|
|
|
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;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
2003-12-13 20:56:31 +00:00
|
|
|
/* Second pass: Walk again through the symbols. Count exports and imports
|
2014-06-30 09:10:35 +00:00
|
|
|
** 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.
|
|
|
|
*/
|
2000-05-28 13:40:48 +00:00
|
|
|
S = SymList;
|
|
|
|
while (S) {
|
2013-05-09 11:56:54 +00:00
|
|
|
if ((S->Flags & SF_UNUSED) == 0 &&
|
|
|
|
(S->Flags & SF_UNDEFMASK) != SF_UNDEFVAL) {
|
2003-12-13 20:56:31 +00:00
|
|
|
|
|
|
|
/* Check for defined symbols that were never referenced */
|
2011-08-18 16:25:58 +00:00
|
|
|
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));
|
|
|
|
}
|
2003-12-13 20:56:31 +00:00
|
|
|
|
|
|
|
/* Assign an index to all imports */
|
2013-05-09 11:56:54 +00:00
|
|
|
if (S->Flags & SF_IMPORT) {
|
|
|
|
if ((S->Flags & (SF_REFERENCED | SF_FORCED)) == SF_NONE) {
|
|
|
|
/* Imported symbol is not referenced */
|
|
|
|
LIWarning (&S->DefLines, 2,
|
2011-01-25 16:27:17 +00:00
|
|
|
"Symbol `%m%p' is imported but never used",
|
|
|
|
GetSymName (S));
|
2013-05-09 11:56:54 +00:00
|
|
|
} else {
|
|
|
|
/* Give the import an id, count imports */
|
|
|
|
S->ImportId = ImportCount++;
|
|
|
|
}
|
|
|
|
}
|
2003-12-13 20:56:31 +00:00
|
|
|
|
2011-08-16 12:52:56 +00:00
|
|
|
/* Count exports, assign the export ID */
|
2013-05-09 11:56:54 +00:00
|
|
|
if (S->Flags & SF_EXPORT) {
|
2011-08-16 12:52:56 +00:00
|
|
|
S->ExportId = ExportCount++;
|
2013-05-09 11:56:54 +00:00
|
|
|
}
|
2003-12-13 20:56:31 +00:00
|
|
|
|
|
|
|
/* If the symbol is defined but has an unknown address size,
|
2014-06-30 09:10:35 +00:00
|
|
|
** recalculate it.
|
|
|
|
*/
|
2003-12-13 20:56:31 +00:00
|
|
|
if (SymHasExpr (S) && S->AddrSize == ADDR_SIZE_DEFAULT) {
|
|
|
|
ExprDesc ED;
|
|
|
|
ED_Init (&ED);
|
|
|
|
StudyExpr (S->Expr, &ED);
|
|
|
|
S->AddrSize = ED.AddrSize;
|
2004-04-19 17:00:12 +00:00
|
|
|
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 */
|
2011-08-18 16:25:58 +00:00
|
|
|
LIWarning (&S->DefLines, 1,
|
2011-01-25 16:27:17 +00:00
|
|
|
"Symbol `%m%p' is %s but exported %s",
|
|
|
|
GetSymName (S),
|
|
|
|
AddrSizeToStr (S->AddrSize),
|
|
|
|
AddrSizeToStr (S->ExportSize));
|
2004-04-19 17:00:12 +00:00
|
|
|
}
|
|
|
|
}
|
2003-12-13 20:56:31 +00:00
|
|
|
ED_Done (&ED);
|
|
|
|
}
|
2006-04-09 10:56:23 +00:00
|
|
|
|
|
|
|
/* If the address size of the symbol was guessed, check the guess
|
2014-06-30 09:10:35 +00:00
|
|
|
** against the actual address size and print a warning if the two
|
|
|
|
** differ.
|
|
|
|
*/
|
2006-04-09 10:56:23 +00:00
|
|
|
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,
|
2008-03-31 20:54:45 +00:00
|
|
|
"Didn't use %s addressing for `%m%p'",
|
2006-04-09 10:56:23 +00:00
|
|
|
AddrSizeToStr (S->AddrSize),
|
|
|
|
GetSymName (S));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Next symbol */
|
|
|
|
S = S->List;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SymDump (FILE* F)
|
|
|
|
/* Dump the symbol table */
|
|
|
|
{
|
|
|
|
SymEntry* S = SymList;
|
|
|
|
|
|
|
|
while (S) {
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Ignore unused symbols */
|
2015-05-16 03:20:15 +00:00
|
|
|
if ((S->Flags & SF_UNUSED) == 0) {
|
2013-05-09 11:56:54 +00:00
|
|
|
fprintf (F,
|
2015-05-16 03:20:15 +00:00
|
|
|
"%-24s %s %s %s %s %s\n",
|
|
|
|
SB_GetConstBuf (GetSymName (S)),
|
2013-05-09 11:56:54 +00:00
|
|
|
(S->Flags & SF_DEFINED)? "DEF" : "---",
|
|
|
|
(S->Flags & SF_REFERENCED)? "REF" : "---",
|
|
|
|
(S->Flags & SF_IMPORT)? "IMP" : "---",
|
|
|
|
(S->Flags & SF_EXPORT)? "EXP" : "---",
|
2003-11-08 23:13:02 +00:00
|
|
|
AddrSizeToStr (S->AddrSize));
|
2013-05-09 11:56:54 +00:00
|
|
|
}
|
|
|
|
/* Next symbol */
|
|
|
|
S = S->List;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void WriteImports (void)
|
|
|
|
/* Write the imports list to the object file */
|
|
|
|
{
|
2011-08-16 12:33:19 +00:00
|
|
|
SymEntry* S;
|
2000-08-02 14:12:36 +00:00
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Tell the object file module that we're about to start the imports */
|
|
|
|
ObjStartImports ();
|
|
|
|
|
|
|
|
/* Write the import count to the list */
|
2000-08-02 13:23:06 +00:00
|
|
|
ObjWriteVar (ImportCount);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2003-03-07 11:33:14 +00:00
|
|
|
/* Walk throught list and write all valid imports to the file. An import
|
2014-06-30 09:10:35 +00:00
|
|
|
** 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).
|
|
|
|
*/
|
2000-05-28 13:40:48 +00:00
|
|
|
S = SymList;
|
|
|
|
while (S) {
|
2003-11-29 07:53:26 +00:00
|
|
|
if ((S->Flags & (SF_UNUSED | SF_IMPORT)) == SF_IMPORT &&
|
2003-03-07 11:33:14 +00:00
|
|
|
(S->Flags & (SF_REFERENCED | SF_FORCED)) != 0) {
|
|
|
|
|
2003-11-28 22:12:14 +00:00
|
|
|
ObjWrite8 (S->AddrSize);
|
2013-05-09 11:56:54 +00:00
|
|
|
ObjWriteVar (S->Name);
|
|
|
|
WriteLineInfo (&S->DefLines);
|
2011-08-18 16:25:58 +00:00
|
|
|
WriteLineInfo (&S->RefLines);
|
2013-05-09 11:56:54 +00:00
|
|
|
}
|
|
|
|
S = S->List;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2000-08-01 15:17:43 +00:00
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Done writing imports */
|
|
|
|
ObjEndImports ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void WriteExports (void)
|
|
|
|
/* Write the exports list to the object file */
|
|
|
|
{
|
|
|
|
SymEntry* S;
|
2000-11-20 15:22:57 +00:00
|
|
|
unsigned Type;
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Tell the object file module that we're about to start the exports */
|
|
|
|
ObjStartExports ();
|
|
|
|
|
|
|
|
/* Write the export count to the list */
|
2000-08-02 13:23:06 +00:00
|
|
|
ObjWriteVar (ExportCount);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
/* Walk throught list and write all exports to the file */
|
|
|
|
S = SymList;
|
|
|
|
while (S) {
|
2013-05-09 11:56:54 +00:00
|
|
|
if ((S->Flags & (SF_UNUSED | SF_EXPORT)) == SF_EXPORT) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Get the expression bits and the value */
|
2003-11-11 13:57:30 +00:00
|
|
|
long ConstVal;
|
2011-08-16 12:08:43 +00:00
|
|
|
unsigned SymFlags = GetSymInfoFlags (S, &ConstVal);
|
2000-10-30 19:30:26 +00:00
|
|
|
|
2011-06-13 18:43:50 +00:00
|
|
|
/* Check if this symbol has a size. If so, remember it in the
|
2014-06-30 09:10:35 +00:00
|
|
|
** flags.
|
|
|
|
*/
|
2011-06-13 18:43:50 +00:00
|
|
|
long Size;
|
|
|
|
SymEntry* SizeSym = FindSizeOfSymbol (S);
|
|
|
|
if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) {
|
2011-08-16 12:08:43 +00:00
|
|
|
SymFlags |= SYM_SIZE;
|
2011-06-13 18:43:50 +00:00
|
|
|
}
|
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
}
|
2000-10-30 19:30:26 +00:00
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Write the type and the export size */
|
|
|
|
ObjWriteVar (SymFlags);
|
2003-11-28 22:12:14 +00:00
|
|
|
ObjWrite8 (S->ExportSize);
|
2000-10-30 19:30:26 +00:00
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
/* 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 name */
|
|
|
|
ObjWriteVar (S->Name);
|
|
|
|
|
|
|
|
/* Write the value */
|
|
|
|
if (SYM_IS_CONST (SymFlags)) {
|
|
|
|
/* Constant value */
|
|
|
|
ObjWrite32 (ConstVal);
|
|
|
|
} else {
|
|
|
|
/* Expression involved */
|
|
|
|
WriteExpr (S->Expr);
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
2000-10-30 19:30:26 +00:00
|
|
|
|
2011-06-13 18:43:50 +00:00
|
|
|
/* If the symbol has a size, write it to the file */
|
2011-08-16 12:08:43 +00:00
|
|
|
if (SYM_HAS_SIZE (SymFlags)) {
|
2011-06-13 18:43:50 +00:00
|
|
|
ObjWriteVar (Size);
|
|
|
|
}
|
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Write the line infos */
|
2011-08-18 16:25:58 +00:00
|
|
|
WriteLineInfo (&S->DefLines);
|
2013-05-09 11:56:54 +00:00
|
|
|
WriteLineInfo (&S->RefLines);
|
|
|
|
}
|
|
|
|
S = S->List;
|
2000-05-28 13:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Done writing exports */
|
|
|
|
ObjEndExports ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void WriteDbgSyms (void)
|
|
|
|
/* Write a list of all symbols to the object file */
|
|
|
|
{
|
|
|
|
unsigned Count;
|
|
|
|
SymEntry* S;
|
|
|
|
|
|
|
|
/* Tell the object file module that we're about to start the debug info */
|
|
|
|
ObjStartDbgSyms ();
|
|
|
|
|
|
|
|
/* Check if debug info is requested */
|
|
|
|
if (DbgSyms) {
|
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Walk through the list, give each symbol an id and count them */
|
|
|
|
Count = 0;
|
|
|
|
S = SymList;
|
|
|
|
while (S) {
|
|
|
|
if (IsDbgSym (S)) {
|
2010-08-17 20:11:27 +00:00
|
|
|
S->DebugSymId = Count++;
|
2013-05-09 11:56:54 +00:00
|
|
|
}
|
|
|
|
S = S->List;
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Write the symbol count to the list */
|
|
|
|
ObjWriteVar (Count);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Walk through list and write all symbols to the file. Ignore size
|
2014-06-30 09:10:35 +00:00
|
|
|
** symbols.
|
|
|
|
*/
|
2013-05-09 11:56:54 +00:00
|
|
|
S = SymList;
|
|
|
|
while (S) {
|
|
|
|
if (IsDbgSym (S)) {
|
2000-05-28 13:40:48 +00:00
|
|
|
|
2010-08-17 20:47:27 +00:00
|
|
|
/* Get the expression bits and the value */
|
2003-11-11 13:57:30 +00:00
|
|
|
long ConstVal;
|
2011-08-16 12:08:43 +00:00
|
|
|
unsigned SymFlags = GetSymInfoFlags (S, &ConstVal);
|
2000-10-30 19:33:04 +00:00
|
|
|
|
2011-06-13 18:43:50 +00:00
|
|
|
/* Check if this symbol has a size. If so, remember it in the
|
2014-06-30 09:10:35 +00:00
|
|
|
** flags.
|
|
|
|
*/
|
2011-06-13 18:43:50 +00:00
|
|
|
long Size;
|
|
|
|
SymEntry* SizeSym = FindSizeOfSymbol (S);
|
|
|
|
if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) {
|
2011-08-16 12:08:43 +00:00
|
|
|
SymFlags |= SYM_SIZE;
|
2011-06-13 18:43:50 +00:00
|
|
|
}
|
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Write the type */
|
|
|
|
ObjWriteVar (SymFlags);
|
2000-10-30 19:33:04 +00:00
|
|
|
|
2003-11-28 22:12:14 +00:00
|
|
|
/* Write the address size */
|
|
|
|
ObjWrite8 (S->AddrSize);
|
|
|
|
|
2011-07-31 13:28:54 +00:00
|
|
|
/* Write the id of the parent. For normal symbols, this is a
|
2014-06-30 09:10:35 +00:00
|
|
|
** scope (symbol table), for cheap locals, it's a symbol.
|
|
|
|
*/
|
2011-08-16 12:08:43 +00:00
|
|
|
if (SYM_IS_STD (SymFlags)) {
|
2011-07-31 13:28:54 +00:00
|
|
|
ObjWriteVar (S->Sym.Tab->Id);
|
|
|
|
} else {
|
|
|
|
ObjWriteVar (S->Sym.Entry->DebugSymId);
|
|
|
|
}
|
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Write the name */
|
|
|
|
ObjWriteVar (S->Name);
|
2000-10-30 19:33:04 +00:00
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Write the value */
|
|
|
|
if (SYM_IS_CONST (SymFlags)) {
|
|
|
|
/* Constant value */
|
|
|
|
ObjWrite32 (ConstVal);
|
|
|
|
} else {
|
|
|
|
/* Expression involved */
|
|
|
|
WriteExpr (S->Expr);
|
|
|
|
}
|
2000-10-30 19:33:04 +00:00
|
|
|
|
2011-06-13 18:43:50 +00:00
|
|
|
/* If the symbol has a size, write it to the file */
|
2011-08-16 12:08:43 +00:00
|
|
|
if (SYM_HAS_SIZE (SymFlags)) {
|
2011-06-13 18:43:50 +00:00
|
|
|
ObjWriteVar (Size);
|
|
|
|
}
|
|
|
|
|
2011-08-16 12:52:56 +00:00
|
|
|
/* If the symbol is an im- or export, write out the ids */
|
2011-08-16 12:33:19 +00:00
|
|
|
if (SYM_IS_IMPORT (SymFlags)) {
|
|
|
|
ObjWriteVar (GetSymImportId (S));
|
|
|
|
}
|
2011-08-16 12:52:56 +00:00
|
|
|
if (SYM_IS_EXPORT (SymFlags)) {
|
|
|
|
ObjWriteVar (GetSymExportId (S));
|
|
|
|
}
|
2011-08-16 12:33:19 +00:00
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
/* Write the line infos */
|
2011-08-18 16:25:58 +00:00
|
|
|
WriteLineInfo (&S->DefLines);
|
2013-05-09 11:56:54 +00:00
|
|
|
WriteLineInfo (&S->RefLines);
|
|
|
|
}
|
|
|
|
S = S->List;
|
|
|
|
}
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
2013-05-09 11:56:54 +00:00
|
|
|
/* No debug symbols */
|
|
|
|
ObjWriteVar (0);
|
2000-05-28 13:40:48 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-08-29 20:02:06 +00:00
|
|
|
/* Write the high level symbols */
|
2011-08-29 20:37:28 +00:00
|
|
|
WriteHLLDbgSyms ();
|
2011-08-29 20:02:06 +00:00
|
|
|
|
2000-05-28 13:40:48 +00:00
|
|
|
/* Done writing debug symbols */
|
|
|
|
ObjEndDbgSyms ();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-28 22:12:14 +00:00
|
|
|
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 ();
|
|
|
|
|
2011-07-31 12:25:02 +00:00
|
|
|
/* We will write scopes only if debug symbols are requested */
|
|
|
|
if (DbgSyms) {
|
|
|
|
|
|
|
|
/* Get head of list */
|
2011-07-31 15:37:51 +00:00
|
|
|
SymTable* S = RootScope;
|
2011-07-31 12:25:02 +00:00
|
|
|
|
|
|
|
/* Write the scope count to the file */
|
|
|
|
ObjWriteVar (ScopeCount);
|
|
|
|
|
|
|
|
/* Walk through all scopes and write them to the file */
|
|
|
|
while (S) {
|
|
|
|
|
2011-07-31 15:37:51 +00:00
|
|
|
/* Flags for this scope */
|
|
|
|
unsigned Flags = 0;
|
|
|
|
|
|
|
|
/* Check if this scope has a size. If so, remember it in the
|
2014-06-30 09:10:35 +00:00
|
|
|
** flags.
|
|
|
|
*/
|
2011-07-31 15:37:51 +00:00
|
|
|
long Size;
|
|
|
|
SymEntry* SizeSym = FindSizeOfScope (S);
|
|
|
|
if (SizeSym != 0 && SymIsConst (SizeSym, &Size)) {
|
|
|
|
Flags |= SCOPE_SIZE;
|
|
|
|
}
|
2011-07-31 12:25:02 +00:00
|
|
|
|
2011-08-07 18:46:56 +00:00
|
|
|
/* Check if the scope has a label */
|
|
|
|
if (S->Label) {
|
|
|
|
Flags |= SCOPE_LABELED;
|
|
|
|
}
|
|
|
|
|
2011-07-31 15:37:51 +00:00
|
|
|
/* Scope must be defined */
|
|
|
|
CHECK (S->Type != SCOPE_UNDEF);
|
2011-07-31 12:25:02 +00:00
|
|
|
|
|
|
|
/* Id of parent scope */
|
|
|
|
if (S->Parent) {
|
|
|
|
ObjWriteVar (S->Parent->Id);
|
|
|
|
} else {
|
|
|
|
ObjWriteVar (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Lexical level */
|
|
|
|
ObjWriteVar (S->Level);
|
|
|
|
|
2011-07-31 15:37:51 +00:00
|
|
|
/* Scope flags */
|
|
|
|
ObjWriteVar (Flags);
|
2011-07-31 12:25:02 +00:00
|
|
|
|
|
|
|
/* Type of scope */
|
|
|
|
ObjWriteVar (S->Type);
|
|
|
|
|
|
|
|
/* Name of the scope */
|
|
|
|
ObjWriteVar (S->Name);
|
|
|
|
|
2011-07-31 15:37:51 +00:00
|
|
|
/* If the scope has a size, write it to the file */
|
|
|
|
if (SCOPE_HAS_SIZE (Flags)) {
|
|
|
|
ObjWriteVar (Size);
|
|
|
|
}
|
|
|
|
|
2011-08-07 18:46:56 +00:00
|
|
|
/* If the scope has a label, write its id to the file */
|
|
|
|
if (SCOPE_HAS_LABEL (Flags)) {
|
|
|
|
ObjWriteVar (S->Label->DebugSymId);
|
|
|
|
}
|
|
|
|
|
2011-08-04 12:49:59 +00:00
|
|
|
/* Spans for this scope */
|
2011-08-21 19:08:23 +00:00
|
|
|
WriteSpanList (&S->Spans);
|
2011-07-31 12:25:02 +00:00
|
|
|
|
|
|
|
/* Next scope */
|
|
|
|
S = S->Next;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* No debug info requested */
|
|
|
|
ObjWriteVar (0);
|
|
|
|
|
|
|
|
}
|
2003-11-28 22:12:14 +00:00
|
|
|
|
|
|
|
/* Done writing the scopes */
|
|
|
|
ObjEndScopes ();
|
|
|
|
}
|