1 /*****************************************************************************/
5 /* Exports handling for the ld65 linker */
9 /* (C) 1998-2011, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
61 /*****************************************************************************/
63 /*****************************************************************************/
68 #define HASHTAB_MASK 0x0FFFU
69 #define HASHTAB_SIZE (HASHTAB_MASK + 1)
70 static Export* HashTab[HASHTAB_SIZE];
72 /* Import management variables */
73 static unsigned ImpCount = 0; /* Import count */
74 static unsigned ImpOpen = 0; /* Count of open imports */
76 /* Export management variables */
77 static unsigned ExpCount = 0; /* Export count */
78 static Export** ExpPool = 0; /* Exports array */
80 /* Defines for the flags in Import */
81 #define IMP_INLIST 0x0001U /* Import is in exports list */
83 /* Defines for the flags in Export */
84 #define EXP_INLIST 0x0001U /* Export is in exports list */
85 #define EXP_USERMARK 0x0002U /* User setable flag */
89 /*****************************************************************************/
91 /*****************************************************************************/
95 static Export* NewExport (unsigned char Type, unsigned char AddrSize,
96 unsigned Name, ObjData* Obj);
97 /* Create a new export and initialize it */
101 static Import* NewImport (unsigned char AddrSize, ObjData* Obj)
102 /* Create a new import and initialize it */
104 /* Allocate memory */
105 Import* I = xmalloc (sizeof (Import));
107 /* Initialize the fields */
110 I->LineInfos = EmptyCollection;
112 I->Name = INVALID_STRING_ID;
114 I->AddrSize = AddrSize;
116 /* Return the new structure */
122 void FreeImport (Import* I)
123 /* Free an import. NOTE: This won't remove the import from the exports table,
124 * so it may only be called for unused imports (imports from modules that
125 * aren't referenced).
129 PRECONDITION ((I->Flags & IMP_INLIST) == 0);
131 /* Free the line info collection */
132 DoneCollection (&I->LineInfos);
134 /* Free the struct */
140 Import* ReadImport (FILE* F, ObjData* Obj)
141 /* Read an import from a file and return it */
145 /* Read the import address size */
146 unsigned char AddrSize = Read8 (F);
148 /* Create a new import */
149 I = NewImport (AddrSize, Obj);
152 I->Name = MakeGlobalStringId (Obj, ReadVar (F));
154 /* Read the line infos */
155 ReadLineInfoList (F, Obj, &I->LineInfos);
157 /* Check the address size */
158 if (I->AddrSize == ADDR_SIZE_DEFAULT || I->AddrSize > ADDR_SIZE_LONG) {
159 /* Beware: This function may be called in cases where the object file
160 * is not read completely into memory. In this case, the file list is
161 * invalid. Be sure not to access it in this case.
163 if (ObjHasFiles (I->Obj)) {
164 const LineInfo* LI = GetImportPos (I);
165 Error ("Invalid import size in for `%s', imported from %s(%lu): 0x%02X",
171 Error ("Invalid import size in for `%s', imported from %s: 0x%02X",
173 GetObjFileName (I->Obj),
178 /* Return the new import */
184 Import* GenImport (unsigned Name, unsigned char AddrSize)
185 /* Generate a new import with the given name and address size and return it */
187 /* Create a new import */
188 Import* I = NewImport (AddrSize, 0);
193 /* Check the address size */
194 if (I->AddrSize == ADDR_SIZE_DEFAULT || I->AddrSize > ADDR_SIZE_LONG) {
195 /* Beware: This function may be called in cases where the object file
196 * is not read completely into memory. In this case, the file list is
197 * invalid. Be sure not to access it in this case.
199 if (ObjHasFiles (I->Obj)) {
200 const LineInfo* LI = GetImportPos (I);
201 Error ("Invalid import size in for `%s', imported from %s(%lu): 0x%02X",
207 Error ("Invalid import size in for `%s', imported from %s: 0x%02X",
209 GetObjFileName (I->Obj),
214 /* Return the new import */
220 Import* InsertImport (Import* I)
221 /* Insert an import into the table, return I */
225 /* As long as the import is not inserted, V.Name is valid */
226 unsigned Name = I->Name;
228 /* Create a hash value for the given name */
229 unsigned Hash = (Name & HASHTAB_MASK);
231 /* Search through the list in that slot and print matching duplicates */
232 if (HashTab[Hash] == 0) {
233 /* The slot is empty, we need to insert a dummy export */
234 E = HashTab[Hash] = NewExport (0, ADDR_SIZE_DEFAULT, Name, 0);
239 if (E->Name == Name) {
240 /* We have an entry, L points to it */
244 /* End of list an entry not found, insert a dummy */
245 E->Next = NewExport (0, ADDR_SIZE_DEFAULT, Name, 0);
246 E = E->Next; /* Point to dummy */
247 ++ExpCount; /* One export more */
255 /* Ok, E now points to a valid exports entry for the given import. Insert
256 * the import into the imports list and update the counters.
259 I->Next = E->ImpList;
262 ++ImpCount; /* Total import count */
264 /* This is a dummy export */
268 /* Mark the import so we know it's in the list */
269 I->Flags |= IMP_INLIST;
271 /* Return the import to allow shorter code */
277 const LineInfo* GetImportPos (const Import* I)
278 /* Return the basic line info of an import */
280 /* Source file position is always in slot zero */
281 return CollConstAt (&I->LineInfos, 0);
286 /*****************************************************************************/
288 /*****************************************************************************/
292 static Export* NewExport (unsigned char Type, unsigned char AddrSize,
293 unsigned Name, ObjData* Obj)
294 /* Create a new export and initialize it */
296 /* Allocate memory */
297 Export* E = xmalloc (sizeof (Export));
299 /* Initialize the fields */
307 E->LineInfos = EmptyCollection;
309 E->AddrSize = AddrSize;
310 memset (E->ConDes, 0, sizeof (E->ConDes));
312 /* Return the new entry */
318 void FreeExport (Export* E)
319 /* Free an export. NOTE: This won't remove the export from the exports table,
320 * so it may only be called for unused exports (exports from modules that
321 * aren't referenced).
325 PRECONDITION ((E->Flags & EXP_INLIST) == 0);
327 /* Free the line infos */
328 DoneCollection (&E->LineInfos);
330 /* Free the export expression */
333 /* Free the struct */
339 Export* ReadExport (FILE* F, ObjData* O)
340 /* Read an export from a file */
342 unsigned ConDesCount;
346 unsigned Type = ReadVar (F);
348 /* Read the address size */
349 unsigned char AddrSize = Read8 (F);
351 /* Create a new export without a name */
352 E = NewExport (Type, AddrSize, INVALID_STRING_ID, O);
354 /* Read the constructor/destructor decls if we have any */
355 ConDesCount = SYM_GET_CONDES_COUNT (Type);
356 if (ConDesCount > 0) {
358 unsigned char ConDes[CD_TYPE_COUNT];
361 /* Read the data into temp storage */
362 ReadData (F, ConDes, ConDesCount);
364 /* Re-order the data. In the file, each decl is encoded into a byte
365 * which contains the type and the priority. In memory, we will use
366 * an array of types which contain the priority. This array was
367 * cleared by the constructor (NewExport), so we must only set the
368 * fields that contain values.
370 for (I = 0; I < ConDesCount; ++I) {
371 unsigned ConDesType = CD_GET_TYPE (ConDes[I]);
372 unsigned ConDesPrio = CD_GET_PRIO (ConDes[I]);
373 E->ConDes[ConDesType] = ConDesPrio;
378 E->Name = MakeGlobalStringId (O, ReadVar (F));
381 if (SYM_IS_EXPR (Type)) {
382 E->Expr = ReadExpr (F, O);
384 E->Expr = LiteralExpr (Read32 (F), O);
387 /* Last is the file position where the definition was done */
388 ReadLineInfoList (F, O, &E->LineInfos);
390 /* Return the new export */
396 void InsertExport (Export* E)
397 /* Insert an exported identifier and check if it's already in the list */
404 /* Mark the export as inserted */
405 E->Flags |= EXP_INLIST;
407 /* Insert the export into any condes tables if needed */
408 if (SYM_IS_CONDES (E->Type)) {
412 /* Create a hash value for the given name */
413 Hash = (E->Name & HASHTAB_MASK);
415 /* Search through the list in that slot */
416 if (HashTab[Hash] == 0) {
417 /* The slot is empty */
425 if (L->Name == E->Name) {
426 /* This may be an unresolved external */
429 /* This *is* an unresolved external. Use the actual export
430 * in E instead of the dummy one in L.
433 E->ImpCount = L->ImpCount;
434 E->ImpList = L->ImpList;
440 ImpOpen -= E->ImpCount; /* Decrease open imports now */
442 /* We must run through the import list and change the
443 * export pointer now.
451 /* Duplicate entry, ignore it */
452 Warning ("Duplicate external identifier: `%s'",
453 GetString (L->Name));
462 /* Insert export at end of queue */
470 const LineInfo* GetExportPos (const Export* E)
471 /* Return the basic line info of an export */
473 /* Source file position is always in slot zero */
474 return CollConstAt (&E->LineInfos, 0);
479 Export* CreateConstExport (unsigned Name, long Value)
480 /* Create an export for a literal date */
482 /* Create a new export */
483 Export* E = NewExport (SYM_CONST | SYM_EQUATE, ADDR_SIZE_ABS, Name, 0);
485 /* Assign the value */
486 E->Expr = LiteralExpr (Value, 0);
488 /* Insert the export */
491 /* Return the new export */
497 Export* CreateExprExport (unsigned Name, ExprNode* Expr, unsigned char AddrSize)
498 /* Create an export for an expression */
500 /* Create a new export */
501 Export* E = NewExport (SYM_EXPR | SYM_EQUATE, AddrSize, Name, 0);
503 /* Assign the value expression */
506 /* Insert the export */
509 /* Return the new export */
515 Export* CreateMemoryExport (unsigned Name, MemoryArea* Mem, unsigned long Offs)
516 /* Create an relative export for a memory area offset */
518 /* Create a new export */
519 Export* E = NewExport (SYM_EXPR | SYM_LABEL, ADDR_SIZE_ABS, Name, 0);
521 /* Assign the value */
522 E->Expr = MemoryExpr (Mem, Offs, 0);
524 /* Insert the export */
527 /* Return the new export */
533 Export* CreateSegmentExport (unsigned Name, Segment* Seg, unsigned long Offs)
534 /* Create a relative export to a segment */
536 /* Create a new export */
537 Export* E = NewExport (SYM_EXPR | SYM_LABEL, Seg->AddrSize, Name, 0);
539 /* Assign the value */
540 E->Expr = SegmentExpr (Seg, Offs, 0);
542 /* Insert the export */
545 /* Return the new export */
551 Export* CreateSectionExport (unsigned Name, Section* Sec, unsigned long Offs)
552 /* Create a relative export to a section */
554 /* Create a new export */
555 Export* E = NewExport (SYM_EXPR | SYM_LABEL, Sec->AddrSize, Name, 0);
557 /* Assign the value */
558 E->Expr = SectionExpr (Sec, Offs, 0);
560 /* Insert the export */
563 /* Return the new export */
569 Export* FindExport (unsigned Name)
570 /* Check for an identifier in the list. Return 0 if not found, otherwise
571 * return a pointer to the export.
574 /* Get a pointer to the list with the symbols hash value */
575 Export* L = HashTab[Name & HASHTAB_MASK];
577 /* Search through the list in that slot */
578 if (L->Name == Name) {
591 int IsUnresolved (unsigned Name)
592 /* Check if this symbol is an unresolved export */
594 /* Find the export */
595 return IsUnresolvedExport (FindExport (Name));
600 int IsUnresolvedExport (const Export* E)
601 /* Return true if the given export is unresolved */
603 /* Check if it's unresolved */
604 return E != 0 && E->Expr == 0;
609 int IsConstExport (const Export* E)
610 /* Return true if the expression associated with this export is const */
613 /* External symbols cannot be const */
616 return IsConstExpr (E->Expr);
622 long GetExportVal (const Export* E)
623 /* Get the value of this export */
627 Internal ("`%s' is an undefined external", GetString (E->Name));
629 return GetExprVal (E->Expr);
634 static void CheckSymType (const Export* E)
635 /* Check the types for one export */
637 /* External with matching imports */
638 Import* I = E->ImpList;
640 if (E->AddrSize != I->AddrSize) {
641 /* Export and import address sizes do not match */
642 StrBuf ExportLoc = STATIC_STRBUF_INITIALIZER;
643 StrBuf ImportLoc = STATIC_STRBUF_INITIALIZER;
644 const char* ExpAddrSize = AddrSizeToStr (E->AddrSize);
645 const char* ImpAddrSize = AddrSizeToStr (I->AddrSize);
646 const LineInfo* ExportLI = GetExportPos (E);
647 const LineInfo* ImportLI = GetImportPos (I);
649 /* Generate strings that describe the location of the im- and
650 * exports. This depends on the place from where they come:
651 * Object file or linker config.
654 /* The export comes from an object file */
655 SB_Printf (&ExportLoc, "%s, %s(%lu)",
656 GetString (E->Obj->Name),
657 GetSourceName (ExportLI),
658 GetSourceLine (ExportLI));
660 SB_Printf (&ExportLoc, "%s(%lu)",
661 GetSourceName (ExportLI),
662 GetSourceLine (ExportLI));
665 /* The import comes from an object file */
666 SB_Printf (&ImportLoc, "%s, %s(%lu)",
667 GetString (I->Obj->Name),
668 GetSourceName (ImportLI),
669 GetSourceLine (ImportLI));
671 SB_Printf (&ImportLoc, "%s(%lu)",
672 GetSourceName (ImportLI),
673 GetSourceLine (ImportLI));
676 /* Output the diagnostic */
677 Warning ("Address size mismatch for `%s': "
678 "Exported from %s as `%s', "
679 "import in %s as `%s'",
681 SB_GetConstBuf (&ExportLoc),
683 SB_GetConstBuf (&ImportLoc),
686 /* Free the temporary strings */
687 SB_Done (&ExportLoc);
688 SB_Done (&ImportLoc);
696 static void CheckSymTypes (void)
697 /* Check for symbol tape mismatches */
701 /* Print all open imports */
702 for (I = 0; I < ExpCount; ++I) {
703 const Export* E = ExpPool [I];
704 if (E->Expr != 0 && E->ImpCount > 0) {
705 /* External with matching imports */
713 static void PrintUnresolved (ExpCheckFunc F, void* Data)
714 /* Print a list of unresolved symbols. On unresolved symbols, F is
715 * called (see the comments on ExpCheckFunc in the data section).
720 /* Print all open imports */
721 for (I = 0; I < ExpCount; ++I) {
722 Export* E = ExpPool [I];
723 if (E->Expr == 0 && E->ImpCount > 0 && F (E->Name, Data) == 0) {
724 /* Unresolved external */
725 Import* Imp = E->ImpList;
727 "Unresolved external `%s' referenced in:\n",
728 GetString (E->Name));
730 const LineInfo* LI = GetImportPos (Imp);
743 static int CmpExpName (const void* K1, const void* K2)
744 /* Compare function for qsort */
746 return SB_Compare (GetStrBuf ((*(Export**)K1)->Name),
747 GetStrBuf ((*(Export**)K2)->Name));
752 static void CreateExportPool (void)
753 /* Create an array with pointer to all exports */
757 /* Allocate memory */
761 ExpPool = xmalloc (ExpCount * sizeof (Export*));
763 /* Walk through the list and insert the exports */
764 for (I = 0, J = 0; I < sizeof (HashTab) / sizeof (HashTab [0]); ++I) {
765 Export* E = HashTab[I];
767 CHECK (J < ExpCount);
773 /* Sort them by name */
774 qsort (ExpPool, ExpCount, sizeof (Export*), CmpExpName);
779 void CheckExports (void)
780 /* Setup the list of all exports and check for export/import symbol type
784 /* Create an export pool */
787 /* Check for symbol type mismatches */
793 void CheckUnresolvedImports (ExpCheckFunc F, void* Data)
794 /* Check if there are any unresolved imports. On unresolved imports, F is
795 * called (see the comments on ExpCheckFunc in the data section).
798 /* Check for unresolved externals */
800 /* Print all open imports */
801 PrintUnresolved (F, Data);
807 static char GetAddrSizeCode (unsigned char AddrSize)
808 /* Get a one char code for the address size */
811 case ADDR_SIZE_ZP: return 'Z';
812 case ADDR_SIZE_ABS: return 'A';
813 case ADDR_SIZE_FAR: return 'F';
814 case ADDR_SIZE_LONG: return 'L';
816 Internal ("Invalid address size: %u", AddrSize);
824 void PrintExportMap (FILE* F)
825 /* Print an export map to the given file */
830 /* Print all exports */
832 for (I = 0; I < ExpCount; ++I) {
833 const Export* E = ExpPool [I];
835 /* Print unreferenced symbols only if explictly requested */
836 if (VerboseMap || E->ImpCount > 0 || SYM_IS_CONDES (E->Type)) {
838 "%-25s %06lX %c%c%c%c ",
841 E->ImpCount? 'R' : ' ',
842 SYM_IS_LABEL (E->Type)? 'L' : 'E',
843 GetAddrSizeCode (E->AddrSize),
844 SYM_IS_CONDES (E->Type)? 'I' : ' ');
856 void PrintImportMap (FILE* F)
857 /* Print an import map to the given file */
862 /* Loop over all exports */
863 for (I = 0; I < ExpCount; ++I) {
866 const Export* Exp = ExpPool [I];
868 /* Print the symbol only if there are imports, or if a verbose map
871 if (VerboseMap || Exp->ImpCount > 0) {
873 /* Print the export */
876 GetString (Exp->Name),
877 GetObjFileName (Exp->Obj));
879 /* Print all imports for this symbol */
883 /* Print the import */
884 const LineInfo* LI = GetImportPos (Imp);
887 GetObjFileName (Imp->Obj),
901 void PrintExportLabels (FILE* F)
902 /* Print the exports in a VICE label file */
906 /* Print all exports */
907 for (I = 0; I < ExpCount; ++I) {
908 const Export* E = ExpPool [I];
909 fprintf (F, "al %06lX .%s\n", GetExportVal (E), GetString (E->Name));
915 void MarkExport (Export* E)
916 /* Mark the export */
918 E->Flags |= EXP_USERMARK;
923 void UnmarkExport (Export* E)
924 /* Remove the mark from the export */
926 E->Flags &= ~EXP_USERMARK;
931 int ExportHasMark (Export* E)
932 /* Return true if the export has a mark */
934 return (E->Flags & EXP_USERMARK) != 0;
939 void CircularRefError (const Export* E)
940 /* Print an error about a circular reference using to define the given export */
942 const LineInfo* LI = GetExportPos (E);
943 Error ("Circular reference for symbol `%s', %s(%lu)",