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