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