]> git.sur5r.net Git - cc65/blobdiff - src/ld65/segments.c
Added support for arbitrary alignments.
[cc65] / src / ld65 / segments.c
index 5397fbcefd9e53506c7a39abbf128f6057f7efce..d3fe119c9a21ccd9068bffe2fcbfd9da0696ffa6 100644 (file)
@@ -37,6 +37,7 @@
 #include <string.h>
 
 /* common */
+#include "alignment.h"
 #include "check.h"
 #include "coll.h"
 #include "exprdefs.h"
@@ -92,14 +93,12 @@ static Segment* NewSegment (unsigned Name, unsigned char AddrSize)
     /* Initialize the fields */
     S->Name        = Name;
     S->Next       = 0;
-    S->SecRoot    = 0;
-    S->SecLast    = 0;
+    S->Sections    = EmptyCollection;
     S->PC         = 0;
     S->Size               = 0;
-    S->AlignObj           = 0;
     S->OutputName  = 0;
     S->OutputOffs  = 0;
-    S->Align       = 0;
+    S->Alignment   = 1;
     S->FillVal    = 0;
     S->AddrSize    = AddrSize;
     S->ReadOnly    = 0;
@@ -155,12 +154,9 @@ Segment* GetSegment (unsigned Name, unsigned char AddrSize, const char* ObjName)
 
 
 
-Section* NewSection (Segment* Seg, unsigned char Align, unsigned char AddrSize)
+Section* NewSection (Segment* Seg, unsigned long Alignment, unsigned char AddrSize)
 /* Create a new section for the given segment */
 {
-    unsigned long V;
-
-
     /* Allocate memory */
     Section* S = xmalloc (sizeof (Section));
 
@@ -171,25 +167,18 @@ Section* NewSection (Segment* Seg, unsigned char Align, unsigned char AddrSize)
     S->FragRoot = 0;
     S->FragLast = 0;
     S->Size    = 0;
-    S->Align    = Align;
+    S->Alignment= Alignment;
     S->AddrSize = AddrSize;
 
     /* Calculate the alignment bytes needed for the section */
-    V = (0x01UL << S->Align) - 1;
-    S->Fill = (((Seg->Size + V) & ~V) - Seg->Size);
+    S->Fill = AlignCount (Seg->Size, S->Alignment);
 
     /* Adjust the segment size and set the section offset */
     Seg->Size  += S->Fill;
     S->Offs    = Seg->Size;    /* Current size is offset */
 
     /* Insert the section into the segment */
-    if (Seg->SecRoot == 0) {
-       /* First section in this segment */
-               Seg->SecRoot = S;
-    } else {
-       Seg->SecLast->Next = S;
-    }
-    Seg->SecLast = S;
+    CollAppend (&Seg->Sections, S);
 
     /* Return the struct */
     return S;
@@ -202,7 +191,7 @@ Section* ReadSection (FILE* F, ObjData* O)
 {
     unsigned      Name;
     unsigned      Size;
-    unsigned char Align;
+    unsigned long Alignment;
     unsigned char Type;
     unsigned      FragCount;
     Segment*      S;
@@ -211,30 +200,40 @@ Section* ReadSection (FILE* F, ObjData* O)
     /* Read the segment data */
     (void) Read32 (F);            /* File size of data */
     Name      = MakeGlobalStringId (O, ReadVar (F));    /* Segment name */
-    Size      = Read32 (F);       /* Size of data */
-    Align     = Read8 (F);        /* Alignment */
+    Size      = ReadVar (F);      /* Size of data */
+    Alignment = ReadVar (F);      /* Alignment */
     Type      = Read8 (F);        /* Segment type */
     FragCount = ReadVar (F);      /* Number of fragments */
 
 
     /* Print some data */
-    Print (stdout, 2, "Module `%s': Found segment `%s', size = %u, align = %u, type = %u\n",
-          GetObjFileName (O), GetString (Name), Size, Align, Type);
+    Print (stdout, 2,
+           "Module `%s': Found segment `%s', size = %u, alignment = %lu, type = %u\n",
+          GetObjFileName (O), GetString (Name), Size, Alignment, Type);
 
     /* Get the segment for this section */
     S = GetSegment (Name, Type, GetObjFileName (O));
 
     /* Allocate the section we will return later */
-    Sec = NewSection (S, Align, Type);
+    Sec = NewSection (S, Alignment, Type);
 
     /* Remember the object file this section was from */
     Sec->Obj = O;
 
-    /* Set up the minimum segment alignment */
-    if (Sec->Align > S->Align) {
-       /* Section needs larger alignment, use this one */
-       S->Align    = Sec->Align;
-       S->AlignObj = O;
+    /* Set up the combined segment alignment */
+    if (Sec->Alignment > 1) {
+        Alignment = LeastCommonMultiple (S->Alignment, Sec->Alignment);
+        if (Alignment > MAX_ALIGNMENT) {
+            Error ("Combined alignment for segment `%s' is %lu which exceeds "
+                   "%lu. Last module requiring alignment was `%s'.",
+                   GetString (Name), Alignment, MAX_ALIGNMENT,
+                   GetObjFileName (O));
+        } else if (Alignment >= LARGE_ALIGNMENT) {
+            Warning ("Combined alignment for segment `%s' is suspiciously "
+                     "large (%lu). Last module requiring alignment was `%s'.",
+                     GetString (Name), Alignment, GetObjFileName (O));
+        }
+        S->Alignment = Alignment;
     }
 
     /* Start reading fragments from the file and insert them into the section . */
@@ -265,7 +264,7 @@ Section* ReadSection (FILE* F, ObjData* O)
 
            case FRAG_FILL:
                /* Will allocate memory, but we don't care... */
-               Frag = NewFragment (Type, ReadVar (F), Sec);
+               Frag = NewFragment (Type, ReadVar (F), Sec);
                break;
 
            default:
@@ -278,9 +277,6 @@ Section* ReadSection (FILE* F, ObjData* O)
         /* Read the line infos into the list of the fragment */
         ReadLineInfoList (F, O, &Frag->LineInfos);
 
-        /* Resolve the back pointers */
-        FragResolveLineInfos (Frag);
-
        /* Remember the module we had this fragment from */
        Frag->Obj = O;
     }
@@ -314,8 +310,12 @@ int IsBSSType (Segment* S)
  */
 {
     /* Loop over all sections */
-    Section* Sec = S->SecRoot;
-    while (Sec) {
+    unsigned I;
+    for (I = 0; I < CollCount (&S->Sections); ++I) {
+
+        /* Get the next section */
+        Section* Sec = CollAtUnchecked (&S->Sections, I);
+
        /* Loop over all fragments */
        Fragment* F = Sec->FragRoot;
        while (F) {
@@ -334,7 +334,6 @@ int IsBSSType (Segment* S)
            }
            F = F->Next;
        }
-       Sec = Sec->Next;
     }
     return 1;
 }
@@ -344,15 +343,15 @@ int IsBSSType (Segment* S)
 void SegDump (void)
 /* Dump the segments and it's contents */
 {
-    unsigned I;
+    unsigned I, J;
     unsigned long Count;
     unsigned char* Data;
 
     for (I = 0; I < CollCount (&SegmentList); ++I) {
-        const Segment* Seg = CollConstAt (&SegmentList, I);
-       Section* S = Seg->SecRoot;
+        Segment* Seg = CollAtUnchecked (&SegmentList, I);
                printf ("Segment: %s (%lu)\n", GetString (Seg->Name), Seg->Size);
-       while (S) {
+        for (J = 0; J < CollCount (&Seg->Sections); ++J) {
+            Section* S = CollAtUnchecked (&Seg->Sections, J);
             unsigned J;
            Fragment* F = S->FragRoot;
            printf ("  Section:\n");
@@ -363,7 +362,7 @@ void SegDump (void)
                        printf ("    Literal (%u bytes):", F->Size);
                        Count = F->Size;
                        Data  = F->LitBuf;
-                       J = 100;
+                       J = 100;
                        while (Count--) {
                            if (J > 75) {
                                printf ("\n   ");
@@ -396,7 +395,6 @@ void SegDump (void)
                }
                F = F->Next;
            }
-           S = S->Next;
        }
     }
 }
@@ -408,14 +406,14 @@ unsigned SegWriteConstExpr (FILE* F, ExprNode* E, int Signed, unsigned Size)
  * check and return one of the SEG_EXPR_xxx codes.
  */
 {
-    static const unsigned long U_HighRange [4] = {
-               0x000000FF, 0x0000FFFF, 0x00FFFFFF, 0xFFFFFFFF
+    static const unsigned long U_Hi[4] = {
+               0x000000FFUL, 0x0000FFFFUL, 0x00FFFFFFUL, 0xFFFFFFFFUL
     };
-    static const long S_HighRange [4] = {
-               0x0000007F, 0x00007FFF, 0x007FFFFF, 0x7FFFFFFF
+    static const long S_Hi[4] = {
+               0x0000007FL, 0x00007FFFL, 0x007FFFFFL, 0x7FFFFFFFL
     };
-    static const long S_LowRange [4] = {
-               0xFFFFFF80, 0xFFFF8000, 0xFF800000, 0x80000000
+    static const long S_Lo[4] = {
+               ~0x0000007FL, ~0x00007FFFL, ~0x007FFFFFL, ~0x7FFFFFFFL
     };
 
 
@@ -427,12 +425,12 @@ unsigned SegWriteConstExpr (FILE* F, ExprNode* E, int Signed, unsigned Size)
 
     /* Check for a range error */
     if (Signed) {
-       if (Val > S_HighRange [Size-1] || Val < S_LowRange [Size-1]) {
+       if (Val > S_Hi[Size-1] || Val < S_Lo[Size-1]) {
            /* Range error */
            return SEG_EXPR_RANGE_ERROR;
        }
     } else {
-       if (((unsigned long)Val) > U_HighRange [Size-1]) {
+       if (((unsigned long)Val) > U_Hi[Size-1]) {
            /* Range error */
            return SEG_EXPR_RANGE_ERROR;
        }
@@ -452,7 +450,7 @@ void SegWrite (const char* TgtName, FILE* Tgt, Segment* S, SegWriteFunc F, void*
  * called (see description of SegWriteFunc above).
  */
 {
-    Section*      Sec;
+    unsigned      I;
     int           Sign;
     unsigned long Offs = 0;
 
@@ -462,8 +460,8 @@ void SegWrite (const char* TgtName, FILE* Tgt, Segment* S, SegWriteFunc F, void*
     S->OutputOffs = (unsigned long) ftell (Tgt);
 
     /* Loop over all sections in this segment */
-    Sec = S->SecRoot;
-    while (Sec) {
+    for (I = 0; I < CollCount (&S->Sections); ++I) {
+        Section* Sec = CollAtUnchecked (&S->Sections, I);
        Fragment* Frag;
 
         /* Output were this section is from */
@@ -479,10 +477,6 @@ void SegWrite (const char* TgtName, FILE* Tgt, Segment* S, SegWriteFunc F, void*
        Frag = Sec->FragRoot;
        while (Frag) {
 
-            /* Do fragment alignment checks */
-
-
-
             /* Output fragment data */
            switch (Frag->Type) {
 
@@ -500,19 +494,19 @@ void SegWrite (const char* TgtName, FILE* Tgt, Segment* S, SegWriteFunc F, void*
                            break;
 
                        case SEG_EXPR_RANGE_ERROR:
-                           Error ("Range error in module `%s', line %lu",
+                           Error ("Range error in module `%s', line %u",
                                   GetFragmentSourceName (Frag),
                                   GetFragmentSourceLine (Frag));
                            break;
 
                        case SEG_EXPR_TOO_COMPLEX:
-                           Error ("Expression too complex in module `%s', line %lu",
+                           Error ("Expression too complex in module `%s', line %u",
                                   GetFragmentSourceName (Frag),
                                   GetFragmentSourceLine (Frag));
                            break;
 
-                       case SEG_EXPR_INVALID:
-                           Error ("Invalid expression in module `%s', line %lu",
+                       case SEG_EXPR_INVALID:
+                           Error ("Invalid expression in module `%s', line %u",
                                   GetFragmentSourceName (Frag),
                                   GetFragmentSourceLine (Frag));
                            break;
@@ -538,9 +532,6 @@ void SegWrite (const char* TgtName, FILE* Tgt, Segment* S, SegWriteFunc F, void*
            /* Next fragment */
            Frag = Frag->Next;
        }
-
-       /* Next section */
-       Sec = Sec->Next;
     }
 }
 
@@ -563,7 +554,7 @@ static int CmpSegStart (const void* K1, const void* K2)
 
     /* Compare the start addresses */
     if (S1->PC > S2->PC) {
-       return 1;
+       return 1;
     } else if (S1->PC < S2->PC) {
        return -1;
     } else {
@@ -591,8 +582,8 @@ void PrintSegmentMap (FILE* F)
     qsort (SegPool, CollCount (&SegmentList), sizeof (Segment*), CmpSegStart);
 
     /* Print a header */
-    fprintf (F, "Name                  Start   End     Size\n"
-               "--------------------------------------------\n");
+    fprintf (F, "Name                   Start     End    Size  Align\n"
+               "----------------------------------------------------\n");
 
     /* Print the segments */
     for (I = 0; I < CollCount (&SegmentList); ++I) {
@@ -608,8 +599,8 @@ void PrintSegmentMap (FILE* F)
                /* Point to last element addressed */
                --End;
            }
-           fprintf (F, "%-20s  %06lX  %06lX  %06lX\n",
-                            GetString (S->Name), S->PC, End, S->Size);
+           fprintf (F, "%-20s  %06lX  %06lX  %06lX  %05lX\n",
+                            GetString (S->Name), S->PC, End, S->Size, S->Alignment);
        }
     }