From 4d1b288e008f13ca9db9606389e93bc3cef7c2d9 Mon Sep 17 00:00:00 2001 From: James-Adam Renquinha Henri Date: Fri, 5 Apr 2019 00:06:34 -0400 Subject: [PATCH 1/6] Basic support in ca65 --- src/ca65/pseudo.c | 9 +++++++++ src/ca65/scanner.c | 1 + src/ca65/symentry.h | 1 + src/ca65/token.h | 1 + 4 files changed, 12 insertions(+) diff --git a/src/ca65/pseudo.c b/src/ca65/pseudo.c index 5b2ef0573..aeda4942c 100644 --- a/src/ca65/pseudo.c +++ b/src/ca65/pseudo.c @@ -1924,6 +1924,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 */ { @@ -2121,6 +2129,7 @@ static CtrlDesc CtrlCmdTab [] = { { ccNone, DoUnion }, { ccNone, DoUnexpected }, /* .VERSION */ { ccNone, DoWarning }, + { ccNone, DoWeak }, { ccNone, DoWord }, { ccNone, DoUnexpected }, /* .XMATCH */ { ccNone, DoZeropage }, diff --git a/src/ca65/scanner.c b/src/ca65/scanner.c index 361a817c1..5f2066e49 100644 --- a/src/ca65/scanner.c +++ b/src/ca65/scanner.c @@ -292,6 +292,7 @@ struct DotKeyword { { ".UNION", TOK_UNION }, { ".VERSION", TOK_VERSION }, { ".WARNING", TOK_WARNING }, + { ".WEAK", TOK_WEAK }, { ".WORD", TOK_WORD }, { ".XMATCH", TOK_XMATCH }, { ".XOR", TOK_BOOLXOR }, diff --git a/src/ca65/symentry.h b/src/ca65/symentry.h index 5ac8f9c41..b5d8a8bd2 100644 --- a/src/ca65/symentry.h +++ b/src/ca65/symentry.h @@ -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 */ diff --git a/src/ca65/token.h b/src/ca65/token.h index 8998cc162..c135247de 100644 --- a/src/ca65/token.h +++ b/src/ca65/token.h @@ -259,6 +259,7 @@ typedef enum token_t { TOK_UNION, TOK_VERSION, TOK_WARNING, + TOK_WEAK, TOK_WORD, TOK_XMATCH, TOK_ZEROPAGE, From bb62011a59b91574fd00651642899f4f560c2c06 Mon Sep 17 00:00:00 2001 From: James-Adam Renquinha Henri Date: Sun, 7 Apr 2019 23:10:57 -0400 Subject: [PATCH 2/6] Emit "weakeness" into the object file. --- src/ca65/symentry.c | 3 +++ src/common/symdefs.h | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/src/ca65/symentry.c b/src/ca65/symentry.c index cf789da5e..33828102e 100644 --- a/src/ca65/symentry.c +++ b/src/ca65/symentry.c @@ -738,6 +738,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; diff --git a/src/common/symdefs.h b/src/common/symdefs.h index 1a487e0f3..76a22e0f5 100644 --- a/src/common/symdefs.h +++ b/src/common/symdefs.h @@ -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 */ From 1ba81c952e9caf4a8bd48fc3b82cf3f89fbc2a10 Mon Sep 17 00:00:00 2001 From: James-Adam Renquinha Henri Date: Sun, 7 Apr 2019 23:12:26 -0400 Subject: [PATCH 3/6] Show weak symbols in od65 --- src/od65/dump.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/od65/dump.c b/src/od65/dump.c index 2f538fe1d..da4dd57bf 100644 --- a/src/od65/dump.c +++ b/src/od65/dump.c @@ -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"); From 850922ae3be024275407f94292a1eb28f909a83e Mon Sep 17 00:00:00 2001 From: James-Adam Renquinha Henri Date: Fri, 19 Apr 2019 16:46:20 -0400 Subject: [PATCH 4/6] Weak symbol handling in ld65. Some refactoring to the symbol table handling code is done in doing so. --- src/ld65/exports.c | 250 +++++++++++++++++++++++++++------------------ 1 file changed, 150 insertions(+), 100 deletions(-) diff --git a/src/ld65/exports.c b/src/ld65/exports.c index 5df7a37c9..c7f54aef0 100644 --- a/src/ld65/exports.c +++ b/src/ld65/exports.c @@ -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); } From 1c73128222790c8136fc94abdc53d90522479b29 Mon Sep 17 00:00:00 2001 From: James-Adam Renquinha Henri Date: Sat, 4 May 2019 10:43:30 -0400 Subject: [PATCH 5/6] Documentation for .WEAK in ca65. --- doc/ca65.sgml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/doc/ca65.sgml b/doc/ca65.sgml index 8d97bddfd..a80da5a4f 100644 --- a/doc/ca65.sgml +++ b/doc/ca65.sgml @@ -3977,6 +3977,28 @@ Here's a list of all control commands and a description, what they do: +.WEAK