void CfgError (const char* Format, ...) /* Print an error message adding file name and line number of the config file */ { char Buf [512]; va_list ap; va_start (ap, Format); xvsprintf (Buf, sizeof (Buf), Format, ap); va_end (ap); Error ("%s(%u): %s", CfgGetName(), CfgErrorLine, Buf); }
static void ParseSegments (void) /* Parse a SEGMENTS section */ { static const IdentTok Attributes [] = { { "ALIGN", CFGTOK_ALIGN }, { "ALIGN_LOAD", CFGTOK_ALIGN_LOAD }, { "DEFINE", CFGTOK_DEFINE }, { "LOAD", CFGTOK_LOAD }, { "OFFSET", CFGTOK_OFFSET }, { "OPTIONAL", CFGTOK_OPTIONAL }, { "RUN", CFGTOK_RUN }, { "START", CFGTOK_START }, { "TYPE", CFGTOK_TYPE }, }; static const IdentTok Types [] = { { "RO", CFGTOK_RO }, { "RW", CFGTOK_RW }, { "BSS", CFGTOK_BSS }, { "ZP", CFGTOK_ZP }, }; unsigned Count; long Val; /* The MEMORY section must preceed the SEGMENTS section */ if ((SectionsEncountered & SE_MEMORY) == 0) { CfgError ("MEMORY must precede SEGMENTS"); } while (CfgTok == CFGTOK_IDENT) { SegDesc* S; /* Create a new entry on the heap */ S = NewSegDesc (GetStringId (CfgSVal)); /* Skip the name and the following colon */ CfgNextTok (); CfgConsumeColon (); /* Read the attributes */ while (CfgTok == CFGTOK_IDENT) { /* Map the identifier to a token */ cfgtok_t AttrTok; CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute"); AttrTok = CfgTok; /* An optional assignment follows */ CfgNextTok (); CfgOptionalAssign (); /* Check which attribute was given */ switch (AttrTok) { case CFGTOK_ALIGN: FlagAttr (&S->Attr, SA_ALIGN, "ALIGN"); Val = CfgCheckedIntExpr (1, 0x10000); S->Align = BitFind (Val); if ((0x01L << S->Align) != Val) { CfgError ("Alignment must be a power of 2"); } S->Flags |= SF_ALIGN; break; case CFGTOK_ALIGN_LOAD: FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD"); Val = CfgCheckedIntExpr (1, 0x10000); S->AlignLoad = BitFind (Val); if ((0x01L << S->AlignLoad) != Val) { CfgError ("Alignment must be a power of 2"); } S->Flags |= SF_ALIGN_LOAD; break; case CFGTOK_DEFINE: FlagAttr (&S->Attr, SA_DEFINE, "DEFINE"); /* Map the token to a boolean */ CfgBoolToken (); if (CfgTok == CFGTOK_TRUE) { S->Flags |= SF_DEFINE; } CfgNextTok (); break; case CFGTOK_LOAD: FlagAttr (&S->Attr, SA_LOAD, "LOAD"); S->Load = CfgGetMemory (GetStringId (CfgSVal)); CfgNextTok (); break; case CFGTOK_OFFSET: FlagAttr (&S->Attr, SA_OFFSET, "OFFSET"); S->Addr = CfgCheckedIntExpr (1, 0x1000000); S->Flags |= SF_OFFSET; break; case CFGTOK_OPTIONAL: FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL"); CfgBoolToken (); if (CfgTok == CFGTOK_TRUE) { S->Flags |= SF_OPTIONAL; } CfgNextTok (); break; case CFGTOK_RUN: FlagAttr (&S->Attr, SA_RUN, "RUN"); S->Run = CfgGetMemory (GetStringId (CfgSVal)); CfgNextTok (); break; case CFGTOK_START: FlagAttr (&S->Attr, SA_START, "START"); S->Addr = CfgCheckedIntExpr (1, 0x1000000); S->Flags |= SF_START; break; case CFGTOK_TYPE: FlagAttr (&S->Attr, SA_TYPE, "TYPE"); CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type"); switch (CfgTok) { case CFGTOK_RO: S->Flags |= SF_RO; break; case CFGTOK_RW: /* Default */ break; case CFGTOK_BSS: S->Flags |= SF_BSS; break; case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break; default: Internal ("Unexpected token: %d", CfgTok); } CfgNextTok (); break; default: FAIL ("Unexpected attribute token"); } /* Skip an optional comma */ CfgOptionalComma (); } /* Check for mandatory parameters */ AttrCheck (S->Attr, SA_LOAD, "LOAD"); /* Set defaults for stuff not given */ if ((S->Attr & SA_RUN) == 0) { S->Attr |= SA_RUN; S->Run = S->Load; } /* If the segment is marked as BSS style, and if the segment exists * in any of the object file, check that there's no initialized data * in the segment. */ if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) { Warning ("%s(%u): Segment with type `bss' contains initialized data", CfgGetName (), CfgErrorLine); } /* An attribute of ALIGN_LOAD doesn't make sense if there are no * separate run and load memory areas. */ if ((S->Flags & SF_ALIGN_LOAD) != 0 && (S->Load == S->Run)) { Warning ("%s(%u): ALIGN_LOAD attribute specified, but no separate " "LOAD and RUN memory areas assigned", CfgGetName (), CfgErrorLine); /* Remove the flag */ S->Flags &= ~SF_ALIGN_LOAD; } /* If the segment is marked as BSS style, it may not have separate * load and run memory areas, because it's is never written to disk. */ if ((S->Flags & SF_BSS) != 0 && (S->Load != S->Run)) { Warning ("%s(%u): Segment with type `bss' has both LOAD and RUN " "memory areas assigned", CfgGetName (), CfgErrorLine); } /* Don't allow read/write data to be put into a readonly area */ if ((S->Flags & SF_RO) == 0) { if (S->Run->Flags & MF_RO) { CfgError ("Cannot put r/w segment `%s' in r/o memory area `%s'", GetString (S->Name), GetString (S->Run->Name)); } } /* Only one of ALIGN, START and OFFSET may be used */ Count = ((S->Flags & SF_ALIGN) != 0) + ((S->Flags & SF_OFFSET) != 0) + ((S->Flags & SF_START) != 0); if (Count > 1) { CfgError ("Only one of ALIGN, START, OFFSET may be used"); } /* If this segment does exist in any of the object files, insert the * descriptor into the list of segment descriptors. Otherwise print a * warning and discard it, because the segment pointer in the * descriptor is invalid. */ if (S->Seg != 0) { /* Insert the descriptor into the list of all descriptors */ SegDescInsert (S); /* Insert the segment into the memory area list */ MemoryInsert (S->Run, S); if (S->Load != S->Run) { /* We have separate RUN and LOAD areas */ MemoryInsert (S->Load, S); } } else { /* Print a warning if the segment is not optional */ if ((S->Flags & SF_OPTIONAL) == 0) { CfgWarning ("Segment `%s' does not exist", GetString (S->Name)); } /* Discard the descriptor */ FreeSegDesc (S); } /* Skip the semicolon */ CfgConsumeSemi (); } /* Remember we had this section */ SectionsEncountered |= SE_SEGMENTS; }