]> git.sur5r.net Git - cc65/blob - src/ld65/config.c
Add support for Atari XEX file format to LD65
[cc65] / src / ld65 / config.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 config.c                                  */
4 /*                                                                           */
5 /*               Target configuration file for the ld65 linker               */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (c) 1998-2013, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /* With contributions from:                                                  */
15 /*                                                                           */
16 /*      - "David M. Lloyd" <david.lloyd@redhat.com>                          */
17 /*                                                                           */
18 /*                                                                           */
19 /* This software is provided 'as-is', without any expressed or implied       */
20 /* warranty.  In no event will the authors be held liable for any damages    */
21 /* arising from the use of this software.                                    */
22 /*                                                                           */
23 /* Permission is granted to anyone to use this software for any purpose,     */
24 /* including commercial applications, and to alter it and redistribute it    */
25 /* freely, subject to the following restrictions:                            */
26 /*                                                                           */
27 /* 1. The origin of this software must not be misrepresented; you must not   */
28 /*    claim that you wrote the original software. If you use this software   */
29 /*    in a product, an acknowledgment in the product documentation would be  */
30 /*    appreciated but is not required.                                       */
31 /* 2. Altered source versions must be plainly marked as such, and must not   */
32 /*    be misrepresented as being the original software.                      */
33 /* 3. This notice may not be removed or altered from any source              */
34 /*    distribution.                                                          */
35 /*                                                                           */
36 /*****************************************************************************/
37
38
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <errno.h>
44
45 /* common */
46 #include "addrsize.h"
47 #include "bitops.h"
48 #include "check.h"
49 #include "print.h"
50 #include "segdefs.h"
51 #include "target.h"
52 #include "xmalloc.h"
53 #include "xsprintf.h"
54
55 /* ld65 */
56 #include "alignment.h"
57 #include "bin.h"
58 #include "binfmt.h"
59 #include "cfgexpr.h"
60 #include "condes.h"
61 #include "config.h"
62 #include "error.h"
63 #include "exports.h"
64 #include "expr.h"
65 #include "global.h"
66 #include "memarea.h"
67 #include "o65.h"
68 #include "objdata.h"
69 #include "scanner.h"
70 #include "spool.h"
71 #include "xex.h"
72
73
74
75 /*****************************************************************************/
76 /*                                   Data                                    */
77 /*****************************************************************************/
78
79
80
81 /* Remember which sections we had encountered */
82 static enum {
83     SE_NONE     = 0x0000,
84     SE_MEMORY   = 0x0001,
85     SE_SEGMENTS = 0x0002,
86     SE_FEATURES = 0x0004,
87     SE_FILES    = 0x0008,
88     SE_FORMATS  = 0x0010,
89     SE_SYMBOLS  = 0x0020
90 } SectionsEncountered = SE_NONE;
91
92
93
94 /* File list */
95 static Collection       FileList = STATIC_COLLECTION_INITIALIZER;
96
97 /* Memory list */
98 static Collection       MemoryAreas = STATIC_COLLECTION_INITIALIZER;
99
100 /* Memory attributes */
101 #define MA_START        0x0001
102 #define MA_SIZE         0x0002
103 #define MA_TYPE         0x0004
104 #define MA_FILE         0x0008
105 #define MA_DEFINE       0x0010
106 #define MA_FILL         0x0020
107 #define MA_FILLVAL      0x0040
108 #define MA_BANK         0x0080
109
110 /* Segment list */
111 static Collection       SegDescList = STATIC_COLLECTION_INITIALIZER;
112
113 /* Segment attributes */
114 #define SA_TYPE         0x0001
115 #define SA_LOAD         0x0002
116 #define SA_RUN          0x0004
117 #define SA_ALIGN        0x0008
118 #define SA_ALIGN_LOAD   0x0010
119 #define SA_DEFINE       0x0020
120 #define SA_OFFSET       0x0040
121 #define SA_START        0x0080
122 #define SA_OPTIONAL     0x0100
123 #define SA_FILLVAL      0x0200
124
125 /* Symbol types used in the CfgSymbol structure */
126 typedef enum {
127     CfgSymExport,               /* Not really used in struct CfgSymbol */
128     CfgSymImport,               /* Dito */
129     CfgSymWeak,                 /* Like export but weak */
130     CfgSymO65Export,            /* An o65 export */
131     CfgSymO65Import,            /* An o65 import */
132 } CfgSymType;
133
134 /* Symbol structure. It is used for o65 imports and exports, but also for
135 ** symbols from the SYMBOLS sections (symbols defined in the config file or
136 ** forced imports).
137 */
138 typedef struct CfgSymbol CfgSymbol;
139 struct CfgSymbol {
140     CfgSymType  Type;           /* Type of symbol */
141     LineInfo*   LI;             /* Config file position */
142     unsigned    Name;           /* Symbol name */
143     ExprNode*   Value;          /* Symbol value if any */
144     unsigned    AddrSize;       /* Address size of symbol */
145 };
146
147 /* Collections with symbols */
148 static Collection       CfgSymbols = STATIC_COLLECTION_INITIALIZER;
149
150 /* Descriptor holding information about the binary formats */
151 static BinDesc* BinFmtDesc      = 0;
152 static O65Desc* O65FmtDesc      = 0;
153 static XexDesc* XexFmtDesc      = 0;
154
155
156
157 /*****************************************************************************/
158 /*                                 Forwards                                  */
159 /*****************************************************************************/
160
161
162
163 static File* NewFile (unsigned Name);
164 /* Create a new file descriptor and insert it into the list */
165
166
167
168 /*****************************************************************************/
169 /*                              List management                              */
170 /*****************************************************************************/
171
172
173
174 static File* FindFile (unsigned Name)
175 /* Find a file with a given name. */
176 {
177     unsigned I;
178     for (I = 0; I < CollCount (&FileList); ++I) {
179         File* F = CollAtUnchecked (&FileList, I);
180         if (F->Name == Name) {
181             return F;
182         }
183     }
184     return 0;
185 }
186
187
188
189 static File* GetFile (unsigned Name)
190 /* Get a file entry with the given name. Create a new one if needed. */
191 {
192     File* F = FindFile (Name);
193     if (F == 0) {
194         /* Create a new one */
195         F = NewFile (Name);
196     }
197     return F;
198 }
199
200
201
202 static void FileInsert (File* F, MemoryArea* M)
203 /* Insert the memory area into the files list */
204 {
205     M->F = F;
206     CollAppend (&F->MemoryAreas, M);
207 }
208
209
210
211 static MemoryArea* CfgFindMemory (unsigned Name)
212 /* Find the memory are with the given name. Return NULL if not found */
213 {
214     unsigned I;
215     for (I = 0; I < CollCount (&MemoryAreas); ++I) {
216         MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
217         if (M->Name == Name) {
218             return M;
219         }
220     }
221     return 0;
222 }
223
224
225
226 static MemoryArea* CfgGetMemory (unsigned Name)
227 /* Find the memory are with the given name. Print an error on an invalid name */
228 {
229     MemoryArea* M = CfgFindMemory (Name);
230     if (M == 0) {
231         CfgError (&CfgErrorPos, "Invalid memory area '%s'", GetString (Name));
232     }
233     return M;
234 }
235
236
237
238 static SegDesc* CfgFindSegDesc (unsigned Name)
239 /* Find the segment descriptor with the given name, return NULL if not found. */
240 {
241     unsigned I;
242     for (I = 0; I < CollCount (&SegDescList); ++I) {
243         SegDesc* S = CollAtUnchecked (&SegDescList, I);
244         if (S->Name == Name) {
245             /* Found */
246             return S;
247         }
248     }
249
250     /* Not found */
251     return 0;
252 }
253
254
255
256 static void MemoryInsert (MemoryArea* M, SegDesc* S)
257 /* Insert the segment descriptor into the memory area list */
258 {
259     /* Insert the segment into the segment list of the memory area */
260     CollAppend (&M->SegList, S);
261 }
262
263
264
265 /*****************************************************************************/
266 /*                         Constructors/Destructors                          */
267 /*****************************************************************************/
268
269
270
271 static CfgSymbol* NewCfgSymbol (CfgSymType Type, unsigned Name)
272 /* Create a new CfgSymbol structure with the given type and name. The
273 ** current config file position is recorded in the returned struct. The
274 ** created struct is inserted into the CfgSymbols collection and returned.
275 */
276 {
277     /* Allocate memory */
278     CfgSymbol* Sym = xmalloc (sizeof (CfgSymbol));
279
280     /* Initialize the fields */
281     Sym->Type     = Type;
282     Sym->LI       = GenLineInfo (&CfgErrorPos);
283     Sym->Name     = Name;
284     Sym->Value    = 0;
285     Sym->AddrSize = ADDR_SIZE_INVALID;
286
287     /* Insert the symbol into the collection */
288     CollAppend (&CfgSymbols, Sym);
289
290     /* Return the initialized struct */
291     return Sym;
292 }
293
294
295
296 static File* NewFile (unsigned Name)
297 /* Create a new file descriptor and insert it into the list */
298 {
299     /* Allocate memory */
300     File* F = xmalloc (sizeof (File));
301
302     /* Initialize the fields */
303     F->Name    = Name;
304     F->Flags   = 0;
305     F->Format  = BINFMT_DEFAULT;
306     F->Size    = 0;
307     InitCollection (&F->MemoryAreas);
308
309     /* Insert the struct into the list */
310     CollAppend (&FileList, F);
311
312     /* ...and return it */
313     return F;
314 }
315
316
317
318 static MemoryArea* CreateMemoryArea (const FilePos* Pos, unsigned Name)
319 /* Create a new memory area and insert it into the list */
320 {
321     /* Check for duplicate names */
322     MemoryArea* M = CfgFindMemory (Name);
323     if (M) {
324         CfgError (&CfgErrorPos,
325                   "Memory area '%s' defined twice",
326                   GetString (Name));
327     }
328
329     /* Create a new memory area */
330     M = NewMemoryArea (Pos, Name);
331
332     /* Insert the struct into the list ... */
333     CollAppend (&MemoryAreas, M);
334
335     /* ...and return it */
336     return M;
337 }
338
339
340
341 static SegDesc* NewSegDesc (unsigned Name)
342 /* Create a segment descriptor and insert it into the list */
343 {
344
345     /* Check for duplicate names */
346     SegDesc* S = CfgFindSegDesc (Name);
347     if (S) {
348         CfgError (&CfgErrorPos, "Segment '%s' defined twice", GetString (Name));
349     }
350
351     /* Allocate memory */
352     S = xmalloc (sizeof (SegDesc));
353
354     /* Initialize the fields */
355     S->Name          = Name;
356     S->LI            = GenLineInfo (&CfgErrorPos);
357     S->Seg           = 0;
358     S->Attr          = 0;
359     S->Flags         = 0;
360     S->FillVal       = 0;
361     S->RunAlignment  = 1;
362     S->LoadAlignment = 1;
363
364     /* Insert the struct into the list ... */
365     CollAppend (&SegDescList, S);
366
367     /* ...and return it */
368     return S;
369 }
370
371
372
373 static void FreeSegDesc (SegDesc* S)
374 /* Free a segment descriptor */
375 {
376     FreeLineInfo (S->LI);
377     xfree (S);
378 }
379
380
381
382 /*****************************************************************************/
383 /*                            Config file parsing                            */
384 /*****************************************************************************/
385
386
387
388 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
389 /* Check if the item is already defined. Print an error if so. If not, set
390 ** the marker that we have a definition now.
391 */
392 {
393     if (*Flags & Mask) {
394         CfgError (&CfgErrorPos, "%s is already defined", Name);
395     }
396     *Flags |= Mask;
397 }
398
399
400
401 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
402 /* Check that a mandatory attribute was given */
403 {
404     if ((Attr & Mask) == 0) {
405         CfgError (&CfgErrorPos, "%s attribute is missing", Name);
406     }
407 }
408
409
410
411 static void ParseMemory (void)
412 /* Parse a MEMORY section */
413 {
414     static const IdentTok Attributes [] = {
415         {   "BANK",     CFGTOK_BANK     },
416         {   "DEFINE",   CFGTOK_DEFINE   },
417         {   "FILE",     CFGTOK_FILE     },
418         {   "FILL",     CFGTOK_FILL     },
419         {   "FILLVAL",  CFGTOK_FILLVAL  },
420         {   "SIZE",     CFGTOK_SIZE     },
421         {   "START",    CFGTOK_START    },
422         {   "TYPE",     CFGTOK_TYPE     },
423     };
424     static const IdentTok Types [] = {
425         {   "RO",       CFGTOK_RO       },
426         {   "RW",       CFGTOK_RW       },
427     };
428
429     while (CfgTok == CFGTOK_IDENT) {
430
431         /* Create a new entry on the heap */
432         MemoryArea* M = CreateMemoryArea (&CfgErrorPos, GetStrBufId (&CfgSVal));
433
434         /* Skip the name and the following colon */
435         CfgNextTok ();
436         CfgConsumeColon ();
437
438         /* Read the attributes */
439         while (CfgTok == CFGTOK_IDENT) {
440
441             /* Map the identifier to a token */
442             cfgtok_t AttrTok;
443             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
444             AttrTok = CfgTok;
445
446             /* An optional assignment follows */
447             CfgNextTok ();
448             CfgOptionalAssign ();
449
450             /* Check which attribute was given */
451             switch (AttrTok) {
452
453                 case CFGTOK_BANK:
454                     FlagAttr (&M->Attr, MA_BANK, "BANK");
455                     M->BankExpr = CfgExpr ();
456                     break;
457
458                 case CFGTOK_DEFINE:
459                     FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
460                     /* Map the token to a boolean */
461                     CfgBoolToken ();
462                     if (CfgTok == CFGTOK_TRUE) {
463                         M->Flags |= MF_DEFINE;
464                     }
465                     CfgNextTok ();
466                     break;
467
468                 case CFGTOK_FILE:
469                     FlagAttr (&M->Attr, MA_FILE, "FILE");
470                     CfgAssureStr ();
471                     /* Get the file entry and insert the memory area */
472                     FileInsert (GetFile (GetStrBufId (&CfgSVal)), M);
473                     CfgNextTok ();
474                     break;
475
476                 case CFGTOK_FILL:
477                     FlagAttr (&M->Attr, MA_FILL, "FILL");
478                     /* Map the token to a boolean */
479                     CfgBoolToken ();
480                     if (CfgTok == CFGTOK_TRUE) {
481                         M->Flags |= MF_FILL;
482                     }
483                     CfgNextTok ();
484                     break;
485
486                 case CFGTOK_FILLVAL:
487                     FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
488                     M->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
489                     break;
490
491                 case CFGTOK_SIZE:
492                     FlagAttr (&M->Attr, MA_SIZE, "SIZE");
493                     M->SizeExpr = CfgExpr ();
494                     break;
495
496                 case CFGTOK_START:
497                     FlagAttr (&M->Attr, MA_START, "START");
498                     M->StartExpr = CfgExpr ();
499                     break;
500
501                 case CFGTOK_TYPE:
502                     FlagAttr (&M->Attr, MA_TYPE, "TYPE");
503                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "TYPE");
504                     if (CfgTok == CFGTOK_RO) {
505                         M->Flags |= MF_RO;
506                     }
507                     CfgNextTok ();
508                     break;
509
510                 default:
511                     FAIL ("Unexpected attribute token");
512
513             }
514
515             /* Skip an optional comma */
516             CfgOptionalComma ();
517         }
518
519         /* Skip the semicolon */
520         CfgConsumeSemi ();
521
522         /* Check for mandatory parameters */
523         AttrCheck (M->Attr, MA_START, "START");
524         AttrCheck (M->Attr, MA_SIZE, "SIZE");
525
526         /* If we don't have a file name for output given, use the default
527         ** file name.
528         */
529         if ((M->Attr & MA_FILE) == 0) {
530             FileInsert (GetFile (GetStringId (OutputName)), M);
531             OutputNameUsed = 1;
532         }
533     }
534
535     /* Remember we had this section */
536     SectionsEncountered |= SE_MEMORY;
537 }
538
539
540
541 static void ParseFiles (void)
542 /* Parse a FILES section */
543 {
544     static const IdentTok Attributes [] = {
545         {   "FORMAT",   CFGTOK_FORMAT   },
546     };
547     static const IdentTok Formats [] = {
548         {   "ATARI",    CFGTOK_ATARIEXE },
549         {   "O65",      CFGTOK_O65      },
550         {   "BIN",      CFGTOK_BIN      },
551         {   "BINARY",   CFGTOK_BIN      },
552     };
553
554
555     /* The MEMORY section must preceed the FILES section */
556     if ((SectionsEncountered & SE_MEMORY) == 0) {
557         CfgError (&CfgErrorPos, "MEMORY must precede FILES");
558     }
559
560     /* Parse all files */
561     while (CfgTok != CFGTOK_RCURLY) {
562
563         File* F;
564
565         /* We expect a string value here */
566         CfgAssureStr ();
567
568         /* Search for the file, it must exist */
569         F = FindFile (GetStrBufId (&CfgSVal));
570         if (F == 0) {
571             CfgError (&CfgErrorPos,
572                       "File '%s' not found in MEMORY section",
573                       SB_GetConstBuf (&CfgSVal));
574         }
575
576         /* Skip the token and the following colon */
577         CfgNextTok ();
578         CfgConsumeColon ();
579
580         /* Read the attributes */
581         while (CfgTok == CFGTOK_IDENT) {
582
583             /* Map the identifier to a token */
584             cfgtok_t AttrTok;
585             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
586             AttrTok = CfgTok;
587
588             /* An optional assignment follows */
589             CfgNextTok ();
590             CfgOptionalAssign ();
591
592             /* Check which attribute was given */
593             switch (AttrTok) {
594
595                 case CFGTOK_FORMAT:
596                     if (F->Format != BINFMT_DEFAULT) {
597                         /* We've set the format already! */
598                         CfgError (&CfgErrorPos,
599                                   "Cannot set a file format twice");
600                     }
601                     /* Read the format token */
602                     CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
603                     switch (CfgTok) {
604
605                         case CFGTOK_BIN:
606                             F->Format = BINFMT_BINARY;
607                             break;
608
609                         case CFGTOK_O65:
610                             F->Format = BINFMT_O65;
611                             break;
612
613                         case CFGTOK_ATARIEXE:
614                             F->Format = BINFMT_ATARIEXE;
615                             break;
616
617                         default:
618                             Error ("Unexpected format token");
619                     }
620                     break;
621
622                 default:
623                     FAIL ("Unexpected attribute token");
624
625             }
626
627             /* Skip the attribute value and an optional comma */
628             CfgNextTok ();
629             CfgOptionalComma ();
630         }
631
632         /* Skip the semicolon */
633         CfgConsumeSemi ();
634
635     }
636
637     /* Remember we had this section */
638     SectionsEncountered |= SE_FILES;
639 }
640
641
642
643 static void ParseSegments (void)
644 /* Parse a SEGMENTS section */
645 {
646     static const IdentTok Attributes [] = {
647         {   "ALIGN",            CFGTOK_ALIGN            },
648         {   "ALIGN_LOAD",       CFGTOK_ALIGN_LOAD       },
649         {   "DEFINE",           CFGTOK_DEFINE           },
650         {   "FILLVAL",          CFGTOK_FILLVAL          },
651         {   "LOAD",             CFGTOK_LOAD             },
652         {   "OFFSET",           CFGTOK_OFFSET           },
653         {   "OPTIONAL",         CFGTOK_OPTIONAL         },
654         {   "RUN",              CFGTOK_RUN              },
655         {   "START",            CFGTOK_START            },
656         {   "TYPE",             CFGTOK_TYPE             },
657     };
658     static const IdentTok Types [] = {
659         {   "RO",               CFGTOK_RO               },
660         {   "RW",               CFGTOK_RW               },
661         {   "BSS",              CFGTOK_BSS              },
662         {   "ZP",               CFGTOK_ZP               },
663         {   "OVERWRITE",        CFGTOK_OVERWRITE        },
664     };
665
666     unsigned Count;
667
668     /* The MEMORY section must preceed the SEGMENTS section */
669     if ((SectionsEncountered & SE_MEMORY) == 0) {
670         CfgError (&CfgErrorPos, "MEMORY must precede SEGMENTS");
671     }
672
673     while (CfgTok == CFGTOK_IDENT) {
674
675         SegDesc* S;
676
677         /* Create a new entry on the heap */
678         S = NewSegDesc (GetStrBufId (&CfgSVal));
679
680         /* Skip the name and the following colon */
681         CfgNextTok ();
682         CfgConsumeColon ();
683
684         /* Read the attributes */
685         while (CfgTok == CFGTOK_IDENT) {
686
687             /* Map the identifier to a token */
688             cfgtok_t AttrTok;
689             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
690             AttrTok = CfgTok;
691
692             /* An optional assignment follows */
693             CfgNextTok ();
694             CfgOptionalAssign ();
695
696             /* Check which attribute was given */
697             switch (AttrTok) {
698
699                 case CFGTOK_ALIGN:
700                     FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
701                     S->RunAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
702                     S->Flags |= SF_ALIGN;
703                     break;
704
705                 case CFGTOK_ALIGN_LOAD:
706                     FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
707                     S->LoadAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
708                     S->Flags |= SF_ALIGN_LOAD;
709                     break;
710
711                 case CFGTOK_DEFINE:
712                     FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
713                     /* Map the token to a boolean */
714                     CfgBoolToken ();
715                     if (CfgTok == CFGTOK_TRUE) {
716                         S->Flags |= SF_DEFINE;
717                     }
718                     CfgNextTok ();
719                     break;
720
721                 case CFGTOK_FILLVAL:
722                     FlagAttr (&S->Attr, SA_FILLVAL, "FILLVAL");
723                     S->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
724                     S->Flags |= SF_FILLVAL;
725                     break;
726
727                 case CFGTOK_LOAD:
728                     FlagAttr (&S->Attr, SA_LOAD, "LOAD");
729                     S->Load = CfgGetMemory (GetStrBufId (&CfgSVal));
730                     CfgNextTok ();
731                     break;
732
733                 case CFGTOK_OFFSET:
734                     FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
735                     S->Addr   = CfgCheckedConstExpr (1, 0x1000000);
736                     S->Flags |= SF_OFFSET;
737                     break;
738
739                 case CFGTOK_OPTIONAL:
740                     FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL");
741                     CfgBoolToken ();
742                     if (CfgTok == CFGTOK_TRUE) {
743                         S->Flags |= SF_OPTIONAL;
744                     }
745                     CfgNextTok ();
746                     break;
747
748                 case CFGTOK_RUN:
749                     FlagAttr (&S->Attr, SA_RUN, "RUN");
750                     S->Run = CfgGetMemory (GetStrBufId (&CfgSVal));
751                     CfgNextTok ();
752                     break;
753
754                 case CFGTOK_START:
755                     FlagAttr (&S->Attr, SA_START, "START");
756                     S->Addr   = CfgCheckedConstExpr (1, 0x1000000);
757                     S->Flags |= SF_START;
758                     break;
759
760                 case CFGTOK_TYPE:
761                     FlagAttr (&S->Attr, SA_TYPE, "TYPE");
762                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
763                     switch (CfgTok) {
764                         case CFGTOK_RO:        S->Flags |= SF_RO;                  break;
765                         case CFGTOK_RW:        /* Default */                       break;
766                         case CFGTOK_BSS:       S->Flags |= SF_BSS;                 break;
767                         case CFGTOK_ZP:        S->Flags |= (SF_BSS | SF_ZP);       break;
768                         case CFGTOK_OVERWRITE: S->Flags |= (SF_OVERWRITE | SF_RO); break;
769                         default:               Internal ("Unexpected token: %d", CfgTok);
770                     }
771                     CfgNextTok ();
772                     break;
773
774                 default:
775                     FAIL ("Unexpected attribute token");
776
777             }
778
779             /* Skip an optional comma */
780             CfgOptionalComma ();
781         }
782
783         /* Check for mandatory parameters */
784         AttrCheck (S->Attr, SA_LOAD, "LOAD");
785
786         /* Set defaults for stuff not given */
787         if ((S->Attr & SA_RUN) == 0) {
788             S->Attr |= SA_RUN;
789             S->Run = S->Load;
790         }
791
792         /* An attribute of ALIGN_LOAD doesn't make sense if there are no
793         ** separate run and load memory areas.
794         */
795         if ((S->Flags & SF_ALIGN_LOAD) != 0 && (S->Load == S->Run)) {
796             CfgWarning (&CfgErrorPos,
797                         "ALIGN_LOAD attribute specified, but no separate "
798                         "LOAD and RUN memory areas assigned");
799             /* Remove the flag */
800             S->Flags &= ~SF_ALIGN_LOAD;
801         }
802
803         /* If the segment is marked as BSS style, it may not have separate
804         ** load and run memory areas, because it's is never written to disk.
805         */
806         if ((S->Flags & SF_BSS) != 0 && (S->Load != S->Run)) {
807             CfgWarning (&CfgErrorPos,
808                         "Segment with type 'bss' has both LOAD and RUN "
809                         "memory areas assigned");
810         }
811
812         /* Don't allow read/write data to be put into a readonly area */
813         if ((S->Flags & SF_RO) == 0) {
814             if (S->Run->Flags & MF_RO) {
815                 CfgError (&CfgErrorPos,
816                           "Cannot put r/w segment '%s' in r/o memory area '%s'",
817                           GetString (S->Name), GetString (S->Run->Name));
818             }
819         }
820
821         /* Only one of ALIGN, START and OFFSET may be used */
822         Count = ((S->Flags & SF_ALIGN)  != 0) +
823                 ((S->Flags & SF_OFFSET) != 0) +
824                 ((S->Flags & SF_START)  != 0);
825         if (Count > 1) {
826             CfgError (&CfgErrorPos,
827                       "Only one of ALIGN, START, OFFSET may be used");
828         }
829
830         /* Skip the semicolon */
831         CfgConsumeSemi ();
832     }
833
834     /* Remember we had this section */
835     SectionsEncountered |= SE_SEGMENTS;
836 }
837
838
839
840 static void ParseO65 (void)
841 /* Parse the o65 format section */
842 {
843     static const IdentTok Attributes [] = {
844         {   "EXPORT",   CFGTOK_EXPORT           },
845         {   "IMPORT",   CFGTOK_IMPORT           },
846         {   "TYPE",     CFGTOK_TYPE             },
847         {   "OS",       CFGTOK_OS               },
848         {   "ID",       CFGTOK_ID               },
849         {   "VERSION",  CFGTOK_VERSION          },
850     };
851     static const IdentTok Types [] = {
852         {   "SMALL",    CFGTOK_SMALL            },
853         {   "LARGE",    CFGTOK_LARGE            },
854     };
855     static const IdentTok OperatingSystems [] = {
856         {   "LUNIX",    CFGTOK_LUNIX            },
857         {   "OSA65",    CFGTOK_OSA65            },
858         {   "CC65",     CFGTOK_CC65             },
859         {   "OPENCBM",  CFGTOK_OPENCBM          },
860     };
861
862     /* Bitmask to remember the attributes we got already */
863     enum {
864         atNone          = 0x0000,
865         atOS            = 0x0001,
866         atOSVersion     = 0x0002,
867         atType          = 0x0004,
868         atImport        = 0x0008,
869         atExport        = 0x0010,
870         atID            = 0x0020,
871         atVersion       = 0x0040
872     };
873     unsigned AttrFlags = atNone;
874
875     /* Remember the attributes read */
876     unsigned OS = 0;            /* Initialize to keep gcc happy */
877     unsigned Version = 0;
878
879     /* Read the attributes */
880     while (CfgTok == CFGTOK_IDENT) {
881
882         /* Map the identifier to a token */
883         cfgtok_t AttrTok;
884         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
885         AttrTok = CfgTok;
886
887         /* An optional assignment follows */
888         CfgNextTok ();
889         CfgOptionalAssign ();
890
891         /* Check which attribute was given */
892         switch (AttrTok) {
893
894             case CFGTOK_EXPORT:
895                 /* Remember we had this token (maybe more than once) */
896                 AttrFlags |= atExport;
897                 /* We expect an identifier */
898                 CfgAssureIdent ();
899                 /* Remember it as an export for later */
900                 NewCfgSymbol (CfgSymO65Export, GetStrBufId (&CfgSVal));
901                 /* Eat the identifier token */
902                 CfgNextTok ();
903                 break;
904
905             case CFGTOK_IMPORT:
906                 /* Remember we had this token (maybe more than once) */
907                 AttrFlags |= atImport;
908                 /* We expect an identifier */
909                 CfgAssureIdent ();
910                 /* Remember it as an import for later */
911                 NewCfgSymbol (CfgSymO65Import, GetStrBufId (&CfgSVal));
912                 /* Eat the identifier token */
913                 CfgNextTok ();
914                 break;
915
916             case CFGTOK_TYPE:
917                 /* Cannot have this attribute twice */
918                 FlagAttr (&AttrFlags, atType, "TYPE");
919                 /* Get the type of the executable */
920                 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
921                 switch (CfgTok) {
922
923                     case CFGTOK_SMALL:
924                         O65SetSmallModel (O65FmtDesc);
925                         break;
926
927                     case CFGTOK_LARGE:
928                         O65SetLargeModel (O65FmtDesc);
929                         break;
930
931                     default:
932                         CfgError (&CfgErrorPos, "Unexpected type token");
933                 }
934                 /* Eat the attribute token */
935                 CfgNextTok ();
936                 break;
937
938             case CFGTOK_OS:
939                 /* Cannot use this attribute twice */
940                 FlagAttr (&AttrFlags, atOS, "OS");
941                 /* Get the operating system. It may be specified as name or
942                 ** as a number in the range 1..255.
943                 */
944                 if (CfgTok == CFGTOK_INTCON) {
945                     CfgRangeCheck (O65OS_MIN, O65OS_MAX);
946                     OS = (unsigned) CfgIVal;
947                 } else {
948                     CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
949                     switch (CfgTok) {
950                         case CFGTOK_LUNIX:    OS = O65OS_LUNIX;     break;
951                         case CFGTOK_OSA65:    OS = O65OS_OSA65;     break;
952                         case CFGTOK_CC65:     OS = O65OS_CC65;      break;
953                         case CFGTOK_OPENCBM:  OS = O65OS_OPENCBM;   break;
954                         default:              CfgError (&CfgErrorPos, "Unexpected OS token");
955                     }
956                 }
957                 CfgNextTok ();
958                 break;
959
960             case CFGTOK_ID:
961                 /* Cannot have this attribute twice */
962                 FlagAttr (&AttrFlags, atID, "ID");
963                 /* We're expecting a number in the 0..$FFFF range*/
964                 ModuleId = (unsigned) CfgCheckedConstExpr (0, 0xFFFF);
965                 break;
966
967             case CFGTOK_VERSION:
968                 /* Cannot have this attribute twice */
969                 FlagAttr (&AttrFlags, atVersion, "VERSION");
970                 /* We're expecting a number in byte range */
971                 Version = (unsigned) CfgCheckedConstExpr (0, 0xFF);
972                 break;
973
974             default:
975                 FAIL ("Unexpected attribute token");
976
977         }
978
979         /* Skip an optional comma */
980         CfgOptionalComma ();
981     }
982
983     /* Check if we have all mandatory attributes */
984     AttrCheck (AttrFlags, atOS, "OS");
985
986     /* Check for attributes that may not be combined */
987     if (OS == O65OS_CC65) {
988         if ((AttrFlags & (atImport | atExport)) != 0 && ModuleId < 0x8000) {
989             CfgError (&CfgErrorPos,
990                       "OS type CC65 may not have imports or exports for ids < $8000");
991         }
992     } else {
993         if (AttrFlags & atID) {
994             CfgError (&CfgErrorPos,
995                       "Operating system does not support the ID attribute");
996         }
997     }
998
999     /* Set the O65 operating system to use */
1000     O65SetOS (O65FmtDesc, OS, Version, ModuleId);
1001 }
1002
1003
1004
1005 static void ParseFormats (void)
1006 /* Parse a target format section */
1007 {
1008     static const IdentTok Formats [] = {
1009         {   "O65",      CFGTOK_O65      },
1010         {   "BIN",      CFGTOK_BIN      },
1011         {   "BINARY",   CFGTOK_BIN      },
1012     };
1013
1014     while (CfgTok == CFGTOK_IDENT) {
1015
1016         /* Map the identifier to a token */
1017         cfgtok_t FormatTok;
1018         CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
1019         FormatTok = CfgTok;
1020
1021         /* Skip the name and the following colon */
1022         CfgNextTok ();
1023         CfgConsumeColon ();
1024
1025         /* Parse the format options */
1026         switch (FormatTok) {
1027
1028             case CFGTOK_O65:
1029                 ParseO65 ();
1030                 break;
1031
1032             case CFGTOK_BIN:
1033             case CFGTOK_ATARIEXE:
1034                 /* No attribibutes available */
1035                 break;
1036
1037             default:
1038                 Error ("Unexpected format token");
1039         }
1040
1041         /* Skip the semicolon */
1042         CfgConsumeSemi ();
1043     }
1044
1045
1046     /* Remember we had this section */
1047     SectionsEncountered |= SE_FORMATS;
1048 }
1049
1050
1051
1052 static void ParseConDes (void)
1053 /* Parse the CONDES feature */
1054 {
1055     static const IdentTok Attributes [] = {
1056         {   "COUNT",            CFGTOK_COUNT            },
1057         {   "IMPORT",           CFGTOK_IMPORT           },
1058         {   "LABEL",            CFGTOK_LABEL            },
1059         {   "ORDER",            CFGTOK_ORDER            },
1060         {   "SEGMENT",          CFGTOK_SEGMENT          },
1061         {   "TYPE",             CFGTOK_TYPE             },
1062     };
1063
1064     static const IdentTok Types [] = {
1065         {   "CONSTRUCTOR",      CFGTOK_CONSTRUCTOR      },
1066         {   "DESTRUCTOR",       CFGTOK_DESTRUCTOR       },
1067         {   "INTERRUPTOR",      CFGTOK_INTERRUPTOR      },
1068     };
1069
1070     static const IdentTok Orders [] = {
1071         {   "DECREASING",       CFGTOK_DECREASING       },
1072         {   "INCREASING",       CFGTOK_INCREASING       },
1073     };
1074
1075     /* Attribute values. */
1076     unsigned Count   = INVALID_STRING_ID;
1077     unsigned Label   = INVALID_STRING_ID;
1078     unsigned SegName = INVALID_STRING_ID;
1079     ConDesImport Import;
1080     /* Initialize to avoid gcc warnings: */
1081     int Type = -1;
1082     ConDesOrder Order = cdIncreasing;
1083
1084     /* Bitmask to remember the attributes we got already */
1085     enum {
1086         atNone          = 0x0000,
1087         atCount         = 0x0001,
1088         atImport        = 0x0002,
1089         atLabel         = 0x0004,
1090         atOrder         = 0x0008,
1091         atSegName       = 0x0010,
1092         atType          = 0x0020,
1093     };
1094     unsigned AttrFlags = atNone;
1095
1096     /* Parse the attributes */
1097     while (1) {
1098
1099         /* Map the identifier to a token */
1100         cfgtok_t AttrTok;
1101         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1102         AttrTok = CfgTok;
1103
1104         /* An optional assignment follows */
1105         CfgNextTok ();
1106         CfgOptionalAssign ();
1107
1108         /* Check which attribute was given */
1109         switch (AttrTok) {
1110
1111             case CFGTOK_COUNT:
1112                 /* Don't allow this twice */
1113                 FlagAttr (&AttrFlags, atCount, "COUNT");
1114                 /* We expect an identifier */
1115                 CfgAssureIdent ();
1116                 /* Remember the value for later */
1117                 Count = GetStrBufId (&CfgSVal);
1118                 break;
1119
1120             case CFGTOK_IMPORT:
1121                 /* Don't allow this twice */
1122                 FlagAttr (&AttrFlags, atImport, "IMPORT");
1123                 /* We expect an identifier */
1124                 CfgAssureIdent ();
1125                 /* Remember value and position for later */
1126                 Import.Name = GetStrBufId (&CfgSVal);
1127                 Import.Pos = CfgErrorPos;
1128                 Import.AddrSize = ADDR_SIZE_ABS;
1129                 break;
1130
1131             case CFGTOK_LABEL:
1132                 /* Don't allow this twice */
1133                 FlagAttr (&AttrFlags, atLabel, "LABEL");
1134                 /* We expect an identifier */
1135                 CfgAssureIdent ();
1136                 /* Remember the value for later */
1137                 Label = GetStrBufId (&CfgSVal);
1138                 break;
1139
1140             case CFGTOK_ORDER:
1141                 /* Don't allow this twice */
1142                 FlagAttr (&AttrFlags, atOrder, "ORDER");
1143                 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1144                 switch (CfgTok) {
1145                     case CFGTOK_DECREASING: Order = cdDecreasing;       break;
1146                     case CFGTOK_INCREASING: Order = cdIncreasing;       break;
1147                     default: FAIL ("Unexpected order token");
1148                 }
1149                 break;
1150
1151             case CFGTOK_SEGMENT:
1152                 /* Don't allow this twice */
1153                 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1154                 /* We expect an identifier */
1155                 CfgAssureIdent ();
1156                 /* Remember the value for later */
1157                 SegName = GetStrBufId (&CfgSVal);
1158                 break;
1159
1160             case CFGTOK_TYPE:
1161                 /* Don't allow this twice */
1162                 FlagAttr (&AttrFlags, atType, "TYPE");
1163                 /* The type may be given as id or numerical */
1164                 if (CfgTok == CFGTOK_INTCON) {
1165                     CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1166                     Type = (int) CfgIVal;
1167                 } else {
1168                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1169                     switch (CfgTok) {
1170                         case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON;    break;
1171                         case CFGTOK_DESTRUCTOR:  Type = CD_TYPE_DES;    break;
1172                         case CFGTOK_INTERRUPTOR: Type = CD_TYPE_INT;    break;
1173                         default: FAIL ("Unexpected type token");
1174                     }
1175                 }
1176                 break;
1177
1178             default:
1179                 FAIL ("Unexpected attribute token");
1180
1181         }
1182
1183         /* Skip the attribute value */
1184         CfgNextTok ();
1185
1186         /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1187         if (CfgTok == CFGTOK_SEMI) {
1188             break;
1189         } else if (CfgTok == CFGTOK_COMMA) {
1190             CfgNextTok ();
1191         }
1192     }
1193
1194     /* Check if we have all mandatory attributes */
1195     AttrCheck (AttrFlags, atSegName, "SEGMENT");
1196     AttrCheck (AttrFlags, atLabel, "LABEL");
1197     AttrCheck (AttrFlags, atType, "TYPE");
1198
1199     /* Check if the condes has already attributes defined */
1200     if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1201         CfgError (&CfgErrorPos,
1202                   "CONDES attributes for type %d are already defined",
1203                   Type);
1204     }
1205
1206     /* Define the attributes */
1207     ConDesSetSegName (Type, SegName);
1208     ConDesSetLabel (Type, Label);
1209     if (AttrFlags & atCount) {
1210         ConDesSetCountSym (Type, Count);
1211     }
1212     if (AttrFlags & atImport) {
1213         ConDesSetImport (Type, &Import);
1214     }
1215     if (AttrFlags & atOrder) {
1216         ConDesSetOrder (Type, Order);
1217     }
1218 }
1219
1220
1221
1222 static void ParseStartAddress (void)
1223 /* Parse the STARTADDRESS feature */
1224 {
1225     static const IdentTok Attributes [] = {
1226         {   "DEFAULT",  CFGTOK_DEFAULT },
1227     };
1228
1229
1230     /* Attribute values. */
1231     unsigned long DefStartAddr = 0;
1232
1233     /* Bitmask to remember the attributes we got already */
1234     enum {
1235         atNone          = 0x0000,
1236         atDefault       = 0x0001
1237     };
1238     unsigned AttrFlags = atNone;
1239
1240     /* Parse the attributes */
1241     while (1) {
1242
1243         /* Map the identifier to a token */
1244         cfgtok_t AttrTok;
1245         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1246         AttrTok = CfgTok;
1247
1248         /* An optional assignment follows */
1249         CfgNextTok ();
1250         CfgOptionalAssign ();
1251
1252         /* Check which attribute was given */
1253         switch (AttrTok) {
1254
1255             case CFGTOK_DEFAULT:
1256                 /* Don't allow this twice */
1257                 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1258                 /* We expect a numeric expression */
1259                 DefStartAddr = CfgCheckedConstExpr (0, 0xFFFFFF);
1260                 break;
1261
1262             default:
1263                 FAIL ("Unexpected attribute token");
1264
1265         }
1266
1267         /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1268         if (CfgTok == CFGTOK_SEMI) {
1269             break;
1270         } else if (CfgTok == CFGTOK_COMMA) {
1271             CfgNextTok ();
1272         }
1273     }
1274
1275     /* Check if we have all mandatory attributes */
1276     AttrCheck (AttrFlags, atDefault, "DEFAULT");
1277
1278     /* If no start address was given on the command line, use the one given
1279     ** here
1280     */
1281     if (!HaveStartAddr) {
1282         StartAddr = DefStartAddr;
1283     }
1284 }
1285
1286
1287
1288 static void ParseFeatures (void)
1289 /* Parse a features section */
1290 {
1291     static const IdentTok Features [] = {
1292         {   "CONDES",       CFGTOK_CONDES       },
1293         {   "STARTADDRESS", CFGTOK_STARTADDRESS },
1294     };
1295
1296     while (CfgTok == CFGTOK_IDENT) {
1297
1298         /* Map the identifier to a token */
1299         cfgtok_t FeatureTok;
1300         CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1301         FeatureTok = CfgTok;
1302
1303         /* Skip the name and the following colon */
1304         CfgNextTok ();
1305         CfgConsumeColon ();
1306
1307         /* Parse the format options */
1308         switch (FeatureTok) {
1309
1310             case CFGTOK_CONDES:
1311                 ParseConDes ();
1312                 break;
1313
1314             case CFGTOK_STARTADDRESS:
1315                 ParseStartAddress ();
1316                 break;
1317
1318
1319             default:
1320                 FAIL ("Unexpected feature token");
1321         }
1322
1323         /* Skip the semicolon */
1324         CfgConsumeSemi ();
1325     }
1326
1327     /* Remember we had this section */
1328     SectionsEncountered |= SE_FEATURES;
1329 }
1330
1331
1332
1333 static void ParseSymbols (void)
1334 /* Parse a symbols section */
1335 {
1336     static const IdentTok Attributes[] = {
1337         {   "ADDRSIZE", CFGTOK_ADDRSIZE },
1338         {   "TYPE",     CFGTOK_TYPE     },
1339         {   "VALUE",    CFGTOK_VALUE    },
1340     };
1341
1342     static const IdentTok AddrSizes [] = {
1343         {   "ABS",      CFGTOK_ABS      },
1344         {   "ABSOLUTE", CFGTOK_ABS      },
1345         {   "DIRECT",   CFGTOK_ZP       },
1346         {   "DWORD",    CFGTOK_LONG     },
1347         {   "FAR",      CFGTOK_FAR      },
1348         {   "LONG",     CFGTOK_LONG     },
1349         {   "NEAR",     CFGTOK_ABS      },
1350         {   "ZEROPAGE", CFGTOK_ZP       },
1351         {   "ZP",       CFGTOK_ZP       },
1352     };
1353
1354     static const IdentTok Types [] = {
1355         {   "EXPORT",   CFGTOK_EXPORT   },
1356         {   "IMPORT",   CFGTOK_IMPORT   },
1357         {   "WEAK",     CFGTOK_WEAK     },
1358     };
1359
1360     while (CfgTok == CFGTOK_IDENT) {
1361
1362         /* Bitmask to remember the attributes we got already */
1363         enum {
1364             atNone      = 0x0000,
1365             atAddrSize  = 0x0001,
1366             atType      = 0x0002,
1367             atValue     = 0x0004,
1368         };
1369         unsigned AttrFlags = atNone;
1370
1371         ExprNode* Value = 0;
1372         CfgSymType Type = CfgSymExport;
1373         unsigned char AddrSize = ADDR_SIZE_ABS;
1374         Import* Imp;
1375         Export* Exp;
1376         CfgSymbol* Sym;
1377
1378         /* Remember the name */
1379         unsigned Name = GetStrBufId (&CfgSVal);
1380         CfgNextTok ();
1381
1382         /* New syntax - skip the colon */
1383         CfgNextTok ();
1384
1385         /* Parse the attributes */
1386         while (1) {
1387
1388             /* Map the identifier to a token */
1389             cfgtok_t AttrTok;
1390             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1391             AttrTok = CfgTok;
1392
1393             /* Skip the attribute name */
1394             CfgNextTok ();
1395
1396             /* An optional assignment follows */
1397             CfgOptionalAssign ();
1398
1399             /* Check which attribute was given */
1400             switch (AttrTok) {
1401
1402                 case CFGTOK_ADDRSIZE:
1403                     /* Don't allow this twice */
1404                     FlagAttr (&AttrFlags, atAddrSize, "ADDRSIZE");
1405                     /* Map the type to a token */
1406                     CfgSpecialToken (AddrSizes, ENTRY_COUNT (AddrSizes), "AddrSize");
1407                     switch (CfgTok) {
1408                         case CFGTOK_ABS:    AddrSize = ADDR_SIZE_ABS;   break;
1409                         case CFGTOK_FAR:    AddrSize = ADDR_SIZE_FAR;   break;
1410                         case CFGTOK_LONG:   AddrSize = ADDR_SIZE_LONG;  break;
1411                         case CFGTOK_ZP:     AddrSize = ADDR_SIZE_ZP;    break;
1412                         default:
1413                             Internal ("Unexpected token: %d", CfgTok);
1414                     }
1415                     CfgNextTok ();
1416                     break;
1417
1418                 case CFGTOK_TYPE:
1419                     /* Don't allow this twice */
1420                     FlagAttr (&AttrFlags, atType, "TYPE");
1421                     /* Map the type to a token */
1422                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1423                     switch (CfgTok) {
1424                         case CFGTOK_EXPORT:     Type = CfgSymExport;    break;
1425                         case CFGTOK_IMPORT:     Type = CfgSymImport;    break;
1426                         case CFGTOK_WEAK:       Type = CfgSymWeak;      break;
1427                         default:
1428                             Internal ("Unexpected token: %d", CfgTok);
1429                     }
1430                     CfgNextTok ();
1431                     break;
1432
1433                 case CFGTOK_VALUE:
1434                     /* Don't allow this twice */
1435                     FlagAttr (&AttrFlags, atValue, "VALUE");
1436                     /* Value is an expression */
1437                     Value = CfgExpr ();
1438                     break;
1439
1440                 default:
1441                     FAIL ("Unexpected attribute token");
1442
1443             }
1444
1445             /* Semicolon ends the decl, otherwise accept an optional comma */
1446             if (CfgTok == CFGTOK_SEMI) {
1447                 break;
1448             } else if (CfgTok == CFGTOK_COMMA) {
1449                 CfgNextTok ();
1450             }
1451         }
1452
1453         /* We must have a type */
1454         AttrCheck (AttrFlags, atType, "TYPE");
1455
1456         /* Further actions depend on the type */
1457         switch (Type) {
1458
1459             case CfgSymExport:
1460                 /* We must have a value */
1461                 AttrCheck (AttrFlags, atValue, "VALUE");
1462                 /* Create the export */
1463                 Exp = CreateExprExport (Name, Value, AddrSize);
1464                 CollAppend (&Exp->DefLines, GenLineInfo (&CfgErrorPos));
1465                 break;
1466
1467             case CfgSymImport:
1468                 /* An import must not have a value */
1469                 if (AttrFlags & atValue) {
1470                     CfgError (&CfgErrorPos, "Imports must not have a value");
1471                 }
1472                 /* Generate the import */
1473                 Imp = InsertImport (GenImport (Name, AddrSize));
1474                 /* Remember the file position */
1475                 CollAppend (&Imp->RefLines, GenLineInfo (&CfgErrorPos));
1476                 break;
1477
1478             case CfgSymWeak:
1479                 /* We must have a value */
1480                 AttrCheck (AttrFlags, atValue, "VALUE");
1481                 /* Remember the symbol for later */
1482                 Sym = NewCfgSymbol (CfgSymWeak, Name);
1483                 Sym->Value = Value;
1484                 Sym->AddrSize = AddrSize;
1485                 break;
1486
1487             default:
1488                 Internal ("Unexpected symbol type %d", Type);
1489         }
1490
1491         /* Skip the semicolon */
1492         CfgConsumeSemi ();
1493     }
1494
1495     /* Remember we had this section */
1496     SectionsEncountered |= SE_SYMBOLS;
1497 }
1498
1499
1500
1501 static void ParseConfig (void)
1502 /* Parse the config file */
1503 {
1504     static const IdentTok BlockNames [] = {
1505         {   "MEMORY",   CFGTOK_MEMORY   },
1506         {   "FILES",    CFGTOK_FILES    },
1507         {   "SEGMENTS", CFGTOK_SEGMENTS },
1508         {   "FORMATS",  CFGTOK_FORMATS  },
1509         {   "FEATURES", CFGTOK_FEATURES },
1510         {   "SYMBOLS",  CFGTOK_SYMBOLS  },
1511     };
1512     cfgtok_t BlockTok;
1513
1514     do {
1515
1516         /* Read the block ident */
1517         CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1518         BlockTok = CfgTok;
1519         CfgNextTok ();
1520
1521         /* Expected a curly brace */
1522         CfgConsume (CFGTOK_LCURLY, "'{' expected");
1523
1524         /* Read the block */
1525         switch (BlockTok) {
1526
1527             case CFGTOK_MEMORY:
1528                 ParseMemory ();
1529                 break;
1530
1531             case CFGTOK_FILES:
1532                 ParseFiles ();
1533                 break;
1534
1535             case CFGTOK_SEGMENTS:
1536                 ParseSegments ();
1537                 break;
1538
1539             case CFGTOK_FORMATS:
1540                 ParseFormats ();
1541                 break;
1542
1543             case CFGTOK_FEATURES:
1544                 ParseFeatures ();
1545                 break;
1546
1547             case CFGTOK_SYMBOLS:
1548                 ParseSymbols ();
1549                 break;
1550
1551             default:
1552                 FAIL ("Unexpected block token");
1553
1554         }
1555
1556         /* Skip closing brace */
1557         CfgConsume (CFGTOK_RCURLY, "'}' expected");
1558
1559     } while (CfgTok != CFGTOK_EOF);
1560 }
1561
1562
1563
1564 void CfgRead (void)
1565 /* Read the configuration */
1566 {
1567     /* Create the descriptors for the binary formats */
1568     BinFmtDesc = NewBinDesc ();
1569     O65FmtDesc = NewO65Desc ();
1570     XexFmtDesc = NewXexDesc ();
1571
1572     /* If we have a config name given, open the file, otherwise we will read
1573     ** from a buffer.
1574     */
1575     CfgOpenInput ();
1576
1577     /* Parse the file */
1578     ParseConfig ();
1579
1580     /* Close the input file */
1581     CfgCloseInput ();
1582 }
1583
1584
1585
1586 /*****************************************************************************/
1587 /*                          Config file processing                           */
1588 /*****************************************************************************/
1589
1590
1591
1592 static void ProcessSegments (void)
1593 /* Process the SEGMENTS section */
1594 {
1595     unsigned I;
1596
1597     /* Walk over the list of segment descriptors */
1598     I = 0;
1599     while (I < CollCount (&SegDescList)) {
1600
1601         /* Get the next segment descriptor */
1602         SegDesc* S = CollAtUnchecked (&SegDescList, I);
1603
1604         /* Search for the actual segment in the input files. The function may
1605         ** return NULL (no such segment), this is checked later.
1606         */
1607         S->Seg = SegFind (S->Name);
1608
1609         /* If the segment is marked as BSS style, and if the segment exists
1610         ** in any of the object file, check that there's no initialized data
1611         ** in the segment.
1612         */
1613         if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
1614             CfgWarning (GetSourcePos (S->LI),
1615                         "Segment '%s' with type 'bss' contains initialized data",
1616                         GetString (S->Name));
1617         }
1618
1619         /* If this segment does exist in any of the object files, insert the
1620         ** segment into the load/run memory areas. Otherwise print a warning
1621         ** and discard it, because the segment pointer in the descriptor is
1622         ** invalid.
1623         */
1624         if (S->Seg != 0) {
1625
1626             /* Insert the segment into the memory area list */
1627             MemoryInsert (S->Run, S);
1628             if (S->Load != S->Run) {
1629                 /* We have separate RUN and LOAD areas */
1630                 MemoryInsert (S->Load, S);
1631             }
1632
1633             /* Use the fill value from the config */
1634             S->Seg->FillVal = S->FillVal;
1635
1636             /* Process the next segment descriptor in the next run */
1637             ++I;
1638
1639         } else {
1640
1641             /* Print a warning if the segment is not optional */
1642             if ((S->Flags & SF_OPTIONAL) == 0) {
1643                 CfgWarning (&CfgErrorPos,
1644                             "Segment '%s' does not exist",
1645                             GetString (S->Name));
1646             }
1647
1648             /* Discard the descriptor and remove it from the collection */
1649             FreeSegDesc (S);
1650             CollDelete (&SegDescList, I);
1651         }
1652     }
1653 }
1654
1655
1656
1657 static void ProcessSymbols (void)
1658 /* Process the SYMBOLS section */
1659 {
1660     Export* E;
1661
1662     /* Walk over all symbols */
1663     unsigned I;
1664     for (I = 0; I < CollCount (&CfgSymbols); ++I) {
1665
1666         /* Get the next symbol */
1667         CfgSymbol* Sym = CollAtUnchecked (&CfgSymbols, I);
1668
1669         /* Check what it is. */
1670         switch (Sym->Type) {
1671
1672             case CfgSymO65Export:
1673                 /* Check if the export symbol is also defined as an import. */
1674                 if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1675                     CfgError (
1676                         GetSourcePos (Sym->LI),
1677                         "Exported o65 symbol '%s' cannot also be an o65 import",
1678                         GetString (Sym->Name)
1679                     );
1680                 }
1681
1682                 /* Check if we have this symbol defined already. The entry
1683                 ** routine will check this also, but we get a more verbose
1684                 ** error message when checking it here.
1685                 */
1686                 if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
1687                     CfgError (
1688                         GetSourcePos (Sym->LI),
1689                         "Duplicate exported o65 symbol: '%s'",
1690                         GetString (Sym->Name)
1691                     );
1692                 }
1693
1694                 /* Insert the symbol into the table */
1695                 O65SetExport (O65FmtDesc, Sym->Name);
1696                 break;
1697
1698             case CfgSymO65Import:
1699                 /* Check if the import symbol is also defined as an export. */
1700                 if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
1701                     CfgError (
1702                         GetSourcePos (Sym->LI),
1703                         "Imported o65 symbol '%s' cannot also be an o65 export",
1704                         GetString (Sym->Name)
1705                     );
1706                 }
1707
1708                 /* Check if we have this symbol defined already. The entry
1709                 ** routine will check this also, but we get a more verbose
1710                 ** error message when checking it here.
1711                 */
1712                 if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1713                     CfgError (
1714                         GetSourcePos (Sym->LI),
1715                         "Duplicate imported o65 symbol: '%s'",
1716                         GetString (Sym->Name)
1717                     );
1718                 }
1719
1720                 /* Insert the symbol into the table */
1721                 O65SetImport (O65FmtDesc, Sym->Name);
1722                 break;
1723
1724             case CfgSymWeak:
1725                 /* If the symbol is not defined until now, define it */
1726                 if ((E = FindExport (Sym->Name)) == 0 || IsUnresolvedExport (E)) {
1727                     /* The symbol is undefined, generate an export */
1728                     E = CreateExprExport (Sym->Name, Sym->Value, Sym->AddrSize);
1729                     CollAppend (&E->DefLines, Sym->LI);
1730                 }
1731                 break;
1732
1733             default:
1734                 Internal ("Unexpected symbol type %d", Sym->Type);
1735                 break;
1736         }
1737     }
1738
1739 }
1740
1741
1742
1743 static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
1744 /* Create the defines for a RUN segment */
1745 {
1746     Export* E;
1747     StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1748
1749     /* Define the run address of the segment */
1750     SB_Printf (&Buf, "__%s_RUN__", GetString (S->Name));
1751     E = CreateMemoryExport (GetStrBufId (&Buf), S->Run, SegAddr - S->Run->Start);
1752     CollAppend (&E->DefLines, S->LI);
1753
1754     /* Define the size of the segment */
1755     SB_Printf (&Buf, "__%s_SIZE__", GetString (S->Name));
1756     E = CreateConstExport (GetStrBufId (&Buf), S->Seg->Size);
1757     CollAppend (&E->DefLines, S->LI);
1758
1759     S->Flags |= SF_RUN_DEF;
1760     SB_Done (&Buf);
1761 }
1762
1763
1764
1765 static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
1766 /* Create the defines for a LOAD segment */
1767 {
1768     Export* E;
1769     StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1770
1771     /* Define the load address of the segment */
1772     SB_Printf (&Buf, "__%s_LOAD__", GetString (S->Name));
1773     E = CreateMemoryExport (GetStrBufId (&Buf), S->Load, SegAddr - S->Load->Start);
1774     CollAppend (&E->DefLines, S->LI);
1775
1776     S->Flags |= SF_LOAD_DEF;
1777     SB_Done (&Buf);
1778 }
1779
1780
1781
1782 unsigned CfgProcess (void)
1783 /* Process the config file, after reading in object files and libraries. This
1784 ** includes postprocessing of the config file data; but also assigning segments,
1785 ** and defining segment/memory-area related symbols. The function will return
1786 ** the number of memory area overflows (so, zero means everything went OK).
1787 ** In case of overflows, a short mapfile can be generated later, to ease the
1788 ** user's task of re-arranging segments.
1789 */
1790 {
1791     unsigned Overflows = 0;
1792     unsigned I;
1793
1794     /* Postprocess symbols. We must do that first, since weak symbols are
1795     ** defined here, which may be needed later.
1796     */
1797     ProcessSymbols ();
1798
1799     /* Postprocess segments */
1800     ProcessSegments ();
1801
1802     /* Walk through each of the memory sections. Add up the sizes; and, check
1803     ** for an overflow of the section. Assign the start addresses of the
1804     ** segments while doing that.
1805     */
1806     for (I = 0; I < CollCount (&MemoryAreas); ++I) {
1807         unsigned J;
1808         unsigned long Addr;
1809         unsigned Overwrites = 0;
1810
1811         /* Get the next memory area */
1812         MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
1813
1814         /* Remember the offset in the output file */
1815         M->FileOffs = M->F->Size;
1816
1817         /* Remember if this is a relocatable memory area */
1818         M->Relocatable = RelocatableBinFmt (M->F->Format);
1819
1820         /* Resolve the start address expression, remember the start address,
1821         ** and mark the memory area as placed.
1822         */
1823         if (!IsConstExpr (M->StartExpr)) {
1824             CfgError (GetSourcePos (M->LI),
1825                       "Start address of memory area '%s' is not constant",
1826                       GetString (M->Name));
1827         }
1828         Addr = M->Start = GetExprVal (M->StartExpr);
1829         M->Flags |= MF_PLACED;
1830
1831         /* If requested, define the symbol for the start of the memory area.
1832         ** Doing it here means that the expression for the size of the area
1833         ** may reference this symbol.
1834         */
1835         if (M->Flags & MF_DEFINE) {
1836             Export* E;
1837             StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1838
1839             /* Define the start of the memory area */
1840             SB_Printf (&Buf, "__%s_START__", GetString (M->Name));
1841             E = CreateMemoryExport (GetStrBufId (&Buf), M, 0);
1842             CollAppend (&E->DefLines, M->LI);
1843
1844             SB_Done (&Buf);
1845         }
1846
1847         /* Resolve the size expression */
1848         if (!IsConstExpr (M->SizeExpr)) {
1849             CfgError (GetSourcePos (M->LI),
1850                       "Size of memory area '%s' is not constant",
1851                       GetString (M->Name));
1852         }
1853         M->Size = GetExprVal (M->SizeExpr);
1854
1855         /* Walk through the segments in this memory area */
1856         for (J = 0; J < CollCount (&M->SegList); ++J) {
1857             /* Get the segment */
1858             SegDesc* S = CollAtUnchecked (&M->SegList, J);
1859
1860             /* Remember the start address before handling this segment */
1861             unsigned long StartAddr = Addr;
1862
1863             /* Take note of "overwrite" segments and make sure there are no
1864             ** other segment types following them in current memory region.
1865             */
1866             if (S->Flags & SF_OVERWRITE) {
1867                 if (S->Flags & (SF_OFFSET | SF_START)) {
1868                     ++Overwrites;
1869                 } else {
1870                     CfgError (GetSourcePos (M->LI),
1871                               "Segment '%s' of type 'overwrite' requires either"
1872                               " 'Start' or 'Offset' attribute to be specified",
1873                               GetString (S->Name));
1874                 }
1875             } else {
1876                 if (Overwrites > 0) {
1877                     CfgError (GetSourcePos (M->LI),
1878                               "Segment '%s' is preceded by at least one segment"
1879                               " of type 'overwrite'",
1880                               GetString (S->Name));
1881                 }
1882             }
1883
1884             /* Some actions depend on whether this is the load or run memory
1885             ** area.
1886             */
1887             if (S->Run == M) {
1888                 /* This is the run (and maybe load) memory area. Handle
1889                 ** alignment and explict start address and offset.
1890                 */
1891
1892                 /* Check if the alignment for the segment from the linker
1893                 ** config is a multiple for that of the segment.
1894                 ** If START or OFFSET is provided instead of ALIGN, check
1895                 ** if its address fits alignment requirements.
1896                 */
1897                 unsigned long AlignedBy = (S->Flags & SF_START) ? S->Addr
1898                     : (S->Flags & SF_OFFSET) ? (S->Addr + M->Start)
1899                     : S->RunAlignment;
1900                 if ((AlignedBy % S->Seg->Alignment) != 0) {
1901                     /* Segment requires another alignment than configured
1902                     ** in the linker.
1903                     */
1904                     CfgWarning (GetSourcePos (S->LI),
1905                                 "Segment '%s' isn't aligned properly; the"
1906                                 " resulting executable might not be functional.",
1907                                 GetString (S->Name));
1908                 }
1909
1910                 if (S->Flags & SF_ALIGN) {
1911                     /* Align the address */
1912                     unsigned long NewAddr = AlignAddr (Addr, S->RunAlignment);
1913
1914                     /* If the first segment placed in the memory area needs
1915                     ** fill bytes for the alignment, emit a warning, since
1916                     ** that is somewhat suspicious.
1917                     */
1918                     if (M->FillLevel == 0 && NewAddr > Addr) {
1919                         CfgWarning (GetSourcePos (S->LI),
1920                                     "The first segment in memory area '%s' "
1921                                     "needs fill bytes for alignment.",
1922                                     GetString (M->Name));
1923                     }
1924
1925                     /* Use the aligned address */
1926                     Addr = NewAddr;
1927
1928                 } else if ((S->Flags & (SF_OFFSET | SF_START)) != 0 &&
1929                            (M->Flags & MF_OVERFLOW) == 0) {
1930                     /* Give the segment a fixed starting address */
1931                     unsigned long NewAddr = S->Addr;
1932
1933                     if (S->Flags & SF_OFFSET) {
1934                         /* An offset was given, no address, make an address */
1935                         NewAddr += M->Start;
1936                     }
1937
1938                     if (S->Flags & SF_OVERWRITE) {
1939                         if (NewAddr < M->Start) {
1940                             CfgError (GetSourcePos (S->LI),
1941                                       "Segment '%s' begins before memory area '%s'",
1942                                       GetString (S->Name), GetString (M->Name));
1943                         } else {
1944                             Addr = NewAddr;
1945                         }
1946                     } else {
1947                         if (NewAddr < Addr) {
1948                             /* Offset already too large */
1949                             ++Overflows;
1950                             if (S->Flags & SF_OFFSET) {
1951                                 CfgWarning (GetSourcePos (S->LI),
1952                                             "Segment '%s' offset is too small in '%s' by %lu byte%c",
1953                                             GetString (S->Name), GetString (M->Name),
1954                                             Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
1955                             } else {
1956                                 CfgWarning (GetSourcePos (S->LI),
1957                                             "Segment '%s' start address is too low in '%s' by %lu byte%c",
1958                                             GetString (S->Name), GetString (M->Name),
1959                                             Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
1960                             }
1961                         } else {
1962                             Addr = NewAddr;
1963                         }
1964                     }
1965                 }
1966
1967                 /* Set the start address of this segment, set the readonly flag
1968                 ** in the segment, and remember if the segment is in a
1969                 ** relocatable file or not.
1970                 */
1971                 S->Seg->PC = Addr;
1972                 S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
1973
1974                 /* Remember the run memory for this segment, which is also a
1975                 ** flag that the segment has been placed.
1976                 */
1977                 S->Seg->MemArea = M;
1978
1979             } else if (S->Load == M) {
1980                 /* This is the load memory area; *and*, run and load are
1981                 ** different (because of the "else" above). Handle alignment.
1982                 */
1983                 if (S->Flags & SF_ALIGN_LOAD) {
1984                     /* Align the address */
1985                     Addr = AlignAddr (Addr, S->LoadAlignment);
1986                 }
1987             }
1988
1989             /* If this is the load memory area, and the segment doesn't have a
1990             ** fill value defined, use the one from the memory area.
1991             */
1992             if (S->Load == M && (S->Flags & SF_FILLVAL) == 0) {
1993                 S->Seg->FillVal = M->FillVal;
1994             }
1995
1996             /* Increment the fill level of the memory area; and, check for an
1997             ** overflow.
1998             */
1999             M->FillLevel = Addr + S->Seg->Size - M->Start;
2000             if (M->FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) {
2001                 ++Overflows;
2002                 M->Flags |= MF_OVERFLOW;
2003                 CfgWarning (GetSourcePos (M->LI),
2004                             "Segment '%s' overflows memory area '%s' by %lu byte%c",
2005                             GetString (S->Name), GetString (M->Name),
2006                             M->FillLevel - M->Size, (M->FillLevel - M->Size == 1) ? ' ' : 's');
2007             }
2008
2009             /* If requested, define symbols for the start and size of the
2010             ** segment.
2011             */
2012             if (S->Flags & SF_DEFINE) {
2013                 if (S->Run == M && (S->Flags & SF_RUN_DEF) == 0) {
2014                     CreateRunDefines (S, Addr);
2015                 }
2016                 if (S->Load == M && (S->Flags & SF_LOAD_DEF) == 0) {
2017                     CreateLoadDefines (S, Addr);
2018                 }
2019             }
2020
2021             /* Calculate the new address */
2022             Addr += S->Seg->Size;
2023
2024             /* If this segment will go out to the file, or its place
2025             ** in the file will be filled, then increase the file size.
2026             */
2027             if (S->Load == M &&
2028                 ((S->Flags & SF_BSS) == 0 || (M->Flags & MF_FILL) != 0)) {
2029                 M->F->Size += Addr - StartAddr;
2030             }
2031         }
2032
2033         /* If requested, define symbols for start, size, and offset of the
2034         ** memory area
2035         */
2036         if (M->Flags & MF_DEFINE) {
2037             Export* E;
2038             StrBuf Buf = STATIC_STRBUF_INITIALIZER;
2039
2040             /* Define the size of the memory area */
2041             SB_Printf (&Buf, "__%s_SIZE__", GetString (M->Name));
2042             E = CreateConstExport (GetStrBufId (&Buf), M->Size);
2043             CollAppend (&E->DefLines, M->LI);
2044
2045             /* Define the fill level of the memory area */
2046             SB_Printf (&Buf, "__%s_LAST__", GetString (M->Name));
2047             E = CreateMemoryExport (GetStrBufId (&Buf), M, M->FillLevel);
2048             CollAppend (&E->DefLines, M->LI);
2049
2050             /* Define the file offset of the memory area. This isn't of much
2051             ** use for relocatable output files.
2052             */
2053             if (!M->Relocatable) {
2054                 SB_Printf (&Buf, "__%s_FILEOFFS__", GetString (M->Name));
2055                 E = CreateConstExport (GetStrBufId (&Buf), M->FileOffs);
2056                 CollAppend (&E->DefLines, M->LI);
2057             }
2058
2059             /* Throw away the string buffer */
2060             SB_Done (&Buf);
2061         }
2062
2063         /* If we didn't have an overflow, and are requested to fill the memory
2064         ** area, account for that in the file size.
2065         */
2066         if ((M->Flags & MF_OVERFLOW) == 0 && (M->Flags & MF_FILL) != 0) {
2067             M->F->Size += (M->Size - M->FillLevel);
2068         }
2069     }
2070
2071     /* Return the number of memory area overflows */
2072     return Overflows;
2073 }
2074
2075
2076
2077 void CfgWriteTarget (void)
2078 /* Write the target file(s) */
2079 {
2080     unsigned I;
2081
2082     /* Walk through the files list */
2083     for (I = 0; I < CollCount (&FileList); ++I) {
2084
2085         /* Get this entry */
2086         File* F = CollAtUnchecked (&FileList, I);
2087
2088         /* We don't need to look at files with no memory areas */
2089         if (CollCount (&F->MemoryAreas) > 0) {
2090
2091             /* Is there an output file? */
2092             if (SB_GetLen (GetStrBuf (F->Name)) > 0) {
2093
2094                 /* Assign a proper binary format */
2095                 if (F->Format == BINFMT_DEFAULT) {
2096                     F->Format = DefaultBinFmt;
2097                 }
2098
2099                 /* Call the apropriate routine for the binary format */
2100                 switch (F->Format) {
2101
2102                     case BINFMT_BINARY:
2103                         BinWriteTarget (BinFmtDesc, F);
2104                         break;
2105
2106                     case BINFMT_O65:
2107                         O65WriteTarget (O65FmtDesc, F);
2108                         break;
2109
2110                     case BINFMT_ATARIEXE:
2111                         XexWriteTarget (XexFmtDesc, F);
2112                         break;
2113
2114                     default:
2115                         Internal ("Invalid binary format: %u", F->Format);
2116
2117                 }
2118
2119             } else {
2120
2121                 /* No output file. Walk through the list and mark all segments
2122                 ** loading into these memory areas in this file as dumped.
2123                 */
2124                 unsigned J;
2125                 for (J = 0; J < CollCount (&F->MemoryAreas); ++J) {
2126
2127                     unsigned K;
2128
2129                     /* Get this entry */
2130                     MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, J);
2131
2132                     /* Debugging */
2133                     Print (stdout, 2, "Skipping '%s'...\n", GetString (M->Name));
2134
2135                     /* Walk throught the segments */
2136                     for (K = 0; K < CollCount (&M->SegList); ++K) {
2137                         SegDesc* S = CollAtUnchecked (&M->SegList, K);
2138                         if (S->Load == M) {
2139                             /* Load area - mark the segment as dumped */
2140                             S->Seg->Dumped = 1;
2141                         }
2142                     }
2143                 }
2144             }
2145         }
2146     }
2147 }