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