]> git.sur5r.net Git - cc65/blobdiff - src/ld65/config.c
Replaced builtin linker configs with ordinary .cfg files.
[cc65] / src / ld65 / config.c
index f6e2ff0ed64ecb00b1a94aeef7445d6f416d51ee..70fa63b545f064c329c7fcda08283f495c9eaedb 100644 (file)
@@ -6,11 +6,15 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2010, Ullrich von Bassewitz                                      */
+/* (C) 1998-2012, 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       */
 /* warranty.  In no event will the authors be held liable for any damages    */
 #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"
@@ -97,6 +104,7 @@ static Collection       MemoryAreas = STATIC_COLLECTION_INITIALIZER;
 #define MA_DEFINE              0x0010
 #define MA_FILL                0x0020
 #define MA_FILLVAL             0x0040
+#define MA_BANK         0x0080
 
 /* Segment list */
 static Collection       SegDescList = STATIC_COLLECTION_INITIALIZER;
@@ -111,6 +119,7 @@ static Collection       SegDescList = STATIC_COLLECTION_INITIALIZER;
 #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 {
@@ -292,6 +301,7 @@ static File* NewFile (unsigned Name)
     F->Name    = Name;
     F->Flags   = 0;
     F->Format  = BINFMT_DEFAULT;
+    F->Size    = 0;
     InitCollection (&F->MemoryAreas);
 
     /* Insert the struct into the list */
@@ -340,12 +350,14 @@ static SegDesc* NewSegDesc (unsigned Name)
     S = xmalloc (sizeof (SegDesc));
 
     /* Initialize the fields */
-    S->Name    = Name;
-    S->LI      = GenLineInfo (&CfgErrorPos);
-    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->FillVal       = 0;
+    S->RunAlignment  = 1;
+    S->LoadAlignment = 1;
 
     /* Insert the struct into the list ... */
     CollAppend (&SegDescList, S);
@@ -359,6 +371,7 @@ static SegDesc* NewSegDesc (unsigned Name)
 static void FreeSegDesc (SegDesc* S)
 /* Free a segment descriptor */
 {
+    FreeLineInfo (S->LI);
     xfree (S);
 }
 
@@ -397,13 +410,14 @@ 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   },
+        {   "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       },
@@ -434,21 +448,17 @@ static void ParseMemory (void)
            /* Check which attribute was given */
            switch (AttrTok) {
 
-               case CFGTOK_START:
-                   FlagAttr (&M->Attr, MA_START, "START");
-                    M->StartExpr = CfgExpr ();
-                   break;
-
-               case CFGTOK_SIZE:
-                   FlagAttr (&M->Attr, MA_SIZE, "SIZE");
-                   M->SizeExpr = CfgExpr ();
+               case CFGTOK_BANK:
+                   FlagAttr (&M->Attr, MA_BANK, "BANK");
+                   M->BankExpr = 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;
+               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;
@@ -461,16 +471,6 @@ static void ParseMemory (void)
                     CfgNextTok ();
                    break;
 
-               case CFGTOK_DEFINE:
-                   FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
-                   /* Map the token to a boolean */
-                   CfgBoolToken ();
-                   if (CfgTok == CFGTOK_TRUE) {
-                       M->Flags |= MF_DEFINE;
-                   }
-                    CfgNextTok ();
-                   break;
-
                case CFGTOK_FILL:
                    FlagAttr (&M->Attr, MA_FILL, "FILL");
                    /* Map the token to a boolean */
@@ -486,6 +486,25 @@ static void ParseMemory (void)
                    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");
 
@@ -621,6 +640,7 @@ static void ParseSegments (void)
         {   "ALIGN",            CFGTOK_ALIGN            },
         {   "ALIGN_LOAD",       CFGTOK_ALIGN_LOAD       },
         {   "DEFINE",           CFGTOK_DEFINE           },
+        {   "FILLVAL",          CFGTOK_FILLVAL          },
                {   "LOAD",             CFGTOK_LOAD             },
        {   "OFFSET",           CFGTOK_OFFSET           },
         {   "OPTIONAL",         CFGTOK_OPTIONAL         },
@@ -636,7 +656,6 @@ static void ParseSegments (void)
     };
 
     unsigned Count;
-    long     Val;
 
     /* The MEMORY section must preceed the SEGMENTS section */
     if ((SectionsEncountered & SE_MEMORY) == 0) {
@@ -671,21 +690,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 (&CfgErrorPos, "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 (&CfgErrorPos, "Alignment must be a power of 2");
-                   }
+                   S->LoadAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
                    S->Flags |= SF_ALIGN_LOAD;
                    break;
 
@@ -699,6 +710,12 @@ static void ParseSegments (void)
                     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));
@@ -1026,11 +1043,12 @@ static void ParseConDes (void)
 /* Parse the CONDES feature */
 {
     static const IdentTok Attributes [] = {
-               {   "SEGMENT",          CFGTOK_SEGMENT          },
-       {   "LABEL",            CFGTOK_LABEL            },
        {   "COUNT",            CFGTOK_COUNT            },
-       {   "TYPE",             CFGTOK_TYPE             },
+        {   "IMPORT",           CFGTOK_IMPORT           },
+       {   "LABEL",            CFGTOK_LABEL            },
        {   "ORDER",            CFGTOK_ORDER            },
+               {   "SEGMENT",          CFGTOK_SEGMENT          },
+       {   "TYPE",             CFGTOK_TYPE             },
     };
 
     static const IdentTok Types [] = {
@@ -1045,9 +1063,10 @@ static void ParseConDes (void)
     };
 
     /* 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;
@@ -1055,11 +1074,12 @@ static void ParseConDes (void)
     /* Bitmask to remember the attributes we got already */
     enum {
        atNone          = 0x0000,
-       atSegName       = 0x0001,
-       atLabel         = 0x0002,
-       atCount         = 0x0004,
-       atType          = 0x0008,
-       atOrder         = 0x0010
+       atCount         = 0x0001,
+        atImport        = 0x0002,
+       atLabel         = 0x0004,
+       atOrder         = 0x0008,
+       atSegName       = 0x0010,
+       atType          = 0x0020,
     };
     unsigned AttrFlags = atNone;
 
@@ -1078,50 +1098,34 @@ static void ParseConDes (void)
        /* Check which attribute was given */
        switch (AttrTok) {
 
-           case CFGTOK_SEGMENT:
-               /* Don't allow this twice */
-               FlagAttr (&AttrFlags, atSegName, "SEGMENT");
+           case CFGTOK_COUNT:
+               /* Don't allow this twice */
+               FlagAttr (&AttrFlags, atCount, "COUNT");
                /* We expect an identifier */
-               CfgAssureIdent ();
-               /* Remember the value for later */
-               SegName = GetStrBufId (&CfgSVal);
+               CfgAssureIdent ();
+               /* Remember the value for later */
+               Count = GetStrBufId (&CfgSVal);
                break;
 
-           case CFGTOK_LABEL:
+           case CFGTOK_IMPORT:
                /* Don't allow this twice */
-               FlagAttr (&AttrFlags, atLabel, "LABEL");
+               FlagAttr (&AttrFlags, atImport, "IMPORT");
                /* We expect an identifier */
-               CfgAssureIdent ();
-               /* Remember the value for later */
-               Label = GetStrBufId (&CfgSVal);
-               break;
+               CfgAssureIdent ();
+               /* Remember value and position for later */
+                       Import.Name = GetStrBufId (&CfgSVal);
+                Import.Pos = CfgErrorPos;
+                Import.AddrSize = ADDR_SIZE_ABS;
+               break;
 
-           case CFGTOK_COUNT:
+           case CFGTOK_LABEL:
                /* Don't allow this twice */
-               FlagAttr (&AttrFlags, atCount, "COUNT");
+               FlagAttr (&AttrFlags, atLabel, "LABEL");
                /* We expect an identifier */
-               CfgAssureIdent ();
-               /* Remember the value for later */
-               Count = 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;
+               CfgAssureIdent ();
+               /* Remember the value for later */
+               Label = GetStrBufId (&CfgSVal);
+               break;
 
            case CFGTOK_ORDER:
                /* Don't allow this twice */
@@ -1134,6 +1138,33 @@ static void ParseConDes (void)
                }
                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;
+
            default:
                FAIL ("Unexpected attribute token");
 
@@ -1168,6 +1199,9 @@ static void ParseConDes (void)
     if (AttrFlags & atCount) {
        ConDesSetCountSym (Type, Count);
     }
+    if (AttrFlags & atImport) {
+       ConDesSetImport (Type, &Import);
+    }
     if (AttrFlags & atOrder) {
        ConDesSetOrder (Type, Order);
     }
@@ -1414,10 +1448,10 @@ static void ParseSymbols (void)
 
             case CfgSymExport:
                 /* We must have a value */
-                AttrCheck (AttrFlags, atType, "TYPE");
+                AttrCheck (AttrFlags, atValue, "VALUE");
                 /* Create the export */
                 Exp = CreateExprExport (Name, Value, AddrSize);
-                CollAppend (&Exp->LineInfos, GenLineInfo (&CfgErrorPos));
+                CollAppend (&Exp->DefLines, GenLineInfo (&CfgErrorPos));
                 break;
 
             case CfgSymImport:
@@ -1428,12 +1462,12 @@ static void ParseSymbols (void)
                 /* Generate the import */
                 Imp = InsertImport (GenImport (Name, AddrSize));
                 /* Remember the file position */
-                CollAppend (&Imp->LineInfos, GenLineInfo (&CfgErrorPos));
+                CollAppend (&Imp->RefLines, GenLineInfo (&CfgErrorPos));
                 break;
 
             case CfgSymWeak:
                 /* We must have a value */
-                AttrCheck (AttrFlags, atType, "TYPE");
+                AttrCheck (AttrFlags, atValue, "VALUE");
                 /* Remember the symbol for later */
                 Sym = NewCfgSymbol (CfgSymWeak, Name);
                 Sym->Value = Value;
@@ -1554,22 +1588,22 @@ static void ProcessSegments (void)
     while (I < CollCount (&SegDescList)) {
 
         /* Get the next segment descriptor */
-       SegDesc* S = CollAtUnchecked (&SegDescList, I);
+       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
+       /* 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)) {
+        */
+       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));
-       }
+                       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
@@ -1585,6 +1619,9 @@ static void ProcessSegments (void)
                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;
 
@@ -1678,7 +1715,7 @@ static void ProcessSymbols (void)
                 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->LineInfos, Sym->LI);
+                    CollAppend (&E->DefLines, Sym->LI);
                 }
                 break;
 
@@ -1701,12 +1738,12 @@ static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
     /* 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->LineInfos, S->LI);
+    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->LineInfos, S->LI);
+    CollAppend (&E->DefLines, S->LI);
 
     S->Flags |= SF_RUN_DEF;
     SB_Done (&Buf);
@@ -1723,7 +1760,7 @@ static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
     /* 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->LineInfos, S->LI);
+    CollAppend (&E->DefLines, S->LI);
 
     S->Flags |= SF_LOAD_DEF;
     SB_Done (&Buf);
@@ -1763,6 +1800,9 @@ unsigned CfgProcess (void)
         /* 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);
 
@@ -1788,7 +1828,7 @@ unsigned CfgProcess (void)
             /* Define the start of the memory area */
            SB_Printf (&Buf, "__%s_START__", GetString (M->Name));
            E = CreateMemoryExport (GetStrBufId (&Buf), M, 0);
-            CollAppend (&E->LineInfos, M->LI);
+            CollAppend (&E->DefLines, M->LI);
 
             SB_Done (&Buf);
         }
@@ -1807,6 +1847,9 @@ unsigned CfgProcess (void)
            /* Get the segment */
            SegDesc* S = CollAtUnchecked (&M->SegList, J);
 
+            /* Remember the start address before handling this segment */
+            unsigned long StartAddr = Addr;
+
             /* Some actions depend on wether this is the load or run memory
              * area.
              */
@@ -1817,8 +1860,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;
@@ -1849,10 +1906,11 @@ unsigned CfgProcess (void)
                  */
                 S->Seg->PC = Addr;
                 S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
-                S->Seg->Relocatable = M->Relocatable;
 
-                /* Remember that this segment is placed */
-                S->Seg->Placed = 1;
+                /* Remember the run memory for this segment, which is also a
+                 * flag that the segment has been placed.
+                 */
+                S->Seg->MemArea = M;
 
             } else if (S->Load == M) {
 
@@ -1861,12 +1919,18 @@ 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);
                 }
 
             }
 
+            /* 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.
             */
@@ -1895,9 +1959,16 @@ unsigned CfgProcess (void)
            /* Calculate the new address */
            Addr += S->Seg->Size;
 
+            /* If this segment goes out to the file, increase the file size */
+            if ((S->Flags & SF_BSS) == 0 && S->Load == M) {
+                M->F->Size += Addr - StartAddr;
+            }
+
        }
 
-       /* If requested, define symbols for start and size of the memory area */
+       /* 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;
@@ -1905,16 +1976,32 @@ unsigned CfgProcess (void)
             /* Define the size of the memory area */
            SB_Printf (&Buf, "__%s_SIZE__", GetString (M->Name));
            E = CreateConstExport (GetStrBufId (&Buf), M->Size);
-            CollAppend (&E->LineInfos, M->LI);
+            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->LineInfos, M->LI);
+            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, acount 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 */