/* */
/* */
/* */
-/* (C) 1999-2010, Ullrich von Bassewitz */
+/* (C) 1999-2011, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
#include <errno.h>
/* common */
+#include "alignment.h"
#include "print.h"
#include "xmalloc.h"
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
/* 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);
/* 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;
/* */
/* */
/* */
-/* (C) 1998-2010, Ullrich von Bassewitz */
+/* (C) 1998-2011, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
#include "xsprintf.h"
/* ld65 */
+#include "alignment.h"
#include "bin.h"
#include "binfmt.h"
#include "cfgexpr.h"
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);
};
unsigned Count;
- long Val;
/* The MEMORY section must preceed the SEGMENTS section */
if ((SectionsEncountered & SE_MEMORY) == 0) {
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;
*/
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;
*/
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);
}
}
/* */
/* */
/* */
-/* (C) 1998-2010, Ullrich von Bassewitz */
+/* (C) 1998-2011, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
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 */
void CfgWriteTarget (void);
/* Write the target file(s) */
-
+
/* End of config.h */
* 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);
}
}
}
/* */
/* */
/* */
-/* (C) 1999-2010, Ullrich von Bassewitz */
+/* (C) 1999-2011, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
-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);
}
}
#include <string.h>
/* common */
+#include "alignment.h"
#include "check.h"
#include "coll.h"
#include "exprdefs.h"
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;
-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));
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;
{
unsigned Name;
unsigned Size;
- unsigned char Align;
+ unsigned long Alignment;
unsigned char Type;
unsigned FragCount;
Segment* S;
(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 . */
Frag = Sec->FragRoot;
while (Frag) {
- /* Do fragment alignment checks */
-
-
-
/* Output fragment data */
switch (Frag->Type) {
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) {
/* 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);
}
}
#include <stdio.h>
-/* common */
+/* common */
#include "coll.h"
#include "exprdefs.h"
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) */
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 */
};
* 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);
{ BINFMT_BINARY, CfgApple2 },
{ BINFMT_BINARY, CfgApple2Enh },
{ BINFMT_BINARY, CfgGeos },
+ { BINFMT_BINARY, CfgGeos },
{ BINFMT_O65, CfgLunix },
{ BINFMT_BINARY, CfgAtmos },
{ BINFMT_BINARY, CfgNES },