]> git.sur5r.net Git - cc65/blob - src/ld65/segments.c
c685ac48eecd6b91bb7b968e7161c33faecd2ca5
[cc65] / src / ld65 / segments.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                segments.c                                 */
4 /*                                                                           */
5 /*                   Segment 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 <stdlib.h>
37 #include <string.h>
38
39 /* common */
40 #include "check.h"
41 #include "exprdefs.h"
42 #include "fragdefs.h"
43 #include "hashstr.h"
44 #include "print.h"
45 #include "segdefs.h"
46 #include "symdefs.h"
47 #include "xmalloc.h"
48
49 /* ld65 */
50 #include "error.h"
51 #include "expr.h"
52 #include "fileio.h"
53 #include "fragment.h"
54 #include "global.h"
55 #include "lineinfo.h"
56 #include "segments.h"
57 #include "spool.h"
58
59
60
61 /*****************************************************************************/
62 /*                                   Data                                    */
63 /*****************************************************************************/
64
65
66
67 /* Hash table */
68 #define HASHTAB_MASK    0x3FU
69 #define HASHTAB_SIZE    (HASHTAB_MASK + 1)
70 static Segment*         HashTab [HASHTAB_SIZE];
71
72 static unsigned         SegCount = 0;   /* Segment count */
73 static Segment*         SegRoot = 0;    /* List of all segments */
74
75
76
77 /*****************************************************************************/
78 /*                                   Code                                    */
79 /*****************************************************************************/
80
81
82
83 static Segment* NewSegment (unsigned Name, unsigned char Type)
84 /* Create a new segment and initialize it */
85 {
86     unsigned Hash;
87
88     /* Allocate memory */
89     Segment* S = xmalloc (sizeof (Segment));
90
91     /* Initialize the fields */
92     S->Name     = Name;
93     S->Next     = 0;
94     S->SecRoot  = 0;
95     S->SecLast  = 0;
96     S->PC       = 0;
97     S->Size     = 0;
98     S->AlignObj = 0;
99     S->Align    = 0;
100     S->FillVal  = 0;
101     S->Type     = Type;
102     S->Dumped   = 0;
103
104     /* Insert the segment into the segment list */
105     S->List = SegRoot;
106     SegRoot = S;
107     ++SegCount;
108
109     /* Insert the segment into the segment hash list */
110     Hash = (S->Name & HASHTAB_MASK);
111     S->Next = HashTab[Hash];
112     HashTab[Hash] = S;
113
114     /* Return the new entry */
115     return S;
116 }
117
118
119
120 Segment* GetSegment (unsigned Name, unsigned char Type, const char* ObjName)
121 /* Search for a segment and return an existing one. If the segment does not
122  * exist, create a new one and return that. ObjName is only used for the error
123  * message and may be NULL if the segment is linker generated.
124  */
125 {
126     /* Try to locate the segment in the table */
127     Segment* S = SegFind (Name);
128
129     /* If we don't have that segment already, allocate it using the type of
130      * the first section.
131      */
132     if (S == 0) {
133         /* Create a new segment */
134         S = NewSegment (Name, Type);
135     } else {
136         /* Check if the existing segment has the requested type */
137         if (S->Type != Type) {
138             /* Allow an empty object name */
139             if (ObjName == 0) {
140                 ObjName = "[linker generated]";
141             }
142             Error ("Module `%s': Type mismatch for segment `%s'", ObjName,
143                    GetString (Name));
144         }
145     }
146
147     /* Return the segment */
148     return S;
149 }
150
151
152
153 Section* NewSection (Segment* Seg, unsigned char Align, unsigned char Type)
154 /* Create a new section for the given segment */
155 {
156     unsigned long V;
157
158
159     /* Allocate memory */
160     Section* S = xmalloc (sizeof (Section));
161
162     /* Initialize the data */
163     S->Next     = 0;
164     S->Seg      = Seg;
165     S->FragRoot = 0;
166     S->FragLast = 0;
167     S->Size     = 0;
168     S->Align    = Align;
169     S->Type     = Type;
170
171     /* Calculate the alignment bytes needed for the section */
172     V = (0x01UL << S->Align) - 1;
173     S->Fill = (unsigned char) (((Seg->Size + V) & ~V) - Seg->Size);
174
175     /* Adjust the segment size and set the section offset */
176     Seg->Size  += S->Fill;
177     S->Offs     = Seg->Size;    /* Current size is offset */
178
179     /* Insert the section into the segment */
180     if (Seg->SecRoot == 0) {
181         /* First section in this segment */
182         Seg->SecRoot = S;
183     } else {
184         Seg->SecLast->Next = S;
185     }
186     Seg->SecLast = S;
187
188     /* Return the struct */
189     return S;
190 }
191
192
193
194 Section* ReadSection (FILE* F, ObjData* O)
195 /* Read a section from a file */
196 {
197     unsigned      Name;
198     unsigned      Size;
199     unsigned char Align;
200     unsigned char Type;
201     unsigned      FragCount;
202     Segment*      S;
203     Section*      Sec;
204
205     /* Read the segment data */
206     (void) Read32 (F);            /* File size of data */
207     Name      = MakeGlobalStringId (O, ReadVar (F));    /* Segment name */
208     Size      = Read32 (F);       /* Size of data */
209     Align     = Read8 (F);        /* Alignment */
210     Type      = Read8 (F);        /* Segment type */
211     FragCount = ReadVar (F);      /* Number of fragments */
212
213
214     /* Print some data */
215     Print (stdout, 2, "Module `%s': Found segment `%s', size = %u, align = %u, type = %u\n",
216            GetObjFileName (O), GetString (Name), Size, Align, Type);
217
218     /* Get the segment for this section */
219     S = GetSegment (Name, Type, GetObjFileName (O));
220
221     /* Allocate the section we will return later */
222     Sec = NewSection (S, Align, Type);
223
224     /* Set up the minimum segment alignment */
225     if (Sec->Align > S->Align) {
226         /* Section needs larger alignment, use this one */
227         S->Align    = Sec->Align;
228         S->AlignObj = O;
229     }
230
231     /* Start reading fragments from the file and insert them into the section . */
232     while (FragCount--) {
233
234         Fragment* Frag;
235         unsigned  LineInfoIndex;
236
237         /* Read the fragment type */
238         unsigned char Type = Read8 (F);
239
240         /* Extract the check mask from the type */
241         unsigned char Bytes = Type & FRAG_BYTEMASK;
242         Type &= FRAG_TYPEMASK;
243
244         /* Handle the different fragment types */
245         switch (Type) {
246
247             case FRAG_LITERAL:
248                 Frag = NewFragment (Type, ReadVar (F), Sec);
249                 ReadData (F, Frag->LitBuf, Frag->Size);
250                 break;
251
252             case FRAG_EXPR:
253             case FRAG_SEXPR:
254                 Frag = NewFragment (Type, Bytes, Sec);
255                 Frag->Expr = ReadExpr (F, O);
256                 break;
257
258             case FRAG_FILL:
259                 /* Will allocate memory, but we don't care... */
260                 Frag = NewFragment (Type, ReadVar (F), Sec);
261                 break;
262
263             default:
264                 Error ("Unknown fragment type in module `%s', segment `%s': %02X",
265                        GetObjFileName (O), GetString (S->Name), Type);
266                 /* NOTREACHED */
267                 return 0;
268         }
269
270         /* Read the file position of the fragment */
271         ReadFilePos (F, &Frag->Pos);
272
273         /* Read the additional line info and resolve it */
274         LineInfoIndex = ReadVar (F);
275         if (LineInfoIndex) {
276             --LineInfoIndex;
277             if (LineInfoIndex >= O->LineInfoCount) {
278                 Internal ("In module `%s', file `%s', line %lu: Invalid line "
279                           "info with index %u (max count %u)",
280                           GetObjFileName (O),
281                           GetSourceFileName (O, Frag->Pos.Name),
282                           Frag->Pos.Line, LineInfoIndex, O->LineInfoCount);
283             }
284             /* Point from the fragment to the line info... */
285             Frag->LI = O->LineInfos[LineInfoIndex];
286             /* ...and back from the line info to the fragment */
287             CollAppend (&Frag->LI->Fragments, Frag);
288         }
289
290         /* Remember the module we had this fragment from */
291         Frag->Obj = O;
292     }
293
294     /* Return the section */
295     return Sec;
296 }
297
298
299
300 Segment* SegFind (unsigned Name)
301 /* Return the given segment or NULL if not found. */
302 {
303     Segment* S = HashTab[Name & HASHTAB_MASK];
304     while (S) {
305         if (Name == S->Name) {
306             /* Found */
307             break;
308         }
309         S = S->Next;
310     }
311     /* Not found */
312     return S;
313 }
314
315
316
317 int IsBSSType (Segment* S)
318 /* Check if the given segment is a BSS style segment, that is, it does not
319  * contain non-zero data.
320  */
321 {
322     /* Loop over all sections */
323     Section* Sec = S->SecRoot;
324     while (Sec) {
325         /* Loop over all fragments */
326         Fragment* F = Sec->FragRoot;
327         while (F) {
328             if (F->Type == FRAG_LITERAL) {
329                 unsigned char* Data = F->LitBuf;
330                 unsigned long Count = F->Size;
331                 while (Count--) {
332                     if (*Data++ != 0) {
333                         return 0;
334                     }
335                 }
336             } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
337                 if (GetExprVal (F->Expr) != 0) {
338                     return 0;
339                 }
340             }
341             F = F->Next;
342         }
343         Sec = Sec->Next;
344     }
345     return 1;
346 }
347
348
349
350 void SegDump (void)
351 /* Dump the segments and it's contents */
352 {
353     unsigned I;
354     unsigned long Count;
355     unsigned char* Data;
356
357     Segment* Seg = SegRoot;
358     while (Seg) {
359         Section* S = Seg->SecRoot;
360         printf ("Segment: %s (%lu)\n", GetString (Seg->Name), Seg->Size);
361         while (S) {
362             Fragment* F = S->FragRoot;
363             printf ("  Section:\n");
364             while (F) {
365                 switch (F->Type) {
366
367                     case FRAG_LITERAL:
368                         printf ("    Literal (%u bytes):", F->Size);
369                         Count = F->Size;
370                         Data  = F->LitBuf;
371                         I = 100;
372                         while (Count--) {
373                             if (I > 75) {
374                                 printf ("\n   ");
375                                 I = 3;
376                             }
377                             printf (" %02X", *Data++);
378                             I += 3;
379                         }
380                         printf ("\n");
381                         break;
382
383                     case FRAG_EXPR:
384                         printf ("    Expression (%u bytes):\n", F->Size);
385                         printf ("    ");
386                         DumpExpr (F->Expr);
387                         break;
388
389                     case FRAG_SEXPR:
390                         printf ("    Signed expression (%u bytes):\n", F->Size);
391                         printf ("      ");
392                         DumpExpr (F->Expr);
393                         break;
394
395                     case FRAG_FILL:
396                         printf ("    Empty space (%u bytes)\n", F->Size);
397                         break;
398
399                     default:
400                         Internal ("Invalid fragment type: %02X", F->Type);
401                 }
402                 F = F->Next;
403             }
404             S = S->Next;
405         }
406         Seg = Seg->List;
407     }
408 }
409
410
411
412 unsigned SegWriteConstExpr (FILE* F, ExprNode* E, int Signed, unsigned Size)
413 /* Write a supposedly constant expression to the target file. Do a range
414  * check and return one of the SEG_EXPR_xxx codes.
415  */
416 {
417     static const unsigned long U_HighRange [4] = {
418         0x000000FF, 0x0000FFFF, 0x00FFFFFF, 0xFFFFFFFF
419     };
420     static const long S_HighRange [4] = {
421         0x0000007F, 0x00007FFF, 0x007FFFFF, 0x7FFFFFFF
422     };
423     static const long S_LowRange [4] = {
424         0xFFFFFF80, 0xFFFF8000, 0xFF800000, 0x80000000
425     };
426
427
428     /* Get the expression value */
429     long Val = GetExprVal (E);
430
431     /* Check the size */
432     CHECK (Size >= 1 && Size <= 4);
433
434     /* Check for a range error */
435     if (Signed) {
436         if (Val > S_HighRange [Size-1] || Val < S_LowRange [Size-1]) {
437             /* Range error */
438             return SEG_EXPR_RANGE_ERROR;
439         }
440     } else {
441         if (((unsigned long)Val) > U_HighRange [Size-1]) {
442             /* Range error */
443             return SEG_EXPR_RANGE_ERROR;
444         }
445     }
446
447     /* Write the value to the file */
448     WriteVal (F, Val, Size);
449
450     /* Success */
451     return SEG_EXPR_OK;
452 }
453
454
455
456 void SegWrite (FILE* Tgt, Segment* S, SegWriteFunc F, void* Data)
457 /* Write the data from the given segment to a file. For expressions, F is
458  * called (see description of SegWriteFunc above).
459  */
460 {
461     int Sign;
462     unsigned long Offs = 0;
463
464     /* Loop over all sections in this segment */
465     Section* Sec = S->SecRoot;
466     while (Sec) {
467         Fragment* Frag;
468
469         /* If we have fill bytes, write them now */
470         WriteMult (Tgt, S->FillVal, Sec->Fill);
471         Offs += Sec->Fill;
472
473         /* Loop over all fragments in this section */
474         Frag = Sec->FragRoot;
475         while (Frag) {
476
477             /* Do fragment alignment checks */
478
479
480
481             /* Output fragment data */
482             switch (Frag->Type) {
483
484                 case FRAG_LITERAL:
485                     WriteData (Tgt, Frag->LitBuf, Frag->Size);
486                     break;
487
488                 case FRAG_EXPR:
489                 case FRAG_SEXPR:
490                     Sign = (Frag->Type == FRAG_SEXPR);
491                     /* Call the users function and evaluate the result */
492                     switch (F (Frag->Expr, Sign, Frag->Size, Offs, Data)) {
493
494                         case SEG_EXPR_OK:
495                             break;
496
497                         case SEG_EXPR_RANGE_ERROR:
498                             Error ("Range error in module `%s', line %lu",
499                                    GetSourceFileName (Frag->Obj, Frag->Pos.Name),
500                                    Frag->Pos.Line);
501                             break;
502
503                         case SEG_EXPR_TOO_COMPLEX:
504                             Error ("Expression too complex in module `%s', line %lu",
505                                    GetSourceFileName (Frag->Obj, Frag->Pos.Name),
506                                    Frag->Pos.Line);
507                             break;
508
509                         case SEG_EXPR_INVALID:
510                             Error ("Invalid expression in module `%s', line %lu",
511                                    GetSourceFileName (Frag->Obj, Frag->Pos.Name),
512                                    Frag->Pos.Line);
513                             break;
514
515                         default:
516                             Internal ("Invalid return code from SegWriteFunc");
517                     }
518                     break;
519
520                 case FRAG_FILL:
521                     WriteMult (Tgt, S->FillVal, Frag->Size);
522                     break;
523
524                 default:
525                     Internal ("Invalid fragment type: %02X", Frag->Type);
526             }
527
528             /* Update the offset */
529             Offs += Frag->Size;
530
531             /* Next fragment */
532             Frag = Frag->Next;
533         }
534
535         /* Next section */
536         Sec = Sec->Next;
537     }
538 }
539
540
541
542 static int CmpSegStart (const void* K1, const void* K2)
543 /* Compare function for qsort */
544 {
545     /* Get the real segment pointers */
546     const Segment* S1 = *(const Segment**)K1;
547     const Segment* S2 = *(const Segment**)K2;
548
549     /* Compare the start addresses */
550     if (S1->PC > S2->PC) {
551         return 1;
552     } else if (S1->PC < S2->PC) {
553         return -1;
554     } else {
555         /* Sort segments with equal starts by name */
556         return strcmp (GetString (S1->Name), GetString (S2->Name));
557     }
558 }
559
560
561
562 void PrintSegmentMap (FILE* F)
563 /* Print a segment map to the given file */
564 {
565     unsigned I;
566     Segment* S;
567     Segment** SegPool;
568
569     /* Allocate memory for the segment pool */
570     SegPool = xmalloc (SegCount * sizeof (Segment*));
571
572     /* Collect pointers to the segments */
573     I = 0;
574     S = SegRoot;
575     while (S) {
576
577         /* Check the count for safety */
578         CHECK (I < SegCount);
579
580         /* Remember the pointer */
581         SegPool [I] = S;
582
583         /* Follow the linked list */
584         S = S->List;
585
586         /* Next array index */
587         ++I;
588     }
589     CHECK (I == SegCount);
590
591     /* Sort the array by increasing start addresses */
592     qsort (SegPool, SegCount, sizeof (Segment*), CmpSegStart);
593
594     /* Print a header */
595     fprintf (F, "Name                  Start   End     Size\n"
596                 "--------------------------------------------\n");
597
598     /* Print the segments */
599     for (I = 0; I < SegCount; ++I) {
600
601         /* Get a pointer to the segment */
602         S = SegPool [I];
603
604         /* Print empty segments only if explicitly requested */
605         if (VerboseMap || S->Size > 0) {
606             /* Print the segment data */
607             long End = S->PC + S->Size;
608             if (S->Size > 0) {
609                 /* Point to last element addressed */
610                 --End;
611             }
612             fprintf (F, "%-20s  %06lX  %06lX  %06lX\n",
613                      GetString (S->Name), S->PC, End, S->Size);
614         }
615     }
616
617     /* Free the segment pool */
618     xfree (SegPool);
619 }
620
621
622
623 void CheckSegments (void)
624 /* Walk through the segment list and check if there are segments that were
625  * not written to the output file. Output an error if this is the case.
626  */
627 {
628     Segment* S = SegRoot;
629     while (S) {
630         if (S->Size > 0 && S->Dumped == 0) {
631             Error ("Missing memory area assignment for segment `%s'",
632                    GetString (S->Name));
633         }
634         S = S->List;
635     }
636 }
637
638
639