]> 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 a5d6ff39ba53ecbc6ecde46b5ed228584e529ced..fdf7d13eb7da070124eae38ff8eb855352bb867f 100644 (file)
@@ -68,6 +68,7 @@
 #include "objdata.h"
 #include "scanner.h"
 #include "spool.h"
+#include "xex.h"
 
 
 
@@ -131,9 +132,9 @@ typedef enum {
 } 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).
- */
+** 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 */
@@ -149,6 +150,7 @@ static Collection       CfgSymbols = STATIC_COLLECTION_INITIALIZER;
 /* Descriptor holding information about the binary formats */
 static BinDesc* BinFmtDesc      = 0;
 static O65Desc* O65FmtDesc      = 0;
+static XexDesc* XexFmtDesc      = 0;
 
 
 
@@ -226,7 +228,7 @@ static MemoryArea* CfgGetMemory (unsigned Name)
 {
     MemoryArea* M = CfgFindMemory (Name);
     if (M == 0) {
-        CfgError (&CfgErrorPos, "Invalid memory area `%s'", GetString (Name));
+        CfgError (&CfgErrorPos, "Invalid memory area '%s'", GetString (Name));
     }
     return M;
 }
@@ -268,9 +270,9 @@ static void MemoryInsert (MemoryArea* M, SegDesc* S)
 
 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.
- */
+** current config file position is recorded in the returned struct. The
+** created struct is inserted into the CfgSymbols collection and returned.
+*/
 {
     /* Allocate memory */
     CfgSymbol* Sym = xmalloc (sizeof (CfgSymbol));
@@ -320,7 +322,7 @@ static MemoryArea* CreateMemoryArea (const FilePos* Pos, unsigned Name)
     MemoryArea* M = CfgFindMemory (Name);
     if (M) {
         CfgError (&CfgErrorPos,
-                  "Memory area `%s' defined twice",
+                  "Memory area '%s' defined twice",
                   GetString (Name));
     }
 
@@ -343,7 +345,7 @@ static SegDesc* NewSegDesc (unsigned Name)
     /* Check for duplicate names */
     SegDesc* S = CfgFindSegDesc (Name);
     if (S) {
-        CfgError (&CfgErrorPos, "Segment `%s' defined twice", GetString (Name));
+        CfgError (&CfgErrorPos, "Segment '%s' defined twice", GetString (Name));
     }
 
     /* Allocate memory */
@@ -385,8 +387,8 @@ static void FreeSegDesc (SegDesc* S)
 
 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 (&CfgErrorPos, "%s is already defined", Name);
@@ -522,8 +524,8 @@ static void ParseMemory (void)
         AttrCheck (M->Attr, MA_SIZE, "SIZE");
 
         /* If we don't have a file name for output given, use the default
-         * file name.
-         */
+        ** file name.
+        */
         if ((M->Attr & MA_FILE) == 0) {
             FileInsert (GetFile (GetStringId (OutputName)), M);
             OutputNameUsed = 1;
@@ -543,6 +545,7 @@ static void ParseFiles (void)
         {   "FORMAT",   CFGTOK_FORMAT   },
     };
     static const IdentTok Formats [] = {
+        {   "ATARI",    CFGTOK_ATARIEXE },
         {   "O65",      CFGTOK_O65      },
         {   "BIN",      CFGTOK_BIN      },
         {   "BINARY",   CFGTOK_BIN      },
@@ -566,7 +569,7 @@ static void ParseFiles (void)
         F = FindFile (GetStrBufId (&CfgSVal));
         if (F == 0) {
             CfgError (&CfgErrorPos,
-                      "File `%s' not found in MEMORY section",
+                      "File '%s' not found in MEMORY section",
                       SB_GetConstBuf (&CfgSVal));
         }
 
@@ -607,6 +610,10 @@ static void ParseFiles (void)
                             F->Format = BINFMT_O65;
                             break;
 
+                        case CFGTOK_ATARIEXE:
+                            F->Format = BINFMT_ATARIEXE;
+                            break;
+
                         default:
                             Error ("Unexpected format token");
                     }
@@ -653,6 +660,7 @@ static void ParseSegments (void)
         {   "RW",               CFGTOK_RW               },
         {   "BSS",              CFGTOK_BSS              },
         {   "ZP",               CFGTOK_ZP               },
+        {   "OVERWRITE",        CFGTOK_OVERWRITE        },
     };
 
     unsigned Count;
@@ -753,11 +761,12 @@ static void ParseSegments (void)
                     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);
+                        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;
@@ -781,8 +790,8 @@ static void ParseSegments (void)
         }
 
         /* 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)) {
             CfgWarning (&CfgErrorPos,
                         "ALIGN_LOAD attribute specified, but no separate "
@@ -792,11 +801,11 @@ static void ParseSegments (void)
         }
 
         /* 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)) {
             CfgWarning (&CfgErrorPos,
-                        "Segment with type `bss' has both LOAD and RUN "
+                        "Segment with type 'bss' has both LOAD and RUN "
                         "memory areas assigned");
         }
 
@@ -804,7 +813,7 @@ static void ParseSegments (void)
         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'",
+                          "Cannot put r/w segment '%s' in r/o memory area '%s'",
                           GetString (S->Name), GetString (S->Run->Name));
             }
         }
@@ -930,8 +939,8 @@ static void ParseO65 (void)
                 /* 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.
-                 */
+                ** as a number in the range 1..255.
+                */
                 if (CfgTok == CFGTOK_INTCON) {
                     CfgRangeCheck (O65OS_MIN, O65OS_MAX);
                     OS = (unsigned) CfgIVal;
@@ -1021,6 +1030,7 @@ static void ParseFormats (void)
                 break;
 
             case CFGTOK_BIN:
+            case CFGTOK_ATARIEXE:
                 /* No attribibutes available */
                 break;
 
@@ -1266,8 +1276,8 @@ static void ParseStartAddress (void)
     AttrCheck (AttrFlags, atDefault, "DEFAULT");
 
     /* If no start address was given on the command line, use the one given
-     * here
-     */
+    ** here
+    */
     if (!HaveStartAddr) {
         StartAddr = DefStartAddr;
     }
@@ -1509,7 +1519,7 @@ static void ParseConfig (void)
         CfgNextTok ();
 
         /* Expected a curly brace */
-        CfgConsume (CFGTOK_LCURLY, "`{' expected");
+        CfgConsume (CFGTOK_LCURLY, "'{' expected");
 
         /* Read the block */
         switch (BlockTok) {
@@ -1544,7 +1554,7 @@ static void ParseConfig (void)
         }
 
         /* Skip closing brace */
-        CfgConsume (CFGTOK_RCURLY, "`}' expected");
+        CfgConsume (CFGTOK_RCURLY, "'}' expected");
 
     } while (CfgTok != CFGTOK_EOF);
 }
@@ -1557,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 */
@@ -1591,25 +1602,25 @@ static void ProcessSegments (void)
         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.
-         */
+        ** 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.
-         */
+        ** 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",
+                        "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.
-         */
+        ** 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 */
@@ -1630,7 +1641,7 @@ static void ProcessSegments (void)
             /* Print a warning if the segment is not optional */
             if ((S->Flags & SF_OPTIONAL) == 0) {
                 CfgWarning (&CfgErrorPos,
-                            "Segment `%s' does not exist",
+                            "Segment '%s' does not exist",
                             GetString (S->Name));
             }
 
@@ -1663,19 +1674,19 @@ static void ProcessSymbols (void)
                 if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
                     CfgError (
                         GetSourcePos (Sym->LI),
-                        "Exported o65 symbol `%s' cannot also be an o65 import",
+                        "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.
-                 */
+                ** 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'",
+                        "Duplicate exported o65 symbol: '%s'",
                         GetString (Sym->Name)
                     );
                 }
@@ -1689,19 +1700,19 @@ static void ProcessSymbols (void)
                 if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
                     CfgError (
                         GetSourcePos (Sym->LI),
-                        "Imported o65 symbol `%s' cannot also be an o65 export",
+                        "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.
-                 */
+                ** 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'",
+                        "Duplicate imported o65 symbol: '%s'",
                         GetString (Sym->Name)
                     );
                 }
@@ -1769,33 +1780,33 @@ static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
 
 
 unsigned CfgProcess (void)
-/* Process the config file after reading in object files and libraries. This
- * includes postprocessing of the config file data but also assigning segments
- * and defining segment/memory area related symbols. The function will return
- * the number of memory area overflows (so zero means anything went ok).
- * In case of overflows, a short mapfile can be generated later, to ease the
- * task of rearranging segments for the user.
- */
+/* 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.
+*/
 {
     unsigned Overflows = 0;
     unsigned I;
 
     /* Postprocess symbols. We must do that first, since weak symbols are
-     * defined here, which may be needed later.
-     */
+    ** defined here, which may be needed later.
+    */
     ProcessSymbols ();
 
     /* Postprocess segments */
     ProcessSegments ();
 
-    /* Walk through each of the memory sections. Add up the sizes and check
-     * for an overflow of the section. Assign the start addresses of the
-     * segments while doing this.
-     */
+    /* 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);
@@ -1806,21 +1817,21 @@ unsigned CfgProcess (void)
         /* 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.
-         */
+        /* 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",
+                      "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.
-         */
+        ** 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;
@@ -1836,117 +1847,168 @@ unsigned CfgProcess (void)
         /* Resolve the size expression */
         if (!IsConstExpr (M->SizeExpr)) {
             CfgError (GetSourcePos (M->LI),
-                      "Size of memory area `%s' is not constant",
+                      "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;
 
-            /* Some actions depend on wether this is the load or run memory
-             * area.
-             */
-            if (S->Run == M) {
+            /* 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 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 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.
-                     */
+                    ** fill bytes for the alignment, emit a warning, since
+                    ** that 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",
+                                    "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)) {
+                } 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) {
-                            CfgError (GetSourcePos (M->LI),
-                                      "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 {
+                            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 {
-                            CfgError (GetSourcePos (M->LI),
-                                      "Start address too low in `%s', segment `%s'",
-                                      GetString (M->Name),
-                                      GetString (S->Name));
+                            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;
 
                 /* Remember the run memory for this segment, which is also a
-                 * flag that the segment has been placed.
-                 */
+                ** flag that the segment has been placed.
+                */
                 S->Seg->MemArea = M;
 
             } else if (S->Load == M) {
-
-                /* This is the load memory area, *and* run and load are
-                 * different (because of the "else" above). Handle alignment.
-                 */
+                /* This is the load memory area; *and*, run and load are
+                ** different (because of the "else" above). Handle alignment.
+                */
                 if (S->Flags & SF_ALIGN_LOAD) {
                     /* Align the address */
                     Addr = AlignAddr (Addr, S->LoadAlignment);
                 }
-
             }
 
-            /* 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 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.
-             */
+            /* 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),
-                            "Memory area overflow in `%s', segment `%s' (%lu bytes)",
-                             GetString (M->Name), GetString (S->Name),
-                             M->FillLevel - M->Size);
+                            "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');
             }
 
             /* If requested, define symbols for the start and size of the
-             * segment.
-             */
+            ** segment.
+            */
             if (S->Flags & SF_DEFINE) {
                 if (S->Run == M && (S->Flags & SF_RUN_DEF) == 0) {
                     CreateRunDefines (S, Addr);
@@ -1960,18 +2022,17 @@ unsigned CfgProcess (void)
             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.
-             */
+            ** 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 requested, define symbols for start, size, and offset of the
+        ** memory area
+        */
         if (M->Flags & MF_DEFINE) {
             Export* E;
             StrBuf Buf = STATIC_STRBUF_INITIALIZER;
@@ -1987,8 +2048,8 @@ unsigned CfgProcess (void)
             CollAppend (&E->DefLines, M->LI);
 
             /* Define the file offset of the memory area. This isn't of much
-             * use for relocatable output files.
-             */
+            ** use for relocatable output files.
+            */
             if (!M->Relocatable) {
                 SB_Printf (&Buf, "__%s_FILEOFFS__", GetString (M->Name));
                 E = CreateConstExport (GetStrBufId (&Buf), M->FileOffs);
@@ -1999,9 +2060,9 @@ unsigned CfgProcess (void)
             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 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);
         }
@@ -2046,6 +2107,10 @@ void CfgWriteTarget (void)
                         O65WriteTarget (O65FmtDesc, F);
                         break;
 
+                    case BINFMT_ATARIEXE:
+                        XexWriteTarget (XexFmtDesc, F);
+                        break;
+
                     default:
                         Internal ("Invalid binary format: %u", F->Format);
 
@@ -2054,8 +2119,8 @@ void CfgWriteTarget (void)
             } else {
 
                 /* No output file. Walk through the list and mark all segments
-                 * loading into these memory areas in this file as dumped.
-                 */
+                ** loading into these memory areas in this file as dumped.
+                */
                 unsigned J;
                 for (J = 0; J < CollCount (&F->MemoryAreas); ++J) {
 
@@ -2065,7 +2130,7 @@ void CfgWriteTarget (void)
                     MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, J);
 
                     /* Debugging */
-                    Print (stdout, 2, "Skipping `%s'...\n", GetString (M->Name));
+                    Print (stdout, 2, "Skipping '%s'...\n", GetString (M->Name));
 
                     /* Walk throught the segments */
                     for (K = 0; K < CollCount (&M->SegList); ++K) {
@@ -2080,6 +2145,3 @@ void CfgWriteTarget (void)
         }
     }
 }
-
-
-