/* */
/* */
/* */
-/* (C) 1998-2002 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@musoftware.de */
+/* (C) 1998-2011, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
#include <errno.h>
/* common */
-#include "check.h"
+#include "addrsize.h"
#include "bitops.h"
+#include "check.h"
#include "print.h"
#include "xmalloc.h"
+#include "xsprintf.h"
/* ld65 */
+#include "alignment.h"
#include "bin.h"
#include "binfmt.h"
+#include "cfgexpr.h"
#include "condes.h"
+#include "config.h"
#include "error.h"
#include "exports.h"
+#include "expr.h"
#include "global.h"
+#include "memarea.h"
#include "o65.h"
+#include "objdata.h"
#include "scanner.h"
-#include "config.h"
+#include "spool.h"
-/* File list */
-static File* FileList; /* Single linked list */
-static unsigned FileCount; /* Number of entries in the list */
+/* Remember which sections we had encountered */
+static enum {
+ SE_NONE = 0x0000,
+ SE_MEMORY = 0x0001,
+ SE_SEGMENTS = 0x0002,
+ SE_FEATURES = 0x0004,
+ SE_FILES = 0x0008,
+ SE_FORMATS = 0x0010,
+ SE_SYMBOLS = 0x0020
+} SectionsEncountered = SE_NONE;
+
+/* File list */
+static Collection FileList = STATIC_COLLECTION_INITIALIZER;
/* Memory list */
-static Memory* MemoryList; /* Single linked list */
-static Memory* MemoryLast; /* Last element in list */
-static unsigned MemoryCount; /* Number of entries in the list */
+static Collection MemoryAreas = STATIC_COLLECTION_INITIALIZER;
/* Memory attributes */
#define MA_START 0x0001
#define MA_FILL 0x0020
#define MA_FILLVAL 0x0040
-
-
/* Segment list */
-SegDesc* SegDescList; /* Single linked list */
-unsigned SegDescCount; /* Number of entries in list */
+static Collection SegDescList = STATIC_COLLECTION_INITIALIZER;
/* Segment attributes */
#define SA_TYPE 0x0001
#define SA_LOAD 0x0002
#define SA_RUN 0x0004
#define SA_ALIGN 0x0008
-#define SA_DEFINE 0x0010
-#define SA_OFFSET 0x0020
-#define SA_START 0x0040
-
-
+#define SA_ALIGN_LOAD 0x0010
+#define SA_DEFINE 0x0020
+#define SA_OFFSET 0x0040
+#define SA_START 0x0080
+#define SA_OPTIONAL 0x0100
+
+/* Symbol types used in the CfgSymbol structure */
+typedef enum {
+ CfgSymExport, /* Not really used in struct CfgSymbol */
+ CfgSymImport, /* Dito */
+ CfgSymWeak, /* Like export but weak */
+ CfgSymO65Export, /* An o65 export */
+ CfgSymO65Import, /* An o65 import */
+} CfgSymType;
+
+/* Symbol structure. It is used for o65 imports and exports, but also for
+ * symbols from the SYMBOLS sections (symbols defined in the config file or
+ * forced imports).
+ */
+typedef struct CfgSymbol CfgSymbol;
+struct CfgSymbol {
+ CfgSymType Type; /* Type of symbol */
+ LineInfo* LI; /* Config file position */
+ unsigned Name; /* Symbol name */
+ ExprNode* Value; /* Symbol value if any */
+ unsigned AddrSize; /* Address size of symbol */
+};
+
+/* Collections with symbols */
+static Collection CfgSymbols = STATIC_COLLECTION_INITIALIZER;
/* Descriptor holding information about the binary formats */
static BinDesc* BinFmtDesc = 0;
-static File* NewFile (const char* Name);
+static File* NewFile (unsigned Name);
/* Create a new file descriptor and insert it into the list */
-static File* FindFile (const char* Name)
+static File* FindFile (unsigned Name)
/* Find a file with a given name. */
{
- File* F = FileList;
- while (F) {
- if (strcmp (F->Name, Name) == 0) {
- return F;
- }
- F = F->Next;
+ unsigned I;
+ for (I = 0; I < CollCount (&FileList); ++I) {
+ File* F = CollAtUnchecked (&FileList, I);
+ if (F->Name == Name) {
+ return F;
+ }
}
return 0;
}
-static File* GetFile (const char* Name)
+static File* GetFile (unsigned Name)
/* Get a file entry with the given name. Create a new one if needed. */
{
File* F = FindFile (Name);
-static void FileInsert (File* F, Memory* M)
+static void FileInsert (File* F, MemoryArea* M)
/* Insert the memory area into the files list */
{
M->F = F;
- if (F->MemList == 0) {
- /* First entry */
- F->MemList = M;
- } else {
- F->MemLast->FNext = M;
- }
- F->MemLast = M;
+ CollAppend (&F->MemoryAreas, M);
}
-static Memory* CfgFindMemory (const char* Name)
+static MemoryArea* CfgFindMemory (unsigned Name)
/* Find the memory are with the given name. Return NULL if not found */
{
- Memory* M = MemoryList;
- while (M) {
- if (strcmp (M->Name, Name) == 0) {
+ unsigned I;
+ for (I = 0; I < CollCount (&MemoryAreas); ++I) {
+ MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
+ if (M->Name == Name) {
return M;
}
- M = M->Next;
}
return 0;
}
-static Memory* CfgGetMemory (const char* Name)
+static MemoryArea* CfgGetMemory (unsigned Name)
/* Find the memory are with the given name. Print an error on an invalid name */
{
- Memory* M = CfgFindMemory (Name);
+ MemoryArea* M = CfgFindMemory (Name);
if (M == 0) {
- CfgError ("Invalid memory area `%s'", Name);
+ CfgError (&CfgErrorPos, "Invalid memory area `%s'", GetString (Name));
}
return M;
}
-static SegDesc* CfgFindSegDesc (const char* Name)
+static SegDesc* CfgFindSegDesc (unsigned Name)
/* Find the segment descriptor with the given name, return NULL if not found. */
{
- SegDesc* S = SegDescList;
- while (S) {
- if (strcmp (S->Name, Name) == 0) {
+ unsigned I;
+ for (I = 0; I < CollCount (&SegDescList); ++I) {
+ SegDesc* S = CollAtUnchecked (&SegDescList, I);
+ if (S->Name == Name) {
/* Found */
return S;
}
- S = S->Next;
}
/* Not found */
-static void SegDescInsert (SegDesc* S)
-/* Insert a segment descriptor into the list of segment descriptors */
-{
- /* Insert the struct into the list */
- S->Next = SegDescList;
- SegDescList = S;
- ++SegDescCount;
-}
-
-
-
-static void MemoryInsert (Memory* M, SegDesc* S)
+static void MemoryInsert (MemoryArea* M, SegDesc* S)
/* Insert the segment descriptor into the memory area list */
{
- /* Create a new node for the entry */
- MemListNode* N = xmalloc (sizeof (MemListNode));
- N->Seg = S;
- N->Next = 0;
-
- if (M->SegLast == 0) {
- /* First entry */
- M->SegList = N;
- } else {
- M->SegLast->Next = N;
- }
- M->SegLast = N;
+ /* Insert the segment into the segment list of the memory area */
+ CollAppend (&M->SegList, S);
}
-static File* NewFile (const char* Name)
-/* Create a new file descriptor and insert it into the list */
+static CfgSymbol* NewCfgSymbol (CfgSymType Type, unsigned Name)
+/* Create a new CfgSymbol structure with the given type and name. The
+ * current config file position is recorded in the returned struct. The
+ * created struct is inserted into the CfgSymbols collection and returned.
+ */
{
- /* Get the length of the name */
- unsigned Len = strlen (Name);
+ /* Allocate memory */
+ CfgSymbol* Sym = xmalloc (sizeof (CfgSymbol));
+
+ /* Initialize the fields */
+ Sym->Type = Type;
+ Sym->LI = GenLineInfo (&CfgErrorPos);
+ Sym->Name = Name;
+ Sym->Value = 0;
+ Sym->AddrSize = ADDR_SIZE_INVALID;
+
+ /* Insert the symbol into the collection */
+ CollAppend (&CfgSymbols, Sym);
+
+ /* Return the initialized struct */
+ return Sym;
+}
+
+
+static File* NewFile (unsigned Name)
+/* Create a new file descriptor and insert it into the list */
+{
/* Allocate memory */
- File* F = xmalloc (sizeof (File) + Len);
+ File* F = xmalloc (sizeof (File));
/* Initialize the fields */
+ F->Name = Name;
F->Flags = 0;
F->Format = BINFMT_DEFAULT;
- F->MemList = 0;
- F->MemLast = 0;
- memcpy (F->Name, Name, Len);
- F->Name [Len] = '\0';
+ InitCollection (&F->MemoryAreas);
/* Insert the struct into the list */
- F->Next = FileList;
- FileList = F;
- ++FileCount;
+ CollAppend (&FileList, F);
/* ...and return it */
return F;
-static Memory* NewMemory (const char* Name)
-/* Create a new memory section and insert it into the list */
+static MemoryArea* CreateMemoryArea (const FilePos* Pos, unsigned Name)
+/* Create a new memory area and insert it into the list */
{
- /* Get the length of the name */
- unsigned Len = strlen (Name);
-
/* Check for duplicate names */
- Memory* M = CfgFindMemory (Name);
+ MemoryArea* M = CfgFindMemory (Name);
if (M) {
- CfgError ("Memory area `%s' defined twice", Name);
+ CfgError (&CfgErrorPos,
+ "Memory area `%s' defined twice",
+ GetString (Name));
}
- /* Allocate memory */
- M = xmalloc (sizeof (Memory) + Len);
+ /* Create a new memory area */
+ M = NewMemoryArea (Pos, Name);
- /* Initialize the fields */
- M->Next = 0;
- M->FNext = 0;
- M->Attr = 0;
- M->Flags = 0;
- M->Start = 0;
- M->Size = 0;
- M->FillLevel = 0;
- M->FillVal = 0;
- M->SegList = 0;
- M->SegLast = 0;
- M->F = 0;
- memcpy (M->Name, Name, Len);
- M->Name [Len] = '\0';
-
- /* Insert the struct into the list */
- if (MemoryLast == 0) {
- /* First element */
- MemoryList = M;
- } else {
- MemoryLast->Next = M;
- }
- MemoryLast = M;
- ++MemoryCount;
+ /* Insert the struct into the list ... */
+ CollAppend (&MemoryAreas, M);
/* ...and return it */
return M;
-static SegDesc* NewSegDesc (const char* Name)
-/* Create a segment descriptor */
+static SegDesc* NewSegDesc (unsigned Name)
+/* Create a segment descriptor and insert it into the list */
{
- Segment* Seg;
-
- /* Get the length of the name */
- unsigned Len = strlen (Name);
/* Check for duplicate names */
SegDesc* S = CfgFindSegDesc (Name);
if (S) {
- CfgError ("Segment `%s' defined twice", Name);
- }
-
- /* Verify that the given segment does really exist */
- Seg = SegFind (Name);
- if (Seg == 0) {
- CfgWarning ("Segment `%s' does not exist", Name);
+ CfgError (&CfgErrorPos, "Segment `%s' defined twice", GetString (Name));
}
/* Allocate memory */
- S = xmalloc (sizeof (SegDesc) + Len);
+ S = xmalloc (sizeof (SegDesc));
/* Initialize the fields */
- S->Next = 0;
- S->Seg = Seg;
- S->Attr = 0;
- S->Flags = 0;
- S->Align = 0;
- memcpy (S->Name, Name, Len);
- S->Name [Len] = '\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);
/* ...and return it */
return S;
static void FreeSegDesc (SegDesc* S)
/* Free a segment descriptor */
{
+ FreeLineInfo (S->LI);
xfree (S);
}
/*****************************************************************************/
-/* Code */
+/* Config file parsing */
/*****************************************************************************/
*/
{
if (*Flags & Mask) {
- CfgError ("%s is already defined", Name);
+ CfgError (&CfgErrorPos, "%s is already defined", Name);
}
*Flags |= Mask;
}
/* Check that a mandatory attribute was given */
{
if ((Attr & Mask) == 0) {
- CfgError ("%s attribute is missing", Name);
+ CfgError (&CfgErrorPos, "%s attribute is missing", Name);
}
}
{
static const IdentTok Attributes [] = {
{ "START", CFGTOK_START },
- { "SIZE", CFGTOK_SIZE },
+ { "SIZE", CFGTOK_SIZE },
{ "TYPE", CFGTOK_TYPE },
{ "FILE", CFGTOK_FILE },
{ "DEFINE", CFGTOK_DEFINE },
- { "FILL", CFGTOK_FILL },
+ { "FILL", CFGTOK_FILL },
{ "FILLVAL", CFGTOK_FILLVAL },
};
static const IdentTok Types [] = {
while (CfgTok == CFGTOK_IDENT) {
/* Create a new entry on the heap */
- Memory* M = NewMemory (CfgSVal);
+ MemoryArea* M = CreateMemoryArea (&CfgErrorPos, GetStrBufId (&CfgSVal));
/* Skip the name and the following colon */
CfgNextTok ();
case CFGTOK_START:
FlagAttr (&M->Attr, MA_START, "START");
- CfgAssureInt ();
- M->Start = CfgIVal;
+ M->StartExpr = CfgExpr ();
break;
case CFGTOK_SIZE:
- FlagAttr (&M->Attr, MA_SIZE, "SIZE");
- CfgAssureInt ();
- M->Size = CfgIVal;
- break;
-
- case CFGTOK_TYPE:
- FlagAttr (&M->Attr, MA_TYPE, "TYPE");
- CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
- if (CfgTok == CFGTOK_RO) {
- M->Flags |= MF_RO;
- }
- break;
+ FlagAttr (&M->Attr, MA_SIZE, "SIZE");
+ M->SizeExpr = CfgExpr ();
+ break;
+
+ case CFGTOK_TYPE:
+ FlagAttr (&M->Attr, MA_TYPE, "TYPE");
+ CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
+ if (CfgTok == CFGTOK_RO) {
+ M->Flags |= MF_RO;
+ }
+ CfgNextTok ();
+ break;
case CFGTOK_FILE:
- FlagAttr (&M->Attr, MA_FILE, "FILE");
- CfgAssureStr ();
+ FlagAttr (&M->Attr, MA_FILE, "FILE");
+ CfgAssureStr ();
/* Get the file entry and insert the memory area */
- FileInsert (GetFile (CfgSVal), M);
- break;
+ FileInsert (GetFile (GetStrBufId (&CfgSVal)), M);
+ CfgNextTok ();
+ break;
case CFGTOK_DEFINE:
- FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
- /* Map the token to a boolean */
- CfgBoolToken ();
- if (CfgTok == CFGTOK_TRUE) {
- M->Flags |= MF_DEFINE;
- }
- break;
+ FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
+ /* Map the token to a boolean */
+ CfgBoolToken ();
+ if (CfgTok == CFGTOK_TRUE) {
+ M->Flags |= MF_DEFINE;
+ }
+ CfgNextTok ();
+ break;
case CFGTOK_FILL:
- FlagAttr (&M->Attr, MA_FILL, "FILL");
- /* Map the token to a boolean */
- CfgBoolToken ();
- if (CfgTok == CFGTOK_TRUE) {
- M->Flags |= MF_FILL;
- }
- break;
+ FlagAttr (&M->Attr, MA_FILL, "FILL");
+ /* Map the token to a boolean */
+ CfgBoolToken ();
+ if (CfgTok == CFGTOK_TRUE) {
+ M->Flags |= MF_FILL;
+ }
+ CfgNextTok ();
+ break;
case CFGTOK_FILLVAL:
- FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
- CfgAssureInt ();
- CfgRangeCheck (0, 0xFF);
- M->FillVal = (unsigned char) CfgIVal;
- break;
+ FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
+ M->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
+ break;
default:
FAIL ("Unexpected attribute token");
}
- /* Skip the attribute value and an optional comma */
- CfgNextTok ();
+ /* Skip an optional comma */
CfgOptionalComma ();
}
* file name.
*/
if ((M->Attr & MA_FILE) == 0) {
- FileInsert (GetFile (OutputName), M);
+ FileInsert (GetFile (GetStringId (OutputName)), M);
+ OutputNameUsed = 1;
}
}
+
+ /* Remember we had this section */
+ SectionsEncountered |= SE_MEMORY;
}
{ "FORMAT", CFGTOK_FORMAT },
};
static const IdentTok Formats [] = {
- { "O65", CFGTOK_O65 },
+ { "O65", CFGTOK_O65 },
{ "BIN", CFGTOK_BIN },
{ "BINARY", CFGTOK_BIN },
};
+ /* The MEMORY section must preceed the FILES section */
+ if ((SectionsEncountered & SE_MEMORY) == 0) {
+ CfgError (&CfgErrorPos, "MEMORY must precede FILES");
+ }
+
/* Parse all files */
while (CfgTok != CFGTOK_RCURLY) {
CfgAssureStr ();
/* Search for the file, it must exist */
- F = FindFile (CfgSVal);
+ F = FindFile (GetStrBufId (&CfgSVal));
if (F == 0) {
- CfgError ("No such file: `%s'", CfgSVal);
+ CfgError (&CfgErrorPos,
+ "File `%s' not found in MEMORY section",
+ SB_GetConstBuf (&CfgSVal));
}
/* Skip the token and the following colon */
case CFGTOK_FORMAT:
if (F->Format != BINFMT_DEFAULT) {
/* We've set the format already! */
- Error ("Cannot set a file format twice");
+ CfgError (&CfgErrorPos,
+ "Cannot set a file format twice");
}
/* Read the format token */
CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
CfgConsumeSemi ();
}
+
+ /* Remember we had this section */
+ SectionsEncountered |= SE_FILES;
}
/* Parse a SEGMENTS section */
{
static const IdentTok Attributes [] = {
- { "LOAD", CFGTOK_LOAD },
- { "RUN", CFGTOK_RUN },
- { "TYPE", CFGTOK_TYPE },
- { "ALIGN", CFGTOK_ALIGN },
- { "DEFINE", CFGTOK_DEFINE },
- { "OFFSET", CFGTOK_OFFSET },
- { "START", CFGTOK_START },
+ { "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 },
- { "WP", CFGTOK_WPROT },
- { "WPROT", CFGTOK_WPROT },
+ { "RO", CFGTOK_RO },
+ { "RW", CFGTOK_RW },
+ { "BSS", CFGTOK_BSS },
+ { "ZP", CFGTOK_ZP },
};
unsigned Count;
+ /* The MEMORY section must preceed the SEGMENTS section */
+ if ((SectionsEncountered & SE_MEMORY) == 0) {
+ CfgError (&CfgErrorPos, "MEMORY must precede SEGMENTS");
+ }
+
while (CfgTok == CFGTOK_IDENT) {
SegDesc* S;
/* Create a new entry on the heap */
- S = NewSegDesc (CfgSVal);
+ S = NewSegDesc (GetStrBufId (&CfgSVal));
/* Skip the name and the following colon */
CfgNextTok ();
/* Check which attribute was given */
switch (AttrTok) {
- case CFGTOK_LOAD:
- FlagAttr (&S->Attr, SA_LOAD, "LOAD");
- S->Load = CfgGetMemory (CfgSVal);
- break;
+ case CFGTOK_ALIGN:
+ FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
+ S->RunAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
+ S->Flags |= SF_ALIGN;
+ break;
- case CFGTOK_RUN:
- FlagAttr (&S->Attr, SA_RUN, "RUN");
- S->Run = CfgGetMemory (CfgSVal);
- break;
+ case CFGTOK_ALIGN_LOAD:
+ FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
+ S->LoadAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
+ S->Flags |= SF_ALIGN_LOAD;
+ 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;
- case CFGTOK_WPROT: S->Flags |= (SF_RO | SF_WPROT); break;
- default: Internal ("Unexpected token: %d", CfgTok);
- }
- 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 (GetStrBufId (&CfgSVal));
+ CfgNextTok ();
+ break;
- case CFGTOK_ALIGN:
- CfgAssureInt ();
- FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
- CfgRangeCheck (1, 0x10000);
- S->Align = BitFind (CfgIVal);
- if ((0x01UL << S->Align) != CfgIVal) {
- CfgError ("Alignment must be a power of 2");
- }
- S->Flags |= SF_ALIGN;
- break;
+ case CFGTOK_OFFSET:
+ FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
+ S->Addr = CfgCheckedConstExpr (1, 0x1000000);
+ S->Flags |= SF_OFFSET;
+ break;
- case CFGTOK_DEFINE:
- FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
- /* Map the token to a boolean */
+ case CFGTOK_OPTIONAL:
+ FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL");
CfgBoolToken ();
if (CfgTok == CFGTOK_TRUE) {
- S->Flags |= SF_DEFINE;
+ S->Flags |= SF_OPTIONAL;
}
- break;
+ CfgNextTok ();
+ break;
- case CFGTOK_OFFSET:
- CfgAssureInt ();
- FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
- CfgRangeCheck (1, 0x1000000);
- S->Addr = CfgIVal;
- S->Flags |= SF_OFFSET;
- break;
+ case CFGTOK_RUN:
+ FlagAttr (&S->Attr, SA_RUN, "RUN");
+ S->Run = CfgGetMemory (GetStrBufId (&CfgSVal));
+ CfgNextTok ();
+ break;
case CFGTOK_START:
- CfgAssureInt ();
- FlagAttr (&S->Attr, SA_START, "START");
- CfgRangeCheck (1, 0x1000000);
- S->Addr = CfgIVal;
- S->Flags |= SF_START;
- break;
-
- default:
+ FlagAttr (&S->Attr, SA_START, "START");
+ S->Addr = CfgCheckedConstExpr (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 the attribute value and an optional comma */
- CfgNextTok ();
+ /* Skip an optional comma */
CfgOptionalComma ();
}
- /* Skip the semicolon */
- CfgConsumeSemi ();
-
/* Check for mandatory parameters */
AttrCheck (S->Attr, SA_LOAD, "LOAD");
if ((S->Attr & SA_RUN) == 0) {
S->Attr |= SA_RUN;
S->Run = S->Load;
- } else {
- /* Both attributes given */
- S->Flags |= SF_LOAD_AND_RUN;
- }
- if ((S->Attr & SA_ALIGN) == 0) {
- S->Attr |= SA_ALIGN;
- S->Align = 0;
}
- /* If the segment is marked as BSS style, check that there's no
- * initialized data in the segment.
- */
- if ((S->Flags & SF_BSS) != 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)) {
+ CfgWarning (&CfgErrorPos,
+ "ALIGN_LOAD attribute specified, but no separate "
+ "LOAD and RUN memory areas assigned");
+ /* 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)) {
+ CfgWarning (&CfgErrorPos,
+ "Segment with type `bss' has both LOAD and RUN "
+ "memory areas assigned");
+ }
/* 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'",
- S->Name, S->Run->Name);
+ CfgError (&CfgErrorPos,
+ "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);
+ ((S->Flags & SF_START) != 0);
if (Count > 1) {
- CfgError ("Only one of ALIGN, START, OFFSET may be used");
+ CfgError (&CfgErrorPos,
+ "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 discard
- * it silently, 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->Flags & SF_LOAD_AND_RUN) != 0) {
- /* We have a separate RUN area given */
- MemoryInsert (S->Load, S);
- }
- } else {
- /* Segment does not exist, discard the descriptor */
- FreeSegDesc (S);
- }
+ /* Skip the semicolon */
+ CfgConsumeSemi ();
}
+
+ /* Remember we had this section */
+ SectionsEncountered |= SE_SEGMENTS;
}
{ "LUNIX", CFGTOK_LUNIX },
{ "OSA65", CFGTOK_OSA65 },
{ "CC65", CFGTOK_CC65 },
+ { "OPENCBM", CFGTOK_OPENCBM },
};
/* Bitmask to remember the attributes we got already */
AttrFlags |= atExport;
/* We expect an identifier */
CfgAssureIdent ();
- /* Check if the export symbol is also defined as an import. */
- if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
- CfgError ("Exported symbol `%s' cannot be an import", CfgSVal);
- }
- /* Check if we have this symbol defined already. The entry
- * routine will check this also, but we get a more verbose
- * error message when checking it here.
- */
- if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
- CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
- }
- /* Insert the symbol into the table */
- O65SetExport (O65FmtDesc, CfgSVal);
+ /* Remember it as an export for later */
+ NewCfgSymbol (CfgSymO65Export, GetStrBufId (&CfgSVal));
+ /* Eat the identifier token */
+ CfgNextTok ();
break;
case CFGTOK_IMPORT:
AttrFlags |= atImport;
/* We expect an identifier */
CfgAssureIdent ();
- /* Check if the imported symbol is also defined as an export. */
- if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
- CfgError ("Imported symbol `%s' cannot be an export", CfgSVal);
- }
- /* Check if we have this symbol defined already. The entry
- * routine will check this also, but we get a more verbose
- * error message when checking it here.
- */
- if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
- CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
- }
- /* Insert the symbol into the table */
- O65SetImport (O65FmtDesc, CfgSVal);
+ /* Remember it as an import for later */
+ NewCfgSymbol (CfgSymO65Import, GetStrBufId (&CfgSVal));
+ /* Eat the identifier token */
+ CfgNextTok ();
break;
case CFGTOK_TYPE:
/* Cannot have this attribute twice */
FlagAttr (&AttrFlags, atType, "TYPE");
- /* Get the type of the executable */
+ /* Get the type of the executable */
CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
switch (CfgTok) {
break;
default:
- CfgError ("Unexpected type token");
+ CfgError (&CfgErrorPos, "Unexpected type token");
}
- break;
+ /* Eat the attribute token */
+ CfgNextTok ();
+ break;
case CFGTOK_OS:
- /* Cannot use this attribute twice */
- FlagAttr (&AttrFlags, atOS, "OS");
- /* Get the operating system */
- CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
- switch (CfgTok) {
- case CFGTOK_LUNIX: OS = O65OS_LUNIX; break;
- case CFGTOK_OSA65: OS = O65OS_OSA65; break;
- case CFGTOK_CC65: OS = O65OS_CC65; break;
- default: CfgError ("Unexpected OS token");
- }
- break;
+ /* Cannot use this attribute twice */
+ FlagAttr (&AttrFlags, atOS, "OS");
+ /* Get the operating system. It may be specified as name or
+ * as a number in the range 1..255.
+ */
+ if (CfgTok == CFGTOK_INTCON) {
+ CfgRangeCheck (O65OS_MIN, O65OS_MAX);
+ OS = (unsigned) CfgIVal;
+ } else {
+ CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
+ switch (CfgTok) {
+ case CFGTOK_LUNIX: OS = O65OS_LUNIX; break;
+ case CFGTOK_OSA65: OS = O65OS_OSA65; break;
+ case CFGTOK_CC65: OS = O65OS_CC65; break;
+ case CFGTOK_OPENCBM: OS = O65OS_OPENCBM; break;
+ default: CfgError (&CfgErrorPos, "Unexpected OS token");
+ }
+ }
+ CfgNextTok ();
+ break;
case CFGTOK_ID:
/* Cannot have this attribute twice */
FlagAttr (&AttrFlags, atID, "ID");
/* We're expecting a number in the 0..$FFFF range*/
- CfgAssureInt ();
- CfgRangeCheck (0, 0xFFFF);
- ModuleId = (unsigned) CfgIVal;
+ ModuleId = (unsigned) CfgCheckedConstExpr (0, 0xFFFF);
break;
case CFGTOK_VERSION:
/* Cannot have this attribute twice */
FlagAttr (&AttrFlags, atVersion, "VERSION");
/* We're expecting a number in byte range */
- CfgAssureInt ();
- CfgRangeCheck (0, 0xFF);
- Version = (unsigned) CfgIVal;
+ Version = (unsigned) CfgCheckedConstExpr (0, 0xFF);
break;
default:
}
- /* Skip the attribute value and an optional comma */
- CfgNextTok ();
+ /* Skip an optional comma */
CfgOptionalComma ();
}
/* Check for attributes that may not be combined */
if (OS == O65OS_CC65) {
- if ((AttrFlags & (atImport | atExport)) != 0) {
- CfgError ("OS type CC65 may not have imports or exports");
+ if ((AttrFlags & (atImport | atExport)) != 0 && ModuleId < 0x8000) {
+ CfgError (&CfgErrorPos,
+ "OS type CC65 may not have imports or exports for ids < $8000");
}
} else {
if (AttrFlags & atID) {
- CfgError ("Operating system does not support the ID attribute");
+ CfgError (&CfgErrorPos,
+ "Operating system does not support the ID attribute");
}
}
/* Skip the semicolon */
CfgConsumeSemi ();
}
+
+
+ /* Remember we had this section */
+ SectionsEncountered |= SE_FORMATS;
}
static const IdentTok Types [] = {
{ "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
{ "DESTRUCTOR", CFGTOK_DESTRUCTOR },
+ { "INTERRUPTOR", CFGTOK_INTERRUPTOR },
};
static const IdentTok Orders [] = {
};
/* Attribute values. */
- char SegName[sizeof (CfgSVal)];
- char Label[sizeof (CfgSVal)];
- char Count[sizeof (CfgSVal)];
+ unsigned SegName = INVALID_STRING_ID;
+ unsigned Label = INVALID_STRING_ID;
+ unsigned Count = INVALID_STRING_ID;
/* Initialize to avoid gcc warnings: */
int Type = -1;
ConDesOrder Order = cdIncreasing;
/* Bitmask to remember the attributes we got already */
enum {
- atNone = 0x0000,
- atSegName = 0x0001,
- atLabel = 0x0002,
- atCount = 0x0004,
- atType = 0x0008,
- atOrder = 0x0010
+ atNone = 0x0000,
+ atSegName = 0x0001,
+ atLabel = 0x0002,
+ atCount = 0x0004,
+ atType = 0x0008,
+ atOrder = 0x0010
};
unsigned AttrFlags = atNone;
/* We expect an identifier */
CfgAssureIdent ();
/* Remember the value for later */
- strcpy (SegName, CfgSVal);
+ SegName = GetStrBufId (&CfgSVal);
break;
case CFGTOK_LABEL:
/* We expect an identifier */
CfgAssureIdent ();
/* Remember the value for later */
- strcpy (Label, CfgSVal);
+ Label = GetStrBufId (&CfgSVal);
break;
case CFGTOK_COUNT:
/* We expect an identifier */
CfgAssureIdent ();
/* Remember the value for later */
- strcpy (Count, CfgSVal);
+ Count = GetStrBufId (&CfgSVal);
break;
case CFGTOK_TYPE:
switch (CfgTok) {
case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
- default: FAIL ("Unexpected type token");
+ case CFGTOK_INTERRUPTOR: Type = CD_TYPE_INT; break;
+ default: FAIL ("Unexpected type token");
}
}
break;
/* Check if the condes has already attributes defined */
if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
- CfgError ("CONDES attributes for type %d are already defined", Type);
+ CfgError (&CfgErrorPos,
+ "CONDES attributes for type %d are already defined",
+ Type);
}
/* Define the attributes */
case CFGTOK_DEFAULT:
/* Don't allow this twice */
FlagAttr (&AttrFlags, atDefault, "DEFAULT");
- /* We expect a number */
- CfgAssureInt ();
- CfgRangeCheck (0, 0xFFFFFF);
- /* Remember the value for later */
- DefStartAddr = CfgIVal;
+ /* We expect a numeric expression */
+ DefStartAddr = CfgCheckedConstExpr (0, 0xFFFFFF);
break;
default:
}
- /* Skip the attribute value */
- CfgNextTok ();
-
/* Semicolon ends the ConDes decl, otherwise accept an optional comma */
if (CfgTok == CFGTOK_SEMI) {
break;
switch (FeatureTok) {
case CFGTOK_CONDES:
- ParseConDes ();
- break;
+ ParseConDes ();
+ break;
case CFGTOK_STARTADDRESS:
ParseStartAddress ();
default:
- Error ("Unexpected feature token");
+ FAIL ("Unexpected feature token");
}
/* Skip the semicolon */
CfgConsumeSemi ();
}
+
+ /* Remember we had this section */
+ SectionsEncountered |= SE_FEATURES;
}
static void ParseSymbols (void)
/* Parse a symbols section */
{
+ static const IdentTok Attributes[] = {
+ { "ADDRSIZE", CFGTOK_ADDRSIZE },
+ { "TYPE", CFGTOK_TYPE },
+ { "VALUE", CFGTOK_VALUE },
+ };
+
+ static const IdentTok AddrSizes [] = {
+ { "ABS", CFGTOK_ABS },
+ { "ABSOLUTE", CFGTOK_ABS },
+ { "DIRECT", CFGTOK_ZP },
+ { "DWORD", CFGTOK_LONG },
+ { "FAR", CFGTOK_FAR },
+ { "LONG", CFGTOK_LONG },
+ { "NEAR", CFGTOK_ABS },
+ { "ZEROPAGE", CFGTOK_ZP },
+ { "ZP", CFGTOK_ZP },
+ };
+
+ static const IdentTok Types [] = {
+ { "EXPORT", CFGTOK_EXPORT },
+ { "IMPORT", CFGTOK_IMPORT },
+ { "WEAK", CFGTOK_WEAK },
+ };
+
while (CfgTok == CFGTOK_IDENT) {
- long Val;
+ /* Bitmask to remember the attributes we got already */
+ enum {
+ atNone = 0x0000,
+ atAddrSize = 0x0001,
+ atType = 0x0002,
+ atValue = 0x0004,
+ };
+ unsigned AttrFlags = atNone;
+
+ ExprNode* Value = 0;
+ CfgSymType Type = CfgSymExport;
+ unsigned char AddrSize = ADDR_SIZE_ABS;
+ Import* Imp;
+ Export* Exp;
+ CfgSymbol* Sym;
/* Remember the name */
- char Name [sizeof (CfgSVal)];
- strcpy (Name, CfgSVal);
+ unsigned Name = GetStrBufId (&CfgSVal);
CfgNextTok ();
- /* Allow an optional assignment */
- CfgOptionalAssign ();
+ /* New syntax - skip the colon */
+ CfgNextTok ();
+
+ /* Parse the attributes */
+ while (1) {
+
+ /* Map the identifier to a token */
+ cfgtok_t AttrTok;
+ CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
+ AttrTok = CfgTok;
+
+ /* Skip the attribute name */
+ CfgNextTok ();
+
+ /* An optional assignment follows */
+ CfgOptionalAssign ();
+
+ /* Check which attribute was given */
+ switch (AttrTok) {
+
+ case CFGTOK_ADDRSIZE:
+ /* Don't allow this twice */
+ FlagAttr (&AttrFlags, atAddrSize, "ADDRSIZE");
+ /* Map the type to a token */
+ CfgSpecialToken (AddrSizes, ENTRY_COUNT (AddrSizes), "AddrSize");
+ switch (CfgTok) {
+ case CFGTOK_ABS: AddrSize = ADDR_SIZE_ABS; break;
+ case CFGTOK_FAR: AddrSize = ADDR_SIZE_FAR; break;
+ case CFGTOK_LONG: AddrSize = ADDR_SIZE_LONG; break;
+ case CFGTOK_ZP: AddrSize = ADDR_SIZE_ZP; break;
+ default:
+ Internal ("Unexpected token: %d", CfgTok);
+ }
+ CfgNextTok ();
+ break;
+
+ case CFGTOK_TYPE:
+ /* Don't allow this twice */
+ FlagAttr (&AttrFlags, atType, "TYPE");
+ /* Map the type to a token */
+ CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
+ switch (CfgTok) {
+ case CFGTOK_EXPORT: Type = CfgSymExport; break;
+ case CFGTOK_IMPORT: Type = CfgSymImport; break;
+ case CFGTOK_WEAK: Type = CfgSymWeak; break;
+ default:
+ Internal ("Unexpected token: %d", CfgTok);
+ }
+ CfgNextTok ();
+ break;
+
+ case CFGTOK_VALUE:
+ /* Don't allow this twice */
+ FlagAttr (&AttrFlags, atValue, "VALUE");
+ /* Value is an expression */
+ Value = CfgExpr ();
+ break;
+
+ default:
+ FAIL ("Unexpected attribute token");
+
+ }
+
+ /* Semicolon ends the decl, otherwise accept an optional comma */
+ if (CfgTok == CFGTOK_SEMI) {
+ break;
+ } else if (CfgTok == CFGTOK_COMMA) {
+ CfgNextTok ();
+ }
+ }
- /* Make sure the next token is an integer, read and skip it */
- CfgAssureInt ();
- Val = CfgIVal;
- CfgNextTok ();
+ /* We must have a type */
+ AttrCheck (AttrFlags, atType, "TYPE");
- /* Generate an export with the given value */
- CreateConstExport (Name, Val);
+ /* Further actions depend on the type */
+ switch (Type) {
- /* Skip the semicolon */
- CfgConsumeSemi ();
+ case CfgSymExport:
+ /* We must have a value */
+ AttrCheck (AttrFlags, atType, "TYPE");
+ /* Create the export */
+ Exp = CreateExprExport (Name, Value, AddrSize);
+ CollAppend (&Exp->DefLines, GenLineInfo (&CfgErrorPos));
+ break;
+
+ case CfgSymImport:
+ /* An import must not have a value */
+ if (AttrFlags & atValue) {
+ CfgError (&CfgErrorPos, "Imports must not have a value");
+ }
+ /* Generate the import */
+ Imp = InsertImport (GenImport (Name, AddrSize));
+ /* Remember the file position */
+ CollAppend (&Imp->DefLines, GenLineInfo (&CfgErrorPos));
+ break;
+
+ case CfgSymWeak:
+ /* We must have a value */
+ AttrCheck (AttrFlags, atType, "TYPE");
+ /* Remember the symbol for later */
+ Sym = NewCfgSymbol (CfgSymWeak, Name);
+ Sym->Value = Value;
+ Sym->AddrSize = AddrSize;
+ break;
+
+ default:
+ Internal ("Unexpected symbol type %d", Type);
+ }
+
+ /* Skip the semicolon */
+ CfgConsumeSemi ();
}
+
+ /* Remember we had this section */
+ SectionsEncountered |= SE_SYMBOLS;
}
-static void CreateRunDefines (Memory* M, SegDesc* S, unsigned long Addr)
+/*****************************************************************************/
+/* Config file processing */
+/*****************************************************************************/
+
+
+
+static void ProcessSegments (void)
+/* Process the SEGMENTS section */
+{
+ unsigned I;
+
+ /* Walk over the list of segment descriptors */
+ I = 0;
+ while (I < CollCount (&SegDescList)) {
+
+ /* Get the next segment descriptor */
+ SegDesc* S = CollAtUnchecked (&SegDescList, I);
+
+ /* Search for the actual segment in the input files. The function may
+ * return NULL (no such segment), this is checked later.
+ */
+ S->Seg = SegFind (S->Name);
+
+ /* 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)) {
+ CfgWarning (GetSourcePos (S->LI),
+ "Segment `%s' with type `bss' contains initialized data",
+ GetString (S->Name));
+ }
+
+ /* If this segment does exist in any of the object files, insert the
+ * segment into the load/run memory areas. Otherwise print a warning
+ * and discard it, because the segment pointer in the descriptor is
+ * invalid.
+ */
+ if (S->Seg != 0) {
+
+ /* 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);
+ }
+
+ /* Process the next segment descriptor in the next run */
+ ++I;
+
+ } else {
+
+ /* Print a warning if the segment is not optional */
+ if ((S->Flags & SF_OPTIONAL) == 0) {
+ CfgWarning (&CfgErrorPos,
+ "Segment `%s' does not exist",
+ GetString (S->Name));
+ }
+
+ /* Discard the descriptor and remove it from the collection */
+ FreeSegDesc (S);
+ CollDelete (&SegDescList, I);
+ }
+ }
+}
+
+
+
+static void ProcessSymbols (void)
+/* Process the SYMBOLS section */
+{
+ Export* E;
+
+ /* Walk over all symbols */
+ unsigned I;
+ for (I = 0; I < CollCount (&CfgSymbols); ++I) {
+
+ /* Get the next symbol */
+ CfgSymbol* Sym = CollAtUnchecked (&CfgSymbols, I);
+
+ /* Check what it is. */
+ switch (Sym->Type) {
+
+ case CfgSymO65Export:
+ /* Check if the export symbol is also defined as an import. */
+ if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
+ CfgError (
+ GetSourcePos (Sym->LI),
+ "Exported o65 symbol `%s' cannot also be an o65 import",
+ GetString (Sym->Name)
+ );
+ }
+
+ /* Check if we have this symbol defined already. The entry
+ * routine will check this also, but we get a more verbose
+ * error message when checking it here.
+ */
+ if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
+ CfgError (
+ GetSourcePos (Sym->LI),
+ "Duplicate exported o65 symbol: `%s'",
+ GetString (Sym->Name)
+ );
+ }
+
+ /* Insert the symbol into the table */
+ O65SetExport (O65FmtDesc, Sym->Name);
+ break;
+
+ case CfgSymO65Import:
+ /* Check if the import symbol is also defined as an export. */
+ if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
+ CfgError (
+ GetSourcePos (Sym->LI),
+ "Imported o65 symbol `%s' cannot also be an o65 export",
+ GetString (Sym->Name)
+ );
+ }
+
+ /* Check if we have this symbol defined already. The entry
+ * routine will check this also, but we get a more verbose
+ * error message when checking it here.
+ */
+ if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
+ CfgError (
+ GetSourcePos (Sym->LI),
+ "Duplicate imported o65 symbol: `%s'",
+ GetString (Sym->Name)
+ );
+ }
+
+ /* Insert the symbol into the table */
+ O65SetImport (O65FmtDesc, Sym->Name);
+ break;
+
+ case CfgSymWeak:
+ /* If the symbol is not defined until now, define it */
+ if ((E = FindExport (Sym->Name)) == 0 || IsUnresolvedExport (E)) {
+ /* The symbol is undefined, generate an export */
+ E = CreateExprExport (Sym->Name, Sym->Value, Sym->AddrSize);
+ CollAppend (&E->DefLines, Sym->LI);
+ }
+ break;
+
+ default:
+ Internal ("Unexpected symbol type %d", Sym->Type);
+ break;
+ }
+ }
+
+}
+
+
+
+static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
/* Create the defines for a RUN segment */
{
- char Buf [256];
+ Export* E;
+ StrBuf Buf = STATIC_STRBUF_INITIALIZER;
+
+ /* Define the run address of the segment */
+ SB_Printf (&Buf, "__%s_RUN__", GetString (S->Name));
+ E = CreateMemoryExport (GetStrBufId (&Buf), S->Run, SegAddr - S->Run->Start);
+ CollAppend (&E->DefLines, S->LI);
+
+ /* Define the size of the segment */
+ SB_Printf (&Buf, "__%s_SIZE__", GetString (S->Name));
+ E = CreateConstExport (GetStrBufId (&Buf), S->Seg->Size);
+ CollAppend (&E->DefLines, S->LI);
- sprintf (Buf, "__%s_RUN__", S->Name);
- CreateMemExport (Buf, M, Addr - M->Start);
- sprintf (Buf, "__%s_SIZE__", S->Name);
- CreateConstExport (Buf, S->Seg->Size);
S->Flags |= SF_RUN_DEF;
+ SB_Done (&Buf);
}
-static void CreateLoadDefines (Memory* M, SegDesc* S, unsigned long Addr)
+static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
/* Create the defines for a LOAD segment */
{
- char Buf [256];
+ Export* E;
+ StrBuf Buf = STATIC_STRBUF_INITIALIZER;
+
+ /* Define the load address of the segment */
+ SB_Printf (&Buf, "__%s_LOAD__", GetString (S->Name));
+ E = CreateMemoryExport (GetStrBufId (&Buf), S->Load, SegAddr - S->Load->Start);
+ CollAppend (&E->DefLines, S->LI);
- sprintf (Buf, "__%s_LOAD__", S->Name);
- CreateMemExport (Buf, M, Addr - M->Start);
S->Flags |= SF_LOAD_DEF;
+ SB_Done (&Buf);
}
-void CfgAssignSegments (void)
-/* Assign segments, define linker symbols where requested */
+unsigned CfgProcess (void)
+/* Process the config file after reading in object files and libraries. This
+ * includes postprocessing of the config file data but also assigning segments
+ * and defining segment/memory area related symbols. The function will return
+ * the number of memory area overflows (so zero means anything went ok).
+ * In case of overflows, a short mapfile can be generated later, to ease the
+ * task of rearranging segments for the user.
+ */
{
+ unsigned Overflows = 0;
+ unsigned I;
+
+ /* Postprocess symbols. We must do that first, since weak symbols are
+ * defined here, which may be needed later.
+ */
+ ProcessSymbols ();
+
+ /* Postprocess segments */
+ ProcessSegments ();
+
/* Walk through each of the memory sections. Add up the sizes and check
* for an overflow of the section. Assign the start addresses of the
* segments while doing this.
*/
- Memory* M = MemoryList;
- while (M) {
+ for (I = 0; I < CollCount (&MemoryAreas); ++I) {
- /* Get the start address of this memory area */
- unsigned long Addr = M->Start;
+ unsigned J;
+ unsigned long Addr;
- /* Walk through the segments in this memory area */
- MemListNode* N = M->SegList;
- while (N) {
-
- /* Get the segment from the node */
- SegDesc* S = N->Seg;
-
- /* Handle ALIGN and OFFSET/START */
- if (S->Flags & SF_ALIGN) {
- /* Align the address */
- unsigned long Val = (0x01UL << S->Align) - 1;
- Addr = (Addr + Val) & ~Val;
- } else if (S->Flags & (SF_OFFSET | SF_START)) {
- /* Give the segment a fixed starting address */
- unsigned long NewAddr = S->Addr;
- if (S->Flags & SF_OFFSET) {
- /* An offset was given, no address, make an address */
- NewAddr += M->Start;
- }
- if (Addr > NewAddr) {
- /* Offset already too large */
- if (S->Flags & SF_OFFSET) {
- Error ("Offset too small in `%s', segment `%s'",
- M->Name, S->Name);
- } else {
- Error ("Start address too low in `%s', segment `%s'",
- M->Name, S->Name);
- }
- }
- Addr = NewAddr;
- }
+ /* Get the next memory area */
+ MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
- /* If this is the run area, set the start address of this segment */
- if (S->Run == M) {
- S->Seg->PC = Addr;
- }
+ /* Remember if this is a relocatable memory area */
+ M->Relocatable = RelocatableBinFmt (M->F->Format);
+
+ /* Resolve the start address expression, remember the start address
+ * and mark the memory area as placed.
+ */
+ if (!IsConstExpr (M->StartExpr)) {
+ CfgError (GetSourcePos (M->LI),
+ "Start address of memory area `%s' is not constant",
+ GetString (M->Name));
+ }
+ Addr = M->Start = GetExprVal (M->StartExpr);
+ M->Flags |= MF_PLACED;
+
+ /* If requested, define the symbol for the start of the memory area.
+ * Doing it here means that the expression for the size of the area
+ * may reference this symbol.
+ */
+ if (M->Flags & MF_DEFINE) {
+ Export* E;
+ StrBuf Buf = STATIC_STRBUF_INITIALIZER;
+
+ /* Define the start of the memory area */
+ SB_Printf (&Buf, "__%s_START__", GetString (M->Name));
+ E = CreateMemoryExport (GetStrBufId (&Buf), M, 0);
+ CollAppend (&E->DefLines, M->LI);
+
+ SB_Done (&Buf);
+ }
+
+ /* Resolve the size expression */
+ if (!IsConstExpr (M->SizeExpr)) {
+ CfgError (GetSourcePos (M->LI),
+ "Size of memory area `%s' is not constant",
+ GetString (M->Name));
+ }
+ M->Size = GetExprVal (M->SizeExpr);
+
+ /* Walk through the segments in this memory area */
+ for (J = 0; J < CollCount (&M->SegList); ++J) {
+
+ /* Get the segment */
+ SegDesc* S = CollAtUnchecked (&M->SegList, J);
+
+ /* Some actions depend on wether this is the load or run memory
+ * area.
+ */
+ if (S->Run == M) {
+
+ /* This is the run (and maybe load) memory area. Handle
+ * alignment and explict start address and offset.
+ */
+ if (S->Flags & SF_ALIGN) {
+ /* Align the address */
+ 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_OFFSET) {
+ /* An offset was given, no address, make an address */
+ NewAddr += M->Start;
+ }
+ if (Addr > NewAddr) {
+ /* Offset already too large */
+ if (S->Flags & SF_OFFSET) {
+ CfgError (GetSourcePos (M->LI),
+ "Offset too small in `%s', segment `%s'",
+ GetString (M->Name),
+ GetString (S->Name));
+ } else {
+ CfgError (GetSourcePos (M->LI),
+ "Start address too low in `%s', segment `%s'",
+ GetString (M->Name),
+ GetString (S->Name));
+ }
+ }
+ Addr = NewAddr;
+ }
+
+ /* Set the start address of this segment, set the readonly flag
+ * in the segment and and remember if the segment is in a
+ * relocatable file or not.
+ */
+ S->Seg->PC = Addr;
+ S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
+ S->Seg->Relocatable = M->Relocatable;
+
+ /* Remember that this segment is placed */
+ S->Seg->Placed = 1;
+
+ } else if (S->Load == M) {
+
+ /* This is the load memory area, *and* run and load are
+ * different (because of the "else" above). Handle alignment.
+ */
+ if (S->Flags & SF_ALIGN_LOAD) {
+ /* Align the address */
+ Addr = AlignAddr (Addr, S->LoadAlignment);
+ }
+
+ }
/* Increment the fill level of the memory area and check for an
* overflow.
*/
M->FillLevel = Addr + S->Seg->Size - M->Start;
- if (M->FillLevel > M->Size) {
- Error ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
- M->Name, S->Name, M->FillLevel - M->Size);
+ if (M->FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) {
+ ++Overflows;
+ M->Flags |= MF_OVERFLOW;
+ CfgWarning (GetSourcePos (M->LI),
+ "Memory area overflow in `%s', segment `%s' (%lu bytes)",
+ GetString (M->Name), GetString (S->Name),
+ M->FillLevel - M->Size);
}
/* If requested, define symbols for the start and size of the
* segment.
*/
if (S->Flags & SF_DEFINE) {
- if ((S->Flags & SF_LOAD_AND_RUN) && S->Run == S->Load) {
- /* RUN and LOAD given and in one memory area.
- * Be careful: We will encounter this code twice, the
- * first time when walking the RUN list, second time when
- * walking the LOAD list. Be sure to define only the
- * relevant symbols on each walk.
- */
- if (S->Load == M) {
- if ((S->Flags & SF_LOAD_DEF) == 0) {
- CreateLoadDefines (M, S, Addr);
- } else {
- CHECK ((S->Flags & SF_RUN_DEF) == 0);
- CreateRunDefines (M, S, Addr);
- }
- }
- } else {
- /* RUN and LOAD in different memory areas, or RUN not
- * given, so RUN defaults to LOAD. In the latter case, we
- * have only one copy of the segment in the area.
- */
- if (S->Run == M) {
- CreateRunDefines (M, S, Addr);
- }
- if (S->Load == M) {
- CreateLoadDefines (M, S, Addr);
- }
- }
+ if (S->Run == M && (S->Flags & SF_RUN_DEF) == 0) {
+ CreateRunDefines (S, Addr);
+ }
+ if (S->Load == M && (S->Flags & SF_LOAD_DEF) == 0) {
+ CreateLoadDefines (S, Addr);
+ }
}
/* Calculate the new address */
Addr += S->Seg->Size;
- /* Next segment */
- N = N->Next;
}
/* If requested, define symbols for start and size of the memory area */
if (M->Flags & MF_DEFINE) {
- char Buf [256];
- sprintf (Buf, "__%s_START__", M->Name);
- CreateMemExport (Buf, M, 0);
- sprintf (Buf, "__%s_SIZE__", M->Name);
- CreateConstExport (Buf, M->Size);
- sprintf (Buf, "__%s_LAST__", M->Name);
- CreateConstExport (Buf, M->FillLevel);
+ Export* E;
+ StrBuf Buf = STATIC_STRBUF_INITIALIZER;
+
+ /* Define the size of the memory area */
+ SB_Printf (&Buf, "__%s_SIZE__", GetString (M->Name));
+ E = CreateConstExport (GetStrBufId (&Buf), M->Size);
+ CollAppend (&E->DefLines, M->LI);
+
+ /* Define the fill level of the memory area */
+ SB_Printf (&Buf, "__%s_LAST__", GetString (M->Name));
+ E = CreateMemoryExport (GetStrBufId (&Buf), M, M->FillLevel);
+ CollAppend (&E->DefLines, M->LI);
+
+ SB_Done (&Buf);
}
- /* Next memory area */
- M = M->Next;
}
+
+ /* Return the number of memory area overflows */
+ return Overflows;
}
void CfgWriteTarget (void)
/* Write the target file(s) */
{
- Memory* M;
+ unsigned I;
/* Walk through the files list */
- File* F = FileList;
- while (F) {
- /* We don't need to look at files with no memory areas */
- if (F->MemList) {
+ for (I = 0; I < CollCount (&FileList); ++I) {
+
+ /* Get this entry */
+ File* F = CollAtUnchecked (&FileList, I);
+
+ /* We don't need to look at files with no memory areas */
+ if (CollCount (&F->MemoryAreas) > 0) {
/* Is there an output file? */
- if (strlen (F->Name) > 0) {
+ if (SB_GetLen (GetStrBuf (F->Name)) > 0) {
/* Assign a proper binary format */
if (F->Format == BINFMT_DEFAULT) {
switch (F->Format) {
case BINFMT_BINARY:
- BinWriteTarget (BinFmtDesc, F);
- break;
+ BinWriteTarget (BinFmtDesc, F);
+ break;
case BINFMT_O65:
- O65WriteTarget (O65FmtDesc, F);
- break;
+ O65WriteTarget (O65FmtDesc, F);
+ break;
default:
Internal ("Invalid binary format: %u", F->Format);
/* No output file. Walk through the list and mark all segments
* loading into these memory areas in this file as dumped.
*/
- M = F->MemList;
- while (M) {
+ unsigned J;
+ for (J = 0; J < CollCount (&F->MemoryAreas); ++J) {
+
+ unsigned K;
- MemListNode* N;
+ /* Get this entry */
+ MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, J);
/* Debugging */
- Print (stdout, 2, "Skipping `%s'...\n", M->Name);
+ Print (stdout, 2, "Skipping `%s'...\n", GetString (M->Name));
/* Walk throught the segments */
- N = M->SegList;
- while (N) {
- if (N->Seg->Load == M) {
- /* Load area - mark the segment as dumped */
- N->Seg->Seg->Dumped = 1;
- }
-
- /* Next segment node */
- N = N->Next;
+ for (K = 0; K < CollCount (&M->SegList); ++K) {
+ SegDesc* S = CollAtUnchecked (&M->SegList, K);
+ if (S->Load == M) {
+ /* Load area - mark the segment as dumped */
+ S->Seg->Dumped = 1;
+ }
}
- /* Next memory area */
- M = M->FNext;
}
}
}
-
- /* Next file */
- F = F->Next;
}
}