X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fld65%2Fsegments.c;h=1474ebe5550f4cba2b108598d110c7b226737575;hb=35e1184901ca38bdb2e56d154ed3b71f6096eacc;hp=f9154e194237ef2626cdc0f83ce9a9e9dbdd61e0;hpb=b936617eb467e67fb919889626ccd52101e9f0ef;p=cc65 diff --git a/src/ld65/segments.c b/src/ld65/segments.c index f9154e194..1474ebe55 100644 --- a/src/ld65/segments.c +++ b/src/ld65/segments.c @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 1998-2010, Ullrich von Bassewitz */ +/* (C) 1998-2012, Ullrich von Bassewitz */ /* Roemerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ @@ -37,10 +37,13 @@ #include /* common */ +#include "addrsize.h" +#include "alignment.h" #include "check.h" +#include "coll.h" #include "exprdefs.h" #include "fragdefs.h" -#include "hashstr.h" +#include "hashfunc.h" #include "print.h" #include "segdefs.h" #include "symdefs.h" @@ -67,10 +70,10 @@ /* Hash table */ #define HASHTAB_MASK 0x3FU #define HASHTAB_SIZE (HASHTAB_MASK + 1) -static Segment* HashTab [HASHTAB_SIZE]; +static Segment* HashTab[HASHTAB_SIZE]; -static unsigned SegCount = 0; /* Segment count */ -static Segment* SegRoot = 0; /* List of all segments */ +/* List of all segments */ +static Collection SegmentList = STATIC_COLLECTION_INITIALIZER; @@ -91,29 +94,22 @@ static Segment* NewSegment (unsigned Name, unsigned char AddrSize) /* Initialize the fields */ S->Name = Name; S->Next = 0; - S->SecRoot = 0; - S->SecLast = 0; + S->Flags = SEG_FLAG_NONE; + S->Sections = EmptyCollection; + S->MemArea = 0; 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; - S->Relocatable = 0; S->Dumped = 0; /* Insert the segment into the segment list and assign the segment id */ - if (SegRoot == 0) { - S->Id = 0; - } else { - S->Id = SegRoot->Id + 1; - } - S->List = SegRoot; - SegRoot = S; - ++SegCount; + S->Id = CollCount (&SegmentList); + CollAppend (&SegmentList, S); /* Insert the segment into the segment hash list */ Hash = (S->Name & HASHTAB_MASK); @@ -159,40 +155,31 @@ 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)); /* Initialize the data */ S->Next = 0; S->Seg = Seg; + S->Obj = 0; 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 = (unsigned char) (((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; @@ -204,47 +191,63 @@ Section* ReadSection (FILE* F, ObjData* O) /* Read a section from a file */ { unsigned Name; + unsigned Flags; unsigned Size; - unsigned char Align; + unsigned long Alignment; unsigned char Type; unsigned FragCount; Segment* S; Section* Sec; - LineInfo* LI; /* Read the segment data */ - (void) Read32 (F); /* File size of 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 */ - Type = Read8 (F); /* Segment type */ - FragCount = ReadVar (F); /* Number of fragments */ + Flags = ReadVar (F); /* Segment flags */ + 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)); + + /* The only possible flag is currently SEG_FLAG_BANKREF, and it must be + * applied to the segment, not the section. + */ + S->Flags |= Flags; /* Allocate the section we will return later */ - Sec = NewSection (S, Align, Type); - - /* 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; + Sec = NewSection (S, Alignment, Type); + + /* Remember the object file this section was from */ + Sec->Obj = 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 . */ - LI = 0; while (FragCount--) { Fragment* Frag; - FilePos Pos; - unsigned LineInfoIndex; /* Read the fragment type */ unsigned char Type = Read8 (F); @@ -269,7 +272,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: @@ -279,43 +282,8 @@ Section* ReadSection (FILE* F, ObjData* O) return 0; } - /* Read the file position of the fragment */ - ReadFilePos (F, &Pos); - - /* Generate a LineInfo for this fragment. First check if this fragment - * was generated by the same line than that before. If not, generate - * a new LineInfo. - */ - if (LI == 0 || LI->Pos.Line != Pos.Line || LI->Pos.Col != Pos.Col || - LI->Pos.Name != Pos.Name) { - /* We don't have a previous line info or this one is different */ - LI = NewLineInfo (O, &Pos); - CollAppend (&O->LineInfos, LI); - } - AddLineInfo (Frag, LI); - - /* Read additional line info and resolve it */ - LineInfoIndex = ReadVar (F); - if (LineInfoIndex) { - --LineInfoIndex; - /* The line info index was written by the assembler and must - * therefore be part of the line infos read from the object file. - * To make sure this is true, don't compare against the count - * of line infos in the collection (which grows) but against the - * count initialized when reading from the file. - */ - if (LineInfoIndex >= O->LineInfoCount) { - Internal ("In module `%s', file `%s', line %lu: Invalid line " - "info with index %u (max count %u)", - GetObjFileName (O), - GetFragmentSourceName (Frag), - GetFragmentSourceLine (Frag), - LineInfoIndex, - O->LineInfoCount); - } - /* Add line info to the fragment */ - AddLineInfo (Frag, CollAt (&O->LineInfos, LineInfoIndex)); - } + /* Read the line infos into the list of the fragment */ + ReadLineInfoList (F, O, &Frag->LineInfos); /* Remember the module we had this fragment from */ Frag->Obj = O; @@ -350,8 +318,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) { @@ -370,7 +342,6 @@ int IsBSSType (Segment* S) } F = F->Next; } - Sec = Sec->Next; } return 1; } @@ -380,32 +351,33 @@ 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; - Segment* Seg = SegRoot; - while (Seg) { - Section* S = Seg->SecRoot; + for (I = 0; I < CollCount (&SegmentList); ++I) { + 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"); while (F) { switch (F->Type) { case FRAG_LITERAL: - printf (" Literal (%u bytes):", F->Size); - Count = F->Size; - Data = F->LitBuf; - I = 100; - while (Count--) { - if (I > 75) { - printf ("\n "); - I = 3; + printf (" Literal (%u bytes):", F->Size); + Count = F->Size; + Data = F->LitBuf; + J = 100; + while (Count--) { + if (J > 75) { + printf ("\n "); + J = 3; } printf (" %02X", *Data++); - I += 3; + J += 3; } printf ("\n"); break; @@ -431,9 +403,7 @@ void SegDump (void) } F = F->Next; } - S = S->Next; } - Seg = Seg->List; } } @@ -444,14 +414,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 }; @@ -463,12 +433,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; } @@ -487,8 +457,8 @@ void SegWrite (const char* TgtName, FILE* Tgt, Segment* S, SegWriteFunc F, void* /* Write the data from the given segment to a file. For expressions, F is * called (see description of SegWriteFunc above). */ -{ - Section* Sec; +{ + unsigned I; int Sign; unsigned long Offs = 0; @@ -498,11 +468,16 @@ 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 */ + Print (stdout, 2, " Section from \"%s\"\n", GetObjFileName (Sec->Obj)); + /* If we have fill bytes, write them now */ + Print (stdout, 2, " Filling 0x%lx bytes with 0x%02x\n", + Sec->Fill, S->FillVal); WriteMult (Tgt, S->FillVal, Sec->Fill); Offs += Sec->Fill; @@ -510,19 +485,15 @@ 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) { + switch (Frag->Type) { - case FRAG_LITERAL: - WriteData (Tgt, Frag->LitBuf, Frag->Size); - break; + case FRAG_LITERAL: + WriteData (Tgt, Frag->LitBuf, Frag->Size); + break; - case FRAG_EXPR: - case FRAG_SEXPR: + case FRAG_EXPR: + case FRAG_SEXPR: Sign = (Frag->Type == FRAG_SEXPR); /* Call the users function and evaluate the result */ switch (F (Frag->Expr, Sign, Frag->Size, Offs, Data)) { @@ -531,19 +502,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; @@ -562,19 +533,26 @@ void SegWrite (const char* TgtName, FILE* Tgt, Segment* S, SegWriteFunc F, void* } /* Update the offset */ + Print (stdout, 2, " Fragment with 0x%x bytes\n", + Frag->Size); Offs += Frag->Size; /* Next fragment */ Frag = Frag->Next; } - - /* Next section */ - Sec = Sec->Next; } } +unsigned SegmentCount (void) +/* Return the total number of segments */ +{ + return CollCount (&SegmentList); +} + + + static int CmpSegStart (const void* K1, const void* K2) /* Compare function for qsort */ { @@ -584,7 +562,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 { @@ -598,44 +576,28 @@ static int CmpSegStart (const void* K1, const void* K2) void PrintSegmentMap (FILE* F) /* Print a segment map to the given file */ { - unsigned I; - Segment* S; - Segment** SegPool; /* Allocate memory for the segment pool */ - SegPool = xmalloc (SegCount * sizeof (Segment*)); - - /* Collect pointers to the segments */ - I = 0; - S = SegRoot; - while (S) { - - /* Check the count for safety */ - CHECK (I < SegCount); + Segment** SegPool = xmalloc (CollCount (&SegmentList) * sizeof (Segment*)); - /* Remember the pointer */ - SegPool [I] = S; - - /* Follow the linked list */ - S = S->List; - - /* Next array index */ - ++I; + /* Copy the segment pointers */ + unsigned I; + for (I = 0; I < CollCount (&SegmentList); ++I) { + SegPool[I] = CollAtUnchecked (&SegmentList, I); } - CHECK (I == SegCount); /* Sort the array by increasing start addresses */ - qsort (SegPool, SegCount, sizeof (Segment*), CmpSegStart); + 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 < SegCount; ++I) { + for (I = 0; I < CollCount (&SegmentList); ++I) { /* Get a pointer to the segment */ - S = SegPool [I]; + Segment* S = SegPool[I]; /* Print empty segments only if explicitly requested */ if (VerboseMap || S->Size > 0) { @@ -645,8 +607,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); } } @@ -660,23 +622,23 @@ void PrintDbgSegments (FILE* F) /* Output the segments to the debug file */ { /* Walk over all segments */ - Segment* S = SegRoot; - while (S) { + unsigned I; + for (I = 0; I < CollCount (&SegmentList); ++I) { + + /* Get the next segment */ + const Segment* S = CollAtUnchecked (&SegmentList, I); /* Print the segment data */ fprintf (F, - "segment\tid=%u,name=\"%s\",start=0x%06lX,size=0x%04lX,addrsize=%s,type=%s", + "seg\tid=%u,name=\"%s\",start=0x%06lX,size=0x%04lX,addrsize=%s,type=%s", S->Id, GetString (S->Name), S->PC, S->Size, AddrSizeToStr (S->AddrSize), S->ReadOnly? "ro" : "rw"); if (S->OutputName) { - fprintf (F, ",outputname=\"%s\",outputoffs=%lu", + fprintf (F, ",oname=\"%s\",ooffs=%lu", S->OutputName, S->OutputOffs); } fputc ('\n', F); - - /* Follow the linked list */ - S = S->List; } } @@ -687,13 +649,17 @@ void CheckSegments (void) * not written to the output file. Output an error if this is the case. */ { - Segment* S = SegRoot; - while (S) { + unsigned I; + for (I = 0; I < CollCount (&SegmentList); ++I) { + + /* Get the next segment */ + const Segment* S = CollAtUnchecked (&SegmentList, I); + + /* Check it */ if (S->Size > 0 && S->Dumped == 0) { Error ("Missing memory area assignment for segment `%s'", GetString (S->Name)); } - S = S->List; } }