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)
71static Export* HashTab[HASHTAB_SIZE];
72
73/* Import management variables */
74static unsigned ImpCount = 0; /* Import count */
75static unsigned ImpOpen = 0; /* Count of open imports */
76
77/* Export management variables */
78static unsigned ExpCount = 0; /* Export count */
79static 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
96static Export* NewExport (unsigned Type, unsigned char AddrSize,
97 unsigned Name, ObjData* Obj);
98/* Create a new export and initialize it */
99
100
101
102static 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
124void 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
143Import* 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
188Import* 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
213Import* 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
270const 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
289static 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
322void 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
344Export* 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
430void 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
504const 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
517Export* 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
535Export* 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
553Export* 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
571Export* 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
589Export* 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
607Export* 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
629int 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
638int 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
647int 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
660long 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
672static 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
742static 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
759static 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
792static 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
801static 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
828void 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
842void 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
856static 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
873void 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
905static 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
916void 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
960void 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
1014void 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
1028void MarkExport (Export* E)
1029/* Mark the export */
1030{
1031 E->Flags |= EXP_USERMARK;
1032}
1033
1034
1035
1036void UnmarkExport (Export* E)
1037/* Remove the mark from the export */
1038{
1039 E->Flags &= ~EXP_USERMARK;
1040}
1041
1042
1043
1044int ExportHasMark (Export* E)
1045/* Return true if the export has a mark */
1046{
1047 return (E->Flags & EXP_USERMARK) != 0;
1048}
1049
1050
1051
1052void 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}
1061