]> git.sur5r.net Git - cc65/blobdiff - src/ld65/config.c
Added support for arbitrary alignments.
[cc65] / src / ld65 / config.c
index 96cf2a26e551e6b24752bd94ba9b2972bb9a9b1d..ebafd0bd3b0996fb227881bf76798f3b43df1d03 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2010, Ullrich von Bassewitz                                      */
+/* (C) 1998-2011, Ullrich von Bassewitz                                      */
 /*                Roemerstrasse 52                                           */
 /*                D-70794 Filderstadt                                        */
 /* EMail:         uz@cc65.org                                                */
@@ -39,6 +39,7 @@
 #include <errno.h>
 
 /* common */
+#include "addrsize.h"
 #include "bitops.h"
 #include "check.h"
 #include "print.h"
@@ -46,6 +47,7 @@
 #include "xsprintf.h"
 
 /* ld65 */
+#include "alignment.h"
 #include "bin.h"
 #include "binfmt.h"
 #include "cfgexpr.h"
@@ -111,30 +113,30 @@ static Collection       SegDescList = STATIC_COLLECTION_INITIALIZER;
 #define SA_START       0x0080
 #define SA_OPTIONAL     0x0100
 
+/* Symbol types used in the CfgSymbol structure */
+typedef enum {
+    CfgSymExport,               /* Not really used in struct CfgSymbol */
+    CfgSymImport,               /* Dito */
+    CfgSymWeak,                 /* Like export but weak */
+    CfgSymO65Export,            /* An o65 export */
+    CfgSymO65Import,            /* An o65 import */
+} CfgSymType;
+
 /* Symbol structure. It is used for o65 imports and exports, but also for
  * symbols from the SYMBOLS sections (symbols defined in the config file or
  * forced imports).
  */
-typedef struct Symbol Symbol;
-struct Symbol {
-    const char* CfgName;        /* Config file name */
-    unsigned    CfgLine;        /* Config file position */
-    unsigned    CfgCol;
+typedef struct CfgSymbol CfgSymbol;
+struct CfgSymbol {
+    CfgSymType  Type;           /* Type of symbol */
+    LineInfo*   LI;             /* Config file position */
     unsigned    Name;           /* Symbol name */
-    unsigned    Flags;          /* Symbol flags */
-    long        Val;            /* Symbol value if any */
+    ExprNode*   Value;          /* Symbol value if any */
+    unsigned    AddrSize;       /* Address size of symbol */
 };
 
 /* Collections with symbols */
-static Collection       O65Imports = STATIC_COLLECTION_INITIALIZER;
-static Collection       O65Exports = STATIC_COLLECTION_INITIALIZER;
-static Collection       Symbols    = STATIC_COLLECTION_INITIALIZER;
-
-/* Symbol flags */
-#define SYM_NONE        0x00    /* No special meaning */
-#define SYM_DEF         0x01    /* Symbol defined in the config file */
-#define SYM_WEAK        0x02    /* Defined symbol is weak */
-#define SYM_IMPORT      0x04    /* A forced import */
+static Collection       CfgSymbols = STATIC_COLLECTION_INITIALIZER;
 
 /* Descriptor holding information about the binary formats */
 static BinDesc*        BinFmtDesc      = 0;
@@ -216,7 +218,7 @@ static MemoryArea* CfgGetMemory (unsigned 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;
 }
@@ -256,21 +258,24 @@ static void MemoryInsert (MemoryArea* M, SegDesc* S)
 
 
 
-static Symbol* NewSymbol (unsigned Name, unsigned Flags, long Val)
-/* Create a new Symbol structure with the given name name and flags. The
- * current config file position is recorded in the returned struct.
+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.
  */
 {
     /* Allocate memory */
-    Symbol* Sym = xmalloc (sizeof (Symbol));
+    CfgSymbol* Sym = xmalloc (sizeof (CfgSymbol));
 
     /* Initialize the fields */
-    Sym->CfgName = CfgGetName ();
-    Sym->CfgLine = CfgErrorLine;
-    Sym->CfgCol  = CfgErrorCol;
-    Sym->Name    = Name;
-    Sym->Flags   = Flags;
-    Sym->Val     = Val;
+    Sym->Type     = Type;
+    Sym->LI       = GenLineInfo (&CfgErrorPos);
+    Sym->Name     = Name;
+    Sym->Value    = 0;
+    Sym->AddrSize = ADDR_SIZE_INVALID;
+
+    /* Insert the symbol into the collection */
+    CollAppend (&CfgSymbols, Sym);
 
     /* Return the initialized struct */
     return Sym;
@@ -278,17 +283,6 @@ static Symbol* NewSymbol (unsigned Name, unsigned Flags, long Val)
 
 
 
-static Symbol* NewO65Symbol (void)
-/* Create a new Symbol structure with the name in the current CfgSVal variable
- * ready for use as an o65 symbol. The current config file position is recorded
- * in the returned struct.
- */
-{
-    return NewSymbol (GetStrBufId (&CfgSVal), SYM_NONE, 0);
-}
-
-
-
 static File* NewFile (unsigned Name)
 /* Create a new file descriptor and insert it into the list */
 {
@@ -310,17 +304,19 @@ static File* NewFile (unsigned Name)
 
 
 
-static MemoryArea* CreateMemoryArea (unsigned Name)
+static MemoryArea* CreateMemoryArea (const FilePos* Pos, unsigned Name)
 /* Create a new memory area and insert it into the list */
 {
     /* Check for duplicate names */
     MemoryArea* M = CfgFindMemory (Name);
     if (M) {
-       CfgError ("Memory area `%s' defined twice", GetString (Name));
+       CfgError (&CfgErrorPos,
+                  "Memory area `%s' defined twice",
+                  GetString (Name));
     }
 
     /* Create a new memory area */
-    M = NewMemoryArea (Name);
+    M = NewMemoryArea (Pos, Name);
 
     /* Insert the struct into the list ... */
     CollAppend (&MemoryAreas, M);
@@ -338,18 +334,20 @@ static SegDesc* NewSegDesc (unsigned Name)
     /* 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));
     }
 
     /* Allocate memory */
     S = xmalloc (sizeof (SegDesc));
 
     /* Initialize the fields */
-    S->Name    = Name;
-    S->Seg     = 0;
-    S->Attr    = 0;
-    S->Flags   = 0;
-    S->Align   = 0;
+    S->Name          = Name;
+    S->LI            = GenLineInfo (&CfgErrorPos);
+    S->Seg           = 0;
+    S->Attr          = 0;
+    S->Flags         = 0;
+    S->RunAlignment  = 1;
+    S->LoadAlignment = 1;
 
     /* Insert the struct into the list ... */
     CollAppend (&SegDescList, S);
@@ -363,6 +361,7 @@ static SegDesc* NewSegDesc (unsigned Name)
 static void FreeSegDesc (SegDesc* S)
 /* Free a segment descriptor */
 {
+    FreeLineInfo (S->LI);
     xfree (S);
 }
 
@@ -380,7 +379,7 @@ static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
  */
 {
     if (*Flags & Mask) {
-       CfgError ("%s is already defined", Name);
+       CfgError (&CfgErrorPos, "%s is already defined", Name);
     }
     *Flags |= Mask;
 }
@@ -391,7 +390,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);
     }
 }
 
@@ -417,7 +416,7 @@ static void ParseMemory (void)
     while (CfgTok == CFGTOK_IDENT) {
 
        /* Create a new entry on the heap */
-               MemoryArea* M = CreateMemoryArea (GetStrBufId (&CfgSVal));
+               MemoryArea* M = CreateMemoryArea (&CfgErrorPos, GetStrBufId (&CfgSVal));
 
        /* Skip the name and the following colon */
        CfgNextTok ();
@@ -528,7 +527,7 @@ static void ParseFiles (void)
                {   "FORMAT",   CFGTOK_FORMAT   },
     };
     static const IdentTok Formats [] = {
-               {   "O65",      CFGTOK_O65           },
+               {   "O65",      CFGTOK_O65      },
                {   "BIN",      CFGTOK_BIN      },
                {   "BINARY",   CFGTOK_BIN      },
     };
@@ -536,7 +535,7 @@ static void ParseFiles (void)
 
     /* 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 */
@@ -550,7 +549,8 @@ static void ParseFiles (void)
        /* Search for the file, it must exist */
                F = FindFile (GetStrBufId (&CfgSVal));
        if (F == 0) {
-                   CfgError ("File `%s' not found in MEMORY section",
+                   CfgError (&CfgErrorPos,
+                      "File `%s' not found in MEMORY section",
                       SB_GetConstBuf (&CfgSVal));
        }
 
@@ -576,7 +576,8 @@ static void ParseFiles (void)
                case CFGTOK_FORMAT:
                    if (F->Format != BINFMT_DEFAULT) {
                        /* We've set the format already! */
-                       Error ("Cannot set a file format twice");
+                       CfgError (&CfgErrorPos,
+                                  "Cannot set a file format twice");
                    }
                    /* Read the format token */
                    CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
@@ -638,11 +639,10 @@ static void ParseSegments (void)
     };
 
     unsigned Count;
-    long     Val;
 
     /* 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) {
@@ -673,21 +673,13 @@ static void ParseSegments (void)
 
                case CFGTOK_ALIGN:
                    FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
-                   Val = CfgCheckedConstExpr (1, 0x10000);
-                   S->Align = BitFind (Val);
-                   if ((0x01L << S->Align) != Val) {
-                       CfgError ("Alignment must be a power of 2");
-                   }
+                   S->RunAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
                    S->Flags |= SF_ALIGN;
                    break;
 
                 case CFGTOK_ALIGN_LOAD:
                    FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
-                   Val = CfgCheckedConstExpr (1, 0x10000);
-                           S->AlignLoad = BitFind (Val);
-                   if ((0x01L << S->AlignLoad) != Val) {
-                       CfgError ("Alignment must be a power of 2");
-                   }
+                   S->LoadAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
                    S->Flags |= SF_ALIGN_LOAD;
                    break;
 
@@ -769,9 +761,9 @@ static void ParseSegments (void)
          * 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;
         }
@@ -780,14 +772,16 @@ static void ParseSegments (void)
          * 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'",
+               CfgError (&CfgErrorPos,
+                          "Cannot put r/w segment `%s' in r/o memory area `%s'",
                          GetString (S->Name), GetString (S->Run->Name));
            }
        }
@@ -797,7 +791,8 @@ static void ParseSegments (void)
                ((S->Flags & SF_OFFSET) != 0) +
                ((S->Flags & SF_START)  != 0);
        if (Count > 1) {
-                   CfgError ("Only one of ALIGN, START, OFFSET may be used");
+                   CfgError (&CfgErrorPos,
+                      "Only one of ALIGN, START, OFFSET may be used");
        }
 
        /* Skip the semicolon */
@@ -870,7 +865,7 @@ static void ParseO65 (void)
                /* We expect an identifier */
                CfgAssureIdent ();
                 /* Remember it as an export for later */
-                CollAppend (&O65Exports, NewO65Symbol ());
+                NewCfgSymbol (CfgSymO65Export, GetStrBufId (&CfgSVal));
                 /* Eat the identifier token */
                 CfgNextTok ();
                break;
@@ -881,7 +876,7 @@ static void ParseO65 (void)
                /* We expect an identifier */
                CfgAssureIdent ();
                 /* Remember it as an import for later */
-                CollAppend (&O65Imports, NewO65Symbol ());
+                NewCfgSymbol (CfgSymO65Import, GetStrBufId (&CfgSVal));
                 /* Eat the identifier token */
                 CfgNextTok ();
                break;
@@ -902,7 +897,7 @@ static void ParseO65 (void)
                        break;
 
                    default:
-                       CfgError ("Unexpected type token");
+                       CfgError (&CfgErrorPos, "Unexpected type token");
                }
                 /* Eat the attribute token */
                 CfgNextTok ();
@@ -924,7 +919,7 @@ static void ParseO65 (void)
                         case CFGTOK_OSA65:    OS = O65OS_OSA65;     break;
                         case CFGTOK_CC65:     OS = O65OS_CC65;      break;
                         case CFGTOK_OPENCBM:  OS = O65OS_OPENCBM;   break;
-                        default:              CfgError ("Unexpected OS token");
+                        default:              CfgError (&CfgErrorPos, "Unexpected OS token");
                     }
                 }
                 CfgNextTok ();
@@ -959,11 +954,13 @@ static void ParseO65 (void)
     /* Check for attributes that may not be combined */
     if (OS == O65OS_CC65) {
         if ((AttrFlags & (atImport | atExport)) != 0 && ModuleId < 0x8000) {
-            CfgError ("OS type CC65 may not have imports or exports for ids < $8000");
+            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");
         }
     }
 
@@ -1154,7 +1151,9 @@ 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 */
@@ -1285,107 +1284,159 @@ static void ParseSymbols (void)
 /* Parse a symbols section */
 {
     static const IdentTok Attributes[] = {
+        {   "ADDRSIZE", CFGTOK_ADDRSIZE },
+        {   "TYPE",     CFGTOK_TYPE     },
                {   "VALUE",    CFGTOK_VALUE    },
-        {   "WEAK",     CFGTOK_WEAK     },
+    };
+
+    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 = 0L;
-        unsigned Flags = SYM_NONE;
+        /* 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 ();
 
-        /* Support both, old and new syntax here. New syntax is a colon
-         * followed by an attribute list, old syntax is an optional equal
-         * sign plus a value.
-         */
-        if (CfgTok != CFGTOK_COLON) {
+        /* New syntax - skip the colon */
+        CfgNextTok ();
 
-            /* Old syntax */
+        /* Parse the attributes */
+        while (1) {
 
-            /* Allow an optional assignment */
-            CfgOptionalAssign ();
+            /* Map the identifier to a token */
+            cfgtok_t AttrTok;
+            CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
+            AttrTok = CfgTok;
 
-            /* Make sure the next token is an integer expression, read and
-             * skip it.
-             */
-            Val = CfgConstExpr ();
+            /* Skip the attribute name */
+            CfgNextTok ();
 
-            /* This is a defined symbol */
-            Flags = SYM_DEF;
+            /* An optional assignment follows */
+            CfgOptionalAssign ();
 
-        } else {
+            /* Check which attribute was given */
+            switch (AttrTok) {
 
-            /* Bitmask to remember the attributes we got already */
-            enum {
-                atNone         = 0x0000,
-                atValue         = 0x0001,
-                atWeak          = 0x0002
-            };
-            unsigned AttrFlags = atNone;
+               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;
 
-            /* New syntax - skip the colon */
-            CfgNextTok ();
+                case CFGTOK_VALUE:
+                    /* Don't allow this twice */
+                    FlagAttr (&AttrFlags, atValue, "VALUE");
+                    /* Value is an expression */
+                    Value = CfgExpr ();
+                    break;
 
-            /* Parse the attributes */
-            while (1) {
+                default:
+                    FAIL ("Unexpected attribute token");
 
-                /* Map the identifier to a token */
-                cfgtok_t AttrTok;
-                CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
-                AttrTok = CfgTok;
+            }
 
-                /* Skip the attribute name */
+            /* Semicolon ends the decl, otherwise accept an optional comma */
+            if (CfgTok == CFGTOK_SEMI) {
+                break;
+            } else if (CfgTok == CFGTOK_COMMA) {
                 CfgNextTok ();
+            }
+        }
 
-                /* An optional assignment follows */
-                CfgOptionalAssign ();
-
-                /* Check which attribute was given */
-                switch (AttrTok) {
-
-                    case CFGTOK_VALUE:
-                        /* Don't allow this twice */
-                        FlagAttr (&AttrFlags, atValue, "VALUE");
-                        /* We expect a numeric expression */
-                        Val = CfgConstExpr ();
-                        /* Symbol is defined */
-                        Flags |= SYM_DEF;
-                        break;
-
-                    case CFGTOK_WEAK:
-                        /* Don't allow this twice */
-                        FlagAttr (&AttrFlags, atWeak, "WEAK");
-                        CfgBoolToken ();
-                        if (CfgTok == CFGTOK_TRUE) {
-                            Flags |= SYM_WEAK;
-                        }
-                        CfgNextTok ();
-                        break;
+        /* We must have a type */
+        AttrCheck (AttrFlags, atType, "TYPE");
 
-                    default:
-                        FAIL ("Unexpected attribute token");
+        /* Further actions depend on the type */
+        switch (Type) {
 
-                }
+            case CfgSymExport:
+                /* We must have a value */
+                AttrCheck (AttrFlags, atType, "TYPE");
+                /* Create the export */
+                Exp = CreateExprExport (Name, Value, AddrSize);
+                CollAppend (&Exp->DefLines, GenLineInfo (&CfgErrorPos));
+                break;
 
-                /* Semicolon ends the decl, otherwise accept an optional comma */
-                if (CfgTok == CFGTOK_SEMI) {
-                    break;
-                } else if (CfgTok == CFGTOK_COMMA) {
-                    CfgNextTok ();
+            case CfgSymImport:
+                /* An import must not have a value */
+                if (AttrFlags & atValue) {
+                    CfgError (&CfgErrorPos, "Imports must not have a value");
                 }
-            }
+                /* Generate the import */
+                Imp = InsertImport (GenImport (Name, AddrSize));
+                /* Remember the file position */
+                CollAppend (&Imp->DefLines, GenLineInfo (&CfgErrorPos));
+                break;
 
-            /* Check if we have all mandatory attributes */
-            AttrCheck (AttrFlags, atValue, "VALUE");
-        }
+            case CfgSymWeak:
+                /* We must have a value */
+                AttrCheck (AttrFlags, atType, "TYPE");
+                /* Remember the symbol for later */
+                Sym = NewCfgSymbol (CfgSymWeak, Name);
+                Sym->Value = Value;
+                Sym->AddrSize = AddrSize;
+                break;
 
-        /* Remember the symbol for later */
-        CollAppend (&Symbols, NewSymbol (Name, Flags, Val));
+            default:
+                Internal ("Unexpected symbol type %d", Type);
+        }
 
        /* Skip the semicolon */
        CfgConsumeSemi ();
@@ -1487,39 +1538,6 @@ void CfgRead (void)
 
 
 
-static void ProcessMemory (void)
-/* Process the MEMORY section */
-{
-    /* Walk over the list with the memory areas */
-    unsigned I;
-    for (I = 0; I < CollCount (&MemoryAreas); ++I) {
-
-        /* Get the next memory area */
-        MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
-
-        /* Remember if this is a relocatable memory area */
-        M->Relocatable = RelocatableBinFmt (M->F->Format);
-
-        /* Resolve the expressions */
-        if (!IsConstExpr (M->StartExpr)) {
-            Error ("Start address of memory area `%s' is not constant",
-                   GetString (M->Name));
-        }
-        M->Start = GetExprVal (M->StartExpr);
-
-        if (!IsConstExpr (M->SizeExpr)) {
-            Error ("Size of memory area `%s' is not constant",
-                   GetString (M->Name));
-        }
-        M->Size = GetExprVal (M->SizeExpr);
-
-        /* Mark the memory area as placed */
-        M->Flags |= MF_PLACED;
-    }
-}
-
-
-
 static void ProcessSegments (void)
 /* Process the SEGMENTS section */
 {
@@ -1542,8 +1560,9 @@ static void ProcessSegments (void)
          * in the segment.
         */
        if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
-                   Warning ("Segment `%s' with type `bss' contains initialized data",
-                    GetString (S->Name));
+                   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
@@ -1567,7 +1586,9 @@ static void ProcessSegments (void)
 
             /* Print a warning if the segment is not optional */
             if ((S->Flags & SF_OPTIONAL) == 0) {
-                CfgWarning ("Segment `%s' does not exist", GetString (S->Name));
+                CfgWarning (&CfgErrorPos,
+                            "Segment `%s' does not exist",
+                            GetString (S->Name));
             }
 
            /* Discard the descriptor and remove it from the collection */
@@ -1579,74 +1600,6 @@ static void ProcessSegments (void)
 
 
 
-static void ProcessO65 (void)
-/* Process the o65 format section */
-{
-    unsigned I;
-
-    /* Walk over the imports, check and add them to the o65 data */
-    for (I = 0; I < CollCount (&O65Imports); ++I) {
-
-        /* Get the import */
-        Symbol* Sym = CollAtUnchecked (&O65Imports, I);
-
-        /* 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) {
-            Error ("%s(%u): Duplicate imported o65 symbol: `%s'",
-                   Sym->CfgName, Sym->CfgLine, GetString (Sym->Name));
-        }
-
-        /* Insert the symbol into the table */
-        O65SetImport (O65FmtDesc, Sym->Name);
-    }
-
-    /* Walk over the exports, check and add them to the o65 data */
-    for (I = 0; I < CollCount (&O65Exports); ++I) {
-
-        /* Get the export */
-        Symbol* Sym = CollAtUnchecked (&O65Exports, I);
-
-        /* Check if the export symbol is also defined as an import. */
-        if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
-            Error ("%s(%u): Exported o65 symbol `%s' cannot also be an o65 import",
-                   Sym->CfgName, Sym->CfgLine, 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) {
-            Error ("%s(%u): Duplicate exported o65 symbol: `%s'",
-                   Sym->CfgName, Sym->CfgLine, GetString (Sym->Name));
-        }
-
-        /* Insert the symbol into the table */
-        O65SetExport (O65FmtDesc, Sym->Name);
-    }
-}
-
-
-
-static void ProcessBin (void)
-/* Process the bin format section */
-{
-}
-
-
-
-static void ProcessFormats (void)
-/* Process the target format section */
-{
-    ProcessO65 ();
-    ProcessBin ();
-}
-
-
-
 static void ProcessSymbols (void)
 /* Process the SYMBOLS section */
 {
@@ -1654,32 +1607,81 @@ static void ProcessSymbols (void)
 
     /* Walk over all symbols */
     unsigned I;
-    for (I = 0; I < CollCount (&Symbols); ++I) {
+    for (I = 0; I < CollCount (&CfgSymbols); ++I) {
 
         /* Get the next symbol */
-        Symbol* Sym = CollAtUnchecked (&Symbols, I);
-
-        /* Do we define this symbol? */
-        if ((Sym->Flags & SYM_DEF) != 0) {
-            /* Check if the symbol is already defined somewhere else */
-            if ((E = FindExport (Sym->Name)) != 0 && !IsUnresolvedExport (E)) {
-                /* If the symbol is not marked as weak, this is an error.
-                 * Otherwise ignore the symbol from the config.
+        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 ((Sym->Flags & SYM_WEAK) == 0) {
-                    CfgError ("Symbol `%s' is already defined",
-                              GetString (Sym->Name));
+                if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
+                    CfgError (
+                        GetSourcePos (Sym->LI),
+                        "Duplicate exported o65 symbol: `%s'",
+                        GetString (Sym->Name)
+                    );
                 }
-            } else {
-                /* The symbol is undefined, generate an export */
-                CreateConstExport (Sym->Name, Sym->Val);
-            }
 
-        } else {
+                /* 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;
         }
     }
+
 }
 
 
@@ -1687,12 +1689,19 @@ static void ProcessSymbols (void)
 static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
 /* Create the defines for a RUN segment */
 {
+    Export* E;
     StrBuf Buf = STATIC_STRBUF_INITIALIZER;
 
+    /* Define the run address of the segment */
     SB_Printf (&Buf, "__%s_RUN__", GetString (S->Name));
-    CreateMemoryExport (GetStrBufId (&Buf), S->Run, SegAddr - S->Run->Start);
+    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));
-    CreateConstExport (GetStrBufId (&Buf), S->Seg->Size);
+    E = CreateConstExport (GetStrBufId (&Buf), S->Seg->Size);
+    CollAppend (&E->DefLines, S->LI);
+
     S->Flags |= SF_RUN_DEF;
     SB_Done (&Buf);
 }
@@ -1702,10 +1711,14 @@ static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
 static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
 /* Create the defines for a LOAD segment */
 {
+    Export* E;
     StrBuf Buf = STATIC_STRBUF_INITIALIZER;
 
+    /* Define the load address of the segment */
     SB_Printf (&Buf, "__%s_LOAD__", GetString (S->Name));
-    CreateMemoryExport (GetStrBufId (&Buf), S->Load, SegAddr - S->Load->Start);
+    E = CreateMemoryExport (GetStrBufId (&Buf), S->Load, SegAddr - S->Load->Start);
+    CollAppend (&E->DefLines, S->LI);
+
     S->Flags |= SF_LOAD_DEF;
     SB_Done (&Buf);
 }
@@ -1724,11 +1737,13 @@ unsigned CfgProcess (void)
     unsigned Overflows = 0;
     unsigned I;
 
-    /* Do postprocessing of the config file data */
-    ProcessSymbols (); /* ######## */
-    ProcessMemory ();
+    /* Postprocess symbols. We must do that first, since weak symbols are
+     * defined here, which may be needed later.
+     */
+    ProcessSymbols ();
+
+    /* Postprocess segments */
     ProcessSegments ();
-    ProcessFormats ();
 
     /* 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
@@ -1737,12 +1752,48 @@ unsigned CfgProcess (void)
     for (I = 0; I < CollCount (&MemoryAreas); ++I) {
 
         unsigned J;
+        unsigned long Addr;
 
-        /* Get this entry */
+        /* Get the next memory area */
         MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
 
-       /* Get the start address of this memory area */
-       unsigned long Addr = M->Start;
+        /* Remember if this is a relocatable memory area */
+        M->Relocatable = RelocatableBinFmt (M->F->Format);
+
+        /* Resolve the start address expression, remember the start address
+         * and mark the memory area as placed.
+         */
+        if (!IsConstExpr (M->StartExpr)) {
+            CfgError (GetSourcePos (M->LI),
+                      "Start address of memory area `%s' is not constant",
+                      GetString (M->Name));
+        }
+        Addr = M->Start = GetExprVal (M->StartExpr);
+        M->Flags |= MF_PLACED;
+
+        /* If requested, define the symbol for the start of the memory area.
+         * Doing it here means that the expression for the size of the area
+         * may reference this symbol.
+         */
+       if (M->Flags & MF_DEFINE) {
+            Export* E;
+           StrBuf Buf = STATIC_STRBUF_INITIALIZER;
+
+            /* Define the start of the memory area */
+           SB_Printf (&Buf, "__%s_START__", GetString (M->Name));
+           E = CreateMemoryExport (GetStrBufId (&Buf), M, 0);
+            CollAppend (&E->DefLines, M->LI);
+
+            SB_Done (&Buf);
+        }
+
+        /* Resolve the size expression */
+        if (!IsConstExpr (M->SizeExpr)) {
+            CfgError (GetSourcePos (M->LI),
+                      "Size of memory area `%s' is not constant",
+                      GetString (M->Name));
+        }
+        M->Size = GetExprVal (M->SizeExpr);
 
        /* Walk through the segments in this memory area */
         for (J = 0; J < CollCount (&M->SegList); ++J) {
@@ -1760,8 +1811,22 @@ unsigned CfgProcess (void)
                  */
                 if (S->Flags & SF_ALIGN) {
                     /* Align the address */
-                    unsigned long Val = (0x01UL << S->Align) - 1;
-                    Addr = (Addr + Val) & ~Val;
+                    unsigned long NewAddr = AlignAddr (Addr, S->RunAlignment);
+
+                    /* If the first segment placed in the memory area needs
+                     * fill bytes for the alignment, emit a warning, since
+                     * this is somewhat suspicious.
+                     */
+                    if (M->FillLevel == 0 && NewAddr > Addr) {
+                        CfgWarning (GetSourcePos (S->LI),
+                                    "First segment in memory area `%s' does "
+                                    "already need fill bytes for alignment",
+                                    GetString (M->Name));
+                    }
+
+                    /* Use the aligned address */
+                    Addr = NewAddr;
+
                 } else if (S->Flags & (SF_OFFSET | SF_START)) {
                     /* Give the segment a fixed starting address */
                     unsigned long NewAddr = S->Addr;
@@ -1772,11 +1837,15 @@ unsigned CfgProcess (void)
                     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));
+                            CfgError (GetSourcePos (M->LI),
+                                      "Offset too small in `%s', segment `%s'",
+                                      GetString (M->Name),
+                                      GetString (S->Name));
                         } else {
-                            Error ("Start address too low in `%s', segment `%s'",
-                                   GetString (M->Name), GetString (S->Name));
+                            CfgError (GetSourcePos (M->LI),
+                                      "Start address too low in `%s', segment `%s'",
+                                      GetString (M->Name),
+                                      GetString (S->Name));
                         }
                     }
                     Addr = NewAddr;
@@ -1800,8 +1869,7 @@ unsigned CfgProcess (void)
                  */
                 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);
                 }
 
             }
@@ -1813,9 +1881,10 @@ unsigned CfgProcess (void)
                    if (M->FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) {
                 ++Overflows;
                 M->Flags |= MF_OVERFLOW;
-                Warning ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
-                         GetString (M->Name), GetString (S->Name),
-                         M->FillLevel - M->Size);
+                CfgWarning (GetSourcePos (M->LI),
+                            "Memory area overflow in `%s', segment `%s' (%lu bytes)",
+                             GetString (M->Name), GetString (S->Name),
+                             M->FillLevel - M->Size);
            }
 
            /* If requested, define symbols for the start and size of the
@@ -1837,13 +1906,19 @@ unsigned CfgProcess (void)
 
        /* If requested, define symbols for start and size of the memory area */
        if (M->Flags & MF_DEFINE) {
+            Export* E;
            StrBuf Buf = STATIC_STRBUF_INITIALIZER;
-           SB_Printf (&Buf, "__%s_START__", GetString (M->Name));
-           CreateMemoryExport (GetStrBufId (&Buf), M, 0);
+
+            /* Define the size of the memory area */
            SB_Printf (&Buf, "__%s_SIZE__", GetString (M->Name));
-           CreateConstExport (GetStrBufId (&Buf), M->Size);
+           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));
-           CreateMemoryExport (GetStrBufId (&Buf), M, M->FillLevel);
+           E = CreateMemoryExport (GetStrBufId (&Buf), M, M->FillLevel);
+            CollAppend (&E->DefLines, M->LI);
+
             SB_Done (&Buf);
        }