From 6ead4abf244abfab4bd52eff55da5cefe4d4a98f Mon Sep 17 00:00:00 2001 From: uz Date: Wed, 28 Dec 2011 16:28:19 +0000 Subject: [PATCH] Added support for arbitrary alignments. git-svn-id: svn://svn.cc65.org/cc65/trunk@5341 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/ld65/bin.c | 24 ++++++++++--------- src/ld65/config.c | 50 ++++++++++++++++++++++------------------ src/ld65/config.h | 8 +++---- src/ld65/mapfile.c | 7 ++++-- src/ld65/o65.c | 8 +++---- src/ld65/segments.c | 56 +++++++++++++++++++++++---------------------- src/ld65/segments.h | 9 ++++---- src/ld65/tgtcfg.c | 1 + 8 files changed, 88 insertions(+), 75 deletions(-) diff --git a/src/ld65/bin.c b/src/ld65/bin.c index 40f72ad81..402cc0443 100644 --- a/src/ld65/bin.c +++ b/src/ld65/bin.c @@ -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 /* 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; diff --git a/src/ld65/config.c b/src/ld65/config.c index 96baf392c..ebafd0bd3 100644 --- a/src/ld65/config.c +++ b/src/ld65/config.c @@ -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); } } diff --git a/src/ld65/config.h b/src/ld65/config.h index 9394f86ca..901796196 100644 --- a/src/ld65/config.h +++ b/src/ld65/config.h @@ -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 */ diff --git a/src/ld65/mapfile.c b/src/ld65/mapfile.c index ff7ee0f84..6dc4ffb60 100644 --- a/src/ld65/mapfile.c +++ b/src/ld65/mapfile.c @@ -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); } } } diff --git a/src/ld65/o65.c b/src/ld65/o65.c index 13bc45f46..1c8eb6cc1 100644 --- a/src/ld65/o65.c +++ b/src/ld65/o65.c @@ -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); } } diff --git a/src/ld65/segments.c b/src/ld65/segments.c index d643c3f46..d3fe119c9 100644 --- a/src/ld65/segments.c +++ b/src/ld65/segments.c @@ -37,6 +37,7 @@ #include /* 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); } } diff --git a/src/ld65/segments.h b/src/ld65/segments.h index 40b06a961..86caa2094 100644 --- a/src/ld65/segments.h +++ b/src/ld65/segments.h @@ -40,7 +40,7 @@ #include -/* 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); diff --git a/src/ld65/tgtcfg.c b/src/ld65/tgtcfg.c index 38d81141c..77b5b2316 100644 --- a/src/ld65/tgtcfg.c +++ b/src/ld65/tgtcfg.c @@ -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 }, -- 2.39.5