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