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