2003-10-22 21:24:37 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* */
|
2013-05-09 13:56:54 +02:00
|
|
|
/* symentry.c */
|
2003-10-22 21:24:37 +00:00
|
|
|
/* */
|
2008-03-31 20:54:45 +00:00
|
|
|
/* Symbol table entry for the ca65 macroassembler */
|
2003-10-22 21:24:37 +00:00
|
|
|
/* */
|
|
|
|
/* */
|
|
|
|
/* */
|
2011-01-16 16:05:43 +00:00
|
|
|
/* (C) 1998-2011, Ullrich von Bassewitz */
|
2010-08-17 20:01:54 +00:00
|
|
|
/* Roemerstrasse 52 */
|
|
|
|
/* D-70794 Filderstadt */
|
|
|
|
/* EMail: uz@cc65.org */
|
2003-10-22 21:24:37 +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>
|
|
|
|
|
|
|
|
/* common */
|
2003-11-07 19:28:37 +00:00
|
|
|
#include "addrsize.h"
|
2010-08-17 20:47:27 +00:00
|
|
|
#include "symdefs.h"
|
2003-10-22 21:24:37 +00:00
|
|
|
#include "xmalloc.h"
|
|
|
|
|
|
|
|
/* ca65 */
|
2003-11-06 11:22:31 +00:00
|
|
|
#include "error.h"
|
|
|
|
#include "expr.h"
|
|
|
|
#include "global.h"
|
2003-10-22 21:24:37 +00:00
|
|
|
#include "scanner.h"
|
2003-11-13 00:21:31 +00:00
|
|
|
#include "segment.h"
|
2003-11-06 11:22:31 +00:00
|
|
|
#include "spool.h"
|
2003-11-30 22:54:13 +00:00
|
|
|
#include "studyexpr.h" /* ### */
|
2003-10-22 21:24:37 +00:00
|
|
|
#include "symentry.h"
|
2003-11-08 17:20:21 +00:00
|
|
|
#include "symtab.h"
|
2003-10-22 21:24:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2013-05-09 13:56:54 +02:00
|
|
|
/* Data */
|
2003-10-22 21:24:37 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-06 11:22:31 +00:00
|
|
|
/* List of all symbol table entries */
|
|
|
|
SymEntry* SymList = 0;
|
|
|
|
|
|
|
|
/* Pointer to last defined symbol */
|
|
|
|
SymEntry* SymLast = 0;
|
2003-10-22 21:24:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2013-05-09 13:56:54 +02:00
|
|
|
/* Code */
|
2003-10-22 21:24:37 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-03-31 20:54:45 +00:00
|
|
|
SymEntry* NewSymEntry (const StrBuf* Name, unsigned Flags)
|
2003-10-22 21:24:37 +00:00
|
|
|
/* Allocate a symbol table entry, initialize and return it */
|
|
|
|
{
|
2006-04-09 10:56:23 +00:00
|
|
|
unsigned I;
|
|
|
|
|
2003-10-22 21:24:37 +00:00
|
|
|
/* Allocate memory */
|
2003-10-31 20:21:48 +00:00
|
|
|
SymEntry* S = xmalloc (sizeof (SymEntry));
|
2003-10-22 21:24:37 +00:00
|
|
|
|
|
|
|
/* Initialize the entry */
|
2013-05-09 13:56:54 +02:00
|
|
|
S->Left = 0;
|
|
|
|
S->Right = 0;
|
|
|
|
S->Locals = 0;
|
2010-08-17 16:58:41 +00:00
|
|
|
S->Sym.Tab = 0;
|
2011-08-18 16:25:58 +00:00
|
|
|
S->DefLines = EmptyCollection;
|
|
|
|
S->RefLines = EmptyCollection;
|
2006-04-09 10:56:23 +00:00
|
|
|
for (I = 0; I < sizeof (S->GuessedUse) / sizeof (S->GuessedUse[0]); ++I) {
|
|
|
|
S->GuessedUse[I] = 0;
|
2012-10-27 11:49:37 +00:00
|
|
|
}
|
2011-08-30 11:42:26 +00:00
|
|
|
S->HLLSym = 0;
|
2013-05-09 13:56:54 +02:00
|
|
|
S->Flags = Flags;
|
2010-08-17 20:11:27 +00:00
|
|
|
S->DebugSymId = ~0U;
|
2010-08-17 20:01:54 +00:00
|
|
|
S->ImportId = ~0U;
|
2011-08-16 12:52:56 +00:00
|
|
|
S->ExportId = ~0U;
|
2003-12-13 20:56:31 +00:00
|
|
|
S->Expr = 0;
|
2003-11-07 19:28:37 +00:00
|
|
|
S->ExprRefs = AUTO_COLLECTION_INITIALIZER;
|
|
|
|
S->ExportSize = ADDR_SIZE_DEFAULT;
|
|
|
|
S->AddrSize = ADDR_SIZE_DEFAULT;
|
2003-10-22 21:24:37 +00:00
|
|
|
memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio));
|
2008-03-31 20:54:45 +00:00
|
|
|
S->Name = GetStrBufId (Name);
|
2003-10-22 21:24:37 +00:00
|
|
|
|
|
|
|
/* Insert it into the list of all entries */
|
|
|
|
S->List = SymList;
|
|
|
|
SymList = S;
|
|
|
|
|
|
|
|
/* Return the initialized entry */
|
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-11-06 11:22:31 +00:00
|
|
|
|
2008-03-31 20:54:45 +00:00
|
|
|
int SymSearchTree (SymEntry* T, const StrBuf* Name, SymEntry** E)
|
2003-11-13 22:03:24 +00:00
|
|
|
/* Search in the given tree for a name. If we find the symbol, the function
|
2014-06-30 05:10:35 -04:00
|
|
|
** 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.
|
|
|
|
*/
|
2003-11-13 22:03:24 +00:00
|
|
|
{
|
|
|
|
/* Is there a tree? */
|
|
|
|
if (T == 0) {
|
2013-05-09 13:56:54 +02:00
|
|
|
*E = 0;
|
|
|
|
return 1;
|
2003-11-13 22:03:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* We have a table, search it */
|
|
|
|
while (1) {
|
|
|
|
|
|
|
|
/* Get the symbol name */
|
2008-03-31 20:54:45 +00:00
|
|
|
const StrBuf* SymName = GetStrBuf (T->Name);
|
2003-11-13 22:03:24 +00:00
|
|
|
|
2013-05-09 13:56:54 +02:00
|
|
|
/* Choose next entry */
|
2008-03-31 20:54:45 +00:00
|
|
|
int Cmp = SB_Compare (Name, SymName);
|
2013-05-09 13:56:54 +02:00
|
|
|
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 */
|
2003-11-13 22:03:24 +00:00
|
|
|
*E = T;
|
|
|
|
return Cmp;
|
2013-05-09 13:56:54 +02:00
|
|
|
}
|
2003-11-13 22:03:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-29 07:53:26 +00:00
|
|
|
void SymTransferExprRefs (SymEntry* From, SymEntry* To)
|
|
|
|
/* Transfer all expression references from one symbol to another. */
|
|
|
|
{
|
|
|
|
unsigned I;
|
|
|
|
|
|
|
|
for (I = 0; I < CollCount (&From->ExprRefs); ++I) {
|
|
|
|
|
|
|
|
/* Get the expression node */
|
|
|
|
ExprNode* E = CollAtUnchecked (&From->ExprRefs, I);
|
|
|
|
|
|
|
|
/* Safety */
|
|
|
|
CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == From);
|
|
|
|
|
|
|
|
/* Replace the symbol reference */
|
|
|
|
E->V.Sym = To;
|
|
|
|
|
|
|
|
/* Add the expression reference */
|
|
|
|
SymAddExprRef (To, E);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove all symbol references from the old symbol */
|
|
|
|
CollDeleteAll (&From->ExprRefs);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-05-11 08:31:42 +00:00
|
|
|
static void SymReplaceExprRefs (SymEntry* S)
|
|
|
|
/* Replace the references to this symbol by a copy of the symbol expression */
|
|
|
|
{
|
|
|
|
unsigned I;
|
|
|
|
long Val;
|
|
|
|
|
|
|
|
/* Check if the expression is const and get its value */
|
|
|
|
int IsConst = IsConstExpr (S->Expr, &Val);
|
|
|
|
CHECK (IsConst);
|
|
|
|
|
|
|
|
/* Loop over all references */
|
|
|
|
for (I = 0; I < CollCount (&S->ExprRefs); ++I) {
|
|
|
|
|
|
|
|
/* Get the expression node */
|
|
|
|
ExprNode* E = CollAtUnchecked (&S->ExprRefs, I);
|
|
|
|
|
|
|
|
/* Safety */
|
|
|
|
CHECK (E->Op == EXPR_SYMBOL && E->V.Sym == S);
|
|
|
|
|
2006-04-09 10:56:23 +00:00
|
|
|
/* We cannot touch the root node, since there are pointers to it.
|
2014-06-30 05:10:35 -04:00
|
|
|
** Replace it by a literal node.
|
|
|
|
*/
|
2005-05-11 08:31:42 +00:00
|
|
|
E->Op = EXPR_LITERAL;
|
2007-08-30 20:24:16 +00:00
|
|
|
E->V.IVal = Val;
|
2005-05-11 08:31:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove all symbol references from the symbol */
|
|
|
|
CollDeleteAll (&S->ExprRefs);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
void SymDef (SymEntry* S, ExprNode* Expr, unsigned char AddrSize, unsigned Flags)
|
2003-11-06 11:22:31 +00:00
|
|
|
/* Define a new symbol */
|
|
|
|
{
|
|
|
|
if (S->Flags & SF_IMPORT) {
|
2013-05-09 13:56:54 +02:00
|
|
|
/* Defined symbol is marked as imported external symbol */
|
|
|
|
Error ("Symbol `%m%p' is already an import", GetSymName (S));
|
|
|
|
return;
|
2003-11-06 11:22:31 +00:00
|
|
|
}
|
2005-05-11 08:31:42 +00:00
|
|
|
if ((Flags & SF_VAR) != 0 && (S->Flags & (SF_EXPORT | SF_GLOBAL))) {
|
|
|
|
/* Variable symbols cannot be exports or globals */
|
2008-03-31 20:54:45 +00:00
|
|
|
Error ("Var symbol `%m%p' cannot be an export or global symbol", GetSymName (S));
|
2005-05-11 08:31:42 +00:00
|
|
|
return;
|
|
|
|
}
|
2003-11-06 11:22:31 +00:00
|
|
|
if (S->Flags & SF_DEFINED) {
|
2013-05-09 13:56:54 +02:00
|
|
|
/* Multiple definition. In case of a variable, this is legal. */
|
2005-05-11 08:31:42 +00:00
|
|
|
if ((S->Flags & SF_VAR) == 0) {
|
2008-03-31 20:54:45 +00:00
|
|
|
Error ("Symbol `%m%p' is already defined", GetSymName (S));
|
2005-05-11 08:31:42 +00:00
|
|
|
S->Flags |= SF_MULTDEF;
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
/* Redefinition must also be a variable symbol */
|
|
|
|
if ((Flags & SF_VAR) == 0) {
|
2008-03-31 20:54:45 +00:00
|
|
|
Error ("Symbol `%m%p' is already different kind", GetSymName (S));
|
2005-05-11 08:31:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* Delete the current symbol expression, since it will get
|
2014-06-30 05:10:35 -04:00
|
|
|
** replaced
|
|
|
|
*/
|
2005-05-11 08:31:42 +00:00
|
|
|
FreeExpr (S->Expr);
|
|
|
|
S->Expr = 0;
|
|
|
|
}
|
2003-11-06 11:22:31 +00:00
|
|
|
}
|
|
|
|
|
2003-11-07 19:28:37 +00:00
|
|
|
/* Map a default address size to a real value */
|
|
|
|
if (AddrSize == ADDR_SIZE_DEFAULT) {
|
2003-11-30 22:54:13 +00:00
|
|
|
/* ### Must go! Delay address size calculation until end of assembly! */
|
|
|
|
ExprDesc ED;
|
|
|
|
ED_Init (&ED);
|
|
|
|
StudyExpr (Expr, &ED);
|
|
|
|
AddrSize = ED.AddrSize;
|
|
|
|
ED_Done (&ED);
|
2003-11-07 19:28:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the symbol value */
|
2003-12-13 20:56:31 +00:00
|
|
|
S->Expr = Expr;
|
2003-11-07 19:28:37 +00:00
|
|
|
|
2006-04-09 10:56:23 +00:00
|
|
|
/* In case of a variable symbol, walk over all expressions containing
|
2014-06-30 05:10:35 -04:00
|
|
|
** this symbol and replace the (sub-)expression by the literal value of
|
|
|
|
** the tree. Be sure to replace the expression node in place, since there
|
|
|
|
** may be pointers to it.
|
|
|
|
*/
|
2005-05-11 08:31:42 +00:00
|
|
|
if (Flags & SF_VAR) {
|
|
|
|
SymReplaceExprRefs (S);
|
|
|
|
}
|
|
|
|
|
2003-11-28 22:12:14 +00:00
|
|
|
/* If the symbol is marked as global, export it. Address size is checked
|
2014-06-30 05:10:35 -04:00
|
|
|
** below.
|
|
|
|
*/
|
2003-11-07 19:28:37 +00:00
|
|
|
if (S->Flags & SF_GLOBAL) {
|
|
|
|
S->Flags = (S->Flags & ~SF_GLOBAL) | SF_EXPORT;
|
2011-08-18 16:25:58 +00:00
|
|
|
ReleaseFullLineInfo (&S->DefLines);
|
2003-11-06 11:22:31 +00:00
|
|
|
}
|
2003-11-07 19:28:37 +00:00
|
|
|
|
|
|
|
/* Mark the symbol as defined and use the given address size */
|
|
|
|
S->Flags |= (SF_DEFINED | Flags);
|
|
|
|
S->AddrSize = AddrSize;
|
|
|
|
|
2011-08-18 16:25:58 +00:00
|
|
|
/* Remember the line info of the symbol definition */
|
|
|
|
GetFullLineInfo (&S->DefLines);
|
|
|
|
|
2003-11-07 19:28:37 +00:00
|
|
|
/* If the symbol is exported, check the address sizes */
|
|
|
|
if (S->Flags & SF_EXPORT) {
|
2003-11-11 13:57:30 +00:00
|
|
|
if (S->ExportSize == ADDR_SIZE_DEFAULT) {
|
|
|
|
/* Use the real size of the symbol */
|
|
|
|
S->ExportSize = S->AddrSize;
|
|
|
|
} else if (S->AddrSize > S->ExportSize) {
|
2003-11-28 22:12:14 +00:00
|
|
|
/* We're exporting a symbol smaller than it actually is */
|
2011-08-18 16:25:58 +00:00
|
|
|
Warning (1, "Symbol `%m%p' is %s but exported %s",
|
|
|
|
GetSymName (S), AddrSizeToStr (S->AddrSize),
|
|
|
|
AddrSizeToStr (S->ExportSize));
|
2003-11-07 19:28:37 +00:00
|
|
|
}
|
2003-11-06 11:22:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If this is not a local symbol, remember it as the last global one */
|
2003-12-03 09:18:31 +00:00
|
|
|
if ((S->Flags & SF_LOCAL) == 0) {
|
2013-05-09 13:56:54 +02:00
|
|
|
SymLast = S;
|
2003-11-06 11:22:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-08-18 16:25:58 +00:00
|
|
|
void SymRef (SymEntry* S)
|
|
|
|
/* Mark the given symbol as referenced */
|
|
|
|
{
|
|
|
|
/* Mark the symbol as referenced */
|
|
|
|
S->Flags |= SF_REFERENCED;
|
|
|
|
|
|
|
|
/* Remember the current location */
|
|
|
|
CollAppend (&S->RefLines, GetAsmLineInfo ());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
void SymImport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
2003-11-07 19:28:37 +00:00
|
|
|
/* Mark the given symbol as an imported symbol */
|
|
|
|
{
|
|
|
|
if (S->Flags & SF_DEFINED) {
|
2013-05-09 13:56:54 +02:00
|
|
|
Error ("Symbol `%m%p' is already defined", GetSymName (S));
|
|
|
|
S->Flags |= SF_MULTDEF;
|
|
|
|
return;
|
2003-11-07 19:28:37 +00:00
|
|
|
}
|
|
|
|
if (S->Flags & SF_EXPORT) {
|
2013-05-09 13:56:54 +02:00
|
|
|
/* The symbol is already marked as exported symbol */
|
|
|
|
Error ("Cannot import exported symbol `%m%p'", GetSymName (S));
|
|
|
|
return;
|
2003-11-07 19:28:37 +00:00
|
|
|
}
|
|
|
|
|
2003-11-28 22:12:14 +00:00
|
|
|
/* If no address size is given, use the address size of the enclosing
|
2014-06-30 05:10:35 -04:00
|
|
|
** segment.
|
|
|
|
*/
|
2003-11-07 19:28:37 +00:00
|
|
|
if (AddrSize == ADDR_SIZE_DEFAULT) {
|
2003-11-28 22:12:14 +00:00
|
|
|
AddrSize = GetCurrentSegAddrSize ();
|
2003-11-07 19:28:37 +00:00
|
|
|
}
|
|
|
|
|
2003-11-28 22:12:14 +00:00
|
|
|
/* If the symbol is marked as import or global, check the address size,
|
2014-06-30 05:10:35 -04:00
|
|
|
** then do silently remove the global flag.
|
|
|
|
*/
|
2003-11-13 00:21:31 +00:00
|
|
|
if (S->Flags & SF_IMPORT) {
|
2013-05-09 13:56:54 +02:00
|
|
|
if ((Flags & SF_FORCED) != (S->Flags & SF_FORCED)) {
|
|
|
|
Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S));
|
|
|
|
}
|
2003-11-13 00:21:31 +00:00
|
|
|
if (AddrSize != S->AddrSize) {
|
2008-03-31 20:54:45 +00:00
|
|
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
2003-11-13 00:21:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (S->Flags & SF_GLOBAL) {
|
2003-11-28 22:12:14 +00:00
|
|
|
S->Flags &= ~SF_GLOBAL;
|
|
|
|
if (AddrSize != S->AddrSize) {
|
2008-03-31 20:54:45 +00:00
|
|
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
2013-05-09 13:56:54 +02:00
|
|
|
}
|
2003-11-07 19:28:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the symbol data */
|
|
|
|
S->Flags |= (SF_IMPORT | Flags);
|
|
|
|
S->AddrSize = AddrSize;
|
2011-08-18 16:25:58 +00:00
|
|
|
|
|
|
|
/* Mark the position of the import as the position of the definition.
|
2014-06-30 05:10:35 -04:00
|
|
|
** Please note: In case of multiple .global or .import statements, the line
|
|
|
|
** infos add up.
|
|
|
|
*/
|
2011-08-18 16:25:58 +00:00
|
|
|
GetFullLineInfo (&S->DefLines);
|
2003-11-07 19:28:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
void SymExport (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
2003-11-07 19:28:37 +00:00
|
|
|
/* Mark the given symbol as an exported symbol */
|
|
|
|
{
|
|
|
|
/* Check if it's ok to export the symbol */
|
|
|
|
if (S->Flags & SF_IMPORT) {
|
2013-05-09 13:56:54 +02:00
|
|
|
/* The symbol is already marked as imported external symbol */
|
|
|
|
Error ("Symbol `%m%p' is already an import", GetSymName (S));
|
|
|
|
return;
|
2003-11-07 19:28:37 +00:00
|
|
|
}
|
2005-05-11 08:31:42 +00:00
|
|
|
if (S->Flags & SF_VAR) {
|
|
|
|
/* Variable symbols cannot be exported */
|
2008-03-31 20:54:45 +00:00
|
|
|
Error ("Var symbol `%m%p' cannot be exported", GetSymName (S));
|
2005-05-11 08:31:42 +00:00
|
|
|
return;
|
|
|
|
}
|
2003-11-07 19:28:37 +00:00
|
|
|
|
2003-11-28 22:12:14 +00:00
|
|
|
/* If the symbol was marked as global before, remove the global flag and
|
2014-06-30 05:10:35 -04:00
|
|
|
** proceed, but check the address size.
|
|
|
|
*/
|
2003-11-13 00:21:31 +00:00
|
|
|
if (S->Flags & SF_GLOBAL) {
|
2003-11-28 22:12:14 +00:00
|
|
|
if (AddrSize != S->ExportSize) {
|
2008-03-31 20:54:45 +00:00
|
|
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
2003-11-28 22:12:14 +00:00
|
|
|
}
|
2003-11-13 00:21:31 +00:00
|
|
|
S->Flags &= ~SF_GLOBAL;
|
2011-08-18 16:25:58 +00:00
|
|
|
|
|
|
|
/* .GLOBAL remembers line infos in case an .IMPORT follows. We have
|
2014-06-30 05:10:35 -04:00
|
|
|
** to remove these here.
|
|
|
|
*/
|
2011-08-18 16:25:58 +00:00
|
|
|
ReleaseFullLineInfo (&S->DefLines);
|
2003-11-13 00:21:31 +00:00
|
|
|
}
|
|
|
|
|
2003-11-28 22:12:14 +00:00
|
|
|
/* If the symbol was already marked as an export, but wasn't defined
|
2014-06-30 05:10:35 -04:00
|
|
|
** before, the address sizes in both definitions must match.
|
|
|
|
*/
|
2003-11-28 22:12:14 +00:00
|
|
|
if ((S->Flags & (SF_EXPORT|SF_DEFINED)) == SF_EXPORT) {
|
|
|
|
if (S->ExportSize != AddrSize) {
|
2008-03-31 20:54:45 +00:00
|
|
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
2003-11-07 19:28:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
S->ExportSize = AddrSize;
|
|
|
|
|
|
|
|
/* If the symbol is already defined, check symbol size against the
|
2014-06-30 05:10:35 -04:00
|
|
|
** exported size.
|
|
|
|
*/
|
2003-11-07 19:28:37 +00:00
|
|
|
if (S->Flags & SF_DEFINED) {
|
2003-11-11 13:57:30 +00:00
|
|
|
if (S->ExportSize == ADDR_SIZE_DEFAULT) {
|
2003-11-13 00:21:31 +00:00
|
|
|
/* No export size given, use the real size of the symbol */
|
2003-11-11 13:57:30 +00:00
|
|
|
S->ExportSize = S->AddrSize;
|
|
|
|
} else if (S->AddrSize > S->ExportSize) {
|
2003-11-28 22:12:14 +00:00
|
|
|
/* We're exporting a symbol smaller than it actually is */
|
2008-03-31 20:54:45 +00:00
|
|
|
Warning (1, "Symbol `%m%p' is %s but exported %s",
|
2003-11-13 00:21:31 +00:00
|
|
|
GetSymName (S), AddrSizeToStr (S->AddrSize),
|
|
|
|
AddrSizeToStr (S->ExportSize));
|
2003-11-07 19:28:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the symbol data */
|
|
|
|
S->Flags |= (SF_EXPORT | SF_REFERENCED | Flags);
|
2011-08-19 11:06:52 +00:00
|
|
|
|
|
|
|
/* Remember line info for this reference */
|
|
|
|
CollAppend (&S->RefLines, GetAsmLineInfo ());
|
2003-11-07 19:28:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
2003-11-07 19:28:37 +00:00
|
|
|
/* Mark the given symbol as a global symbol, that is, as a symbol that is
|
2014-06-30 05:10:35 -04:00
|
|
|
** either imported or exported.
|
|
|
|
*/
|
2003-11-07 19:28:37 +00:00
|
|
|
{
|
2005-05-11 08:31:42 +00:00
|
|
|
if (S->Flags & SF_VAR) {
|
|
|
|
/* Variable symbols cannot be exported or imported */
|
2008-03-31 20:54:45 +00:00
|
|
|
Error ("Var symbol `%m%p' cannot be made global", GetSymName (S));
|
2005-05-11 08:31:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-11-28 22:12:14 +00:00
|
|
|
/* If the symbol is already marked as import, the address size must match.
|
2014-06-30 05:10:35 -04:00
|
|
|
** Apart from that, ignore the global declaration.
|
|
|
|
*/
|
2003-11-07 19:28:37 +00:00
|
|
|
if (S->Flags & SF_IMPORT) {
|
2003-11-28 22:12:14 +00:00
|
|
|
if (AddrSize == ADDR_SIZE_DEFAULT) {
|
|
|
|
/* Use the size of the current segment */
|
|
|
|
AddrSize = GetCurrentSegAddrSize ();
|
|
|
|
}
|
|
|
|
if (AddrSize != S->AddrSize) {
|
2008-03-31 20:54:45 +00:00
|
|
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
2003-11-07 19:28:37 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2003-11-28 22:12:14 +00:00
|
|
|
|
|
|
|
/* If the symbol is already an export: If it is not defined, the address
|
2014-06-30 05:10:35 -04:00
|
|
|
** sizes must match.
|
|
|
|
*/
|
2003-11-07 19:28:37 +00:00
|
|
|
if (S->Flags & SF_EXPORT) {
|
2003-11-28 22:12:14 +00:00
|
|
|
if ((S->Flags & SF_DEFINED) == 0) {
|
|
|
|
/* Symbol is undefined */
|
|
|
|
if (AddrSize != S->ExportSize) {
|
2008-03-31 20:54:45 +00:00
|
|
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
2003-11-28 22:12:14 +00:00
|
|
|
}
|
|
|
|
} else if (AddrSize != ADDR_SIZE_DEFAULT) {
|
|
|
|
/* Symbol is defined and address size given */
|
|
|
|
if (AddrSize != S->ExportSize) {
|
2008-03-31 20:54:45 +00:00
|
|
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
2003-11-28 22:12:14 +00:00
|
|
|
}
|
2003-11-13 00:21:31 +00:00
|
|
|
}
|
2003-11-28 22:12:14 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the symbol is already marked as global, the address size must match.
|
2014-06-30 05:10:35 -04:00
|
|
|
** Use the ExportSize here, since it contains the actual address size
|
|
|
|
** passed to this function.
|
|
|
|
*/
|
2003-11-28 22:12:14 +00:00
|
|
|
if (S->Flags & SF_GLOBAL) {
|
2003-11-07 19:28:37 +00:00
|
|
|
if (AddrSize != S->ExportSize) {
|
2008-03-31 20:54:45 +00:00
|
|
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
2003-11-07 19:28:37 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-11-28 22:12:14 +00:00
|
|
|
/* If we come here, the symbol was neither declared as export, import or
|
2014-06-30 05:10:35 -04:00
|
|
|
** global before. Check if it is already defined, in which case it will
|
|
|
|
** become an export. If it is not defined, mark it as global and remember
|
|
|
|
** the given address sizes.
|
|
|
|
*/
|
2003-11-07 19:28:37 +00:00
|
|
|
if (S->Flags & SF_DEFINED) {
|
|
|
|
/* The symbol is defined, export it */
|
2003-11-13 00:21:31 +00:00
|
|
|
S->ExportSize = AddrSize;
|
|
|
|
if (S->ExportSize == ADDR_SIZE_DEFAULT) {
|
|
|
|
/* No export size given, use the real size of the symbol */
|
|
|
|
S->ExportSize = S->AddrSize;
|
|
|
|
} else if (S->AddrSize > S->ExportSize) {
|
2003-11-28 22:12:14 +00:00
|
|
|
/* We're exporting a symbol smaller than it actually is */
|
2008-03-31 20:54:45 +00:00
|
|
|
Warning (1, "Symbol `%m%p' is %s but exported %s",
|
2003-11-13 00:21:31 +00:00
|
|
|
GetSymName (S), AddrSizeToStr (S->AddrSize),
|
|
|
|
AddrSizeToStr (S->ExportSize));
|
2003-11-07 19:28:37 +00:00
|
|
|
}
|
|
|
|
S->Flags |= (SF_EXPORT | Flags);
|
|
|
|
} else {
|
2003-11-28 22:12:14 +00:00
|
|
|
/* Since we don't know if the symbol will get exported or imported,
|
2014-06-30 05:10:35 -04:00
|
|
|
** remember two different address sizes: One for an import in AddrSize,
|
|
|
|
** and the other one for an export in ExportSize.
|
|
|
|
*/
|
2003-11-07 19:28:37 +00:00
|
|
|
S->AddrSize = AddrSize;
|
2003-11-28 22:12:14 +00:00
|
|
|
if (S->AddrSize == ADDR_SIZE_DEFAULT) {
|
|
|
|
/* Use the size of the current segment */
|
|
|
|
S->AddrSize = GetCurrentSegAddrSize ();
|
|
|
|
}
|
|
|
|
S->ExportSize = AddrSize;
|
|
|
|
S->Flags |= (SF_GLOBAL | Flags);
|
2011-08-18 16:25:58 +00:00
|
|
|
|
|
|
|
/* Remember the current location as location of definition in case
|
2014-06-30 05:10:35 -04:00
|
|
|
** an .IMPORT follows later.
|
|
|
|
*/
|
2011-08-18 16:25:58 +00:00
|
|
|
GetFullLineInfo (&S->DefLines);
|
2003-11-07 19:28:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-13 00:21:31 +00:00
|
|
|
void SymConDes (SymEntry* S, unsigned char AddrSize, unsigned Type, unsigned Prio)
|
|
|
|
/* Mark the given symbol as a module constructor/destructor. This will also
|
2014-06-30 05:10:35 -04:00
|
|
|
** mark the symbol as an export. Initializers may never be zero page symbols.
|
|
|
|
*/
|
2003-11-13 00:21:31 +00:00
|
|
|
{
|
|
|
|
/* Check the parameters */
|
|
|
|
#if (CD_TYPE_MIN != 0)
|
|
|
|
CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
|
|
|
|
#else
|
|
|
|
CHECK (Type <= CD_TYPE_MAX);
|
|
|
|
#endif
|
|
|
|
CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
|
|
|
|
|
|
|
|
/* Check for errors */
|
|
|
|
if (S->Flags & SF_IMPORT) {
|
2013-05-09 13:56:54 +02:00
|
|
|
/* The symbol is already marked as imported external symbol */
|
|
|
|
Error ("Symbol `%m%p' is already an import", GetSymName (S));
|
|
|
|
return;
|
2003-11-13 00:21:31 +00:00
|
|
|
}
|
2005-05-11 08:31:42 +00:00
|
|
|
if (S->Flags & SF_VAR) {
|
|
|
|
/* Variable symbols cannot be exported or imported */
|
2008-03-31 20:54:45 +00:00
|
|
|
Error ("Var symbol `%m%p' cannot be exported", GetSymName (S));
|
2005-05-11 08:31:42 +00:00
|
|
|
return;
|
|
|
|
}
|
2003-11-13 00:21:31 +00:00
|
|
|
|
|
|
|
/* If the symbol was already marked as an export or global, check if
|
2014-06-30 05:10:35 -04:00
|
|
|
** this was done specifiying the same address size. In case of a global
|
|
|
|
** declaration, silently remove the global flag.
|
|
|
|
*/
|
2003-11-13 00:21:31 +00:00
|
|
|
if (S->Flags & (SF_EXPORT | SF_GLOBAL)) {
|
|
|
|
if (S->ExportSize != AddrSize) {
|
2008-03-31 20:54:45 +00:00
|
|
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
2003-11-13 00:21:31 +00:00
|
|
|
}
|
|
|
|
S->Flags &= ~SF_GLOBAL;
|
|
|
|
}
|
|
|
|
S->ExportSize = AddrSize;
|
|
|
|
|
|
|
|
/* If the symbol is already defined, check symbol size against the
|
2014-06-30 05:10:35 -04:00
|
|
|
** exported size.
|
|
|
|
*/
|
2003-11-13 00:21:31 +00:00
|
|
|
if (S->Flags & SF_DEFINED) {
|
|
|
|
if (S->ExportSize == ADDR_SIZE_DEFAULT) {
|
|
|
|
/* Use the real size of the symbol */
|
|
|
|
S->ExportSize = S->AddrSize;
|
|
|
|
} else if (S->AddrSize != S->ExportSize) {
|
2008-03-31 20:54:45 +00:00
|
|
|
Error ("Address size mismatch for symbol `%m%p'", GetSymName (S));
|
2003-11-13 00:21:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the symbol was already declared as a condes, check if the new
|
2014-06-30 05:10:35 -04:00
|
|
|
** priority value is the same as the old one.
|
|
|
|
*/
|
2003-11-13 00:21:31 +00:00
|
|
|
if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
|
2013-05-09 13:56:54 +02:00
|
|
|
if (S->ConDesPrio[Type] != Prio) {
|
|
|
|
Error ("Redeclaration mismatch for symbol `%m%p'", GetSymName (S));
|
|
|
|
}
|
2003-11-13 00:21:31 +00:00
|
|
|
}
|
|
|
|
S->ConDesPrio[Type] = Prio;
|
|
|
|
|
|
|
|
/* Set the symbol data */
|
|
|
|
S->Flags |= (SF_EXPORT | SF_REFERENCED);
|
2011-08-18 16:25:58 +00:00
|
|
|
|
|
|
|
/* In case we have no line info for the definition, record it now */
|
|
|
|
if (CollCount (&S->DefLines) == 0) {
|
|
|
|
GetFullLineInfo (&S->DefLines);
|
|
|
|
}
|
2003-11-13 00:21:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2006-04-09 10:56:23 +00:00
|
|
|
void SymGuessedAddrSize (SymEntry* Sym, unsigned char AddrSize)
|
|
|
|
/* Mark the address size of the given symbol as guessed. The address size
|
2014-06-30 05:10:35 -04:00
|
|
|
** passed as argument is the one NOT used, because the actual address size
|
|
|
|
** wasn't known. Example: Zero page addressing was not used because symbol
|
|
|
|
** is undefined, and absolute addressing was available.
|
|
|
|
*/
|
2006-04-09 10:56:23 +00:00
|
|
|
{
|
|
|
|
/* We must have a valid address size passed */
|
|
|
|
PRECONDITION (AddrSize != ADDR_SIZE_DEFAULT);
|
|
|
|
|
|
|
|
/* We do not support all address sizes currently */
|
|
|
|
if (AddrSize > sizeof (Sym->GuessedUse) / sizeof (Sym->GuessedUse[0])) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We can only remember one such occurance */
|
|
|
|
if (Sym->GuessedUse[AddrSize-1]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ok, remember the file position */
|
2011-01-16 16:05:43 +00:00
|
|
|
Sym->GuessedUse[AddrSize-1] = xdup (&CurTok.Pos, sizeof (CurTok.Pos));
|
2006-04-09 10:56:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2004-04-19 17:00:12 +00:00
|
|
|
void SymExportFromGlobal (SymEntry* S)
|
|
|
|
/* Called at the end of assembly. Converts a global symbol that is defined
|
2014-06-30 05:10:35 -04:00
|
|
|
** into an export.
|
|
|
|
*/
|
2004-04-19 17:00:12 +00:00
|
|
|
{
|
|
|
|
/* Remove the global flag and make the symbol an export */
|
|
|
|
S->Flags &= ~SF_GLOBAL;
|
|
|
|
S->Flags |= SF_EXPORT;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SymImportFromGlobal (SymEntry* S)
|
|
|
|
/* Called at the end of assembly. Converts a global symbol that is undefined
|
2014-06-30 05:10:35 -04:00
|
|
|
** into an import.
|
|
|
|
*/
|
2004-04-19 17:00:12 +00:00
|
|
|
{
|
|
|
|
/* Remove the global flag and make it an import */
|
|
|
|
S->Flags &= ~SF_GLOBAL;
|
|
|
|
S->Flags |= SF_IMPORT;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-08-17 20:47:27 +00:00
|
|
|
int SymIsConst (const SymEntry* S, long* Val)
|
2003-11-11 13:57:30 +00:00
|
|
|
/* Return true if the given symbol has a constant value. If Val is not NULL
|
2014-06-30 05:10:35 -04:00
|
|
|
** and the symbol has a constant value, store it's value there.
|
|
|
|
*/
|
2003-11-06 11:22:31 +00:00
|
|
|
{
|
2003-11-11 13:57:30 +00:00
|
|
|
/* Check for constness */
|
2003-12-13 20:56:31 +00:00
|
|
|
return (SymHasExpr (S) && IsConstExpr (S->Expr, Val));
|
2003-11-06 11:22:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-12-12 15:40:08 +00:00
|
|
|
SymTable* GetSymParentScope (SymEntry* S)
|
|
|
|
/* Get the parent scope of the symbol (not the one it is defined in). Return
|
2014-06-30 05:10:35 -04:00
|
|
|
** NULL if the symbol is a cheap local, or defined on global level.
|
|
|
|
*/
|
2003-12-12 15:40:08 +00:00
|
|
|
{
|
2010-08-17 16:58:41 +00:00
|
|
|
if ((S->Flags & SF_LOCAL) != 0) {
|
|
|
|
/* This is a cheap local symbol */
|
|
|
|
return 0;
|
2011-05-31 14:51:21 +00:00
|
|
|
} else if (S->Sym.Tab == 0) {
|
|
|
|
/* Symbol not in a table. This may happen if there have been errors
|
2014-06-30 05:10:35 -04:00
|
|
|
** before. Return NULL in this case to avoid further errors.
|
|
|
|
*/
|
2011-05-31 14:51:21 +00:00
|
|
|
return 0;
|
2010-08-17 16:58:41 +00:00
|
|
|
} else {
|
|
|
|
/* This is a global symbol */
|
|
|
|
return S->Sym.Tab->Parent;
|
|
|
|
}
|
2003-12-12 15:40:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-11 13:57:30 +00:00
|
|
|
struct ExprNode* GetSymExpr (SymEntry* S)
|
|
|
|
/* Get the expression for a non-const symbol */
|
2003-11-06 11:22:31 +00:00
|
|
|
{
|
2003-11-11 13:57:30 +00:00
|
|
|
PRECONDITION (S != 0 && SymHasExpr (S));
|
2003-12-13 20:56:31 +00:00
|
|
|
return S->Expr;
|
2003-11-06 11:22:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-11 13:57:30 +00:00
|
|
|
const struct ExprNode* SymResolve (const SymEntry* S)
|
|
|
|
/* Helper function for DumpExpr. Resolves a symbol into an expression or return
|
2014-06-30 05:10:35 -04:00
|
|
|
** NULL. Do not call in other contexts!
|
|
|
|
*/
|
2003-11-06 11:22:31 +00:00
|
|
|
{
|
2003-12-13 20:56:31 +00:00
|
|
|
return SymHasExpr (S)? S->Expr : 0;
|
2003-11-06 11:22:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-11-13 22:03:24 +00:00
|
|
|
long GetSymVal (SymEntry* S)
|
|
|
|
/* Return the value of a symbol assuming it's constant. FAIL will be called
|
2014-06-30 05:10:35 -04:00
|
|
|
** in case the symbol is undefined or not constant.
|
|
|
|
*/
|
2003-11-13 22:03:24 +00:00
|
|
|
{
|
|
|
|
long Val;
|
|
|
|
CHECK (S != 0 && SymHasExpr (S) && IsConstExpr (GetSymExpr (S), &Val));
|
|
|
|
return Val;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-08-17 20:01:54 +00:00
|
|
|
unsigned GetSymImportId (const SymEntry* S)
|
|
|
|
/* Return the import id for the given symbol */
|
2003-11-06 11:22:31 +00:00
|
|
|
{
|
2010-08-17 20:01:54 +00:00
|
|
|
PRECONDITION (S != 0 && (S->Flags & SF_IMPORT) && S->ImportId != ~0U);
|
|
|
|
return S->ImportId;
|
2003-11-06 11:22:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-08-16 12:52:56 +00:00
|
|
|
unsigned GetSymExportId (const SymEntry* S)
|
|
|
|
/* Return the export id for the given symbol */
|
|
|
|
{
|
2011-08-16 13:39:00 +00:00
|
|
|
PRECONDITION (S != 0 && (S->Flags & SF_EXPORT) && S->ExportId != ~0U);
|
2011-08-16 12:52:56 +00:00
|
|
|
return S->ExportId;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-08-17 20:47:27 +00:00
|
|
|
unsigned GetSymInfoFlags (const SymEntry* S, long* ConstVal)
|
|
|
|
/* Return a set of flags used when writing symbol information into a file.
|
2014-06-30 05:10:35 -04:00
|
|
|
** If the SYM_CONST bit is set, ConstVal will contain the constant value
|
|
|
|
** of the symbol. The result does not include the condes count.
|
|
|
|
** See common/symdefs.h for more information.
|
|
|
|
*/
|
2010-08-17 20:47:27 +00:00
|
|
|
{
|
|
|
|
/* Setup info flags */
|
|
|
|
unsigned Flags = 0;
|
|
|
|
Flags |= SymIsConst (S, ConstVal)? SYM_CONST : SYM_EXPR;
|
|
|
|
Flags |= (S->Flags & SF_LABEL)? SYM_LABEL : SYM_EQUATE;
|
2010-08-17 20:54:02 +00:00
|
|
|
Flags |= (S->Flags & SF_LOCAL)? SYM_CHEAP_LOCAL : SYM_STD;
|
2011-08-16 11:37:19 +00:00
|
|
|
if (S->Flags & SF_EXPORT) {
|
|
|
|
Flags |= SYM_EXPORT;
|
|
|
|
}
|
|
|
|
if (S->Flags & SF_IMPORT) {
|
|
|
|
Flags |= SYM_IMPORT;
|
|
|
|
}
|
2010-08-17 20:47:27 +00:00
|
|
|
|
|
|
|
/* Return the result */
|
|
|
|
return Flags;
|
|
|
|
}
|