]> git.sur5r.net Git - cc65/commitdiff
Added support for arbitrary alignments.
authoruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Wed, 28 Dec 2011 16:28:19 +0000 (16:28 +0000)
committeruz <uz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Wed, 28 Dec 2011 16:28:19 +0000 (16:28 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@5341 b7a2c559-68d2-44c3-8de9-860c34a00d81

src/ld65/bin.c
src/ld65/config.c
src/ld65/config.h
src/ld65/mapfile.c
src/ld65/o65.c
src/ld65/segments.c
src/ld65/segments.h
src/ld65/tgtcfg.c

index 40f72ad81fecfccc31ffb44d987294b02f53f3e2..402cc04438d94f51933e1919fcddf8510f873156 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1999-2010, Ullrich von Bassewitz                                      */
+/* (C) 1999-2011, Ullrich von Bassewitz                                      */
 /*                Roemerstrasse 52                                           */
 /*                D-70794 Filderstadt                                        */
 /* EMail:         uz@cc65.org                                                */
@@ -38,6 +38,7 @@
 #include <errno.h>
 
 /* common */
+#include "alignment.h"
 #include "print.h"
 #include "xmalloc.h"
 
@@ -161,13 +162,16 @@ static void BinWriteMem (BinDesc* D, MemoryArea* M)
         PrintNumVal  ("Address", Addr);
         PrintNumVal  ("FileOffs", (unsigned long) ftell (D->F));
 
-       /* Check if we would need an alignment */
-       if (S->Seg->Align > S->Align) {
-           /* Segment itself requires larger alignment than configured
+               /* Check if the alignment for the segment from the linker config is
+         * a multiple for that of the segment.
+         */
+        if ((S->RunAlignment % S->Seg->Alignment) != 0) {
+                   /* Segment requires another alignment than configured
             * in the linker.
             */
-           Warning ("Segment `%s' in module `%s' requires larger alignment",
-                    GetString (S->Name), GetObjFileName (S->Seg->AlignObj));
+           Warning ("Segment `%s' is not aligned properly. Resulting "
+                     "executable may not be functional.",
+                    GetString (S->Name));              
        }
 
         /* If this is the run memory area, we must apply run alignment. If
@@ -181,8 +185,7 @@ static void BinWriteMem (BinDesc* D, MemoryArea* M)
             /* Handle ALIGN and OFFSET/START */
             if (S->Flags & SF_ALIGN) {
                 /* Align the address */
-                unsigned long Val = (0x01UL << S->Align) - 1;
-                unsigned long NewAddr = (Addr + Val) & ~Val;
+                unsigned long NewAddr = AlignAddr (Addr, S->RunAlignment);
                 if (DoWrite || (M->Flags & MF_FILL) != 0) {
                     WriteMult (D->F, M->FillVal, NewAddr - Addr);
                     PrintNumVal ("SF_ALIGN", NewAddr - Addr);
@@ -206,10 +209,9 @@ static void BinWriteMem (BinDesc* D, MemoryArea* M)
             /* Handle ALIGN_LOAD */
             if (S->Flags & SF_ALIGN_LOAD) {
                 /* Align the address */
-                unsigned long Val = (0x01UL << S->AlignLoad) - 1;
-                unsigned long NewAddr = (Addr + Val) & ~Val;
+                unsigned long NewAddr = AlignAddr (Addr, S->LoadAlignment);
                 if (DoWrite || (M->Flags & MF_FILL) != 0) {
-                    WriteMult (D->F, M->FillVal, NewAddr-Addr);
+                    WriteMult (D->F, M->FillVal, NewAddr - Addr);
                     PrintNumVal ("SF_ALIGN_LOAD", NewAddr - Addr);
                 }
                 Addr = NewAddr;
index 96baf392c2a18268c99adb7ee6c10635e77d65f3..ebafd0bd3b0996fb227881bf76798f3b43df1d03 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2010, Ullrich von Bassewitz                                      */
+/* (C) 1998-2011, Ullrich von Bassewitz                                      */
 /*                Roemerstrasse 52                                           */
 /*                D-70794 Filderstadt                                        */
 /* EMail:         uz@cc65.org                                                */
@@ -47,6 +47,7 @@
 #include "xsprintf.h"
 
 /* ld65 */
+#include "alignment.h"
 #include "bin.h"
 #include "binfmt.h"
 #include "cfgexpr.h"
@@ -340,12 +341,13 @@ static SegDesc* NewSegDesc (unsigned Name)
     S = xmalloc (sizeof (SegDesc));
 
     /* Initialize the fields */
-    S->Name    = Name;
-    S->LI      = GenLineInfo (&CfgErrorPos);
-    S->Seg     = 0;
-    S->Attr    = 0;
-    S->Flags   = 0;
-    S->Align   = 0;
+    S->Name          = Name;
+    S->LI            = GenLineInfo (&CfgErrorPos);
+    S->Seg           = 0;
+    S->Attr          = 0;
+    S->Flags         = 0;
+    S->RunAlignment  = 1;
+    S->LoadAlignment = 1;
 
     /* Insert the struct into the list ... */
     CollAppend (&SegDescList, S);
@@ -637,7 +639,6 @@ static void ParseSegments (void)
     };
 
     unsigned Count;
-    long     Val;
 
     /* The MEMORY section must preceed the SEGMENTS section */
     if ((SectionsEncountered & SE_MEMORY) == 0) {
@@ -672,21 +673,13 @@ static void ParseSegments (void)
 
                case CFGTOK_ALIGN:
                    FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
-                   Val = CfgCheckedConstExpr (1, 0x10000);
-                   S->Align = BitFind (Val);
-                   if ((0x01L << S->Align) != Val) {
-                       CfgError (&CfgErrorPos, "Alignment must be a power of 2");
-                   }
+                   S->RunAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
                    S->Flags |= SF_ALIGN;
                    break;
 
                 case CFGTOK_ALIGN_LOAD:
                    FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
-                   Val = CfgCheckedConstExpr (1, 0x10000);
-                           S->AlignLoad = BitFind (Val);
-                   if ((0x01L << S->AlignLoad) != Val) {
-                       CfgError (&CfgErrorPos, "Alignment must be a power of 2");
-                   }
+                   S->LoadAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
                    S->Flags |= SF_ALIGN_LOAD;
                    break;
 
@@ -1818,8 +1811,22 @@ unsigned CfgProcess (void)
                  */
                 if (S->Flags & SF_ALIGN) {
                     /* Align the address */
-                    unsigned long Val = (0x01UL << S->Align) - 1;
-                    Addr = (Addr + Val) & ~Val;
+                    unsigned long NewAddr = AlignAddr (Addr, S->RunAlignment);
+
+                    /* If the first segment placed in the memory area needs
+                     * fill bytes for the alignment, emit a warning, since
+                     * this is somewhat suspicious.
+                     */
+                    if (M->FillLevel == 0 && NewAddr > Addr) {
+                        CfgWarning (GetSourcePos (S->LI),
+                                    "First segment in memory area `%s' does "
+                                    "already need fill bytes for alignment",
+                                    GetString (M->Name));
+                    }
+
+                    /* Use the aligned address */
+                    Addr = NewAddr;
+
                 } else if (S->Flags & (SF_OFFSET | SF_START)) {
                     /* Give the segment a fixed starting address */
                     unsigned long NewAddr = S->Addr;
@@ -1862,8 +1869,7 @@ unsigned CfgProcess (void)
                  */
                 if (S->Flags & SF_ALIGN_LOAD) {
                     /* Align the address */
-                    unsigned long Val = (0x01UL << S->AlignLoad) - 1;
-                    Addr = (Addr + Val) & ~Val;
+                    Addr = AlignAddr (Addr, S->LoadAlignment);
                 }
 
             }
index 9394f86ca2012b4a004905981b6ec317b9ce3a0e..901796196968c46c82b77724aee8ed155de70bea 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2010, Ullrich von Bassewitz                                      */
+/* (C) 1998-2011, Ullrich von Bassewitz                                      */
 /*                Roemerstrasse 52                                           */
 /*                D-70794 Filderstadt                                        */
 /* EMail:         uz@cc65.org                                                */
@@ -77,8 +77,8 @@ struct SegDesc {
     struct MemoryArea*  Load;           /* Load memory section */
     struct MemoryArea*  Run;            /* Run memory section */
     unsigned long              Addr;           /* Start address or offset into segment */
-    unsigned char      Align;          /* Run area alignment if given */
-    unsigned char       AlignLoad;      /* Load area alignment if given */
+    unsigned long       RunAlignment;   /* Run area alignment if given */
+    unsigned long       LoadAlignment;  /* Load area alignment if given */
 };
 
 /* Segment flags */
@@ -116,7 +116,7 @@ unsigned CfgProcess (void);
 
 void CfgWriteTarget (void);
 /* Write the target file(s) */
-                             
+
 
 
 /* End of config.h */
index ff7ee0f84116cb36dcd89db437aa3424e7059e95..6dc4ffb60cb1663c015a9df7237d8248d899e1f8 100644 (file)
@@ -93,8 +93,11 @@ void CreateMapFile (int ShortMap)
              * requested
              */
             if (VerboseMap || S->Size > 0) {
-                fprintf (F, "    %-17s Offs = %06lX   Size = %06lX\n",
-                         GetString (S->Seg->Name), S->Offs, S->Size);
+                fprintf (F, 
+                         "    %-17s Offs=%06lX  Size=%06lX  "
+                         "Align=%05lX  Fill=%04lX\n",
+                         GetString (S->Seg->Name), S->Offs, S->Size,
+                         S->Alignment, S->Fill);
             }
         }
     }
index 13bc45f4649acf2ccbb8599a76e5074db4e786c5..1c8eb6cc1db510516198e8ef24c96c563a6ad77a 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1999-2010, Ullrich von Bassewitz                                      */
+/* (C) 1999-2011, Ullrich von Bassewitz                                      */
 /*                Roemerstrasse 52                                           */
 /*                D-70794 Filderstadt                                        */
 /* EMail:         uz@cc65.org                                                */
@@ -1109,19 +1109,19 @@ void O65SetLargeModel (O65Desc* D)
 
 
 
-void O65SetAlignment (O65Desc* D, unsigned Align)
+void O65SetAlignment (O65Desc* D, unsigned Alignment)
 /* Set the executable alignment */
 {
     /* Remove all alignment bits from the mode word */
     D->Header.Mode &= ~MF_ALIGN_MASK;
 
     /* Set the alignment bits */
-    switch (Align) {
+    switch (Alignment) {
        case 1:   D->Header.Mode |= MF_ALIGN_1;   break;
        case 2:   D->Header.Mode |= MF_ALIGN_2;   break;
        case 4:   D->Header.Mode |= MF_ALIGN_4;   break;
         case 256: D->Header.Mode |= MF_ALIGN_256; break;
-        default:  Error ("Invalid alignment for O65 format: %u", Align);
+        default:  Error ("Invalid alignment for O65 format: %u", Alignment);
     }
 }
 
index d643c3f464a7522ca400c1df01cb94c92bcc1118..d3fe119c9a21ccd9068bffe2fcbfd9da0696ffa6 100644 (file)
@@ -37,6 +37,7 @@
 #include <string.h>
 
 /* common */
+#include "alignment.h"
 #include "check.h"
 #include "coll.h"
 #include "exprdefs.h"
@@ -95,10 +96,9 @@ static Segment* NewSegment (unsigned Name, unsigned char AddrSize)
     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;
@@ -154,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));
 
@@ -170,12 +167,11 @@ 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;
@@ -195,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;
@@ -205,29 +201,39 @@ Section* ReadSection (FILE* F, ObjData* O)
     (void) Read32 (F);            /* File size of data */
     Name      = MakeGlobalStringId (O, ReadVar (F));    /* Segment name */
     Size      = ReadVar (F);      /* Size of data */
-    Align     = Read8 (F);        /* Alignment */
+    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 . */
@@ -471,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) {
 
@@ -580,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) {
@@ -597,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);
        }
     }
 
index 40b06a9619d95fe596d2938ccc9f96a4cde33f42..86caa209489b2400d23fff8bb19636b0b5952eb1 100644 (file)
@@ -40,7 +40,7 @@
 
 #include <stdio.h>
 
-/* common */  
+/* common */
 #include "coll.h"
 #include "exprdefs.h"
 
@@ -61,10 +61,9 @@ struct Segment {
     Collection          Sections;       /* Sections in this segment */
     unsigned long      PC;             /* PC were this segment is located */
     unsigned long      Size;           /* Size of data so far */
-    struct ObjData*    AlignObj;       /* Module that requested the alignment */
     const char*         OutputName;     /* Name of output file or NULL */
     unsigned long       OutputOffs;     /* Offset in output file */
-    unsigned char      Align;          /* Alignment needed */
+    unsigned long       Alignment;      /* Alignment needed */
     unsigned char      FillVal;        /* Value to use for fill bytes */
     unsigned char      AddrSize;       /* Address size of segment */
     unsigned char       ReadOnly;       /* True for readonly segments (config) */
@@ -86,7 +85,7 @@ struct Section {
     unsigned long      Offs;           /* Offset into the segment */
     unsigned long      Size;           /* Size of the section */
     unsigned long       Fill;           /* Fill bytes for alignment */
-    unsigned char      Align;          /* Alignment */
+    unsigned long       Alignment;      /* Alignment */
     unsigned char      AddrSize;       /* Address size of segment */
 };
 
@@ -120,7 +119,7 @@ Segment* GetSegment (unsigned Name, unsigned char AddrSize, const char* ObjName)
  * message and may be NULL if the segment is linker generated.
  */
 
-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 */
 
 Section* ReadSection (FILE* F, struct ObjData* O);
index 38d81141c5481a358ededcfab0067f79956bf49e..77b5b23167714cfbf6a2978e7bf2e892de4a8ff9 100644 (file)
@@ -95,6 +95,7 @@ const TargetDesc Targets[TGT_COUNT] = {
     {   BINFMT_BINARY, CfgApple2       },
     {   BINFMT_BINARY,  CfgApple2Enh    },
     {   BINFMT_BINARY,  CfgGeos         },
+    {   BINFMT_BINARY,  CfgGeos         },
     {   BINFMT_O65,     CfgLunix        },
     {          BINFMT_BINARY,  CfgAtmos        },
     {          BINFMT_BINARY,  CfgNES          },