]> git.sur5r.net Git - cc65/blob - src/ld65/exports.c
Added the NES target
[cc65] / src / ld65 / exports.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 exports.c                                 */
4 /*                                                                           */
5 /*                   Exports handling for the ld65 linker                    */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998     Ullrich von Bassewitz                                        */
10 /*              Wacholderweg 14                                              */
11 /*              D-70597 Stuttgart                                            */
12 /* EMail:       uz@musoftware.de                                             */
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 "check.h"
42 #include "coll.h"
43 #include "hashstr.h"
44 #include "symdefs.h"
45 #include "xmalloc.h"
46
47 /* ld65 */
48 #include "condes.h"
49 #include "error.h"
50 #include "fileio.h"
51 #include "global.h"
52 #include "objdata.h"
53 #include "expr.h"
54 #include "exports.h"
55
56
57
58 /*****************************************************************************/
59 /*                                   Data                                    */
60 /*****************************************************************************/
61
62
63
64 /* Hash table */
65 #define HASHTAB_SIZE    4081
66 static Export*          HashTab [HASHTAB_SIZE];
67
68 /* Import management variables */
69 static unsigned         ImpCount = 0;           /* Import count */
70 static unsigned         ImpOpen  = 0;           /* Count of open imports */
71
72 /* Export management variables */
73 static unsigned         ExpCount = 0;           /* Export count */
74 static Export**         ExpPool  = 0;           /* Exports array */
75
76 /* Defines for the flags in Export */
77 #define EXP_USERMARK    0x0001
78
79
80
81 /*****************************************************************************/
82 /*                              Import handling                              */
83 /*****************************************************************************/
84
85
86
87 static Export* NewExport (unsigned char Type, const char* Name, ObjData* Obj);
88 /* Create a new export and initialize it */
89
90
91
92 static Import* NewImport (unsigned char Type, ObjData* Obj)
93 /* Create a new import and initialize it */
94 {
95     /* Allocate memory */
96     Import* I = xmalloc (sizeof (Import));
97
98     /* Initialize the fields */
99     I->Next     = 0;
100     I->Obj      = Obj;
101     I->V.Name   = 0;
102     I->Type     = Type;
103
104     /* Return the new structure */
105     return I;
106 }
107
108
109
110 void InsertImport (Import* I)
111 /* Insert an import into the table */
112 {
113     Export* E;
114     unsigned HashVal;
115
116     /* As long as the import is not inserted, V.Name is valid */
117     char* Name = I->V.Name;
118
119     /* Create a hash value for the given name */
120     HashVal = HashStr (Name) % HASHTAB_SIZE;
121
122     /* Search through the list in that slot and print matching duplicates */
123     if (HashTab [HashVal] == 0) {
124         /* The slot is empty, we need to insert a dummy export */
125         E = HashTab [HashVal] = NewExport (0, Name, 0);
126         ++ExpCount;
127     } else {
128         E = HashTab [HashVal];
129         while (1) {
130             if (strcmp (E->Name, Name) == 0) {
131                 /* We have an entry, L points to it */
132                 break;
133             }
134             if (E->Next == 0) {
135                 /* End of list an entry not found, insert a dummy */
136                 E->Next = NewExport (0, Name, 0);
137                 E = E->Next;            /* Point to dummy */
138                 ++ExpCount;             /* One export more */
139                 break;
140             } else {
141                 E = E->Next;
142             }
143         }
144     }
145
146     /* Ok, E now points to a valid exports entry for the given import. Insert
147      * the import into the imports list and update the counters.
148      */
149     I->V.Exp   = E;
150     I->Next    = E->ImpList;
151     E->ImpList = I;
152     E->ImpCount++;
153     ++ImpCount;                 /* Total import count */
154     if (E->Expr == 0) {
155         /* This is a dummy export */
156         ++ImpOpen;
157     }
158
159     /* Now free the name since it's no longer needed */
160     xfree (Name);
161 }
162
163
164
165 Import* ReadImport (FILE* F, ObjData* Obj)
166 /* Read an import from a file and return it */
167 {
168     Import* I;
169
170     /* Read the import type and check it */
171     unsigned char Type = Read8 (F);
172     if (Type != IMP_ZP && Type != IMP_ABS) {
173         Error ("Unknown import type in module `%s': %02X",
174                GetObjFileName (Obj), Type);
175     }
176
177     /* Create a new import */
178     I = NewImport (Type, Obj);
179
180     /* Read the name */
181     I->V.Name = ReadStr (F);
182
183     /* Read the file position */
184     ReadFilePos (F, &I->Pos);
185
186     /* Return the new import */
187     return I;
188 }
189
190
191
192 /*****************************************************************************/
193 /*                                   Code                                    */
194 /*****************************************************************************/
195
196
197
198 static Export* NewExport (unsigned char Type, const char* Name, ObjData* Obj)
199 /* Create a new export and initialize it */
200 {
201     /* Allocate memory */
202     Export* E = xmalloc (sizeof (Export));
203
204     /* Initialize the fields */
205     E->Next     = 0;
206     E->Flags    = 0;
207     E->Obj      = Obj;
208     E->ImpCount = 0;
209     E->ImpList  = 0;
210     E->Expr     = 0;
211     E->Type     = Type;
212     memset (E->ConDes, 0, sizeof (E->ConDes));
213     if (Name) {
214         E->Name = xstrdup (Name);
215     } else {
216         /* Name will get added later */
217         E->Name = 0;
218     }
219
220     /* Return the new entry */
221     return E;
222 }
223
224
225
226 void InsertExport (Export* E)
227 /* Insert an exported identifier and check if it's already in the list */
228 {
229     Export* L;
230     Export* Last;
231     Import* Imp;
232     unsigned HashVal;
233
234     /* Insert the export into any condes tables if needed */
235     if (IS_EXP_CONDES (E->Type)) {
236         ConDesAddExport (E);
237     }
238
239     /* Create a hash value for the given name */
240     HashVal = HashStr (E->Name) % HASHTAB_SIZE;
241
242     /* Search through the list in that slot */
243     if (HashTab [HashVal] == 0) {
244         /* The slot is empty */
245         HashTab [HashVal] = E;
246         ++ExpCount;
247     } else {
248
249         Last = 0;
250         L = HashTab [HashVal];
251         do {
252             if (strcmp (L->Name, E->Name) == 0) {
253                 /* This may be an unresolved external */
254                 if (L->Expr == 0) {
255
256                     /* This *is* an unresolved external */
257                     E->Next     = L->Next;
258                     E->ImpCount = L->ImpCount;
259                     E->ImpList  = L->ImpList;
260                     if (Last) {
261                         Last->Next = E;
262                     } else {
263                         HashTab [HashVal] = E;
264                     }
265                     ImpOpen -= E->ImpCount;     /* Decrease open imports now */
266                     xfree (L);
267                     /* We must run through the import list and change the
268                      * export pointer now.
269                      */
270                     Imp = E->ImpList;
271                     while (Imp) {
272                         Imp->V.Exp = E;
273                         Imp = Imp->Next;
274                     }
275                 } else {
276                     /* Duplicate entry, ignore it */
277                     Warning ("Duplicate external identifier: `%s'", L->Name);
278                 }
279                 return;
280             }
281             Last = L;
282             L = L->Next;
283
284         } while (L);
285
286         /* Insert export at end of queue */
287         Last->Next = E;
288         ++ExpCount;
289     }
290 }
291
292
293
294 Export* ReadExport (FILE* F, ObjData* O)
295 /* Read an export from a file */
296 {
297     unsigned char Type;
298     unsigned      ConDesCount;
299     Export* E;
300
301     /* Read the type */
302     Type = Read8 (F);
303
304     /* Create a new export without a name */
305     E = NewExport (Type, 0, O);
306
307     /* Read the constructor/destructor decls if we have any */
308     ConDesCount = GET_EXP_CONDES_COUNT (Type);
309     if (ConDesCount > 0) {
310
311         unsigned char ConDes[CD_TYPE_COUNT];
312         unsigned I;
313
314         /* Read the data into temp storage */
315         ReadData (F, ConDes, ConDesCount);
316
317         /* Re-order the data. In the file, each decl is encoded into a byte
318          * which contains the type and the priority. In memory, we will use
319          * an array of types which contain the priority. This array was
320          * cleared by the constructor (NewExport), so we must only set the
321          * fields that contain values.
322          */
323         for (I = 0; I < ConDesCount; ++I) {
324             unsigned ConDesType = CD_GET_TYPE (ConDes[I]);
325             unsigned ConDesPrio = CD_GET_PRIO (ConDes[I]);
326             E->ConDes[ConDesType] = ConDesPrio;
327         }
328     }
329
330     /* Read the name */
331     E->Name = ReadStr (F);
332
333     /* Read the value */
334     if (IS_EXP_EXPR (Type)) {
335         E->Expr = ReadExpr (F, O);
336     } else {
337         E->Expr = LiteralExpr (Read32 (F), O);
338     }
339
340     /* Last is the file position where the definition was done */
341     ReadFilePos (F, &E->Pos);
342
343     /* Return the new export */
344     return E;
345 }
346
347
348
349 Export* CreateConstExport (const char* Name, long Value)
350 /* Create an export for a literal date */
351 {
352     /* Create a new export */
353     Export* E = NewExport (EXP_ABS | EXP_CONST | EXP_EQUATE, Name, 0);
354
355     /* Assign the value */
356     E->Expr = LiteralExpr (Value, 0);
357
358     /* Insert the export */
359     InsertExport (E);
360
361     /* Return the new export */
362     return E;
363 }
364
365
366
367 Export* CreateMemoryExport (const char* Name, Memory* Mem, unsigned long Offs)
368 /* Create an relative export for a memory area offset */
369 {
370     /* Create a new export */
371     Export* E = NewExport (EXP_ABS | EXP_EXPR | EXP_LABEL, Name, 0);
372
373     /* Assign the value */
374     E->Expr = MemoryExpr (Mem, Offs, 0);
375
376     /* Insert the export */
377     InsertExport (E);
378
379     /* Return the new export */
380     return E;
381 }
382
383
384
385 Export* CreateSegmentExport (const char* Name, Segment* Seg, unsigned long Offs)
386 /* Create a relative export to a segment */
387 {
388     /* Create a new export */
389     Export* E = NewExport (EXP_ABS | EXP_EXPR | EXP_LABEL, Name, 0);
390
391     /* Assign the value */
392     E->Expr = SegmentExpr (Seg, Offs, 0);
393
394     /* Insert the export */
395     InsertExport (E);
396
397     /* Return the new export */
398     return E;
399 }
400
401
402
403 Export* CreateSectionExport (const char* Name, Section* Sec, unsigned long Offs)
404 /* Create a relative export to a section */
405 {
406     /* Create a new export */
407     Export* E = NewExport (EXP_ABS | EXP_EXPR | EXP_LABEL, Name, 0);
408
409     /* Assign the value */
410     E->Expr = SectionExpr (Sec, Offs, 0);
411
412     /* Insert the export */
413     InsertExport (E);
414
415     /* Return the new export */
416     return E;
417 }
418
419
420
421 Export* FindExport (const char* Name)
422 /* Check for an identifier in the list. Return 0 if not found, otherwise
423  * return a pointer to the export.
424  */
425 {
426     /* Get a pointer to the list with the symbols hash value */
427     Export* L = HashTab [HashStr (Name) % HASHTAB_SIZE];
428     while (L) {
429         /* Search through the list in that slot */
430         if (strcmp (L->Name, Name) == 0) {
431             /* Entry found */
432             return L;
433         }
434         L = L->Next;
435     }
436
437     /* Not found */
438     return 0;
439 }
440
441
442
443 int IsUnresolved (const char* Name)
444 /* Check if this symbol is an unresolved export */
445 {
446     /* Find the export */
447     return IsUnresolvedExport (FindExport (Name));
448 }
449
450
451
452 int IsUnresolvedExport (const Export* E)
453 /* Return true if the given export is unresolved */
454 {
455     /* Check if it's unresolved */
456     return E != 0 && E->Expr == 0;
457 }
458
459
460
461 int IsConstExport (const Export* E)
462 /* Return true if the expression associated with this export is const */
463 {
464     if (E->Expr == 0) {
465         /* External symbols cannot be const */
466         return 0;
467     } else {
468         return IsConstExpr (E->Expr);
469     }
470 }
471
472
473
474 long GetExportVal (const Export* E)
475 /* Get the value of this export */
476 {
477     if (E->Expr == 0) {
478         /* OOPS */
479         Internal ("`%s' is an undefined external", E->Name);
480     }
481     return GetExprVal (E->Expr);
482 }
483
484
485
486 static void CheckSymType (const Export* E)
487 /* Check the types for one export */
488 {
489     /* External with matching imports */
490     Import* Imp = E->ImpList;
491     int ZP = IS_EXP_ZP (E->Type);
492     while (Imp) {
493         if (ZP != IS_IMP_ZP (Imp->Type)) {
494             /* Export is ZP, import is abs or the other way round */
495             if (E->Obj) {
496                 /* User defined export */
497                 Warning ("Type mismatch for `%s', export in "
498                          "%s(%lu), import in %s(%lu)",
499                          E->Name, GetSourceFileName (E->Obj, Imp->Pos.Name),
500                          E->Pos.Line, GetSourceFileName (Imp->Obj, Imp->Pos.Name),
501                          Imp->Pos.Line);
502             } else {
503                 /* Export created by the linker */
504                 Warning ("Type mismatch for `%s', imported from %s(%lu)",
505                          E->Name, GetSourceFileName (Imp->Obj, Imp->Pos.Name),
506                          Imp->Pos.Line);
507             }
508         }
509         Imp = Imp->Next;
510     }
511 }
512
513
514
515 static void CheckSymTypes (void)
516 /* Check for symbol tape mismatches */
517 {
518     unsigned I;
519
520     /* Print all open imports */
521     for (I = 0; I < ExpCount; ++I) {
522         const Export* E = ExpPool [I];
523         if (E->Expr != 0 && E->ImpCount > 0) {
524             /* External with matching imports */
525             CheckSymType (E);
526         }
527     }
528 }
529
530
531
532 static void PrintUnresolved (ExpCheckFunc F, void* Data)
533 /* Print a list of unresolved symbols. On unresolved symbols, F is
534  * called (see the comments on ExpCheckFunc in the data section).
535  */
536 {
537     unsigned I;
538
539     /* Print all open imports */
540     for (I = 0; I < ExpCount; ++I) {
541         Export* E = ExpPool [I];
542         if (E->Expr == 0 && E->ImpCount > 0 && F (E->Name, Data) == 0) {
543             /* Unresolved external */
544             Import* Imp = E->ImpList;
545             fprintf (stderr,
546                      "Unresolved external `%s' referenced in:\n",
547                      E->Name);
548             while (Imp) {
549                 const char* Name = GetSourceFileName (Imp->Obj, Imp->Pos.Name);
550                 fprintf (stderr, "  %s(%lu)\n", Name, Imp->Pos.Line);
551                 Imp = Imp->Next;
552             }
553         }
554     }
555 }
556
557
558
559 static int CmpExpName (const void* K1, const void* K2)
560 /* Compare function for qsort */
561 {
562     return strcmp ((*(Export**)K1)->Name, (*(Export**)K2)->Name);
563 }
564
565
566
567 static void CreateExportPool (void)
568 /* Create an array with pointer to all exports */
569 {
570     unsigned I, J;
571
572     /* Allocate memory */
573     if (ExpPool) {
574         xfree (ExpPool);
575     }
576     ExpPool = xmalloc (ExpCount * sizeof (Export*));
577
578     /* Walk through the list and insert the exports */
579     for (I = 0, J = 0; I < sizeof (HashTab) / sizeof (HashTab [0]); ++I) {
580         Export* E = HashTab [I];
581         while (E) {
582             CHECK (J < ExpCount);
583             ExpPool [J++] = E;
584             E = E->Next;
585         }
586     }
587
588     /* Sort them by name */
589     qsort (ExpPool, ExpCount, sizeof (Export*), CmpExpName);
590 }
591
592
593
594 void CheckExports (ExpCheckFunc F, void* Data)
595 /* Check if there are any unresolved symbols. On unresolved symbols, F is
596  * called (see the comments on ExpCheckFunc in the data section).
597  */
598 {
599     /* Create an export pool */
600     CreateExportPool ();
601
602     /* Check for symbol type mismatches */
603     CheckSymTypes ();
604
605     /* Check for unresolved externals (check here for special bin formats) */
606     if (ImpOpen != 0) {
607         /* Print all open imports */
608         PrintUnresolved (F, Data);
609     }
610 }
611
612
613
614 void PrintExportMap (FILE* F)
615 /* Print an export map to the given file */
616 {
617     unsigned I;
618     unsigned Count;
619
620     /* Print all exports */
621     Count = 0;
622     for (I = 0; I < ExpCount; ++I) {
623         const Export* E = ExpPool [I];
624
625         /* Print unreferenced symbols only if explictly requested */
626         if (VerboseMap || E->ImpCount > 0 || IS_EXP_CONDES (E->Type)) {
627             fprintf (F,
628                      "%-25s %06lX %c%c%c%c   ",
629                      E->Name,
630                      GetExportVal (E),
631                      E->ImpCount? 'R' : ' ',
632                      IS_EXP_LABEL (E->Type)? 'L' : 'E',
633                      IS_EXP_ZP (E->Type)? 'Z' : ' ',
634                      IS_EXP_CONDES (E->Type)? 'I' : ' ');
635             if (++Count == 2) {
636                 Count = 0;
637                 fprintf (F, "\n");
638             }
639         }
640     }
641     fprintf (F, "\n");
642 }
643
644
645
646 void PrintImportMap (FILE* F)
647 /* Print an import map to the given file */
648 {
649     unsigned I;
650     const Import* Imp;
651
652     /* Loop over all exports */
653     for (I = 0; I < ExpCount; ++I) {
654
655         /* Get the export */
656         const Export* Exp = ExpPool [I];
657
658         /* Print the symbol only if there are imports, or if a verbose map
659          * file is requested.
660          */
661         if (VerboseMap || Exp->ImpCount > 0) {
662
663             /* Print the export */
664             fprintf (F,
665                      "%s (%s):\n",
666                      Exp->Name,
667                      GetObjFileName (Exp->Obj));
668
669             /* Print all imports for this symbol */
670             Imp = Exp->ImpList;
671             while (Imp) {
672
673                 /* Print the import */
674                 fprintf (F,
675                          "    %-25s %s(%lu)\n",
676                          GetObjFileName (Imp->Obj),
677                          GetSourceFileName (Imp->Obj, Imp->Pos.Name),
678                          Imp->Pos.Line);
679
680                 /* Next import */
681                 Imp = Imp->Next;
682             }
683         }
684     }
685     fprintf (F, "\n");
686 }
687
688
689
690 void PrintExportLabels (FILE* F)
691 /* Print the exports in a VICE label file */
692 {
693     unsigned I;
694
695     /* Print all exports */
696     for (I = 0; I < ExpCount; ++I) {
697         const Export* E = ExpPool [I];
698         fprintf (F, "al %06lX .%s\n", GetExportVal (E), E->Name);
699     }
700 }
701
702
703
704 void MarkExport (Export* E)
705 /* Mark the export */
706 {
707     E->Flags |= EXP_USERMARK;
708 }
709
710
711
712 void UnmarkExport (Export* E)
713 /* Remove the mark from the export */
714 {
715     E->Flags &= ~EXP_USERMARK;
716 }
717
718
719
720 int ExportHasMark (Export* E)
721 /* Return true if the export has a mark */
722 {
723     return (E->Flags & EXP_USERMARK) != 0;
724 }
725
726
727
728 void CircularRefError (const Export* E)
729 /* Print an error about a circular reference using to define the given export */
730 {
731     Error ("Circular reference for symbol `%s', %s(%lu)",
732            E->Name, GetSourceFileName (E->Obj, E->Pos.Name), E->Pos.Line);
733 }
734
735
736