]> git.sur5r.net Git - cc65/blob - src/ld65/exports.c
New module to handle initializers
[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 "initfunc.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     const 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", Obj->Name, Type);
174     }
175
176     /* Create a new import */
177     I = NewImport (Type, Obj);
178
179     /* Read the name */
180     I->V.Name = ReadStr (F);
181
182     /* Read the file position */
183     ReadFilePos (F, &I->Pos);
184
185     /* Return the new import */
186     return I;
187 }
188
189
190
191 /*****************************************************************************/
192 /*                                   Code                                    */
193 /*****************************************************************************/
194
195
196
197 static Export* NewExport (unsigned char Type, const char* Name, ObjData* Obj)
198 /* Create a new export and initialize it */
199 {
200     /* Allocate memory */
201     Export* E = xmalloc (sizeof (Export));
202
203     /* Initialize the fields */
204     E->Next     = 0;
205     E->Flags    = 0;
206     E->Obj      = Obj;
207     E->ImpCount = 0;
208     E->ImpList  = 0;
209     E->Expr     = 0;
210     E->Type     = Type;
211     if (Name) {
212         E->Name = xstrdup (Name);
213     } else {
214         /* Name will get added later */
215         E->Name = 0;
216     }
217
218     /* Return the new entry */
219     return E;
220 }
221
222
223
224 void InsertExport (Export* E)
225 /* Insert an exported identifier and check if it's already in the list */
226 {
227     Export* L;
228     Export* Last;
229     Import* Imp;
230     unsigned HashVal;
231
232     /* If this is an initializer, insert it into the initializer list */
233     if (IS_EXP_INIT (E->Type)) {
234         AddInitFunc (E);
235     }
236
237     /* Create a hash value for the given name */
238     HashVal = HashStr (E->Name) % HASHTAB_SIZE;
239
240     /* Search through the list in that slot */
241     if (HashTab [HashVal] == 0) {
242         /* The slot is empty */
243         HashTab [HashVal] = E;
244         ++ExpCount;
245     } else {
246
247         Last = 0;
248         L = HashTab [HashVal];
249         do {
250             if (strcmp (L->Name, E->Name) == 0) {
251                 /* This may be an unresolved external */
252                 if (L->Expr == 0) {
253
254                     /* This *is* an unresolved external */
255                     E->Next     = L->Next;
256                     E->ImpCount = L->ImpCount;
257                     E->ImpList  = L->ImpList;
258                     if (Last) {
259                         Last->Next = E;
260                     } else {
261                         HashTab [HashVal] = E;
262                     }
263                     ImpOpen -= E->ImpCount;     /* Decrease open imports now */
264                     xfree (L);
265                     /* We must run through the import list and change the
266                      * export pointer now.
267                      */
268                     Imp = E->ImpList;
269                     while (Imp) {
270                         Imp->V.Exp = E;
271                         Imp = Imp->Next;
272                     }
273                 } else {
274                     /* Duplicate entry, ignore it */
275                     Warning ("Duplicate external identifier: `%s'", L->Name);
276                 }
277                 return;
278             }
279             Last = L;
280             L = L->Next;
281
282         } while (L);
283
284         /* Insert export at end of queue */
285         Last->Next = E;
286         ++ExpCount;
287     }
288 }
289
290
291
292 Export* ReadExport (FILE* F, ObjData* O)
293 /* Read an export from a file */
294 {
295     unsigned char Type;
296     Export* E;
297
298     /* Read the type */
299     Type = Read8 (F);
300
301     /* Create a new export without a name */
302     E = NewExport (Type, 0, O);
303
304     /* Read the name */
305     E->Name = ReadStr (F);
306
307     /* Read the value */
308     if (IS_EXP_EXPR (Type)) {
309         E->Expr = ReadExpr (F, O);
310     } else {
311         E->Expr = LiteralExpr (Read32 (F), O);
312     }
313
314     /* Last is the file position where the definition was done */
315     ReadFilePos (F, &E->Pos);
316
317     /* Return the new export */
318     return E;
319 }
320
321
322
323 Export* CreateConstExport (const char* Name, long Value)
324 /* Create an export for a literal date */
325 {
326     /* Create a new export */
327     Export* E = NewExport (EXP_ABS, Name, 0);
328
329     /* Assign the value */
330     E->Expr = LiteralExpr (Value, 0);
331
332     /* Insert the export */
333     InsertExport (E);
334
335     /* Return the new export */
336     return E;
337 }
338
339
340
341 Export* CreateMemExport (const char* Name, Memory* Mem, unsigned long Offs)
342 /* Create an relative export for a memory area offset */
343 {
344     /* Create a new export */
345     Export* E = NewExport (EXP_ABS, Name, 0);
346
347     /* Assign the value */
348     E->Expr = MemExpr (Mem, Offs, 0);
349
350     /* Insert the export */
351     InsertExport (E);
352
353     /* Return the new export */
354     return E;
355 }
356
357
358
359 static Export* FindExport (const char* Name)
360 /* Check for an identifier in the list. Return 0 if not found, otherwise
361  * return a pointer to the export.
362  */
363 {
364     /* Get a pointer to the list with the symbols hash value */
365     Export* L = HashTab [HashStr (Name) % HASHTAB_SIZE];
366     while (L) {
367         /* Search through the list in that slot */
368         if (strcmp (L->Name, Name) == 0) {
369             /* Entry found */
370             return L;
371         }
372         L = L->Next;
373     }
374
375     /* Not found */
376     return 0;
377 }
378
379
380
381 int IsUnresolved (const char* Name)
382 /* Check if this symbol is an unresolved export */
383 {
384     /* Find the export */
385     Export* E = FindExport (Name);
386
387     /* Check if it's unresolved */
388     return E != 0 && E->Expr == 0;
389 }
390
391
392
393 int IsConstExport (const Export* E)
394 /* Return true if the expression associated with this export is const */
395 {
396     if (E->Expr == 0) {
397         /* External symbols cannot be const */
398         return 0;
399     } else {
400         return IsConstExpr (E->Expr);
401     }
402 }
403
404
405
406 long GetExportVal (const Export* E)
407 /* Get the value of this export */
408 {
409     if (E->Expr == 0) {
410         /* OOPS */
411         Internal ("`%s' is an undefined external", E->Name);
412     }
413     return GetExprVal (E->Expr);
414 }
415
416
417
418 static void CheckSymType (const Export* E)
419 /* Check the types for one export */
420 {
421     /* External with matching imports */
422     Import* Imp = E->ImpList;
423     int ZP = IS_EXP_ZP (E->Type);
424     while (Imp) {
425         if (ZP != IS_IMP_ZP (Imp->Type)) {
426             /* Export is ZP, import is abs or the other way round */
427             if (E->Obj) {
428                 /* User defined export */
429                 Warning ("Type mismatch for `%s', export in "
430                          "%s(%lu), import in %s(%lu)",
431                          E->Name, E->Obj->Files [Imp->Pos.Name],
432                          E->Pos.Line, Imp->Obj->Files [Imp->Pos.Name],
433                          Imp->Pos.Line);
434             } else {
435                 /* Export created by the linker */
436                 Warning ("Type mismatch for `%s', imported from %s(%lu)",
437                          E->Name, Imp->Obj->Files [Imp->Pos.Name],
438                          Imp->Pos.Line);
439             }
440         }
441         Imp = Imp->Next;
442     }
443 }
444
445
446
447 static void CheckSymTypes (void)
448 /* Check for symbol tape mismatches */
449 {
450     unsigned I;
451
452     /* Print all open imports */
453     for (I = 0; I < ExpCount; ++I) {
454         const Export* E = ExpPool [I];
455         if (E->Expr != 0 && E->ImpCount > 0) {
456             /* External with matching imports */
457             CheckSymType (E);
458         }
459     }
460 }
461
462
463
464 static void PrintUnresolved (ExpCheckFunc F, void* Data)
465 /* Print a list of unresolved symbols. On unresolved symbols, F is
466  * called (see the comments on ExpCheckFunc in the data section).
467  */
468 {
469     unsigned I;
470
471     /* Print all open imports */
472     for (I = 0; I < ExpCount; ++I) {
473         Export* E = ExpPool [I];
474         if (E->Expr == 0 && E->ImpCount > 0 && F (E->Name, Data) == 0) {
475             /* Unresolved external */
476             Import* Imp = E->ImpList;
477             fprintf (stderr,
478                      "Unresolved external `%s' referenced in:\n",
479                      E->Name);
480             while (Imp) {
481                 const char* Name = Imp->Obj->Files [Imp->Pos.Name];
482                 fprintf (stderr, "  %s(%lu)\n", Name, Imp->Pos.Line);
483                 Imp = Imp->Next;
484             }
485         }
486     }
487 }
488
489
490
491 static int CmpExpName (const void* K1, const void* K2)
492 /* Compare function for qsort */
493 {
494     return strcmp ((*(Export**)K1)->Name, (*(Export**)K2)->Name);
495 }
496
497
498
499 static void CreateExportPool (void)
500 /* Create an array with pointer to all exports */
501 {
502     unsigned I, J;
503
504     /* Allocate memory */
505     if (ExpPool) {
506         xfree (ExpPool);
507     }
508     ExpPool = xmalloc (ExpCount * sizeof (Export*));
509
510     /* Walk through the list and insert the exports */
511     for (I = 0, J = 0; I < sizeof (HashTab) / sizeof (HashTab [0]); ++I) {
512         Export* E = HashTab [I];
513         while (E) {
514             CHECK (J < ExpCount);
515             ExpPool [J++] = E;
516             E = E->Next;
517         }
518     }
519
520     /* Sort them by name */
521     qsort (ExpPool, ExpCount, sizeof (Export*), CmpExpName);
522 }
523
524
525
526 void CheckExports (ExpCheckFunc F, void* Data)
527 /* Check if there are any unresolved symbols. On unresolved symbols, F is
528  * called (see the comments on ExpCheckFunc in the data section).
529  */
530 {
531     /* Create an export pool */
532     CreateExportPool ();
533
534     /* Check for symbol type mismatches */
535     CheckSymTypes ();
536
537     /* Check for unresolved externals (check here for special bin formats) */
538     if (ImpOpen != 0) {
539         /* Print all open imports */
540         PrintUnresolved (F, Data);
541     }
542 }
543
544
545
546 void PrintExportMap (FILE* F)
547 /* Print an export map to the given file */
548 {
549     unsigned I;
550     unsigned Count;
551
552     /* Print all exports */
553     Count = 0;
554     for (I = 0; I < ExpCount; ++I) {
555         const Export* E = ExpPool [I];
556
557         /* Print unreferenced symbols only if explictly requested */
558         if (VerboseMap || E->ImpCount > 0) {
559             fprintf (F,
560                      "%-25s %06lX %c%c%c   ",
561                      E->Name,
562                      GetExportVal (E),
563                      E->ImpCount? 'R' : ' ',
564                      IS_EXP_ZP (E->Type)? 'Z' : ' ',
565                      IS_EXP_INIT (E->Type)? 'I' : ' ');
566             if (++Count == 2) {
567                 Count = 0;
568                 fprintf (F, "\n");
569             }
570         }
571     }
572     fprintf (F, "\n");
573 }
574
575
576
577 void PrintImportMap (FILE* F)
578 /* Print an import map to the given file */
579 {
580     unsigned I;
581     const Import* Imp;
582
583     /* Loop over all exports */
584     for (I = 0; I < ExpCount; ++I) {
585
586         /* Get the export */
587         const Export* Exp = ExpPool [I];
588
589         /* Print the symbol only if there are imports, or if a verbose map
590          * file is requested.
591          */
592         if (VerboseMap || Exp->ImpCount > 0) {
593
594             /* Get the name of the object file that exports the symbol.
595              * Beware: There may be no object file if the symbol is a linker
596              * generated symbol.
597              */
598             const char* ObjName = (Exp->Obj != 0)? Exp->Obj->Name : "linker generated";
599
600             /* Print the export */
601             fprintf (F,
602                      "%s (%s):\n",
603                      Exp->Name,
604                      ObjName);
605
606             /* Print all imports for this symbol */
607             Imp = Exp->ImpList;
608             while (Imp) {
609
610                 /* Print the import */
611                 fprintf (F,
612                          "    %-25s %s(%lu)\n",
613                          Imp->Obj->Name,
614                          Imp->Obj->Files [Imp->Pos.Name],
615                          Imp->Pos.Line);
616
617                 /* Next import */
618                 Imp = Imp->Next;
619             }
620         }
621     }
622     fprintf (F, "\n");
623 }
624
625
626
627 void PrintExportLabels (FILE* F)
628 /* Print the exports in a VICE label file */
629 {
630     unsigned I;
631
632     /* Print all exports */
633     for (I = 0; I < ExpCount; ++I) {
634         const Export* E = ExpPool [I];
635         fprintf (F, "al %06lX .%s\n", GetExportVal (E), E->Name);
636     }
637 }
638
639
640
641 void MarkExport (Export* E)
642 /* Mark the export */
643 {
644     E->Flags |= EXP_USERMARK;
645 }
646
647
648
649 void UnmarkExport (Export* E)
650 /* Remove the mark from the export */
651 {
652     E->Flags &= ~EXP_USERMARK;
653 }
654
655
656
657 int ExportHasMark (Export* E)
658 /* Return true if the export has a mark */
659 {
660     return (E->Flags & EXP_USERMARK) != 0;
661 }
662
663
664
665 void CircularRefError (const Export* E)
666 /* Print an error about a circular reference using to define the given export */
667 {
668     Error ("Circular reference for symbol `%s', %s(%lu)",
669            E->Name, E->Obj->Files [E->Pos.Name], E->Pos.Line);
670 }
671
672
673