mirror of https://github.com/cc65/cc65.git
Merge 179efc99fd
into b1e1c13d4b
This commit is contained in:
commit
22b73a7e3b
|
@ -4156,6 +4156,28 @@ See: <tt><ref id=".ASCIIZ" name=".ASCIIZ"></tt>,<tt><ref id=".BYTE" name=".BYTE"
|
|||
<tt><ref id=".OUT" name=".OUT"></tt>
|
||||
|
||||
|
||||
<sect1><tt>.WEAK</tt><label id=".WEAK"><p>
|
||||
|
||||
Declare or make an existing symbol weak. Weak symbols can be overriden by a
|
||||
"strong" (regular) symbol or other weak symbols at the link stage. Note that
|
||||
redefinition of a symbol is still not allowed within the same source file,
|
||||
even for weak ones.
|
||||
|
||||
You don't need to use an additional <tt><ref id=".GLOBAL" name=".GLOBAL"></tt>
|
||||
statement, this is implied by <tt/.WEAK/.
|
||||
|
||||
Example:
|
||||
|
||||
<tscreen><verb>
|
||||
.weak NumDisks
|
||||
|
||||
NumDisks = 1 ; NumDisks has a default value of 1, but another source
|
||||
; file may override it.
|
||||
</verb></tscreen>
|
||||
|
||||
See also: <tt><ref id=".GLOBAL" name=".GLOBAL"></tt>
|
||||
|
||||
|
||||
<sect1><tt>.WORD</tt><label id=".WORD"><p>
|
||||
|
||||
Define word sized data. Must be followed by a sequence of (word ranged,
|
||||
|
|
|
@ -2000,6 +2000,14 @@ static void DoWarning (void)
|
|||
|
||||
|
||||
|
||||
static void DoWeak (void)
|
||||
/* Declare a weak symbol */
|
||||
{
|
||||
ExportImport (SymGlobal, ADDR_SIZE_DEFAULT, SF_WEAK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void DoWord (void)
|
||||
/* Define words */
|
||||
{
|
||||
|
@ -2203,6 +2211,7 @@ static CtrlDesc CtrlCmdTab [] = {
|
|||
{ ccNone, DoUnion },
|
||||
{ ccNone, DoUnexpected }, /* .VERSION */
|
||||
{ ccNone, DoWarning },
|
||||
{ ccNone, DoWeak },
|
||||
{ ccNone, DoWord },
|
||||
{ ccNone, DoUnexpected }, /* .XMATCH */
|
||||
{ ccNone, DoZeropage },
|
||||
|
|
|
@ -300,6 +300,7 @@ struct DotKeyword {
|
|||
{ ".UNION", TOK_UNION },
|
||||
{ ".VERSION", TOK_VERSION },
|
||||
{ ".WARNING", TOK_WARNING },
|
||||
{ ".WEAK", TOK_WEAK },
|
||||
{ ".WORD", TOK_WORD },
|
||||
{ ".XMATCH", TOK_XMATCH },
|
||||
{ ".XOR", TOK_BOOLXOR },
|
||||
|
|
|
@ -452,6 +452,11 @@ void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
|||
return;
|
||||
}
|
||||
|
||||
/* In any case, mark the symbol as "weak", if it is not an import. This will
|
||||
** allow declaring a global or an export, then "weaken" it afterwards.
|
||||
*/
|
||||
S->Flags |= (Flags & SF_WEAK);
|
||||
|
||||
/* If the symbol is already an export: If it is not defined, the address
|
||||
** sizes must match.
|
||||
*/
|
||||
|
@ -738,6 +743,9 @@ unsigned GetSymInfoFlags (const SymEntry* S, long* ConstVal)
|
|||
if (S->Flags & SF_IMPORT) {
|
||||
Flags |= SYM_IMPORT;
|
||||
}
|
||||
if (S->Flags & SF_WEAK) {
|
||||
Flags |= SYM_WEAK;
|
||||
}
|
||||
|
||||
/* Return the result */
|
||||
return Flags;
|
||||
|
|
|
@ -71,6 +71,7 @@ struct HLLDbgSym;
|
|||
#define SF_VAR 0x0080 /* Variable symbol */
|
||||
#define SF_FORCED 0x0100 /* Forced import, SF_IMPORT also set */
|
||||
#define SF_FIXED 0x0200 /* May not be trampoline */
|
||||
#define SF_WEAK 0x0400 /* Weak symbol */
|
||||
#define SF_MULTDEF 0x1000 /* Multiply defined symbol */
|
||||
#define SF_DEFINED 0x2000 /* Defined */
|
||||
#define SF_REFERENCED 0x4000 /* Referenced */
|
||||
|
|
|
@ -265,6 +265,7 @@ typedef enum token_t {
|
|||
TOK_UNION,
|
||||
TOK_VERSION,
|
||||
TOK_WARNING,
|
||||
TOK_WEAK,
|
||||
TOK_WORD,
|
||||
TOK_XMATCH,
|
||||
TOK_ZEROPAGE,
|
||||
|
|
|
@ -98,6 +98,12 @@
|
|||
|
||||
#define SYM_IS_IMPORT(x) (((x) & SYM_MASK_IMPORT) == SYM_IMPORT)
|
||||
|
||||
/* Weak symbols */
|
||||
#define SYM_WEAK 0x0200U /* Weak */
|
||||
#define SYM_MASK_WEAK 0x0200U /* Value mask */
|
||||
|
||||
#define SYM_IS_WEAK(x) (((x) & SYM_MASK_WEAK) == SYM_WEAK)
|
||||
|
||||
|
||||
|
||||
/* End of symdefs.h */
|
||||
|
|
|
@ -88,7 +88,7 @@ static Export** ExpPool = 0; /* Exports array */
|
|||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Import handling */
|
||||
/* Symbol table handling */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
@ -99,6 +99,114 @@ static Export* NewExport (unsigned Type, unsigned char AddrSize,
|
|||
|
||||
|
||||
|
||||
static void UpdateExportsInImportList (Export *E)
|
||||
/* Update all exports in the given export's import list */
|
||||
{
|
||||
Import* I = E->ImpList;
|
||||
|
||||
while (I) {
|
||||
I->Exp = E;
|
||||
I = I->Next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static Export** GetExportRefRaw (unsigned Name)
|
||||
/* Check for an identifier in the symbol table and return the pointer to its
|
||||
** preceding chain pointer. If the element is not found, the last pointer in
|
||||
** the chain is returned.
|
||||
**/
|
||||
{
|
||||
/* Pointer to the first chain in the bucket. */
|
||||
Export** Ref = &HashTab[Name & HASHTAB_MASK];
|
||||
Export* E;
|
||||
|
||||
while (1)
|
||||
{
|
||||
E = *Ref;
|
||||
/* Either its the end of chain, or the element is found. */
|
||||
if (E == 0 || E->Name == Name)
|
||||
return Ref;
|
||||
|
||||
/* Go to the next element in the chain. */
|
||||
Ref = &E->Next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static Export* InsertExportAt (Export** Ref, Export* Value)
|
||||
/* Insert an export at a given position */
|
||||
{
|
||||
/* Value must not be NULL */
|
||||
PRECONDITION (Value != 0);
|
||||
|
||||
/* Not at end of chain? */
|
||||
if (*Ref != 0) {
|
||||
/* Point to the rest of the chain. */
|
||||
Value->Next = (*Ref)->Next;
|
||||
}
|
||||
|
||||
*Ref = Value;
|
||||
++ExpCount; /* One more export */
|
||||
|
||||
return Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static Export* ReplaceExportAt (Export** Ref, Export* Value)
|
||||
/* Replace the given export by another one */
|
||||
{
|
||||
/* Value must not be NULL */
|
||||
PRECONDITION (Value != 0);
|
||||
|
||||
Export* E = *Ref;
|
||||
|
||||
/* At end of chain? */
|
||||
if (E == 0) {
|
||||
/* Treat it as an insertion and quit */
|
||||
return InsertExportAt (Ref, Value);
|
||||
}
|
||||
|
||||
Value->Next = E->Next;
|
||||
Value->ImpCount = E->ImpCount;
|
||||
Value->ImpList = E->ImpList;
|
||||
*Ref = Value;
|
||||
xfree (E);
|
||||
/* We must run through the import list and change the
|
||||
** export pointer now.
|
||||
*/
|
||||
UpdateExportsInImportList (Value);
|
||||
|
||||
return Value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static Export* GetOrCreateExport (unsigned Name)
|
||||
/* Try to find an export, create one if it doesn't exist */
|
||||
{
|
||||
Export** Ref = GetExportRefRaw (Name);
|
||||
|
||||
/* Not found? */
|
||||
if (*Ref == 0) {
|
||||
/* Insert a dummy export */
|
||||
InsertExportAt (Ref, NewExport (0, ADDR_SIZE_DEFAULT, Name, 0));
|
||||
}
|
||||
|
||||
return *Ref;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Import handling */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
static Import* NewImport (unsigned char AddrSize, ObjData* Obj)
|
||||
/* Create a new import and initialize it */
|
||||
{
|
||||
|
@ -213,41 +321,10 @@ Import* GenImport (unsigned Name, unsigned char AddrSize)
|
|||
Import* InsertImport (Import* I)
|
||||
/* Insert an import into the table, return I */
|
||||
{
|
||||
Export* E;
|
||||
|
||||
/* As long as the import is not inserted, V.Name is valid */
|
||||
unsigned Name = I->Name;
|
||||
Export* E = GetOrCreateExport (I->Name);
|
||||
|
||||
/* Create a hash value for the given name */
|
||||
unsigned Hash = (Name & HASHTAB_MASK);
|
||||
|
||||
/* Search through the list in that slot for a symbol with that name */
|
||||
if (HashTab[Hash] == 0) {
|
||||
/* The slot is empty, we need to insert a dummy export */
|
||||
E = HashTab[Hash] = NewExport (0, ADDR_SIZE_DEFAULT, Name, 0);
|
||||
++ExpCount;
|
||||
} else {
|
||||
E = HashTab [Hash];
|
||||
while (1) {
|
||||
if (E->Name == Name) {
|
||||
/* We have an entry, L points to it */
|
||||
break;
|
||||
}
|
||||
if (E->Next == 0) {
|
||||
/* End of list an entry not found, insert a dummy */
|
||||
E->Next = NewExport (0, ADDR_SIZE_DEFAULT, Name, 0);
|
||||
E = E->Next; /* Point to dummy */
|
||||
++ExpCount; /* One export more */
|
||||
break;
|
||||
} else {
|
||||
E = E->Next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Ok, E now points to a valid exports entry for the given import. Insert
|
||||
** the import into the imports list and update the counters.
|
||||
*/
|
||||
/* Insert the import into the imports list and update the counters. */
|
||||
I->Exp = E;
|
||||
I->Next = E->ImpList;
|
||||
E->ImpList = I;
|
||||
|
@ -281,7 +358,7 @@ const LineInfo* GetImportPos (const Import* Imp)
|
|||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Code */
|
||||
/* Export handling */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
@ -430,10 +507,8 @@ Export* ReadExport (FILE* F, ObjData* O)
|
|||
void InsertExport (Export* E)
|
||||
/* Insert an exported identifier and check if it's already in the list */
|
||||
{
|
||||
Export** ExportRef;
|
||||
Export* L;
|
||||
Export* Last;
|
||||
Import* Imp;
|
||||
unsigned Hash;
|
||||
|
||||
/* Mark the export as inserted */
|
||||
E->Flags |= EXP_INLIST;
|
||||
|
@ -443,59 +518,45 @@ void InsertExport (Export* E)
|
|||
ConDesAddExport (E);
|
||||
}
|
||||
|
||||
/* Create a hash value for the given name */
|
||||
Hash = (E->Name & HASHTAB_MASK);
|
||||
|
||||
/* Search through the list in that slot */
|
||||
if (HashTab[Hash] == 0) {
|
||||
/* The slot is empty */
|
||||
HashTab[Hash] = E;
|
||||
++ExpCount;
|
||||
ExportRef = GetExportRefRaw (E->Name);
|
||||
L = *ExportRef;
|
||||
|
||||
if (L == 0) {
|
||||
/* The symbol was not found, so store the export in the symbol table. */
|
||||
InsertExportAt (ExportRef, E);
|
||||
} else {
|
||||
|
||||
Last = 0;
|
||||
L = HashTab[Hash];
|
||||
do {
|
||||
if (L->Name == E->Name) {
|
||||
/* This may be an unresolved external */
|
||||
if (L->Expr == 0) {
|
||||
|
||||
/* This *is* an unresolved external. Use the actual export
|
||||
** in E instead of the dummy one in L.
|
||||
*/
|
||||
E->Next = L->Next;
|
||||
E->ImpCount = L->ImpCount;
|
||||
E->ImpList = L->ImpList;
|
||||
if (Last) {
|
||||
Last->Next = E;
|
||||
} else {
|
||||
HashTab[Hash] = E;
|
||||
}
|
||||
ImpOpen -= E->ImpCount; /* Decrease open imports now */
|
||||
xfree (L);
|
||||
/* We must run through the import list and change the
|
||||
** export pointer now.
|
||||
*/
|
||||
Imp = E->ImpList;
|
||||
while (Imp) {
|
||||
Imp->Exp = E;
|
||||
Imp = Imp->Next;
|
||||
}
|
||||
} else if (AllowMultDef == 0) {
|
||||
/* Duplicate entry, this is fatal unless allowed by the user */
|
||||
Error ("Duplicate external identifier: '%s'",
|
||||
GetString (L->Name));
|
||||
}
|
||||
return;
|
||||
/* Unresolved external, weak symbol or ODR (One Definition Rule)
|
||||
** violation?
|
||||
*/
|
||||
if (L->Expr == 0) {
|
||||
/* This *is* an unresolved external. Use the actual export
|
||||
** in E instead of the dummy one in L.
|
||||
*/
|
||||
ReplaceExportAt (ExportRef, E);
|
||||
ImpOpen -= E->ImpCount; /* Decrease open imports now */
|
||||
} else if (SYM_IS_WEAK (L->Type)) {
|
||||
/* The existing export is a weak symbol. Override it with the new
|
||||
** symbol (strong or weak) without any fuss.
|
||||
*/
|
||||
ReplaceExportAt (ExportRef, E);
|
||||
} else {
|
||||
/* Here the existing export is "strong" (not weak). If the new
|
||||
** symbol is weak, *or* we explicitely specified at the command-line
|
||||
** that we allow multiple definitions (which effectively make all
|
||||
** symbols weak) then that's OK and we can ignore the new weak
|
||||
** symbol.
|
||||
*/
|
||||
if (!SYM_IS_WEAK (E->Type) && AllowMultDef == 0) {
|
||||
/* Both the existing export and the new symbol are strong, so
|
||||
** this is an ODR violation.
|
||||
*/
|
||||
Error ("Duplicate external identifier: '%s'",
|
||||
GetString (L->Name));
|
||||
}
|
||||
Last = L;
|
||||
L = L->Next;
|
||||
|
||||
} while (L);
|
||||
|
||||
/* Insert export at end of queue */
|
||||
Last->Next = E;
|
||||
++ExpCount;
|
||||
xfree (E);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -609,19 +670,8 @@ Export* FindExport (unsigned Name)
|
|||
** return a pointer to the export.
|
||||
*/
|
||||
{
|
||||
/* Get a pointer to the list with the symbols hash value */
|
||||
Export* L = HashTab[Name & HASHTAB_MASK];
|
||||
while (L) {
|
||||
/* Search through the list in that slot */
|
||||
if (L->Name == Name) {
|
||||
/* Entry found */
|
||||
return L;
|
||||
}
|
||||
L = L->Next;
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return 0;
|
||||
/* This gives a end of chain (NULL) or the pointer to the export */
|
||||
return *GetExportRefRaw (Name);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -221,6 +221,10 @@ static const char* GetExportFlags (unsigned Flags, const unsigned char* ConDes)
|
|||
case SYM_EXPR: strcat (TypeDesc, ",SYM_EXPR"); break;
|
||||
}
|
||||
|
||||
/* Is the symbol weak? */
|
||||
if (Flags & SYM_MASK_WEAK) {
|
||||
strcat (TypeDesc, ",SYM_WEAK");
|
||||
}
|
||||
/* Size available? */
|
||||
if (SYM_HAS_SIZE (Flags)) {
|
||||
strcat (TypeDesc, ",SYM_SIZE");
|
||||
|
|
Loading…
Reference in New Issue