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