]> git.sur5r.net Git - cc65/blob - src/ld65/exports.c
ld65: implement '--allow-multiple-definition' command line parameter
[cc65] / src / ld65 / exports.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 exports.c                                 */
4 /*                                                                           */
5 /*                   Exports handling for the ld65 linker                    */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2013, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
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.                                    */
18 /*                                                                           */
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:                            */
22 /*                                                                           */
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              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 /* common */
41 #include "addrsize.h"
42 #include "check.h"
43 #include "hashfunc.h"
44 #include "lidefs.h"
45 #include "symdefs.h"
46 #include "xmalloc.h"
47
48 /* ld65 */
49 #include "condes.h"
50 #include "error.h"
51 #include "exports.h"
52 #include "expr.h"
53 #include "fileio.h"
54 #include "global.h"
55 #include "lineinfo.h"
56 #include "memarea.h"
57 #include "objdata.h"
58 #include "spool.h"
59
60
61
62 /*****************************************************************************/
63 /*                                   Data                                    */
64 /*****************************************************************************/
65
66
67
68 /* Hash table */
69 #define HASHTAB_MASK    0x0FFFU
70 #define HASHTAB_SIZE    (HASHTAB_MASK + 1)
71 static Export*          HashTab[HASHTAB_SIZE];
72
73 /* Import management variables */
74 static unsigned         ImpCount = 0;           /* Import count */
75 static unsigned         ImpOpen  = 0;           /* Count of open imports */
76
77 /* Export management variables */
78 static unsigned         ExpCount = 0;           /* Export count */
79 static Export**         ExpPool  = 0;           /* Exports array */
80
81 /* Defines for the flags in Import */
82 #define IMP_INLIST      0x0001U                 /* Import is in exports list */
83
84 /* Defines for the flags in Export */
85 #define EXP_INLIST      0x0001U                 /* Export is in exports list */
86 #define EXP_USERMARK    0x0002U                 /* User setable flag */
87
88
89
90 /*****************************************************************************/
91 /*                              Import handling                              */
92 /*****************************************************************************/
93
94
95
96 static Export* NewExport (unsigned Type, unsigned char AddrSize,
97                           unsigned Name, ObjData* Obj);
98 /* Create a new export and initialize it */
99
100
101
102 static Import* NewImport (unsigned char AddrSize, ObjData* Obj)
103 /* Create a new import and initialize it */
104 {
105     /* Allocate memory */
106     Import* I    = xmalloc (sizeof (Import));
107
108     /* Initialize the fields */
109     I->Next      = 0;
110     I->Obj       = Obj;
111     I->DefLines  = EmptyCollection;
112     I->RefLines  = EmptyCollection;
113     I->Exp       = 0;
114     I->Name      = INVALID_STRING_ID;
115     I->Flags     = 0;
116     I->AddrSize  = AddrSize;
117
118     /* Return the new structure */
119     return I;
120 }
121
122
123
124 void FreeImport (Import* I)
125 /* Free an import. NOTE: This won't remove the import from the exports table,
126 ** so it may only be called for unused imports (imports from modules that
127 ** aren't referenced).
128 */
129 {
130     /* Safety */
131     PRECONDITION ((I->Flags & IMP_INLIST) == 0);
132
133     /* Free the line info collections */
134     DoneCollection (&I->DefLines);
135     DoneCollection (&I->RefLines);
136
137     /* Free the struct */
138     xfree (I);
139 }
140
141
142
143 Import* ReadImport (FILE* F, ObjData* Obj)
144 /* Read an import from a file and return it */
145 {
146     Import* I;
147
148     /* Read the import address size */
149     unsigned char AddrSize = Read8 (F);
150
151     /* Create a new import */
152     I = NewImport (AddrSize, Obj);
153
154     /* Read the name */
155     I->Name = MakeGlobalStringId (Obj, ReadVar (F));
156
157     /* Read the line infos */
158     ReadLineInfoList (F, Obj, &I->DefLines);
159     ReadLineInfoList (F, Obj, &I->RefLines);
160
161     /* Check the address size */
162     if (I->AddrSize == ADDR_SIZE_DEFAULT || I->AddrSize > ADDR_SIZE_LONG) {
163         /* Beware: This function may be called in cases where the object file
164         ** is not read completely into memory. In this case, the file list is
165         ** invalid. Be sure not to access it in this case.
166         */
167         if (ObjHasFiles (I->Obj)) {
168             const LineInfo* LI = GetImportPos (I);
169             Error ("Invalid import size in for '%s', imported from %s(%u): 0x%02X",
170                    GetString (I->Name),
171                    GetSourceName (LI),
172                    GetSourceLine (LI),
173                    I->AddrSize);
174         } else {
175             Error ("Invalid import size in for '%s', imported from %s: 0x%02X",
176                    GetString (I->Name),
177                    GetObjFileName (I->Obj),
178                    I->AddrSize);
179         }
180     }
181
182     /* Return the new import */
183     return I;
184 }
185
186
187
188 Import* GenImport (unsigned Name, unsigned char AddrSize)
189 /* Generate a new import with the given name and address size and return it */
190 {
191     /* Create a new import */
192     Import* I = NewImport (AddrSize, 0);
193
194     /* Read the name */
195     I->Name = Name;
196
197     /* Check the address size */
198     if (I->AddrSize == ADDR_SIZE_DEFAULT || I->AddrSize > ADDR_SIZE_LONG) {
199         /* We have no object file information and no line info for a new
200         ** import
201         */
202         Error ("Invalid import size 0x%02X for symbol '%s'",
203                I->AddrSize,
204                GetString (I->Name));
205     }
206
207     /* Return the new import */
208     return I;
209 }
210
211
212
213 Import* InsertImport (Import* I)
214 /* Insert an import into the table, return I */
215 {
216     Export* E;
217
218     /* As long as the import is not inserted, V.Name is valid */
219     unsigned Name = I->Name;
220
221     /* Create a hash value for the given name */
222     unsigned Hash = (Name & HASHTAB_MASK);
223
224     /* Search through the list in that slot for a symbol with that name */
225     if (HashTab[Hash] == 0) {
226         /* The slot is empty, we need to insert a dummy export */
227         E = HashTab[Hash] = NewExport (0, ADDR_SIZE_DEFAULT, Name, 0);
228         ++ExpCount;
229     } else {
230         E = HashTab [Hash];
231         while (1) {
232             if (E->Name == Name) {
233                 /* We have an entry, L points to it */
234                 break;
235             }
236             if (E->Next == 0) {
237                 /* End of list an entry not found, insert a dummy */
238                 E->Next = NewExport (0, ADDR_SIZE_DEFAULT, Name, 0);
239                 E = E->Next;            /* Point to dummy */
240                 ++ExpCount;             /* One export more */
241                 break;
242             } else {
243                 E = E->Next;
244             }
245         }
246     }
247
248     /* Ok, E now points to a valid exports entry for the given import. Insert
249     ** the import into the imports list and update the counters.
250     */
251     I->Exp     = E;
252     I->Next    = E->ImpList;
253     E->ImpList = I;
254     E->ImpCount++;
255     ++ImpCount;                 /* Total import count */
256     if (E->Expr == 0) {
257         /* This is a dummy export */
258         ++ImpOpen;
259     }
260
261     /* Mark the import so we know it's in the list */
262     I->Flags |= IMP_INLIST;
263
264     /* Return the import to allow shorter code */
265     return I;
266 }
267
268
269
270 const LineInfo* GetImportPos (const Import* Imp)
271 /* Return the basic line info of an import */
272 {
273     /* Search in DefLines, then in RefLines */
274     const LineInfo* LI = GetAsmLineInfo (&Imp->DefLines);
275     if (LI == 0) {
276         LI = GetAsmLineInfo (&Imp->RefLines);
277     }
278     return LI;
279 }
280
281
282
283 /*****************************************************************************/
284 /*                                   Code                                    */
285 /*****************************************************************************/
286
287
288
289 static Export* NewExport (unsigned Type, unsigned char AddrSize,
290                           unsigned Name, ObjData* Obj)
291 /* Create a new export and initialize it */
292 {
293     unsigned I;
294
295     /* Allocate memory */
296     Export* E = xmalloc (sizeof (Export));
297
298     /* Initialize the fields */
299     E->Name      = Name;
300     E->Next      = 0;
301     E->Flags     = 0;
302     E->Obj       = Obj;
303     E->ImpCount  = 0;
304     E->ImpList   = 0;
305     E->Expr      = 0;
306     E->Size      = 0;
307     E->DefLines  = EmptyCollection;
308     E->RefLines  = EmptyCollection;
309     E->DbgSymId  = ~0U;
310     E->Type      = Type | SYM_EXPORT;
311     E->AddrSize  = AddrSize;
312     for (I = 0; I < sizeof (E->ConDes) / sizeof (E->ConDes[0]); ++I) {
313         E->ConDes[I] = CD_PRIO_NONE;
314     }
315
316     /* Return the new entry */
317     return E;
318 }
319
320
321
322 void FreeExport (Export* E)
323 /* Free an export. NOTE: This won't remove the export from the exports table,
324 ** so it may only be called for unused exports (exports from modules that
325 ** aren't referenced).
326 */
327 {
328     /* Safety */
329     PRECONDITION ((E->Flags & EXP_INLIST) == 0);
330
331     /* Free the line infos */
332     DoneCollection (&E->DefLines);
333     DoneCollection (&E->RefLines);
334
335     /* Free the export expression */
336     FreeExpr (E->Expr);
337
338     /* Free the struct */
339     xfree (E);
340 }
341
342
343
344 Export* ReadExport (FILE* F, ObjData* O)
345 /* Read an export from a file */
346 {
347     unsigned    ConDesCount;
348     unsigned    I;
349     Export*     E;
350
351     /* Read the type */
352     unsigned Type = ReadVar (F);
353
354     /* Read the address size */
355     unsigned char AddrSize = Read8 (F);
356
357     /* Create a new export without a name */
358     E = NewExport (Type, AddrSize, INVALID_STRING_ID, O);
359
360     /* Read the constructor/destructor decls if we have any */
361     ConDesCount = SYM_GET_CONDES_COUNT (Type);
362     if (ConDesCount > 0) {
363
364         unsigned char ConDes[CD_TYPE_COUNT];
365
366         /* Read the data into temp storage */
367         ReadData (F, ConDes, ConDesCount);
368
369         /* Re-order the data. In the file, each decl is encoded into a byte
370         ** which contains the type and the priority. In memory, we will use
371         ** an array of types which contain the priority.
372         */
373         for (I = 0; I < ConDesCount; ++I) {
374             E->ConDes[CD_GET_TYPE (ConDes[I])] = CD_GET_PRIO (ConDes[I]);
375         }
376     }
377
378     /* Read the name */
379     E->Name = MakeGlobalStringId (O, ReadVar (F));
380
381     /* Read the value */
382     if (SYM_IS_EXPR (Type)) {
383         E->Expr = ReadExpr (F, O);
384     } else {
385         E->Expr = LiteralExpr (Read32 (F), O);
386     }
387
388     /* Read the size */
389     if (SYM_HAS_SIZE (Type)) {
390         E->Size = ReadVar (F);
391     }
392
393     /* Last are the locations */
394     ReadLineInfoList (F, O, &E->DefLines);
395     ReadLineInfoList (F, O, &E->RefLines);
396
397     /* If this symbol is exported as a condes, and the condes type declares a
398     ** forced import, add this import to the object module.
399     */
400     for (I = 0; I < CD_TYPE_COUNT; ++I) {
401         const ConDesImport* CDI;
402
403         if (E->ConDes[I] != CD_PRIO_NONE && (CDI = ConDesGetImport (I)) != 0) {
404             unsigned J;
405
406             /* Generate a new import, and add it to the module's import list. */
407             Import* Imp = GenImport (CDI->Name, CDI->AddrSize);
408
409             Imp->Obj = O;
410             CollAppend (&O->Imports, Imp);
411
412             /* Add line info for the export that is actually the condes that
413             ** forces the import.  Then, add line info for the config. file.
414             ** The export's info is added first because the import pretends
415             ** that it came from the object module instead of the config. file.
416             */
417             for (J = 0; J < CollCount (&E->DefLines); ++J) {
418                 CollAppend (&Imp->RefLines, DupLineInfo (CollAt (&E->DefLines, J)));
419             }
420             CollAppend (&Imp->RefLines, GenLineInfo (&CDI->Pos));
421         }
422     }
423
424     /* Return the new export */
425     return E;
426 }
427
428
429
430 void InsertExport (Export* E)
431 /* Insert an exported identifier and check if it's already in the list */
432 {
433     Export* L;
434     Export* Last;
435     Import* Imp;
436     unsigned Hash;
437
438     /* Mark the export as inserted */
439     E->Flags |= EXP_INLIST;
440
441     /* Insert the export into any condes tables if needed */
442     if (SYM_IS_CONDES (E->Type)) {
443         ConDesAddExport (E);
444     }
445
446     /* Create a hash value for the given name */
447     Hash = (E->Name & HASHTAB_MASK);
448
449     /* Search through the list in that slot */
450     if (HashTab[Hash] == 0) {
451         /* The slot is empty */
452         HashTab[Hash] = E;
453         ++ExpCount;
454     } else {
455
456         Last = 0;
457         L = HashTab[Hash];
458         do {
459             if (L->Name == E->Name) {
460                 /* This may be an unresolved external */
461                 if (L->Expr == 0) {
462
463                     /* This *is* an unresolved external. Use the actual export
464                     ** in E instead of the dummy one in L.
465                     */
466                     E->Next     = L->Next;
467                     E->ImpCount = L->ImpCount;
468                     E->ImpList  = L->ImpList;
469                     if (Last) {
470                         Last->Next = E;
471                     } else {
472                         HashTab[Hash] = E;
473                     }
474                     ImpOpen -= E->ImpCount;     /* Decrease open imports now */
475                     xfree (L);
476                     /* We must run through the import list and change the
477                     ** export pointer now.
478                     */
479                     Imp = E->ImpList;
480                     while (Imp) {
481                         Imp->Exp = E;
482                         Imp = Imp->Next;
483                     }
484                 } else if (AllowMultDef == 0) {
485                     /* Duplicate entry, this is fatal unless allowed by the user */
486                     Error ("Duplicate external identifier: '%s'",
487                            GetString (L->Name));
488                 }
489                 return;
490             }
491             Last = L;
492             L = L->Next;
493
494         } while (L);
495
496         /* Insert export at end of queue */
497         Last->Next = E;
498         ++ExpCount;
499     }
500 }
501
502
503
504 const LineInfo* GetExportPos (const Export* E)
505 /* Return the basic line info of an export */
506 {
507     /* Search in DefLines, then in RefLines */
508     const LineInfo* LI = GetAsmLineInfo (&E->DefLines);
509     if (LI == 0) {
510         LI = GetAsmLineInfo (&E->RefLines);
511     }
512     return LI;
513 }
514
515
516
517 Export* CreateConstExport (unsigned Name, long Value)
518 /* Create an export for a literal date */
519 {
520     /* Create a new export */
521     Export* E = NewExport (SYM_CONST|SYM_EQUATE, ADDR_SIZE_ABS, Name, 0);
522
523     /* Assign the value */
524     E->Expr = LiteralExpr (Value, 0);
525
526     /* Insert the export */
527     InsertExport (E);
528
529     /* Return the new export */
530     return E;
531 }
532
533
534
535 Export* CreateExprExport (unsigned Name, ExprNode* Expr, unsigned char AddrSize)
536 /* Create an export for an expression */
537 {
538     /* Create a new export */
539     Export* E = NewExport (SYM_EXPR|SYM_EQUATE, AddrSize, Name, 0);
540
541     /* Assign the value expression */
542     E->Expr = Expr;
543
544     /* Insert the export */
545     InsertExport (E);
546
547     /* Return the new export */
548     return E;
549 }
550
551
552
553 Export* CreateMemoryExport (unsigned Name, MemoryArea* Mem, unsigned long Offs)
554 /* Create an relative export for a memory area offset */
555 {
556     /* Create a new export */
557     Export* E = NewExport (SYM_EXPR | SYM_LABEL, ADDR_SIZE_ABS, Name, 0);
558
559     /* Assign the value */
560     E->Expr = MemoryExpr (Mem, Offs, 0);
561
562     /* Insert the export */
563     InsertExport (E);
564
565     /* Return the new export */
566     return E;
567 }
568
569
570
571 Export* CreateSegmentExport (unsigned Name, Segment* Seg, unsigned long Offs)
572 /* Create a relative export to a segment */
573 {
574     /* Create a new export */
575     Export* E = NewExport (SYM_EXPR | SYM_LABEL, Seg->AddrSize, Name, 0);
576
577     /* Assign the value */
578     E->Expr = SegmentExpr (Seg, Offs, 0);
579
580     /* Insert the export */
581     InsertExport (E);
582
583     /* Return the new export */
584     return E;
585 }
586
587
588
589 Export* CreateSectionExport (unsigned Name, Section* Sec, unsigned long Offs)
590 /* Create a relative export to a section */
591 {
592     /* Create a new export */
593     Export* E = NewExport (SYM_EXPR | SYM_LABEL, Sec->AddrSize, Name, 0);
594
595     /* Assign the value */
596     E->Expr = SectionExpr (Sec, Offs, 0);
597
598     /* Insert the export */
599     InsertExport (E);
600
601     /* Return the new export */
602     return E;
603 }
604
605
606
607 Export* FindExport (unsigned Name)
608 /* Check for an identifier in the list. Return 0 if not found, otherwise
609 ** return a pointer to the export.
610 */
611 {
612     /* Get a pointer to the list with the symbols hash value */
613     Export* L = HashTab[Name & HASHTAB_MASK];
614     while (L) {
615         /* Search through the list in that slot */
616         if (L->Name == Name) {
617             /* Entry found */
618             return L;
619         }
620         L = L->Next;
621     }
622
623     /* Not found */
624     return 0;
625 }
626
627
628
629 int IsUnresolved (unsigned Name)
630 /* Check if this symbol is an unresolved export */
631 {
632     /* Find the export */
633     return IsUnresolvedExport (FindExport (Name));
634 }
635
636
637
638 int IsUnresolvedExport (const Export* E)
639 /* Return true if the given export is unresolved */
640 {
641     /* Check if it's unresolved */
642     return E != 0 && E->Expr == 0;
643 }
644
645
646
647 int IsConstExport (const Export* E)
648 /* Return true if the expression associated with this export is const */
649 {
650     if (E->Expr == 0) {
651         /* External symbols cannot be const */
652         return 0;
653     } else {
654         return IsConstExpr (E->Expr);
655     }
656 }
657
658
659
660 long GetExportVal (const Export* E)
661 /* Get the value of this export */
662 {
663     if (E->Expr == 0) {
664         /* OOPS */
665         Internal ("'%s' is an undefined external", GetString (E->Name));
666     }
667     return GetExprVal (E->Expr);
668 }
669
670
671
672 static void CheckSymType (const Export* E)
673 /* Check the types for one export */
674 {
675     /* External with matching imports */
676     Import* I = E->ImpList;
677     while (I) {
678         if (E->AddrSize != I->AddrSize) {
679             /* Export and import address sizes do not match */
680             StrBuf ExportLoc = STATIC_STRBUF_INITIALIZER;
681             StrBuf ImportLoc = STATIC_STRBUF_INITIALIZER;
682             const char* ExpAddrSize = AddrSizeToStr ((unsigned char) E->AddrSize);
683             const char* ImpAddrSize = AddrSizeToStr ((unsigned char) I->AddrSize);
684             const LineInfo* ExportLI = GetExportPos (E);
685             const LineInfo* ImportLI = GetImportPos (I);
686
687             /* Generate strings that describe the location of the im- and
688             ** exports. This depends on the place from where they come:
689             ** Object file or linker config.
690             */
691             if (E->Obj) {
692                 /* The export comes from an object file */
693                 SB_Printf (&ExportLoc, "%s, %s(%u)",
694                            GetString (E->Obj->Name),
695                            GetSourceName (ExportLI),
696                            GetSourceLine (ExportLI));
697             } else {
698                 SB_Printf (&ExportLoc, "%s(%u)",
699                            GetSourceName (ExportLI),
700                            GetSourceLine (ExportLI));
701             }
702             if (I->Obj) {
703                 /* The import comes from an object file */
704                 SB_Printf (&ImportLoc, "%s, %s(%u)",
705                            GetString (I->Obj->Name),
706                            GetSourceName (ImportLI),
707                            GetSourceLine (ImportLI));
708             } else if (ImportLI) {
709                 /* The import is linker generated and we have line
710                 ** information
711                 */
712                 SB_Printf (&ImportLoc, "%s(%u)",
713                            GetSourceName (ImportLI),
714                            GetSourceLine (ImportLI));
715             } else {
716                 /* The import is linker generated and we don't have line
717                 ** information
718                 */
719                 SB_Printf (&ImportLoc, "%s", GetObjFileName (I->Obj));
720             }
721
722             /* Output the diagnostic */
723             Warning ("Address size mismatch for '%s': "
724                      "Exported from %s as '%s', "
725                      "import in %s as '%s'",
726                      GetString (E->Name),
727                      SB_GetConstBuf (&ExportLoc),
728                      ExpAddrSize,
729                      SB_GetConstBuf (&ImportLoc),
730                      ImpAddrSize);
731
732             /* Free the temporary strings */
733             SB_Done (&ExportLoc);
734             SB_Done (&ImportLoc);
735         }
736         I = I->Next;
737     }
738 }
739
740
741
742 static void CheckSymTypes (void)
743 /* Check for symbol tape mismatches */
744 {
745     unsigned I;
746
747     /* Print all open imports */
748     for (I = 0; I < ExpCount; ++I) {
749         const Export* E = ExpPool [I];
750         if (E->Expr != 0 && E->ImpCount > 0) {
751             /* External with matching imports */
752             CheckSymType (E);
753         }
754     }
755 }
756
757
758
759 static void PrintUnresolved (ExpCheckFunc F, void* Data)
760 /* Print a list of unresolved symbols. On unresolved symbols, F is
761 ** called (see the comments on ExpCheckFunc in the data section).
762 */
763 {
764     unsigned I;
765
766     /* Print all open imports */
767     for (I = 0; I < ExpCount; ++I) {
768         Export* E = ExpPool [I];
769         if (E->Expr == 0 && E->ImpCount > 0 && F (E->Name, Data) == 0) {
770             /* Unresolved external */
771             Import* Imp = E->ImpList;
772             fprintf (stderr,
773                      "Unresolved external '%s' referenced in:\n",
774                      GetString (E->Name));
775             while (Imp) {
776                 unsigned J;
777                 for (J = 0; J < CollCount (&Imp->RefLines); ++J) {
778                     const LineInfo* LI = CollConstAt (&Imp->RefLines, J);
779                     fprintf (stderr,
780                          "  %s(%u)\n",
781                          GetSourceName (LI),
782                          GetSourceLine (LI));
783                 }
784                 Imp = Imp->Next;
785             }
786         }
787     }
788 }
789
790
791
792 static int CmpExpName (const void* K1, const void* K2)
793 /* Compare function for qsort */
794 {
795     return SB_Compare (GetStrBuf ((*(Export**)K1)->Name),
796                        GetStrBuf ((*(Export**)K2)->Name));
797 }
798
799
800
801 static void CreateExportPool (void)
802 /* Create an array with pointer to all exports */
803 {
804     unsigned I, J;
805
806     /* Allocate memory */
807     if (ExpPool) {
808         xfree (ExpPool);
809     }
810     ExpPool = xmalloc (ExpCount * sizeof (Export*));
811
812     /* Walk through the list and insert the exports */
813     for (I = 0, J = 0; I < sizeof (HashTab) / sizeof (HashTab [0]); ++I) {
814         Export* E = HashTab[I];
815         while (E) {
816             CHECK (J < ExpCount);
817             ExpPool[J++] = E;
818             E = E->Next;
819         }
820     }
821
822     /* Sort them by name */
823     qsort (ExpPool, ExpCount, sizeof (Export*), CmpExpName);
824 }
825
826
827
828 void CheckExports (void)
829 /* Setup the list of all exports and check for export/import symbol type
830 ** mismatches.
831 */
832 {
833     /* Create an export pool */
834     CreateExportPool ();
835
836     /* Check for symbol type mismatches */
837     CheckSymTypes ();
838 }
839
840
841
842 void CheckUnresolvedImports (ExpCheckFunc F, void* Data)
843 /* Check if there are any unresolved imports. On unresolved imports, F is
844 ** called (see the comments on ExpCheckFunc in the data section).
845 */
846 {
847     /* Check for unresolved externals */
848     if (ImpOpen != 0) {
849         /* Print all open imports */
850         PrintUnresolved (F, Data);
851     }
852 }
853
854
855
856 static char GetAddrSizeCode (unsigned char AddrSize)
857 /* Get a one char code for the address size */
858 {
859     switch (AddrSize) {
860         case ADDR_SIZE_ZP:      return 'Z';
861         case ADDR_SIZE_ABS:     return 'A';
862         case ADDR_SIZE_FAR:     return 'F';
863         case ADDR_SIZE_LONG:    return 'L';
864         default:
865             Internal ("Invalid address size: %u", AddrSize);
866             /* NOTREACHED */
867             return '-';
868     }
869 }
870
871
872
873 void PrintExportMapByName (FILE* F)
874 /* Print an export map, sorted by symbol name, to the given file */
875 {
876     unsigned I;
877     unsigned Count;
878
879     /* Print all exports */
880     Count = 0;
881     for (I = 0; I < ExpCount; ++I) {
882         const Export* E = ExpPool [I];
883
884         /* Print unreferenced symbols only if explictly requested */
885         if (VerboseMap || E->ImpCount > 0 || SYM_IS_CONDES (E->Type)) {
886             fprintf (F,
887                      "%-25s %06lX %c%c%c%c   ",
888                      GetString (E->Name),
889                      GetExportVal (E),
890                      E->ImpCount? 'R' : ' ',
891                      SYM_IS_LABEL (E->Type)? 'L' : 'E',
892                      GetAddrSizeCode ((unsigned char) E->AddrSize),
893                      SYM_IS_CONDES (E->Type)? 'I' : ' ');
894             if (++Count == 2) {
895                 Count = 0;
896                 fprintf (F, "\n");
897             }
898         }
899     }
900     fprintf (F, "\n");
901 }
902
903
904
905 static int CmpExpValue (const void* I1, const void* I2)
906 /* Compare function for qsort */
907 {
908     long V1 = GetExportVal (ExpPool [*(unsigned *)I1]);
909     long V2 = GetExportVal (ExpPool [*(unsigned *)I2]);
910
911     return V1 < V2 ? -1 : V1 == V2 ? 0 : 1;
912 }
913
914
915
916 void PrintExportMapByValue (FILE* F)
917 /* Print an export map, sorted by symbol value, to the given file */
918 {
919     unsigned I;
920     unsigned Count;
921     unsigned *ExpValXlat;
922
923     /* Create a translation table where the symbols are sorted by value. */
924     ExpValXlat = xmalloc (ExpCount * sizeof (unsigned));
925     for (I = 0; I < ExpCount; ++I) {
926         /* Initialize table with current sort order.  */
927         ExpValXlat [I] = I;
928     }
929
930     /* Sort them by value */
931     qsort (ExpValXlat, ExpCount, sizeof (unsigned), CmpExpValue);
932
933     /* Print all exports */
934     Count = 0;
935     for (I = 0; I < ExpCount; ++I) {
936         const Export* E = ExpPool [ExpValXlat [I]];
937
938         /* Print unreferenced symbols only if explictly requested */
939         if (VerboseMap || E->ImpCount > 0 || SYM_IS_CONDES (E->Type)) {
940             fprintf (F,
941                      "%-25s %06lX %c%c%c%c   ",
942                      GetString (E->Name),
943                      GetExportVal (E),
944                      E->ImpCount? 'R' : ' ',
945                      SYM_IS_LABEL (E->Type)? 'L' : 'E',
946                      GetAddrSizeCode ((unsigned char) E->AddrSize),
947                      SYM_IS_CONDES (E->Type)? 'I' : ' ');
948             if (++Count == 2) {
949                 Count = 0;
950                 fprintf (F, "\n");
951             }
952         }
953     }
954     fprintf (F, "\n");
955     xfree (ExpValXlat);
956 }
957
958
959
960 void PrintImportMap (FILE* F)
961 /* Print an import map to the given file */
962 {
963     unsigned I;
964     const Import* Imp;
965
966     /* Loop over all exports */
967     for (I = 0; I < ExpCount; ++I) {
968
969         /* Get the export */
970         const Export* Exp = ExpPool [I];
971
972         /* Print the symbol only if there are imports, or if a verbose map
973         ** file is requested.
974         */
975         if (VerboseMap || Exp->ImpCount > 0) {
976
977             /* Print the export */
978             fprintf (F,
979                      "%s (%s):\n",
980                      GetString (Exp->Name),
981                      GetObjFileName (Exp->Obj));
982
983             /* Print all imports for this symbol */
984             Imp = Exp->ImpList;
985             while (Imp) {
986
987                 /* Print the import. Beware: The import might be linker
988                 ** generated, in which case there is no object file and
989                 ** sometimes no line information.
990                 */
991                 const LineInfo* LI = GetImportPos (Imp);
992                 if (LI) {
993                     fprintf (F,
994                              "    %-25s %s(%u)\n",
995                              GetObjFileName (Imp->Obj),
996                              GetSourceName (LI),
997                              GetSourceLine (LI));
998                 } else {
999                     fprintf (F,
1000                              "    %-25s\n",
1001                              GetObjFileName (Imp->Obj));
1002                 }
1003
1004                 /* Next import */
1005                 Imp = Imp->Next;
1006             }
1007         }
1008     }
1009     fprintf (F, "\n");
1010 }
1011
1012
1013
1014 void PrintExportLabels (FILE* F)
1015 /* Print the exports in a VICE label file */
1016 {
1017     unsigned I;
1018
1019     /* Print all exports */
1020     for (I = 0; I < ExpCount; ++I) {
1021         const Export* E = ExpPool [I];
1022         fprintf (F, "al %06lX .%s\n", GetExportVal (E), GetString (E->Name));
1023     }
1024 }
1025
1026
1027
1028 void MarkExport (Export* E)
1029 /* Mark the export */
1030 {
1031     E->Flags |= EXP_USERMARK;
1032 }
1033
1034
1035
1036 void UnmarkExport (Export* E)
1037 /* Remove the mark from the export */
1038 {
1039     E->Flags &= ~EXP_USERMARK;
1040 }
1041
1042
1043
1044 int ExportHasMark (Export* E)
1045 /* Return true if the export has a mark */
1046 {
1047     return (E->Flags & EXP_USERMARK) != 0;
1048 }
1049
1050
1051
1052 void CircularRefError (const Export* E)
1053 /* Print an error about a circular reference using to define the given export */
1054 {
1055     const LineInfo* LI = GetExportPos (E);
1056     Error ("Circular reference for symbol '%s', %s(%u)",
1057            GetString (E->Name),
1058            GetSourceName (LI),
1059            GetSourceLine (LI));
1060 }