1 /*****************************************************************************/
5 /* Segment handling for the ld65 linker */
9 /* (C) 1998-2011, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
62 /*****************************************************************************/
64 /*****************************************************************************/
69 #define HASHTAB_MASK 0x3FU
70 #define HASHTAB_SIZE (HASHTAB_MASK + 1)
71 static Segment* HashTab[HASHTAB_SIZE];
73 /* List of all segments */
74 static Collection SegmentList = STATIC_COLLECTION_INITIALIZER;
78 /*****************************************************************************/
80 /*****************************************************************************/
84 static Segment* NewSegment (unsigned Name, unsigned char AddrSize)
85 /* Create a new segment and initialize it */
90 Segment* S = xmalloc (sizeof (Segment));
92 /* Initialize the fields */
95 S->Sections = EmptyCollection;
103 S->AddrSize = AddrSize;
109 /* Insert the segment into the segment list and assign the segment id */
110 S->Id = CollCount (&SegmentList);
111 CollAppend (&SegmentList, S);
113 /* Insert the segment into the segment hash list */
114 Hash = (S->Name & HASHTAB_MASK);
115 S->Next = HashTab[Hash];
118 /* Return the new entry */
124 Segment* GetSegment (unsigned Name, unsigned char AddrSize, const char* ObjName)
125 /* Search for a segment and return an existing one. If the segment does not
126 * exist, create a new one and return that. ObjName is only used for the error
127 * message and may be NULL if the segment is linker generated.
130 /* Try to locate the segment in the table */
131 Segment* S = SegFind (Name);
133 /* If we don't have that segment already, allocate it using the type of
137 /* Create a new segment */
138 S = NewSegment (Name, AddrSize);
140 /* Check if the existing segment has the requested address size */
141 if (S->AddrSize != AddrSize) {
142 /* Allow an empty object name */
144 ObjName = "[linker generated]";
146 Error ("Module `%s': Type mismatch for segment `%s'", ObjName,
151 /* Return the segment */
157 Section* NewSection (Segment* Seg, unsigned char Align, unsigned char AddrSize)
158 /* Create a new section for the given segment */
163 /* Allocate memory */
164 Section* S = xmalloc (sizeof (Section));
166 /* Initialize the data */
174 S->AddrSize = AddrSize;
176 /* Calculate the alignment bytes needed for the section */
177 V = (0x01UL << S->Align) - 1;
178 S->Fill = (((Seg->Size + V) & ~V) - Seg->Size);
180 /* Adjust the segment size and set the section offset */
181 Seg->Size += S->Fill;
182 S->Offs = Seg->Size; /* Current size is offset */
184 /* Insert the section into the segment */
185 CollAppend (&Seg->Sections, S);
187 /* Return the struct */
193 Section* ReadSection (FILE* F, ObjData* O)
194 /* Read a section from a file */
204 /* Read the segment data */
205 (void) Read32 (F); /* File size of data */
206 Name = MakeGlobalStringId (O, ReadVar (F)); /* Segment name */
207 Size = Read32 (F); /* Size of data */
208 Align = Read8 (F); /* Alignment */
209 Type = Read8 (F); /* Segment type */
210 FragCount = ReadVar (F); /* Number of fragments */
213 /* Print some data */
214 Print (stdout, 2, "Module `%s': Found segment `%s', size = %u, align = %u, type = %u\n",
215 GetObjFileName (O), GetString (Name), Size, Align, Type);
217 /* Get the segment for this section */
218 S = GetSegment (Name, Type, GetObjFileName (O));
220 /* Allocate the section we will return later */
221 Sec = NewSection (S, Align, Type);
223 /* Remember the object file this section was from */
226 /* Set up the minimum segment alignment */
227 if (Sec->Align > S->Align) {
228 /* Section needs larger alignment, use this one */
229 S->Align = Sec->Align;
233 /* Start reading fragments from the file and insert them into the section . */
234 while (FragCount--) {
238 /* Read the fragment type */
239 unsigned char Type = Read8 (F);
241 /* Extract the check mask from the type */
242 unsigned char Bytes = Type & FRAG_BYTEMASK;
243 Type &= FRAG_TYPEMASK;
245 /* Handle the different fragment types */
249 Frag = NewFragment (Type, ReadVar (F), Sec);
250 ReadData (F, Frag->LitBuf, Frag->Size);
255 Frag = NewFragment (Type, Bytes, Sec);
256 Frag->Expr = ReadExpr (F, O);
260 /* Will allocate memory, but we don't care... */
261 Frag = NewFragment (Type, ReadVar (F), Sec);
265 Error ("Unknown fragment type in module `%s', segment `%s': %02X",
266 GetObjFileName (O), GetString (S->Name), Type);
271 /* Read the line infos into the list of the fragment */
272 ReadLineInfoList (F, O, &Frag->LineInfos);
274 /* Remember the module we had this fragment from */
278 /* Return the section */
284 Segment* SegFind (unsigned Name)
285 /* Return the given segment or NULL if not found. */
287 Segment* S = HashTab[Name & HASHTAB_MASK];
289 if (Name == S->Name) {
301 int IsBSSType (Segment* S)
302 /* Check if the given segment is a BSS style segment, that is, it does not
303 * contain non-zero data.
306 /* Loop over all sections */
308 for (I = 0; I < CollCount (&S->Sections); ++I) {
310 /* Get the next section */
311 Section* Sec = CollAtUnchecked (&S->Sections, I);
313 /* Loop over all fragments */
314 Fragment* F = Sec->FragRoot;
316 if (F->Type == FRAG_LITERAL) {
317 unsigned char* Data = F->LitBuf;
318 unsigned long Count = F->Size;
324 } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
325 if (GetExprVal (F->Expr) != 0) {
338 /* Dump the segments and it's contents */
344 for (I = 0; I < CollCount (&SegmentList); ++I) {
345 Segment* Seg = CollAtUnchecked (&SegmentList, I);
346 printf ("Segment: %s (%lu)\n", GetString (Seg->Name), Seg->Size);
347 for (J = 0; J < CollCount (&Seg->Sections); ++J) {
348 Section* S = CollAtUnchecked (&Seg->Sections, J);
350 Fragment* F = S->FragRoot;
351 printf (" Section:\n");
356 printf (" Literal (%u bytes):", F->Size);
365 printf (" %02X", *Data++);
372 printf (" Expression (%u bytes):\n", F->Size);
374 DumpExpr (F->Expr, 0);
378 printf (" Signed expression (%u bytes):\n", F->Size);
380 DumpExpr (F->Expr, 0);
384 printf (" Empty space (%u bytes)\n", F->Size);
388 Internal ("Invalid fragment type: %02X", F->Type);
398 unsigned SegWriteConstExpr (FILE* F, ExprNode* E, int Signed, unsigned Size)
399 /* Write a supposedly constant expression to the target file. Do a range
400 * check and return one of the SEG_EXPR_xxx codes.
403 static const unsigned long U_Hi[4] = {
404 0x000000FFUL, 0x0000FFFFUL, 0x00FFFFFFUL, 0xFFFFFFFFUL
406 static const long S_Hi[4] = {
407 0x0000007FL, 0x00007FFFL, 0x007FFFFFL, 0x7FFFFFFFL
409 static const long S_Lo[4] = {
410 ~0x0000007FL, ~0x00007FFFL, ~0x007FFFFFL, ~0x7FFFFFFFL
414 /* Get the expression value */
415 long Val = GetExprVal (E);
418 CHECK (Size >= 1 && Size <= 4);
420 /* Check for a range error */
422 if (Val > S_Hi[Size-1] || Val < S_Lo[Size-1]) {
424 return SEG_EXPR_RANGE_ERROR;
427 if (((unsigned long)Val) > U_Hi[Size-1]) {
429 return SEG_EXPR_RANGE_ERROR;
433 /* Write the value to the file */
434 WriteVal (F, Val, Size);
442 void SegWrite (const char* TgtName, FILE* Tgt, Segment* S, SegWriteFunc F, void* Data)
443 /* Write the data from the given segment to a file. For expressions, F is
444 * called (see description of SegWriteFunc above).
449 unsigned long Offs = 0;
452 /* Remember the output file and offset for the segment */
453 S->OutputName = TgtName;
454 S->OutputOffs = (unsigned long) ftell (Tgt);
456 /* Loop over all sections in this segment */
457 for (I = 0; I < CollCount (&S->Sections); ++I) {
458 Section* Sec = CollAtUnchecked (&S->Sections, I);
461 /* Output were this section is from */
462 Print (stdout, 2, " Section from \"%s\"\n", GetObjFileName (Sec->Obj));
464 /* If we have fill bytes, write them now */
465 Print (stdout, 2, " Filling 0x%lx bytes with 0x%02x\n",
466 Sec->Fill, S->FillVal);
467 WriteMult (Tgt, S->FillVal, Sec->Fill);
470 /* Loop over all fragments in this section */
471 Frag = Sec->FragRoot;
474 /* Do fragment alignment checks */
478 /* Output fragment data */
479 switch (Frag->Type) {
482 WriteData (Tgt, Frag->LitBuf, Frag->Size);
487 Sign = (Frag->Type == FRAG_SEXPR);
488 /* Call the users function and evaluate the result */
489 switch (F (Frag->Expr, Sign, Frag->Size, Offs, Data)) {
494 case SEG_EXPR_RANGE_ERROR:
495 Error ("Range error in module `%s', line %lu",
496 GetFragmentSourceName (Frag),
497 GetFragmentSourceLine (Frag));
500 case SEG_EXPR_TOO_COMPLEX:
501 Error ("Expression too complex in module `%s', line %lu",
502 GetFragmentSourceName (Frag),
503 GetFragmentSourceLine (Frag));
506 case SEG_EXPR_INVALID:
507 Error ("Invalid expression in module `%s', line %lu",
508 GetFragmentSourceName (Frag),
509 GetFragmentSourceLine (Frag));
513 Internal ("Invalid return code from SegWriteFunc");
518 WriteMult (Tgt, S->FillVal, Frag->Size);
522 Internal ("Invalid fragment type: %02X", Frag->Type);
525 /* Update the offset */
526 Print (stdout, 2, " Fragment with 0x%x bytes\n",
538 unsigned SegmentCount (void)
539 /* Return the total number of segments */
541 return CollCount (&SegmentList);
546 static int CmpSegStart (const void* K1, const void* K2)
547 /* Compare function for qsort */
549 /* Get the real segment pointers */
550 const Segment* S1 = *(const Segment**)K1;
551 const Segment* S2 = *(const Segment**)K2;
553 /* Compare the start addresses */
554 if (S1->PC > S2->PC) {
556 } else if (S1->PC < S2->PC) {
559 /* Sort segments with equal starts by name */
560 return strcmp (GetString (S1->Name), GetString (S2->Name));
566 void PrintSegmentMap (FILE* F)
567 /* Print a segment map to the given file */
570 /* Allocate memory for the segment pool */
571 Segment** SegPool = xmalloc (CollCount (&SegmentList) * sizeof (Segment*));
573 /* Copy the segment pointers */
575 for (I = 0; I < CollCount (&SegmentList); ++I) {
576 SegPool[I] = CollAtUnchecked (&SegmentList, I);
579 /* Sort the array by increasing start addresses */
580 qsort (SegPool, CollCount (&SegmentList), sizeof (Segment*), CmpSegStart);
583 fprintf (F, "Name Start End Size\n"
584 "--------------------------------------------\n");
586 /* Print the segments */
587 for (I = 0; I < CollCount (&SegmentList); ++I) {
589 /* Get a pointer to the segment */
590 Segment* S = SegPool[I];
592 /* Print empty segments only if explicitly requested */
593 if (VerboseMap || S->Size > 0) {
594 /* Print the segment data */
595 long End = S->PC + S->Size;
597 /* Point to last element addressed */
600 fprintf (F, "%-20s %06lX %06lX %06lX\n",
601 GetString (S->Name), S->PC, End, S->Size);
605 /* Free the segment pool */
611 void PrintDbgSegments (FILE* F)
612 /* Output the segments to the debug file */
614 /* Walk over all segments */
616 for (I = 0; I < CollCount (&SegmentList); ++I) {
618 /* Get the next segment */
619 const Segment* S = CollAtUnchecked (&SegmentList, I);
621 /* Print the segment data */
623 "seg\tid=%u,name=\"%s\",start=0x%06lX,size=0x%04lX,addrsize=%s,type=%s",
624 S->Id, GetString (S->Name), S->PC, S->Size,
625 AddrSizeToStr (S->AddrSize),
626 S->ReadOnly? "ro" : "rw");
628 fprintf (F, ",oname=\"%s\",ooffs=%lu",
629 S->OutputName, S->OutputOffs);
637 void CheckSegments (void)
638 /* Walk through the segment list and check if there are segments that were
639 * not written to the output file. Output an error if this is the case.
643 for (I = 0; I < CollCount (&SegmentList); ++I) {
645 /* Get the next segment */
646 const Segment* S = CollAtUnchecked (&SegmentList, I);
649 if (S->Size > 0 && S->Dumped == 0) {
650 Error ("Missing memory area assignment for segment `%s'",
651 GetString (S->Name));