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