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