mirror of
https://github.com/cc65/cc65.git
synced 2024-06-17 00:29:31 +00:00
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>
|
<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>
|
<sect1><tt>.WORD</tt><label id=".WORD"><p>
|
||||||
|
|
||||||
Define word sized data. Must be followed by a sequence of (word ranged,
|
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)
|
static void DoWord (void)
|
||||||
/* Define words */
|
/* Define words */
|
||||||
{
|
{
|
||||||
|
@ -2203,6 +2211,7 @@ static CtrlDesc CtrlCmdTab [] = {
|
||||||
{ ccNone, DoUnion },
|
{ ccNone, DoUnion },
|
||||||
{ ccNone, DoUnexpected }, /* .VERSION */
|
{ ccNone, DoUnexpected }, /* .VERSION */
|
||||||
{ ccNone, DoWarning },
|
{ ccNone, DoWarning },
|
||||||
|
{ ccNone, DoWeak },
|
||||||
{ ccNone, DoWord },
|
{ ccNone, DoWord },
|
||||||
{ ccNone, DoUnexpected }, /* .XMATCH */
|
{ ccNone, DoUnexpected }, /* .XMATCH */
|
||||||
{ ccNone, DoZeropage },
|
{ ccNone, DoZeropage },
|
||||||
|
|
|
@ -300,6 +300,7 @@ struct DotKeyword {
|
||||||
{ ".UNION", TOK_UNION },
|
{ ".UNION", TOK_UNION },
|
||||||
{ ".VERSION", TOK_VERSION },
|
{ ".VERSION", TOK_VERSION },
|
||||||
{ ".WARNING", TOK_WARNING },
|
{ ".WARNING", TOK_WARNING },
|
||||||
|
{ ".WEAK", TOK_WEAK },
|
||||||
{ ".WORD", TOK_WORD },
|
{ ".WORD", TOK_WORD },
|
||||||
{ ".XMATCH", TOK_XMATCH },
|
{ ".XMATCH", TOK_XMATCH },
|
||||||
{ ".XOR", TOK_BOOLXOR },
|
{ ".XOR", TOK_BOOLXOR },
|
||||||
|
|
|
@ -452,6 +452,11 @@ void SymGlobal (SymEntry* S, unsigned char AddrSize, unsigned Flags)
|
||||||
return;
|
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
|
/* If the symbol is already an export: If it is not defined, the address
|
||||||
** sizes must match.
|
** sizes must match.
|
||||||
*/
|
*/
|
||||||
|
@ -738,6 +743,9 @@ unsigned GetSymInfoFlags (const SymEntry* S, long* ConstVal)
|
||||||
if (S->Flags & SF_IMPORT) {
|
if (S->Flags & SF_IMPORT) {
|
||||||
Flags |= SYM_IMPORT;
|
Flags |= SYM_IMPORT;
|
||||||
}
|
}
|
||||||
|
if (S->Flags & SF_WEAK) {
|
||||||
|
Flags |= SYM_WEAK;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the result */
|
/* Return the result */
|
||||||
return Flags;
|
return Flags;
|
||||||
|
|
|
@ -71,6 +71,7 @@ struct HLLDbgSym;
|
||||||
#define SF_VAR 0x0080 /* Variable symbol */
|
#define SF_VAR 0x0080 /* Variable symbol */
|
||||||
#define SF_FORCED 0x0100 /* Forced import, SF_IMPORT also set */
|
#define SF_FORCED 0x0100 /* Forced import, SF_IMPORT also set */
|
||||||
#define SF_FIXED 0x0200 /* May not be trampoline */
|
#define SF_FIXED 0x0200 /* May not be trampoline */
|
||||||
|
#define SF_WEAK 0x0400 /* Weak symbol */
|
||||||
#define SF_MULTDEF 0x1000 /* Multiply defined symbol */
|
#define SF_MULTDEF 0x1000 /* Multiply defined symbol */
|
||||||
#define SF_DEFINED 0x2000 /* Defined */
|
#define SF_DEFINED 0x2000 /* Defined */
|
||||||
#define SF_REFERENCED 0x4000 /* Referenced */
|
#define SF_REFERENCED 0x4000 /* Referenced */
|
||||||
|
|
|
@ -265,6 +265,7 @@ typedef enum token_t {
|
||||||
TOK_UNION,
|
TOK_UNION,
|
||||||
TOK_VERSION,
|
TOK_VERSION,
|
||||||
TOK_WARNING,
|
TOK_WARNING,
|
||||||
|
TOK_WEAK,
|
||||||
TOK_WORD,
|
TOK_WORD,
|
||||||
TOK_XMATCH,
|
TOK_XMATCH,
|
||||||
TOK_ZEROPAGE,
|
TOK_ZEROPAGE,
|
||||||
|
|
|
@ -98,6 +98,12 @@
|
||||||
|
|
||||||
#define SYM_IS_IMPORT(x) (((x) & SYM_MASK_IMPORT) == SYM_IMPORT)
|
#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 */
|
/* 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)
|
static Import* NewImport (unsigned char AddrSize, ObjData* Obj)
|
||||||
/* Create a new import and initialize it */
|
/* Create a new import and initialize it */
|
||||||
{
|
{
|
||||||
|
@ -213,41 +321,10 @@ Import* GenImport (unsigned Name, unsigned char AddrSize)
|
||||||
Import* InsertImport (Import* I)
|
Import* InsertImport (Import* I)
|
||||||
/* Insert an import into the table, return I */
|
/* Insert an import into the table, return I */
|
||||||
{
|
{
|
||||||
Export* E;
|
|
||||||
|
|
||||||
/* As long as the import is not inserted, V.Name is valid */
|
/* 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 */
|
/* Insert the import into the imports list and update the counters. */
|
||||||
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.
|
|
||||||
*/
|
|
||||||
I->Exp = E;
|
I->Exp = E;
|
||||||
I->Next = E->ImpList;
|
I->Next = E->ImpList;
|
||||||
E->ImpList = I;
|
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)
|
void InsertExport (Export* E)
|
||||||
/* Insert an exported identifier and check if it's already in the list */
|
/* Insert an exported identifier and check if it's already in the list */
|
||||||
{
|
{
|
||||||
|
Export** ExportRef;
|
||||||
Export* L;
|
Export* L;
|
||||||
Export* Last;
|
|
||||||
Import* Imp;
|
|
||||||
unsigned Hash;
|
|
||||||
|
|
||||||
/* Mark the export as inserted */
|
/* Mark the export as inserted */
|
||||||
E->Flags |= EXP_INLIST;
|
E->Flags |= EXP_INLIST;
|
||||||
|
@ -443,59 +518,45 @@ void InsertExport (Export* E)
|
||||||
ConDesAddExport (E);
|
ConDesAddExport (E);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a hash value for the given name */
|
|
||||||
Hash = (E->Name & HASHTAB_MASK);
|
|
||||||
|
|
||||||
/* Search through the list in that slot */
|
/* Search through the list in that slot */
|
||||||
if (HashTab[Hash] == 0) {
|
ExportRef = GetExportRefRaw (E->Name);
|
||||||
/* The slot is empty */
|
L = *ExportRef;
|
||||||
HashTab[Hash] = E;
|
|
||||||
++ExpCount;
|
if (L == 0) {
|
||||||
|
/* The symbol was not found, so store the export in the symbol table. */
|
||||||
|
InsertExportAt (ExportRef, E);
|
||||||
} else {
|
} else {
|
||||||
|
/* Unresolved external, weak symbol or ODR (One Definition Rule)
|
||||||
Last = 0;
|
** violation?
|
||||||
L = HashTab[Hash];
|
*/
|
||||||
do {
|
if (L->Expr == 0) {
|
||||||
if (L->Name == E->Name) {
|
/* This *is* an unresolved external. Use the actual export
|
||||||
/* This may be an unresolved external */
|
** in E instead of the dummy one in L.
|
||||||
if (L->Expr == 0) {
|
*/
|
||||||
|
ReplaceExportAt (ExportRef, E);
|
||||||
/* This *is* an unresolved external. Use the actual export
|
ImpOpen -= E->ImpCount; /* Decrease open imports now */
|
||||||
** in E instead of the dummy one in L.
|
} else if (SYM_IS_WEAK (L->Type)) {
|
||||||
*/
|
/* The existing export is a weak symbol. Override it with the new
|
||||||
E->Next = L->Next;
|
** symbol (strong or weak) without any fuss.
|
||||||
E->ImpCount = L->ImpCount;
|
*/
|
||||||
E->ImpList = L->ImpList;
|
ReplaceExportAt (ExportRef, E);
|
||||||
if (Last) {
|
} else {
|
||||||
Last->Next = E;
|
/* Here the existing export is "strong" (not weak). If the new
|
||||||
} else {
|
** symbol is weak, *or* we explicitely specified at the command-line
|
||||||
HashTab[Hash] = E;
|
** that we allow multiple definitions (which effectively make all
|
||||||
}
|
** symbols weak) then that's OK and we can ignore the new weak
|
||||||
ImpOpen -= E->ImpCount; /* Decrease open imports now */
|
** symbol.
|
||||||
xfree (L);
|
*/
|
||||||
/* We must run through the import list and change the
|
if (!SYM_IS_WEAK (E->Type) && AllowMultDef == 0) {
|
||||||
** export pointer now.
|
/* Both the existing export and the new symbol are strong, so
|
||||||
*/
|
** this is an ODR violation.
|
||||||
Imp = E->ImpList;
|
*/
|
||||||
while (Imp) {
|
Error ("Duplicate external identifier: '%s'",
|
||||||
Imp->Exp = E;
|
GetString (L->Name));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
Last = L;
|
|
||||||
L = L->Next;
|
|
||||||
|
|
||||||
} while (L);
|
xfree (E);
|
||||||
|
}
|
||||||
/* Insert export at end of queue */
|
|
||||||
Last->Next = E;
|
|
||||||
++ExpCount;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,19 +670,8 @@ Export* FindExport (unsigned Name)
|
||||||
** return a pointer to the export.
|
** return a pointer to the export.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
/* Get a pointer to the list with the symbols hash value */
|
/* This gives a end of chain (NULL) or the pointer to the export */
|
||||||
Export* L = HashTab[Name & HASHTAB_MASK];
|
return *GetExportRefRaw (Name);
|
||||||
while (L) {
|
|
||||||
/* Search through the list in that slot */
|
|
||||||
if (L->Name == Name) {
|
|
||||||
/* Entry found */
|
|
||||||
return L;
|
|
||||||
}
|
|
||||||
L = L->Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Not found */
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -221,6 +221,10 @@ static const char* GetExportFlags (unsigned Flags, const unsigned char* ConDes)
|
||||||
case SYM_EXPR: strcat (TypeDesc, ",SYM_EXPR"); break;
|
case SYM_EXPR: strcat (TypeDesc, ",SYM_EXPR"); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Is the symbol weak? */
|
||||||
|
if (Flags & SYM_MASK_WEAK) {
|
||||||
|
strcat (TypeDesc, ",SYM_WEAK");
|
||||||
|
}
|
||||||
/* Size available? */
|
/* Size available? */
|
||||||
if (SYM_HAS_SIZE (Flags)) {
|
if (SYM_HAS_SIZE (Flags)) {
|
||||||
strcat (TypeDesc, ",SYM_SIZE");
|
strcat (TypeDesc, ",SYM_SIZE");
|
||||||
|
|
Loading…
Reference in New Issue
Block a user