]> git.sur5r.net Git - cc65/blobdiff - src/ld65/config.c
Add support for Atari XEX file format to LD65
[cc65] / src / ld65 / config.c
index 5317e7015bf4297148bcd6d1a459b3642bae3a05..fdf7d13eb7da070124eae38ff8eb855352bb867f 100644 (file)
@@ -1,15 +1,19 @@
 /*****************************************************************************/
 /*                                                                           */
-/*                                config.c                                  */
+/*                                 config.c                                  */
 /*                                                                           */
-/*              Target configuration file for the ld65 linker               */
+/*               Target configuration file for the ld65 linker               */
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2005 Ullrich von Bassewitz                                       */
-/*               Römerstrasse 52                                             */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/* (c) 1998-2013, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
+/*                                                                           */
+/* With contributions from:                                                  */
+/*                                                                           */
+/*      - "David M. Lloyd" <david.lloyd@redhat.com>                          */
 /*                                                                           */
 /*                                                                           */
 /* 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 "segdefs.h"
+#include "target.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 "spool.h"
+#include "xex.h"
 
 
 
 /*****************************************************************************/
-/*                                          Data                                    */
+/*                                   Data                                    */
 /*****************************************************************************/
 
 
@@ -79,52 +92,70 @@ static enum {
 
 
 /* File list */
-static File*           FileList;       /* Single linked list */
-static unsigned                FileCount;      /* Number of entries in the 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_SIZE                0x0002
-#define MA_TYPE                0x0004
-#define MA_FILE                0x0008
-#define MA_DEFINE              0x0010
-#define MA_FILL                0x0020
-#define MA_FILLVAL             0x0040
-
-
+#define MA_START        0x0001
+#define MA_SIZE         0x0002
+#define MA_TYPE         0x0004
+#define MA_FILE         0x0008
+#define MA_DEFINE       0x0010
+#define MA_FILL         0x0020
+#define MA_FILLVAL      0x0040
+#define MA_BANK         0x0080
 
 /* 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_TYPE         0x0001
+#define SA_LOAD         0x0002
+#define SA_RUN          0x0004
+#define SA_ALIGN        0x0008
 #define SA_ALIGN_LOAD   0x0010
-#define SA_DEFINE      0x0020
-#define SA_OFFSET      0x0040
-#define SA_START       0x0080
+#define SA_DEFINE       0x0020
+#define SA_OFFSET       0x0040
+#define SA_START        0x0080
 #define SA_OPTIONAL     0x0100
-
-
+#define SA_FILLVAL      0x0200
+
+/* 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 O65Desc* O65FmtDesc     = 0;
+static BinDesc* BinFmtDesc      = 0;
+static O65Desc* O65FmtDesc      = 0;
+static XexDesc* XexFmtDesc      = 0;
 
 
 
 /*****************************************************************************/
-/*                                Forwards                                  */
+/*                                 Forwards                                  */
 /*****************************************************************************/
 
 
@@ -135,7 +166,7 @@ static File* NewFile (unsigned Name);
 
 
 /*****************************************************************************/
-/*                             List management                              */
+/*                              List management                              */
 /*****************************************************************************/
 
 
@@ -143,12 +174,12 @@ static File* NewFile (unsigned Name);
 static File* FindFile (unsigned Name)
 /* Find a file with a given name. */
 {
-    File* F = FileList;
-    while (F) {
-       if (F->Name == Name) {
-           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;
 }
@@ -160,50 +191,44 @@ static File* GetFile (unsigned Name)
 {
     File* F = FindFile (Name);
     if (F == 0) {
-       /* Create a new one */
-       F = NewFile (Name);
+        /* Create a new one */
+        F = NewFile (Name);
     }
     return F;
 }
 
 
 
-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 (unsigned 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 (M->Name == Name) {
-                   return M;
-               }
-               M = M->Next;
+    unsigned I;
+    for (I = 0; I < CollCount (&MemoryAreas); ++I) {
+        MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
+        if (M->Name == Name) {
+            return M;
+        }
     }
     return 0;
 }
 
 
 
-static Memory* CfgGetMemory (unsigned 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'", GetString (Name));
+        CfgError (&CfgErrorPos, "Invalid memory area '%s'", GetString (Name));
     }
     return M;
 }
@@ -213,13 +238,13 @@ static Memory* CfgGetMemory (unsigned 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 (S->Name == Name) {
-           /* Found */
-           return S;
-               }
-       S = S->Next;
+    unsigned I;
+    for (I = 0; I < CollCount (&SegDescList); ++I) {
+        SegDesc* S = CollAtUnchecked (&SegDescList, I);
+        if (S->Name == Name) {
+            /* Found */
+            return S;
+        }
     }
 
     /* Not found */
@@ -228,39 +253,43 @@ static SegDesc* CfgFindSegDesc (unsigned Name)
 
 
 
-static void SegDescInsert (SegDesc* S)
-/* Insert a segment descriptor into the list of segment descriptors */
+static void MemoryInsert (MemoryArea* M, SegDesc* S)
+/* Insert the segment descriptor into the memory area list */
 {
-    /* Insert the struct into the list */
-    S->Next = SegDescList;
-    SegDescList = S;
-    ++SegDescCount;
+    /* Insert the segment into the segment list of the memory area */
+    CollAppend (&M->SegList, S);
 }
 
 
 
-static void MemoryInsert (Memory* M, SegDesc* S)
-/* Insert the segment descriptor into the memory area list */
+/*****************************************************************************/
+/*                         Constructors/Destructors                          */
+/*****************************************************************************/
+
+
+
+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.
+*/
 {
-    /* 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;
-}
+    /* 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);
 
-/*****************************************************************************/
-/*                        Constructors/Destructors                          */
-/*****************************************************************************/
+    /* Return the initialized struct */
+    return Sym;
+}
 
 
 
@@ -274,13 +303,11 @@ static File* NewFile (unsigned Name)
     F->Name    = Name;
     F->Flags   = 0;
     F->Format  = BINFMT_DEFAULT;
-    F->MemList = 0;
-    F->MemLast = 0;
+    F->Size    = 0;
+    InitCollection (&F->MemoryAreas);
 
     /* Insert the struct into the list */
-    F->Next  = FileList;
-    FileList = F;
-    ++FileCount;
+    CollAppend (&FileList, F);
 
     /* ...and return it */
     return F;
@@ -288,42 +315,22 @@ static File* NewFile (unsigned Name)
 
 
 
-static Memory* NewMemory (unsigned 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 */
 {
     /* Check for duplicate names */
-    Memory* M =        CfgFindMemory (Name);
+    MemoryArea* M = CfgFindMemory (Name);
     if (M) {
-       CfgError ("Memory area `%s' defined twice", GetString (Name));
+        CfgError (&CfgErrorPos,
+                  "Memory area '%s' defined twice",
+                  GetString (Name));
     }
 
-    /* Allocate memory */
-    M = xmalloc (sizeof (Memory));
+    /* Create a new memory area */
+    M = NewMemoryArea (Pos, Name);
 
-    /* Initialize the fields */
-    M->Name        = Name;
-    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->Relocatable = 0;
-    M->SegList     = 0;
-    M->SegLast     = 0;
-    M->F           = 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;
@@ -332,31 +339,30 @@ static Memory* NewMemory (unsigned Name)
 
 
 static SegDesc* NewSegDesc (unsigned Name)
-/* Create a segment descriptor */
+/* Create a segment descriptor and insert it into the list */
 {
-    Segment* Seg;
 
     /* Check for duplicate names */
     SegDesc* S = CfgFindSegDesc (Name);
     if (S) {
-       CfgError ("Segment `%s' defined twice", GetString (Name));
+        CfgError (&CfgErrorPos, "Segment '%s' defined twice", GetString (Name));
     }
 
-    /* Search for the actual segment in the input files. The function may
-     * return NULL (no such segment), this is checked later.
-     */
-    Seg = SegFind (Name);
-
     /* Allocate memory */
     S = xmalloc (sizeof (SegDesc));
 
     /* Initialize the fields */
-    S->Name    = Name;
-    S->Next    = 0;
-    S->Seg     = Seg;
-    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->FillVal       = 0;
+    S->RunAlignment  = 1;
+    S->LoadAlignment = 1;
+
+    /* Insert the struct into the list ... */
+    CollAppend (&SegDescList, S);
 
     /* ...and return it */
     return S;
@@ -367,24 +373,25 @@ static SegDesc* NewSegDesc (unsigned Name)
 static void FreeSegDesc (SegDesc* S)
 /* Free a segment descriptor */
 {
+    FreeLineInfo (S->LI);
     xfree (S);
 }
 
 
 
 /*****************************************************************************/
-/*                                          Code                                    */
+/*                            Config file parsing                            */
 /*****************************************************************************/
 
 
 
 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
 /* Check if the item is already defined. Print an error if so. If not, set
- * the marker that we have a definition now.
- */
+** the marker that we have a definition now.
+*/
 {
     if (*Flags & Mask) {
-       CfgError ("%s is already defined", Name);
+        CfgError (&CfgErrorPos, "%s is already defined", Name);
     }
     *Flags |= Mask;
 }
@@ -395,7 +402,7 @@ static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
 /* Check that a mandatory attribute was given */
 {
     if ((Attr & Mask) == 0) {
-       CfgError ("%s attribute is missing", Name);
+        CfgError (&CfgErrorPos, "%s attribute is missing", Name);
     }
 }
 
@@ -405,118 +412,124 @@ static void ParseMemory (void)
 /* Parse a MEMORY section */
 {
     static const IdentTok Attributes [] = {
-               {   "START",    CFGTOK_START    },
-       {   "SIZE",     CFGTOK_SIZE     },
-        {   "TYPE",     CFGTOK_TYPE     },
-        {   "FILE",     CFGTOK_FILE     },
+        {   "BANK",     CFGTOK_BANK     },
         {   "DEFINE",   CFGTOK_DEFINE   },
-       {   "FILL",     CFGTOK_FILL     },
-               {   "FILLVAL",  CFGTOK_FILLVAL  },
+        {   "FILE",     CFGTOK_FILE     },
+        {   "FILL",     CFGTOK_FILL     },
+        {   "FILLVAL",  CFGTOK_FILLVAL  },
+        {   "SIZE",     CFGTOK_SIZE     },
+        {   "START",    CFGTOK_START    },
+        {   "TYPE",     CFGTOK_TYPE     },
     };
     static const IdentTok Types [] = {
-               {   "RO",       CFGTOK_RO       },
-               {   "RW",       CFGTOK_RW       },
+        {   "RO",       CFGTOK_RO       },
+        {   "RW",       CFGTOK_RW       },
     };
 
     while (CfgTok == CFGTOK_IDENT) {
 
-       /* Create a new entry on the heap */
-               Memory* M = NewMemory (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_START:
-                   FlagAttr (&M->Attr, MA_START, "START");
-                   CfgAssureInt ();
-                   M->Start = CfgIVal;
-                   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;
-
-               case CFGTOK_FILE:
-                   FlagAttr (&M->Attr, MA_FILE, "FILE");
-                   CfgAssureStr ();
-                           /* Get the file entry and insert the memory area */
-                   FileInsert (GetFile (GetStringId (CfgSVal)), M);
-                   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;
-
-               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;
-
-               case CFGTOK_FILLVAL:
-                   FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
-                   CfgAssureInt ();
-                   CfgRangeCheck (0, 0xFF);
-                   M->FillVal = (unsigned char) CfgIVal;
-                   break;
-
-               default:
-                   FAIL ("Unexpected attribute token");
-
-           }
-
-           /* Skip the attribute value and an optional comma */
-           CfgNextTok ();
-           CfgOptionalComma ();
-       }
-
-       /* Skip the semicolon */
-       CfgConsumeSemi ();
-
-       /* Check for mandatory parameters */
-               AttrCheck (M->Attr, MA_START, "START");
-       AttrCheck (M->Attr, MA_SIZE, "SIZE");
-
-       /* If we don't have a file name for output given, use the default
-        * file name.
-        */
-       if ((M->Attr & MA_FILE) == 0) {
-           FileInsert (GetFile (GetStringId (OutputName)), M);
-       }
+        /* Create a new entry on the heap */
+        MemoryArea* M = CreateMemoryArea (&CfgErrorPos, GetStrBufId (&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_BANK:
+                    FlagAttr (&M->Attr, MA_BANK, "BANK");
+                    M->BankExpr = CfgExpr ();
+                    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;
+                    }
+                    CfgNextTok ();
+                    break;
+
+                case CFGTOK_FILE:
+                    FlagAttr (&M->Attr, MA_FILE, "FILE");
+                    CfgAssureStr ();
+                    /* Get the file entry and insert the memory area */
+                    FileInsert (GetFile (GetStrBufId (&CfgSVal)), M);
+                    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;
+                    }
+                    CfgNextTok ();
+                    break;
+
+                case CFGTOK_FILLVAL:
+                    FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
+                    M->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
+                    break;
+
+                case CFGTOK_SIZE:
+                    FlagAttr (&M->Attr, MA_SIZE, "SIZE");
+                    M->SizeExpr = CfgExpr ();
+                    break;
+
+                case CFGTOK_START:
+                    FlagAttr (&M->Attr, MA_START, "START");
+                    M->StartExpr = 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;
+
+                default:
+                    FAIL ("Unexpected attribute token");
+
+            }
+
+            /* Skip an optional comma */
+            CfgOptionalComma ();
+        }
+
+        /* Skip the semicolon */
+        CfgConsumeSemi ();
+
+        /* Check for mandatory parameters */
+        AttrCheck (M->Attr, MA_START, "START");
+        AttrCheck (M->Attr, MA_SIZE, "SIZE");
+
+        /* If we don't have a file name for output given, use the default
+        ** file name.
+        */
+        if ((M->Attr & MA_FILE) == 0) {
+            FileInsert (GetFile (GetStringId (OutputName)), M);
+            OutputNameUsed = 1;
+        }
     }
 
     /* Remember we had this section */
@@ -529,93 +542,101 @@ static void ParseFiles (void)
 /* Parse a FILES section */
 {
     static const IdentTok Attributes [] = {
-               {   "FORMAT",   CFGTOK_FORMAT   },
+        {   "FORMAT",   CFGTOK_FORMAT   },
     };
     static const IdentTok Formats [] = {
-               {   "O65",      CFGTOK_O65           },
-               {   "BIN",      CFGTOK_BIN      },
-               {   "BINARY",   CFGTOK_BIN      },
+        {   "ATARI",    CFGTOK_ATARIEXE },
+        {   "O65",      CFGTOK_O65      },
+        {   "BIN",      CFGTOK_BIN      },
+        {   "BINARY",   CFGTOK_BIN      },
     };
 
 
     /* The MEMORY section must preceed the FILES section */
     if ((SectionsEncountered & SE_MEMORY) == 0) {
-        CfgError ("MEMORY must precede FILES");
+        CfgError (&CfgErrorPos, "MEMORY must precede FILES");
     }
 
     /* Parse all files */
     while (CfgTok != CFGTOK_RCURLY) {
 
-       File* F;
+        File* F;
 
-       /* We expect a string value here */
-       CfgAssureStr ();
+        /* We expect a string value here */
+        CfgAssureStr ();
 
-       /* Search for the file, it must exist */
-               F = FindFile (GetStringId (CfgSVal));
-       if (F == 0) {
-                   CfgError ("File `%s' not found in MEMORY section", CfgSVal);
-       }
+        /* Search for the file, it must exist */
+        F = FindFile (GetStrBufId (&CfgSVal));
+        if (F == 0) {
+            CfgError (&CfgErrorPos,
+                      "File '%s' not found in MEMORY section",
+                      SB_GetConstBuf (&CfgSVal));
+        }
 
-       /* Skip the token and the following colon */
-       CfgNextTok ();
-       CfgConsumeColon ();
+        /* Skip the token and the following colon */
+        CfgNextTok ();
+        CfgConsumeColon ();
 
-       /* Read the attributes */
-       while (CfgTok == CFGTOK_IDENT) {
+        /* Read the attributes */
+        while (CfgTok == CFGTOK_IDENT) {
 
-           /* Map the identifier to a token */
-           cfgtok_t AttrTok;
-           CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
-           AttrTok = CfgTok;
+            /* Map the identifier to a token */
+            cfgtok_t AttrTok;
+            CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
+            AttrTok = CfgTok;
 
-           /* An optional assignment follows */
-           CfgNextTok ();
-           CfgOptionalAssign ();
+            /* An optional assignment follows */
+            CfgNextTok ();
+            CfgOptionalAssign ();
 
-           /* Check which attribute was given */
-           switch (AttrTok) {
+            /* Check which attribute was given */
+            switch (AttrTok) {
 
-               case CFGTOK_FORMAT:
-                   if (F->Format != BINFMT_DEFAULT) {
-                       /* We've set the format already! */
-                       Error ("Cannot set a file format twice");
-                   }
-                   /* Read the format token */
-                   CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
-                   switch (CfgTok) {
+                case CFGTOK_FORMAT:
+                    if (F->Format != BINFMT_DEFAULT) {
+                        /* We've set the format already! */
+                        CfgError (&CfgErrorPos,
+                                  "Cannot set a file format twice");
+                    }
+                    /* Read the format token */
+                    CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
+                    switch (CfgTok) {
 
-                       case CFGTOK_BIN:
-                           F->Format = BINFMT_BINARY;
-                           break;
+                        case CFGTOK_BIN:
+                            F->Format = BINFMT_BINARY;
+                            break;
 
-                       case CFGTOK_O65:
-                           F->Format = BINFMT_O65;
-                           break;
+                        case CFGTOK_O65:
+                            F->Format = BINFMT_O65;
+                            break;
 
-                       default:
-                           Error ("Unexpected format token");
-                   }
-                   break;
+                        case CFGTOK_ATARIEXE:
+                            F->Format = BINFMT_ATARIEXE;
+                            break;
 
-               default:
-                   FAIL ("Unexpected attribute token");
+                        default:
+                            Error ("Unexpected format token");
+                    }
+                    break;
+
+                default:
+                    FAIL ("Unexpected attribute token");
 
-           }
+            }
 
-           /* Skip the attribute value and an optional comma */
-           CfgNextTok ();
-           CfgOptionalComma ();
-       }
+            /* Skip the attribute value and an optional comma */
+            CfgNextTok ();
+            CfgOptionalComma ();
+        }
 
-       /* Skip the semicolon */
-       CfgConsumeSemi ();
+        /* Skip the semicolon */
+        CfgConsumeSemi ();
 
     }
 
     /* Remember we had this section */
     SectionsEncountered |= SE_FILES;
-}                                     
+}
 
 
 
@@ -626,218 +647,188 @@ static void ParseSegments (void)
         {   "ALIGN",            CFGTOK_ALIGN            },
         {   "ALIGN_LOAD",       CFGTOK_ALIGN_LOAD       },
         {   "DEFINE",           CFGTOK_DEFINE           },
-               {   "LOAD",             CFGTOK_LOAD             },
-       {   "OFFSET",           CFGTOK_OFFSET           },
+        {   "FILLVAL",          CFGTOK_FILLVAL          },
+        {   "LOAD",             CFGTOK_LOAD             },
+        {   "OFFSET",           CFGTOK_OFFSET           },
         {   "OPTIONAL",         CFGTOK_OPTIONAL         },
-       {   "RUN",              CFGTOK_RUN              },
-       {   "START",            CFGTOK_START            },
+        {   "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               },
+        {   "RO",               CFGTOK_RO               },
+        {   "RW",               CFGTOK_RW               },
+        {   "BSS",              CFGTOK_BSS              },
+        {   "ZP",               CFGTOK_ZP               },
+        {   "OVERWRITE",        CFGTOK_OVERWRITE        },
     };
 
     unsigned Count;
 
     /* The MEMORY section must preceed the SEGMENTS section */
     if ((SectionsEncountered & SE_MEMORY) == 0) {
-        CfgError ("MEMORY must precede SEGMENTS");
+        CfgError (&CfgErrorPos, "MEMORY must precede SEGMENTS");
     }
 
     while (CfgTok == CFGTOK_IDENT) {
 
-       SegDesc* S;
+        SegDesc* S;
 
-       /* Create a new entry on the heap */
-               S = NewSegDesc (GetStringId (CfgSVal));
+        /* Create a new entry on the heap */
+        S = NewSegDesc (GetStrBufId (&CfgSVal));
 
-       /* Skip the name and the following colon */
-       CfgNextTok ();
-       CfgConsumeColon ();
+        /* Skip the name and the following colon */
+        CfgNextTok ();
+        CfgConsumeColon ();
 
-               /* Read the attributes */
-       while (CfgTok == CFGTOK_IDENT) {
+        /* Read the attributes */
+        while (CfgTok == CFGTOK_IDENT) {
 
-           /* Map the identifier to a token */
-           cfgtok_t AttrTok;
-           CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
-           AttrTok = CfgTok;
+            /* Map the identifier to a token */
+            cfgtok_t AttrTok;
+            CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
+            AttrTok = CfgTok;
 
-           /* An optional assignment follows */
-           CfgNextTok ();
-           CfgOptionalAssign ();
+            /* An optional assignment follows */
+            CfgNextTok ();
+            CfgOptionalAssign ();
 
-           /* Check which attribute was given */
-           switch (AttrTok) {
+            /* Check which attribute was given */
+            switch (AttrTok) {
 
-               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_ALIGN:
+                    FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
+                    S->RunAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
+                    S->Flags |= SF_ALIGN;
+                    break;
 
                 case CFGTOK_ALIGN_LOAD:
-                   CfgAssureInt ();
-                   FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
-                   CfgRangeCheck (1, 0x10000);
-                           S->AlignLoad = BitFind (CfgIVal);
-                   if ((0x01UL << S->AlignLoad) != CfgIVal) {
-                       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;
-                   }
-                   break;
-
-               case CFGTOK_LOAD:
-                   FlagAttr (&S->Attr, SA_LOAD, "LOAD");
-                   S->Load = CfgGetMemory (GetStringId (CfgSVal));
-                   break;
-
-               case CFGTOK_OFFSET:
-                   CfgAssureInt ();
-                   FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
-                   CfgRangeCheck (1, 0x1000000);
-                   S->Addr   = CfgIVal;
-                   S->Flags |= SF_OFFSET;
-                   break;
-
-               case CFGTOK_OPTIONAL:
-                   FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL");
-                   CfgBoolToken ();
-                   if (CfgTok == CFGTOK_TRUE) {
-                       S->Flags |= SF_OPTIONAL;
-                   }
-                   break;
-
-               case CFGTOK_RUN:
-                   FlagAttr (&S->Attr, SA_RUN, "RUN");
-                   S->Run = CfgGetMemory (GetStringId (CfgSVal));
-                   break;
-
-               case CFGTOK_START:
-                   CfgAssureInt ();
-                   FlagAttr (&S->Attr, SA_START, "START");
-                   CfgRangeCheck (1, 0x1000000);
-                   S->Addr   = CfgIVal;
-                   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);
-                   }
-                   break;
-
-               default:
-                           FAIL ("Unexpected attribute token");
-
-           }
-
-           /* Skip the attribute value and an optional comma */
-           CfgNextTok ();
-           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);
-       }
+                    FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
+                    S->LoadAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
+                    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_FILLVAL:
+                    FlagAttr (&S->Attr, SA_FILLVAL, "FILLVAL");
+                    S->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
+                    S->Flags |= SF_FILLVAL;
+                    break;
+
+                case CFGTOK_LOAD:
+                    FlagAttr (&S->Attr, SA_LOAD, "LOAD");
+                    S->Load = CfgGetMemory (GetStrBufId (&CfgSVal));
+                    CfgNextTok ();
+                    break;
+
+                case CFGTOK_OFFSET:
+                    FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
+                    S->Addr   = CfgCheckedConstExpr (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 (GetStrBufId (&CfgSVal));
+                    CfgNextTok ();
+                    break;
+
+                case CFGTOK_START:
+                    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;
+                        case CFGTOK_OVERWRITE: S->Flags |= (SF_OVERWRITE | SF_RO); 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;
+        }
 
         /* An attribute of ALIGN_LOAD doesn't make sense if there are no
-         * separate run and load memory areas.
-         */
+        ** 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);
+            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.
-         */
+        ** 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);
+            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'",
-                         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));
+        /* 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 (&CfgErrorPos,
+                          "Cannot put r/w segment '%s' in r/o memory area '%s'",
+                          GetString (S->Name), GetString (S->Run->Name));
             }
-           /* Discard the descriptor */
-           FreeSegDesc (S);
-       }
+        }
 
-       /* Skip the semicolon */
-       CfgConsumeSemi ();
+        /* 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 (&CfgErrorPos,
+                      "Only one of ALIGN, START, OFFSET may be used");
+        }
+
+        /* Skip the semicolon */
+        CfgConsumeSemi ();
     }
 
     /* Remember we had this section */
@@ -850,159 +841,143 @@ static void ParseO65 (void)
 /* Parse the o65 format section */
 {
     static const IdentTok Attributes [] = {
-               {   "EXPORT",   CFGTOK_EXPORT           },
-       {   "IMPORT",   CFGTOK_IMPORT           },
-        {   "TYPE",     CFGTOK_TYPE            },
-               {   "OS",       CFGTOK_OS               },
-               {   "ID",       CFGTOK_ID               },
-               {   "VERSION",  CFGTOK_VERSION          },
+        {   "EXPORT",   CFGTOK_EXPORT           },
+        {   "IMPORT",   CFGTOK_IMPORT           },
+        {   "TYPE",     CFGTOK_TYPE             },
+        {   "OS",       CFGTOK_OS               },
+        {   "ID",       CFGTOK_ID               },
+        {   "VERSION",  CFGTOK_VERSION          },
     };
     static const IdentTok Types [] = {
-               {   "SMALL",    CFGTOK_SMALL            },
-               {   "LARGE",    CFGTOK_LARGE            },
+        {   "SMALL",    CFGTOK_SMALL            },
+        {   "LARGE",    CFGTOK_LARGE            },
     };
     static const IdentTok OperatingSystems [] = {
-               {   "LUNIX",    CFGTOK_LUNIX            },
-               {   "OSA65",    CFGTOK_OSA65            },
+        {   "LUNIX",    CFGTOK_LUNIX            },
+        {   "OSA65",    CFGTOK_OSA65            },
         {   "CC65",     CFGTOK_CC65             },
+        {   "OPENCBM",  CFGTOK_OPENCBM          },
     };
 
     /* Bitmask to remember the attributes we got already */
     enum {
-               atNone          = 0x0000,
-       atOS            = 0x0001,
+        atNone          = 0x0000,
+        atOS            = 0x0001,
         atOSVersion     = 0x0002,
-       atType          = 0x0004,
-       atImport        = 0x0008,
-       atExport        = 0x0010,
+        atType          = 0x0004,
+        atImport        = 0x0008,
+        atExport        = 0x0010,
         atID            = 0x0020,
         atVersion       = 0x0040
     };
     unsigned AttrFlags = atNone;
 
     /* Remember the attributes read */
-    unsigned CfgSValId;
     unsigned OS = 0;            /* Initialize to keep gcc happy */
     unsigned Version = 0;
 
     /* Read the attributes */
     while (CfgTok == CFGTOK_IDENT) {
 
-       /* Map the identifier to a token */
-       cfgtok_t AttrTok;
-               CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
-       AttrTok = CfgTok;
+        /* Map the identifier to a token */
+        cfgtok_t AttrTok;
+        CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
+        AttrTok = CfgTok;
 
-       /* An optional assignment follows */
-       CfgNextTok ();
-       CfgOptionalAssign ();
+        /* An optional assignment follows */
+        CfgNextTok ();
+        CfgOptionalAssign ();
 
-       /* Check which attribute was given */
-       switch (AttrTok) {
+        /* Check which attribute was given */
+        switch (AttrTok) {
 
-           case CFGTOK_EXPORT:
+            case CFGTOK_EXPORT:
                 /* Remember we had this token (maybe more than once) */
                 AttrFlags |= atExport;
-               /* We expect an identifier */
-               CfgAssureIdent ();
-                /* Convert the string into a string index */
-                CfgSValId = GetStringId (CfgSVal);
-               /* Check if the export symbol is also defined as an import. */
-               if (O65GetImport (O65FmtDesc, CfgSValId) != 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, CfgSValId) != 0) {
-                   CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
-               }
-               /* Insert the symbol into the table */
-               O65SetExport (O65FmtDesc, CfgSValId);
-               break;
-
-           case CFGTOK_IMPORT:
+                /* We expect an identifier */
+                CfgAssureIdent ();
+                /* Remember it as an export for later */
+                NewCfgSymbol (CfgSymO65Export, GetStrBufId (&CfgSVal));
+                /* Eat the identifier token */
+                CfgNextTok ();
+                break;
+
+            case CFGTOK_IMPORT:
                 /* Remember we had this token (maybe more than once) */
                 AttrFlags |= atImport;
-               /* We expect an identifier */
-               CfgAssureIdent ();
-                /* Convert the string into a string index */
-                CfgSValId = GetStringId (CfgSVal);
-               /* Check if the imported symbol is also defined as an export. */
-               if (O65GetExport (O65FmtDesc, CfgSValId) != 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, CfgSValId) != 0) {
-                   CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
-               }
-               /* Insert the symbol into the table */
-               O65SetImport (O65FmtDesc, CfgSValId);
-               break;
-
-           case CFGTOK_TYPE:
-               /* Cannot have this attribute twice */
-               FlagAttr (&AttrFlags, atType, "TYPE");
-               /* Get the type of the executable */
-               CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
-               switch (CfgTok) {
-
-                   case CFGTOK_SMALL:
-                       O65SetSmallModel (O65FmtDesc);
-                       break;
-
-                   case CFGTOK_LARGE:
-                       O65SetLargeModel (O65FmtDesc);
-                       break;
-
-                   default:
-                       CfgError ("Unexpected type token");
-               }
-               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;
+                /* We expect an identifier */
+                CfgAssureIdent ();
+                /* 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 */
+                CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
+                switch (CfgTok) {
+
+                    case CFGTOK_SMALL:
+                        O65SetSmallModel (O65FmtDesc);
+                        break;
+
+                    case CFGTOK_LARGE:
+                        O65SetLargeModel (O65FmtDesc);
+                        break;
+
+                    default:
+                        CfgError (&CfgErrorPos, "Unexpected type token");
+                }
+                /* Eat the attribute token */
+                CfgNextTok ();
+                break;
+
+            case CFGTOK_OS:
+                /* 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:
-               FAIL ("Unexpected attribute token");
+            default:
+                FAIL ("Unexpected attribute token");
 
-       }
+        }
 
-       /* Skip the attribute value and an optional comma */
-       CfgNextTok ();
-       CfgOptionalComma ();
+        /* Skip an optional comma */
+        CfgOptionalComma ();
     }
 
     /* Check if we have all mandatory attributes */
@@ -1010,12 +985,14 @@ static void ParseO65 (void)
 
     /* 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");
         }
     }
 
@@ -1029,39 +1006,40 @@ static void ParseFormats (void)
 /* Parse a target format section */
 {
     static const IdentTok Formats [] = {
-               {   "O65",      CFGTOK_O65      },
-               {   "BIN",      CFGTOK_BIN      },
-               {   "BINARY",   CFGTOK_BIN      },
+        {   "O65",      CFGTOK_O65      },
+        {   "BIN",      CFGTOK_BIN      },
+        {   "BINARY",   CFGTOK_BIN      },
     };
 
     while (CfgTok == CFGTOK_IDENT) {
 
-       /* Map the identifier to a token */
-       cfgtok_t FormatTok;
-               CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
-       FormatTok = CfgTok;
+        /* Map the identifier to a token */
+        cfgtok_t FormatTok;
+        CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
+        FormatTok = CfgTok;
 
-       /* Skip the name and the following colon */
-       CfgNextTok ();
-       CfgConsumeColon ();
+        /* Skip the name and the following colon */
+        CfgNextTok ();
+        CfgConsumeColon ();
 
-       /* Parse the format options */
-       switch (FormatTok) {
+        /* Parse the format options */
+        switch (FormatTok) {
 
-           case CFGTOK_O65:
-               ParseO65 ();
-               break;
+            case CFGTOK_O65:
+                ParseO65 ();
+                break;
 
-           case CFGTOK_BIN:
-               /* No attribibutes available */
-               break;
+            case CFGTOK_BIN:
+            case CFGTOK_ATARIEXE:
+                /* No attribibutes available */
+                break;
 
-           default:
-               Error ("Unexpected format token");
-       }
+            default:
+                Error ("Unexpected format token");
+        }
 
-       /* Skip the semicolon */
-       CfgConsumeSemi ();
+        /* Skip the semicolon */
+        CfgConsumeSemi ();
     }
 
 
@@ -1075,128 +1053,142 @@ static void ParseConDes (void)
 /* Parse the CONDES feature */
 {
     static const IdentTok Attributes [] = {
-               {   "SEGMENT",          CFGTOK_SEGMENT          },
-       {   "LABEL",            CFGTOK_LABEL            },
-       {   "COUNT",            CFGTOK_COUNT            },
-       {   "TYPE",             CFGTOK_TYPE             },
-       {   "ORDER",            CFGTOK_ORDER            },
+        {   "COUNT",            CFGTOK_COUNT            },
+        {   "IMPORT",           CFGTOK_IMPORT           },
+        {   "LABEL",            CFGTOK_LABEL            },
+        {   "ORDER",            CFGTOK_ORDER            },
+        {   "SEGMENT",          CFGTOK_SEGMENT          },
+        {   "TYPE",             CFGTOK_TYPE             },
     };
 
     static const IdentTok Types [] = {
-               {   "CONSTRUCTOR",      CFGTOK_CONSTRUCTOR      },
-       {   "DESTRUCTOR",       CFGTOK_DESTRUCTOR       },
+        {   "CONSTRUCTOR",      CFGTOK_CONSTRUCTOR      },
+        {   "DESTRUCTOR",       CFGTOK_DESTRUCTOR       },
         {   "INTERRUPTOR",      CFGTOK_INTERRUPTOR      },
     };
 
     static const IdentTok Orders [] = {
-       {   "DECREASING",       CFGTOK_DECREASING       },
-               {   "INCREASING",       CFGTOK_INCREASING       },
+        {   "DECREASING",       CFGTOK_DECREASING       },
+        {   "INCREASING",       CFGTOK_INCREASING       },
     };
 
     /* Attribute values. */
-    unsigned SegName = INVALID_STRING_ID;
-    unsigned Label   = INVALID_STRING_ID;
     unsigned Count   = INVALID_STRING_ID;
+    unsigned Label   = INVALID_STRING_ID;
+    unsigned SegName = INVALID_STRING_ID;
+    ConDesImport Import;
     /* 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,
+        atCount         = 0x0001,
+        atImport        = 0x0002,
+        atLabel         = 0x0004,
+        atOrder         = 0x0008,
+        atSegName       = 0x0010,
+        atType          = 0x0020,
     };
     unsigned AttrFlags = atNone;
 
     /* Parse the attributes */
     while (1) {
 
-       /* 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_SEGMENT:
-               /* Don't allow this twice */
-               FlagAttr (&AttrFlags, atSegName, "SEGMENT");
-               /* We expect an identifier */
-               CfgAssureIdent ();
-               /* Remember the value for later */
-               SegName = GetStringId (CfgSVal);
-               break;
-
-           case CFGTOK_LABEL:
-               /* Don't allow this twice */
-               FlagAttr (&AttrFlags, atLabel, "LABEL");
-               /* We expect an identifier */
-               CfgAssureIdent ();
-               /* Remember the value for later */
-               Label = GetStringId (CfgSVal);
-               break;
-
-           case CFGTOK_COUNT:
-               /* Don't allow this twice */
-               FlagAttr (&AttrFlags, atCount, "COUNT");
-               /* We expect an identifier */
-               CfgAssureIdent ();
-               /* Remember the value for later */
-               Count = GetStringId (CfgSVal);
-               break;
-
-           case CFGTOK_TYPE:
-               /* Don't allow this twice */
-               FlagAttr (&AttrFlags, atType, "TYPE");
-               /* The type may be given as id or numerical */
-               if (CfgTok == CFGTOK_INTCON) {
-                   CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
-                   Type = (int) CfgIVal;
-               } else {
-                   CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
-                   switch (CfgTok) {
-                       case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON;    break;
-                       case CFGTOK_DESTRUCTOR:  Type = CD_TYPE_DES;    break;
+        /* 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_COUNT:
+                /* Don't allow this twice */
+                FlagAttr (&AttrFlags, atCount, "COUNT");
+                /* We expect an identifier */
+                CfgAssureIdent ();
+                /* Remember the value for later */
+                Count = GetStrBufId (&CfgSVal);
+                break;
+
+            case CFGTOK_IMPORT:
+                /* Don't allow this twice */
+                FlagAttr (&AttrFlags, atImport, "IMPORT");
+                /* We expect an identifier */
+                CfgAssureIdent ();
+                /* Remember value and position for later */
+                Import.Name = GetStrBufId (&CfgSVal);
+                Import.Pos = CfgErrorPos;
+                Import.AddrSize = ADDR_SIZE_ABS;
+                break;
+
+            case CFGTOK_LABEL:
+                /* Don't allow this twice */
+                FlagAttr (&AttrFlags, atLabel, "LABEL");
+                /* We expect an identifier */
+                CfgAssureIdent ();
+                /* Remember the value for later */
+                Label = GetStrBufId (&CfgSVal);
+                break;
+
+            case CFGTOK_ORDER:
+                /* Don't allow this twice */
+                FlagAttr (&AttrFlags, atOrder, "ORDER");
+                CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
+                switch (CfgTok) {
+                    case CFGTOK_DECREASING: Order = cdDecreasing;       break;
+                    case CFGTOK_INCREASING: Order = cdIncreasing;       break;
+                    default: FAIL ("Unexpected order token");
+                }
+                break;
+
+            case CFGTOK_SEGMENT:
+                /* Don't allow this twice */
+                FlagAttr (&AttrFlags, atSegName, "SEGMENT");
+                /* We expect an identifier */
+                CfgAssureIdent ();
+                /* Remember the value for later */
+                SegName = GetStrBufId (&CfgSVal);
+                break;
+
+            case CFGTOK_TYPE:
+                /* Don't allow this twice */
+                FlagAttr (&AttrFlags, atType, "TYPE");
+                /* The type may be given as id or numerical */
+                if (CfgTok == CFGTOK_INTCON) {
+                    CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
+                    Type = (int) CfgIVal;
+                } else {
+                    CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
+                    switch (CfgTok) {
+                        case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON;    break;
+                        case CFGTOK_DESTRUCTOR:  Type = CD_TYPE_DES;    break;
                         case CFGTOK_INTERRUPTOR: Type = CD_TYPE_INT;    break;
-                       default: FAIL ("Unexpected type token");
-                   }
-               }
-               break;
-
-           case CFGTOK_ORDER:
-               /* Don't allow this twice */
-               FlagAttr (&AttrFlags, atOrder, "ORDER");
-               CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
-               switch (CfgTok) {
-                   case CFGTOK_DECREASING: Order = cdDecreasing;       break;
-                   case CFGTOK_INCREASING: Order = cdIncreasing;       break;
-                   default: FAIL ("Unexpected order token");
-               }
-               break;
-
-           default:
-               FAIL ("Unexpected attribute token");
-
-       }
-
-               /* Skip the attribute value */
-       CfgNextTok ();
-
-       /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
-       if (CfgTok == CFGTOK_SEMI) {
-           break;
-       } else if (CfgTok == CFGTOK_COMMA) {
-           CfgNextTok ();
-       }
+                        default: FAIL ("Unexpected type token");
+                    }
+                }
+                break;
+
+            default:
+                FAIL ("Unexpected attribute token");
+
+        }
+
+        /* Skip the attribute value */
+        CfgNextTok ();
+
+        /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
+        if (CfgTok == CFGTOK_SEMI) {
+            break;
+        } else if (CfgTok == CFGTOK_COMMA) {
+            CfgNextTok ();
+        }
     }
 
     /* Check if we have all mandatory attributes */
@@ -1206,17 +1198,22 @@ static void ParseConDes (void)
 
     /* 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 */
     ConDesSetSegName (Type, SegName);
     ConDesSetLabel (Type, Label);
     if (AttrFlags & atCount) {
-       ConDesSetCountSym (Type, Count);
+        ConDesSetCountSym (Type, Count);
+    }
+    if (AttrFlags & atImport) {
+        ConDesSetImport (Type, &Import);
     }
     if (AttrFlags & atOrder) {
-       ConDesSetOrder (Type, Order);
+        ConDesSetOrder (Type, Order);
     }
 }
 
@@ -1226,7 +1223,7 @@ static void ParseStartAddress (void)
 /* Parse the STARTADDRESS feature */
 {
     static const IdentTok Attributes [] = {
-               {   "DEFAULT",  CFGTOK_DEFAULT },
+        {   "DEFAULT",  CFGTOK_DEFAULT },
     };
 
 
@@ -1235,58 +1232,52 @@ static void ParseStartAddress (void)
 
     /* Bitmask to remember the attributes we got already */
     enum {
-       atNone          = 0x0000,
-               atDefault       = 0x0001
+        atNone          = 0x0000,
+        atDefault       = 0x0001
     };
     unsigned AttrFlags = atNone;
 
     /* Parse the attributes */
     while (1) {
 
-       /* 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_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;
-               break;
-
-           default:
-               FAIL ("Unexpected attribute token");
-
-       }
-
-               /* Skip the attribute value */
-       CfgNextTok ();
-
-       /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
-       if (CfgTok == CFGTOK_SEMI) {
-           break;
-       } else if (CfgTok == CFGTOK_COMMA) {
-           CfgNextTok ();
-       }
+        /* 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_DEFAULT:
+                /* Don't allow this twice */
+                FlagAttr (&AttrFlags, atDefault, "DEFAULT");
+                /* We expect a numeric expression */
+                DefStartAddr = CfgCheckedConstExpr (0, 0xFFFFFF);
+                break;
+
+            default:
+                FAIL ("Unexpected attribute token");
+
+        }
+
+        /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
+        if (CfgTok == CFGTOK_SEMI) {
+            break;
+        } else if (CfgTok == CFGTOK_COMMA) {
+            CfgNextTok ();
+        }
     }
 
     /* Check if we have all mandatory attributes */
     AttrCheck (AttrFlags, atDefault, "DEFAULT");
 
     /* If no start address was given on the command line, use the one given
-     * here
-     */
+    ** here
+    */
     if (!HaveStartAddr) {
         StartAddr = DefStartAddr;
     }
@@ -1298,39 +1289,39 @@ static void ParseFeatures (void)
 /* Parse a features section */
 {
     static const IdentTok Features [] = {
-               {   "CONDES",       CFGTOK_CONDES       },
+        {   "CONDES",       CFGTOK_CONDES       },
         {   "STARTADDRESS", CFGTOK_STARTADDRESS },
     };
 
     while (CfgTok == CFGTOK_IDENT) {
 
-       /* Map the identifier to a token */
-       cfgtok_t FeatureTok;
-               CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
-               FeatureTok = CfgTok;
+        /* Map the identifier to a token */
+        cfgtok_t FeatureTok;
+        CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
+        FeatureTok = CfgTok;
 
-       /* Skip the name and the following colon */
-       CfgNextTok ();
-       CfgConsumeColon ();
+        /* Skip the name and the following colon */
+        CfgNextTok ();
+        CfgConsumeColon ();
 
-       /* Parse the format options */
-       switch (FeatureTok) {
+        /* Parse the format options */
+        switch (FeatureTok) {
 
-           case CFGTOK_CONDES:
-               ParseConDes ();
-               break;
+            case CFGTOK_CONDES:
+                ParseConDes ();
+                break;
 
             case CFGTOK_STARTADDRESS:
                 ParseStartAddress ();
                 break;
 
 
-           default:
-               Error ("Unexpected feature token");
-       }
+            default:
+                FAIL ("Unexpected feature token");
+        }
 
-       /* Skip the semicolon */
-       CfgConsumeSemi ();
+        /* Skip the semicolon */
+        CfgConsumeSemi ();
     }
 
     /* Remember we had this section */
@@ -1342,27 +1333,163 @@ static void ParseFeatures (void)
 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 */
+        unsigned Name = GetStrBufId (&CfgSVal);
+        CfgNextTok ();
+
+        /* 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");
 
-       /* Remember the name */
-       unsigned Name = GetStringId (CfgSVal);
-       CfgNextTok ();
+            }
+
+            /* Semicolon ends the decl, otherwise accept an optional comma */
+            if (CfgTok == CFGTOK_SEMI) {
+                break;
+            } else if (CfgTok == CFGTOK_COMMA) {
+                CfgNextTok ();
+            }
+        }
+
+        /* We must have a type */
+        AttrCheck (AttrFlags, atType, "TYPE");
+
+        /* Further actions depend on the type */
+        switch (Type) {
+
+            case CfgSymExport:
+                /* We must have a value */
+                AttrCheck (AttrFlags, atValue, "VALUE");
+                /* Create the export */
+                Exp = CreateExprExport (Name, Value, AddrSize);
+                CollAppend (&Exp->DefLines, GenLineInfo (&CfgErrorPos));
+                break;
 
-       /* Allow an optional assignment */
-       CfgOptionalAssign ();
+            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->RefLines, GenLineInfo (&CfgErrorPos));
+                break;
 
-       /* Make sure the next token is an integer, read and skip it */
-       CfgAssureInt ();
-       Val = CfgIVal;
-       CfgNextTok ();
+            case CfgSymWeak:
+                /* We must have a value */
+                AttrCheck (AttrFlags, atValue, "VALUE");
+                /* Remember the symbol for later */
+                Sym = NewCfgSymbol (CfgSymWeak, Name);
+                Sym->Value = Value;
+                Sym->AddrSize = AddrSize;
+                break;
 
-       /* Generate an export with the given value */
-       CreateConstExport (Name, Val);
+            default:
+                Internal ("Unexpected symbol type %d", Type);
+        }
 
-       /* Skip the semicolon */
-       CfgConsumeSemi ();
+        /* Skip the semicolon */
+        CfgConsumeSemi ();
     }
 
     /* Remember we had this section */
@@ -1375,59 +1502,59 @@ static void ParseConfig (void)
 /* Parse the config file */
 {
     static const IdentTok BlockNames [] = {
-       {   "MEMORY",   CFGTOK_MEMORY   },
-       {   "FILES",    CFGTOK_FILES    },
+        {   "MEMORY",   CFGTOK_MEMORY   },
+        {   "FILES",    CFGTOK_FILES    },
         {   "SEGMENTS", CFGTOK_SEGMENTS },
-       {   "FORMATS",  CFGTOK_FORMATS  },
-       {   "FEATURES", CFGTOK_FEATURES },
-       {   "SYMBOLS",  CFGTOK_SYMBOLS  },
+        {   "FORMATS",  CFGTOK_FORMATS  },
+        {   "FEATURES", CFGTOK_FEATURES },
+        {   "SYMBOLS",  CFGTOK_SYMBOLS  },
     };
     cfgtok_t BlockTok;
 
     do {
 
-       /* Read the block ident */
-               CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
-       BlockTok = CfgTok;
-       CfgNextTok ();
+        /* Read the block ident */
+        CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
+        BlockTok = CfgTok;
+        CfgNextTok ();
 
-       /* Expected a curly brace */
-       CfgConsume (CFGTOK_LCURLY, "`{' expected");
+        /* Expected a curly brace */
+        CfgConsume (CFGTOK_LCURLY, "'{' expected");
 
-       /* Read the block */
-       switch (BlockTok) {
+        /* Read the block */
+        switch (BlockTok) {
 
-           case CFGTOK_MEMORY:
-               ParseMemory ();
-               break;
+            case CFGTOK_MEMORY:
+                ParseMemory ();
+                break;
 
-           case CFGTOK_FILES:
-               ParseFiles ();
-               break;
+            case CFGTOK_FILES:
+                ParseFiles ();
+                break;
 
-           case CFGTOK_SEGMENTS:
-               ParseSegments ();
-               break;
+            case CFGTOK_SEGMENTS:
+                ParseSegments ();
+                break;
 
-           case CFGTOK_FORMATS:
-               ParseFormats ();
-               break;
+            case CFGTOK_FORMATS:
+                ParseFormats ();
+                break;
 
-           case CFGTOK_FEATURES:
-               ParseFeatures ();
-               break;
+            case CFGTOK_FEATURES:
+                ParseFeatures ();
+                break;
 
-           case CFGTOK_SYMBOLS:
-               ParseSymbols ();
-               break;
+            case CFGTOK_SYMBOLS:
+                ParseSymbols ();
+                break;
 
-           default:
-               FAIL ("Unexpected block token");
+            default:
+                FAIL ("Unexpected block token");
 
-       }
+        }
 
-       /* Skip closing brace */
-       CfgConsume (CFGTOK_RCURLY, "`}' expected");
+        /* Skip closing brace */
+        CfgConsume (CFGTOK_RCURLY, "'}' expected");
 
     } while (CfgTok != CFGTOK_EOF);
 }
@@ -1440,10 +1567,11 @@ void CfgRead (void)
     /* Create the descriptors for the binary formats */
     BinFmtDesc = NewBinDesc ();
     O65FmtDesc = NewO65Desc ();
+    XexFmtDesc = NewXexDesc ();
 
     /* If we have a config name given, open the file, otherwise we will read
-     * from a buffer.
-     */
+    ** from a buffer.
+    */
     CfgOpenInput ();
 
     /* Parse the file */
@@ -1455,16 +1583,181 @@ void CfgRead (void)
 
 
 
+/*****************************************************************************/
+/*                          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);
+            }
+
+            /* Use the fill value from the config */
+            S->Seg->FillVal = S->FillVal;
+
+            /* 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);
 
-    xsprintf (Buf, sizeof (Buf), "__%s_RUN__", GetString (S->Name));
-    CreateMemoryExport (GetStringId (Buf), S->Run, SegAddr - S->Run->Start);
-    xsprintf (Buf, sizeof (Buf), "__%s_SIZE__", GetString (S->Name));
-    CreateConstExport (GetStringId (Buf), S->Seg->Size);
     S->Flags |= SF_RUN_DEF;
+    SB_Done (&Buf);
 }
 
 
@@ -1472,136 +1765,311 @@ static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
 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);
 
-    xsprintf (Buf, sizeof (Buf), "__%s_LOAD__", GetString (S->Name));
-    CreateMemoryExport (GetStringId (Buf), S->Load, SegAddr - S->Load->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 everything went OK).
+** In case of overflows, a short mapfile can be generated later, to ease the
+** user's task of re-arranging segments.
+*/
 {
-    /* 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) {
+    unsigned Overflows = 0;
+    unsigned I;
+
+    /* Postprocess symbols. We must do that first, since weak symbols are
+    ** defined here, which may be needed later.
+    */
+    ProcessSymbols ();
 
-        MemListNode* N;
+    /* Postprocess segments */
+    ProcessSegments ();
 
-       /* Get the start address of this memory area */
-       unsigned long Addr = M->Start;
+    /* 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 that.
+    */
+    for (I = 0; I < CollCount (&MemoryAreas); ++I) {
+        unsigned J;
+        unsigned long Addr;
+        unsigned Overwrites = 0;
+
+        /* Get the next memory area */
+        MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
+
+        /* Remember the offset in the output file */
+        M->FileOffs = M->F->Size;
 
         /* Remember if this is a relocatable memory area */
         M->Relocatable = RelocatableBinFmt (M->F->Format);
 
-       /* Walk through the segments in this memory area */
-       N = M->SegList;
-       while (N) {
+        /* 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);
+        }
 
-           /* Get the segment from the node */
-           SegDesc* S = N->Seg;
+        /* 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);
+
+            /* Remember the start address before handling this segment */
+            unsigned long StartAddr = Addr;
+
+            /* Take note of "overwrite" segments and make sure there are no
+            ** other segment types following them in current memory region.
+            */
+            if (S->Flags & SF_OVERWRITE) {
+                if (S->Flags & (SF_OFFSET | SF_START)) {
+                    ++Overwrites;
+                } else {
+                    CfgError (GetSourcePos (M->LI),
+                              "Segment '%s' of type 'overwrite' requires either"
+                              " 'Start' or 'Offset' attribute to be specified",
+                              GetString (S->Name));
+                }
+            } else {
+                if (Overwrites > 0) {
+                    CfgError (GetSourcePos (M->LI),
+                              "Segment '%s' is preceded by at least one segment"
+                              " of type 'overwrite'",
+                              GetString (S->Name));
+                }
+            }
 
-            /* Some actions depend on wether this is the load or run memory
-             * area.
-             */
+            /* Some actions depend on whether 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.
-                 */
+                ** alignment and explict start address and offset.
+                */
+
+                /* Check if the alignment for the segment from the linker
+                ** config is a multiple for that of the segment.
+                ** If START or OFFSET is provided instead of ALIGN, check
+                ** if its address fits alignment requirements.
+                */
+                unsigned long AlignedBy = (S->Flags & SF_START) ? S->Addr
+                    : (S->Flags & SF_OFFSET) ? (S->Addr + M->Start)
+                    : S->RunAlignment;
+                if ((AlignedBy % S->Seg->Alignment) != 0) {
+                    /* Segment requires another alignment than configured
+                    ** in the linker.
+                    */
+                    CfgWarning (GetSourcePos (S->LI),
+                                "Segment '%s' isn't aligned properly; the"
+                                " resulting executable might not be functional.",
+                                GetString (S->Name));
+                }
+
                 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)) {
+                    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
+                    ** that is somewhat suspicious.
+                    */
+                    if (M->FillLevel == 0 && NewAddr > Addr) {
+                        CfgWarning (GetSourcePos (S->LI),
+                                    "The first segment in memory area '%s' "
+                                    "needs fill bytes for alignment.",
+                                    GetString (M->Name));
+                    }
+
+                    /* Use the aligned address */
+                    Addr = NewAddr;
+
+                } else if ((S->Flags & (SF_OFFSET | SF_START)) != 0 &&
+                           (M->Flags & MF_OVERFLOW) == 0) {
                     /* 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'",
-                                   GetString (M->Name), GetString (S->Name));
+
+                    if (S->Flags & SF_OVERWRITE) {
+                        if (NewAddr < M->Start) {
+                            CfgError (GetSourcePos (S->LI),
+                                      "Segment '%s' begins before memory area '%s'",
+                                      GetString (S->Name), GetString (M->Name));
                         } else {
-                            Error ("Start address too low in `%s', segment `%s'",
-                                   GetString (M->Name), GetString (S->Name));
+                            Addr = NewAddr;
+                        }
+                    } else {
+                        if (NewAddr < Addr) {
+                            /* Offset already too large */
+                            ++Overflows;
+                            if (S->Flags & SF_OFFSET) {
+                                CfgWarning (GetSourcePos (S->LI),
+                                            "Segment '%s' offset is too small in '%s' by %lu byte%c",
+                                            GetString (S->Name), GetString (M->Name),
+                                            Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
+                            } else {
+                                CfgWarning (GetSourcePos (S->LI),
+                                            "Segment '%s' start address is too low in '%s' by %lu byte%c",
+                                            GetString (S->Name), GetString (M->Name),
+                                            Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
+                            }
+                        } else {
+                            Addr = NewAddr;
                         }
                     }
-                    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.
-                 */
+                ** in the segment, 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;
 
-            } else if (S->Load == M) {
+                /* Remember the run memory for this segment, which is also a
+                ** flag that the segment has been placed.
+                */
+                S->Seg->MemArea = M;
 
-                /* This is the load memory area, *and* run and load are
-                 * different (because of the "else" above). Handle alignment.
-                 */
+            } 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 */
-                    unsigned long Val = (0x01UL << S->AlignLoad) - 1;
-                    Addr = (Addr + Val) & ~Val;
+                    Addr = AlignAddr (Addr, S->LoadAlignment);
                 }
+            }
+
+            /* If this is the load memory area, and the segment doesn't have a
+            ** fill value defined, use the one from the memory area.
+            */
+            if (S->Load == M && (S->Flags & SF_FILLVAL) == 0) {
+                S->Seg->FillVal = M->FillVal;
+            }
 
+            /* 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 && (M->Flags & MF_OVERFLOW) == 0) {
+                ++Overflows;
+                M->Flags |= MF_OVERFLOW;
+                CfgWarning (GetSourcePos (M->LI),
+                            "Segment '%s' overflows memory area '%s' by %lu byte%c",
+                            GetString (S->Name), GetString (M->Name),
+                            M->FillLevel - M->Size, (M->FillLevel - M->Size == 1) ? ' ' : 's');
             }
 
-           /* 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)",
-                      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 requested, define symbols for the start and size of the
+            ** segment.
+            */
+            if (S->Flags & SF_DEFINE) {
                 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__", GetString (M->Name));
-           CreateMemoryExport (GetStringId (Buf), M, 0);
-           sprintf (Buf, "__%s_SIZE__", GetString (M->Name));
-           CreateConstExport (GetStringId (Buf), M->Size);
-           sprintf (Buf, "__%s_LAST__", GetString (M->Name));
-           CreateMemoryExport (GetStringId (Buf), M, M->FillLevel);
-       }
-
-       /* Next memory area */
-       M = M->Next;
+            }
+
+            /* Calculate the new address */
+            Addr += S->Seg->Size;
+
+            /* If this segment will go out to the file, or its place
+            ** in the file will be filled, then increase the file size.
+            */
+            if (S->Load == M &&
+                ((S->Flags & SF_BSS) == 0 || (M->Flags & MF_FILL) != 0)) {
+                M->F->Size += Addr - StartAddr;
+            }
+        }
+
+        /* If requested, define symbols for start, size, and offset of the
+        ** memory area
+        */
+        if (M->Flags & MF_DEFINE) {
+            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);
+
+            /* Define the file offset of the memory area. This isn't of much
+            ** use for relocatable output files.
+            */
+            if (!M->Relocatable) {
+                SB_Printf (&Buf, "__%s_FILEOFFS__", GetString (M->Name));
+                E = CreateConstExport (GetStrBufId (&Buf), M->FileOffs);
+                CollAppend (&E->DefLines, M->LI);
+            }
+
+            /* Throw away the string buffer */
+            SB_Done (&Buf);
+        }
+
+        /* If we didn't have an overflow, and are requested to fill the memory
+        ** area, account for that in the file size.
+        */
+        if ((M->Flags & MF_OVERFLOW) == 0 && (M->Flags & MF_FILL) != 0) {
+            M->F->Size += (M->Size - M->FillLevel);
+        }
     }
+
+    /* Return the number of memory area overflows */
+    return Overflows;
 }
 
 
@@ -1609,72 +2077,71 @@ void CfgAssignSegments (void)
 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) {
-
-           /* Is there an output file? */
-           if (strlen (GetString (F->Name)) > 0) {
-
-               /* Assign a proper binary format */
-               if (F->Format == BINFMT_DEFAULT) {
-                   F->Format = DefaultBinFmt;
-               }
-
-               /* Call the apropriate routine for the binary format */
-               switch (F->Format) {
-
-                   case BINFMT_BINARY:
-                       BinWriteTarget (BinFmtDesc, F);
-                       break;
-
-                   case BINFMT_O65:
-                       O65WriteTarget (O65FmtDesc, F);
-                       break;
-
-                   default:
-                       Internal ("Invalid binary format: %u", F->Format);
-
-               }
-
-           } else {
-
-               /* 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) {
-
-                   MemListNode* N;
-
-                   /* Debugging */
-                           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;
-                   }
-                   /* Next memory area */
-                   M = M->FNext;
-               }
-           }
-       }
-
-       /* Next file */
-       F = F->Next;
-    }
-}
+    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 (SB_GetLen (GetStrBuf (F->Name)) > 0) {
+
+                /* Assign a proper binary format */
+                if (F->Format == BINFMT_DEFAULT) {
+                    F->Format = DefaultBinFmt;
+                }
 
+                /* Call the apropriate routine for the binary format */
+                switch (F->Format) {
 
+                    case BINFMT_BINARY:
+                        BinWriteTarget (BinFmtDesc, F);
+                        break;
 
+                    case BINFMT_O65:
+                        O65WriteTarget (O65FmtDesc, F);
+                        break;
+
+                    case BINFMT_ATARIEXE:
+                        XexWriteTarget (XexFmtDesc, F);
+                        break;
+
+                    default:
+                        Internal ("Invalid binary format: %u", F->Format);
+
+                }
+
+            } else {
+
+                /* No output file. Walk through the list and mark all segments
+                ** loading into these memory areas in this file as dumped.
+                */
+                unsigned J;
+                for (J = 0; J < CollCount (&F->MemoryAreas); ++J) {
+
+                    unsigned K;
+
+                    /* Get this entry */
+                    MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, J);
+
+                    /* Debugging */
+                    Print (stdout, 2, "Skipping '%s'...\n", GetString (M->Name));
+
+                    /* Walk throught the segments */
+                    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;
+                        }
+                    }
+                }
+            }
+        }
+    }
+}