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