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 */
308 E->LineInfos = EmptyCollection;
310 E->AddrSize = AddrSize;
311 memset (E->ConDes, 0, sizeof (E->ConDes));
313 /* Return the new entry */
319 void FreeExport (Export* E)
320 /* Free an export. NOTE: This won't remove the export from the exports table,
321 * so it may only be called for unused exports (exports from modules that
322 * aren't referenced).
326 PRECONDITION ((E->Flags & EXP_INLIST) == 0);
328 /* Free the line infos */
329 DoneCollection (&E->LineInfos);
331 /* Free the export expression */
334 /* Free the struct */
340 Export* ReadExport (FILE* F, ObjData* O)
341 /* Read an export from a file */
343 unsigned ConDesCount;
347 unsigned Type = ReadVar (F);
349 /* Read the address size */
350 unsigned char AddrSize = Read8 (F);
352 /* Create a new export without a name */
353 E = NewExport (Type, AddrSize, INVALID_STRING_ID, O);
355 /* Read the constructor/destructor decls if we have any */
356 ConDesCount = SYM_GET_CONDES_COUNT (Type);
357 if (ConDesCount > 0) {
359 unsigned char ConDes[CD_TYPE_COUNT];
362 /* Read the data into temp storage */
363 ReadData (F, ConDes, ConDesCount);
365 /* Re-order the data. In the file, each decl is encoded into a byte
366 * which contains the type and the priority. In memory, we will use
367 * an array of types which contain the priority. This array was
368 * cleared by the constructor (NewExport), so we must only set the
369 * fields that contain values.
371 for (I = 0; I < ConDesCount; ++I) {
372 unsigned ConDesType = CD_GET_TYPE (ConDes[I]);
373 unsigned ConDesPrio = CD_GET_PRIO (ConDes[I]);
374 E->ConDes[ConDesType] = ConDesPrio;
379 E->Name = MakeGlobalStringId (O, ReadVar (F));
382 if (SYM_IS_EXPR (Type)) {
383 E->Expr = ReadExpr (F, O);
385 E->Expr = LiteralExpr (Read32 (F), O);
389 if (SYM_HAS_SIZE (Type)) {
390 E->Size = ReadVar (F);
393 /* Last is the file position where the definition was done */
394 ReadLineInfoList (F, O, &E->LineInfos);
396 /* Return the new export */
402 void InsertExport (Export* E)
403 /* Insert an exported identifier and check if it's already in the list */
410 /* Mark the export as inserted */
411 E->Flags |= EXP_INLIST;
413 /* Insert the export into any condes tables if needed */
414 if (SYM_IS_CONDES (E->Type)) {
418 /* Create a hash value for the given name */
419 Hash = (E->Name & HASHTAB_MASK);
421 /* Search through the list in that slot */
422 if (HashTab[Hash] == 0) {
423 /* The slot is empty */
431 if (L->Name == E->Name) {
432 /* This may be an unresolved external */
435 /* This *is* an unresolved external. Use the actual export
436 * in E instead of the dummy one in L.
439 E->ImpCount = L->ImpCount;
440 E->ImpList = L->ImpList;
446 ImpOpen -= E->ImpCount; /* Decrease open imports now */
448 /* We must run through the import list and change the
449 * export pointer now.
457 /* Duplicate entry, ignore it */
458 Warning ("Duplicate external identifier: `%s'",
459 GetString (L->Name));
468 /* Insert export at end of queue */
476 const LineInfo* GetExportPos (const Export* E)
477 /* Return the basic line info of an export */
479 /* Source file position is always in slot zero */
480 return CollConstAt (&E->LineInfos, 0);
485 Export* CreateConstExport (unsigned Name, long Value)
486 /* Create an export for a literal date */
488 /* Create a new export */
489 Export* E = NewExport (SYM_CONST | SYM_EQUATE, ADDR_SIZE_ABS, Name, 0);
491 /* Assign the value */
492 E->Expr = LiteralExpr (Value, 0);
494 /* Insert the export */
497 /* Return the new export */
503 Export* CreateExprExport (unsigned Name, ExprNode* Expr, unsigned char AddrSize)
504 /* Create an export for an expression */
506 /* Create a new export */
507 Export* E = NewExport (SYM_EXPR | SYM_EQUATE, AddrSize, Name, 0);
509 /* Assign the value expression */
512 /* Insert the export */
515 /* Return the new export */
521 Export* CreateMemoryExport (unsigned Name, MemoryArea* Mem, unsigned long Offs)
522 /* Create an relative export for a memory area offset */
524 /* Create a new export */
525 Export* E = NewExport (SYM_EXPR | SYM_LABEL, ADDR_SIZE_ABS, Name, 0);
527 /* Assign the value */
528 E->Expr = MemoryExpr (Mem, Offs, 0);
530 /* Insert the export */
533 /* Return the new export */
539 Export* CreateSegmentExport (unsigned Name, Segment* Seg, unsigned long Offs)
540 /* Create a relative export to a segment */
542 /* Create a new export */
543 Export* E = NewExport (SYM_EXPR | SYM_LABEL, Seg->AddrSize, Name, 0);
545 /* Assign the value */
546 E->Expr = SegmentExpr (Seg, Offs, 0);
548 /* Insert the export */
551 /* Return the new export */
557 Export* CreateSectionExport (unsigned Name, Section* Sec, unsigned long Offs)
558 /* Create a relative export to a section */
560 /* Create a new export */
561 Export* E = NewExport (SYM_EXPR | SYM_LABEL, Sec->AddrSize, Name, 0);
563 /* Assign the value */
564 E->Expr = SectionExpr (Sec, Offs, 0);
566 /* Insert the export */
569 /* Return the new export */
575 Export* FindExport (unsigned Name)
576 /* Check for an identifier in the list. Return 0 if not found, otherwise
577 * return a pointer to the export.
580 /* Get a pointer to the list with the symbols hash value */
581 Export* L = HashTab[Name & HASHTAB_MASK];
583 /* Search through the list in that slot */
584 if (L->Name == Name) {
597 int IsUnresolved (unsigned Name)
598 /* Check if this symbol is an unresolved export */
600 /* Find the export */
601 return IsUnresolvedExport (FindExport (Name));
606 int IsUnresolvedExport (const Export* E)
607 /* Return true if the given export is unresolved */
609 /* Check if it's unresolved */
610 return E != 0 && E->Expr == 0;
615 int IsConstExport (const Export* E)
616 /* Return true if the expression associated with this export is const */
619 /* External symbols cannot be const */
622 return IsConstExpr (E->Expr);
628 long GetExportVal (const Export* E)
629 /* Get the value of this export */
633 Internal ("`%s' is an undefined external", GetString (E->Name));
635 return GetExprVal (E->Expr);
640 static void CheckSymType (const Export* E)
641 /* Check the types for one export */
643 /* External with matching imports */
644 Import* I = E->ImpList;
646 if (E->AddrSize != I->AddrSize) {
647 /* Export and import address sizes do not match */
648 StrBuf ExportLoc = STATIC_STRBUF_INITIALIZER;
649 StrBuf ImportLoc = STATIC_STRBUF_INITIALIZER;
650 const char* ExpAddrSize = AddrSizeToStr (E->AddrSize);
651 const char* ImpAddrSize = AddrSizeToStr (I->AddrSize);
652 const LineInfo* ExportLI = GetExportPos (E);
653 const LineInfo* ImportLI = GetImportPos (I);
655 /* Generate strings that describe the location of the im- and
656 * exports. This depends on the place from where they come:
657 * Object file or linker config.
660 /* The export comes from an object file */
661 SB_Printf (&ExportLoc, "%s, %s(%lu)",
662 GetString (E->Obj->Name),
663 GetSourceName (ExportLI),
664 GetSourceLine (ExportLI));
666 SB_Printf (&ExportLoc, "%s(%lu)",
667 GetSourceName (ExportLI),
668 GetSourceLine (ExportLI));
671 /* The import comes from an object file */
672 SB_Printf (&ImportLoc, "%s, %s(%lu)",
673 GetString (I->Obj->Name),
674 GetSourceName (ImportLI),
675 GetSourceLine (ImportLI));
677 SB_Printf (&ImportLoc, "%s(%lu)",
678 GetSourceName (ImportLI),
679 GetSourceLine (ImportLI));
682 /* Output the diagnostic */
683 Warning ("Address size mismatch for `%s': "
684 "Exported from %s as `%s', "
685 "import in %s as `%s'",
687 SB_GetConstBuf (&ExportLoc),
689 SB_GetConstBuf (&ImportLoc),
692 /* Free the temporary strings */
693 SB_Done (&ExportLoc);
694 SB_Done (&ImportLoc);
702 static void CheckSymTypes (void)
703 /* Check for symbol tape mismatches */
707 /* Print all open imports */
708 for (I = 0; I < ExpCount; ++I) {
709 const Export* E = ExpPool [I];
710 if (E->Expr != 0 && E->ImpCount > 0) {
711 /* External with matching imports */
719 static void PrintUnresolved (ExpCheckFunc F, void* Data)
720 /* Print a list of unresolved symbols. On unresolved symbols, F is
721 * called (see the comments on ExpCheckFunc in the data section).
726 /* Print all open imports */
727 for (I = 0; I < ExpCount; ++I) {
728 Export* E = ExpPool [I];
729 if (E->Expr == 0 && E->ImpCount > 0 && F (E->Name, Data) == 0) {
730 /* Unresolved external */
731 Import* Imp = E->ImpList;
733 "Unresolved external `%s' referenced in:\n",
734 GetString (E->Name));
736 const LineInfo* LI = GetImportPos (Imp);
749 static int CmpExpName (const void* K1, const void* K2)
750 /* Compare function for qsort */
752 return SB_Compare (GetStrBuf ((*(Export**)K1)->Name),
753 GetStrBuf ((*(Export**)K2)->Name));
758 static void CreateExportPool (void)
759 /* Create an array with pointer to all exports */
763 /* Allocate memory */
767 ExpPool = xmalloc (ExpCount * sizeof (Export*));
769 /* Walk through the list and insert the exports */
770 for (I = 0, J = 0; I < sizeof (HashTab) / sizeof (HashTab [0]); ++I) {
771 Export* E = HashTab[I];
773 CHECK (J < ExpCount);
779 /* Sort them by name */
780 qsort (ExpPool, ExpCount, sizeof (Export*), CmpExpName);
785 void CheckExports (void)
786 /* Setup the list of all exports and check for export/import symbol type
790 /* Create an export pool */
793 /* Check for symbol type mismatches */
799 void CheckUnresolvedImports (ExpCheckFunc F, void* Data)
800 /* Check if there are any unresolved imports. On unresolved imports, F is
801 * called (see the comments on ExpCheckFunc in the data section).
804 /* Check for unresolved externals */
806 /* Print all open imports */
807 PrintUnresolved (F, Data);
813 static char GetAddrSizeCode (unsigned char AddrSize)
814 /* Get a one char code for the address size */
817 case ADDR_SIZE_ZP: return 'Z';
818 case ADDR_SIZE_ABS: return 'A';
819 case ADDR_SIZE_FAR: return 'F';
820 case ADDR_SIZE_LONG: return 'L';
822 Internal ("Invalid address size: %u", AddrSize);
830 void PrintExportMap (FILE* F)
831 /* Print an export map to the given file */
836 /* Print all exports */
838 for (I = 0; I < ExpCount; ++I) {
839 const Export* E = ExpPool [I];
841 /* Print unreferenced symbols only if explictly requested */
842 if (VerboseMap || E->ImpCount > 0 || SYM_IS_CONDES (E->Type)) {
844 "%-25s %06lX %c%c%c%c ",
847 E->ImpCount? 'R' : ' ',
848 SYM_IS_LABEL (E->Type)? 'L' : 'E',
849 GetAddrSizeCode (E->AddrSize),
850 SYM_IS_CONDES (E->Type)? 'I' : ' ');
862 void PrintImportMap (FILE* F)
863 /* Print an import map to the given file */
868 /* Loop over all exports */
869 for (I = 0; I < ExpCount; ++I) {
872 const Export* Exp = ExpPool [I];
874 /* Print the symbol only if there are imports, or if a verbose map
877 if (VerboseMap || Exp->ImpCount > 0) {
879 /* Print the export */
882 GetString (Exp->Name),
883 GetObjFileName (Exp->Obj));
885 /* Print all imports for this symbol */
889 /* Print the import */
890 const LineInfo* LI = GetImportPos (Imp);
893 GetObjFileName (Imp->Obj),
907 void PrintExportLabels (FILE* F)
908 /* Print the exports in a VICE label file */
912 /* Print all exports */
913 for (I = 0; I < ExpCount; ++I) {
914 const Export* E = ExpPool [I];
915 fprintf (F, "al %06lX .%s\n", GetExportVal (E), GetString (E->Name));
921 void MarkExport (Export* E)
922 /* Mark the export */
924 E->Flags |= EXP_USERMARK;
929 void UnmarkExport (Export* E)
930 /* Remove the mark from the export */
932 E->Flags &= ~EXP_USERMARK;
937 int ExportHasMark (Export* E)
938 /* Return true if the export has a mark */
940 return (E->Flags & EXP_USERMARK) != 0;
945 void CircularRefError (const Export* E)
946 /* Print an error about a circular reference using to define the given export */
948 const LineInfo* LI = GetExportPos (E);
949 Error ("Circular reference for symbol `%s', %s(%lu)",