]> git.sur5r.net Git - cc65/blob - src/ld65/config.c
Only write full ATARI XEX header in the first chunk.
[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 ParseXex (void)
1006 /* Parse the o65 format section */
1007 {
1008     static const IdentTok Attributes [] = {
1009         {   "RUNAD",    CFGTOK_RUNAD            },
1010     };
1011
1012     /* Remember the attributes read */
1013     /* Bitmask to remember the attributes we got already */
1014     enum {
1015         atNone          = 0x0000,
1016         atRunAd         = 0x0001,
1017     };
1018     unsigned AttrFlags = atNone;
1019     Import *RunAd = 0;
1020
1021     /* Read the attributes */
1022     while (CfgTok == CFGTOK_IDENT) {
1023
1024         /* Map the identifier to a token */
1025         cfgtok_t AttrTok;
1026         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1027         AttrTok = CfgTok;
1028
1029         /* An optional assignment follows */
1030         CfgNextTok ();
1031         CfgOptionalAssign ();
1032
1033         /* Check which attribute was given */
1034         switch (AttrTok) {
1035
1036             case CFGTOK_RUNAD:
1037                 /* Cannot have this attribute twice */
1038                 FlagAttr (&AttrFlags, atRunAd, "RUNAD");
1039                 /* We expect an identifier */
1040                 CfgAssureIdent ();
1041                 /* Generate an import for the symbol */
1042                 RunAd = InsertImport (GenImport (GetStrBufId (&CfgSVal), ADDR_SIZE_ABS));
1043                 /* Remember the file position */
1044                 CollAppend (&RunAd->RefLines, GenLineInfo (&CfgErrorPos));
1045                 /* Eat the identifier token */
1046                 CfgNextTok ();
1047                 break;
1048
1049             default:
1050                 FAIL ("Unexpected attribute token");
1051
1052         }
1053
1054         /* Skip an optional comma */
1055         CfgOptionalComma ();
1056     }
1057
1058     /* Set the RUNAD import if we have one */
1059     if ( RunAd )
1060         XexSetRunAd (XexFmtDesc, RunAd);
1061 }
1062
1063
1064
1065 static void ParseFormats (void)
1066 /* Parse a target format section */
1067 {
1068     static const IdentTok Formats [] = {
1069         {   "O65",      CFGTOK_O65      },
1070         {   "BIN",      CFGTOK_BIN      },
1071         {   "BINARY",   CFGTOK_BIN      },
1072         {   "ATARI",    CFGTOK_ATARIEXE },
1073     };
1074
1075     while (CfgTok == CFGTOK_IDENT) {
1076
1077         /* Map the identifier to a token */
1078         cfgtok_t FormatTok;
1079         CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
1080         FormatTok = CfgTok;
1081
1082         /* Skip the name and the following colon */
1083         CfgNextTok ();
1084         CfgConsumeColon ();
1085
1086         /* Parse the format options */
1087         switch (FormatTok) {
1088
1089             case CFGTOK_O65:
1090                 ParseO65 ();
1091                 break;
1092
1093             case CFGTOK_ATARIEXE:
1094                 ParseXex ();
1095                 break;
1096
1097             case CFGTOK_BIN:
1098                 /* No attribibutes available */
1099                 break;
1100
1101             default:
1102                 Error ("Unexpected format token");
1103         }
1104
1105         /* Skip the semicolon */
1106         CfgConsumeSemi ();
1107     }
1108
1109
1110     /* Remember we had this section */
1111     SectionsEncountered |= SE_FORMATS;
1112 }
1113
1114
1115
1116 static void ParseConDes (void)
1117 /* Parse the CONDES feature */
1118 {
1119     static const IdentTok Attributes [] = {
1120         {   "COUNT",            CFGTOK_COUNT            },
1121         {   "IMPORT",           CFGTOK_IMPORT           },
1122         {   "LABEL",            CFGTOK_LABEL            },
1123         {   "ORDER",            CFGTOK_ORDER            },
1124         {   "SEGMENT",          CFGTOK_SEGMENT          },
1125         {   "TYPE",             CFGTOK_TYPE             },
1126     };
1127
1128     static const IdentTok Types [] = {
1129         {   "CONSTRUCTOR",      CFGTOK_CONSTRUCTOR      },
1130         {   "DESTRUCTOR",       CFGTOK_DESTRUCTOR       },
1131         {   "INTERRUPTOR",      CFGTOK_INTERRUPTOR      },
1132     };
1133
1134     static const IdentTok Orders [] = {
1135         {   "DECREASING",       CFGTOK_DECREASING       },
1136         {   "INCREASING",       CFGTOK_INCREASING       },
1137     };
1138
1139     /* Attribute values. */
1140     unsigned Count   = INVALID_STRING_ID;
1141     unsigned Label   = INVALID_STRING_ID;
1142     unsigned SegName = INVALID_STRING_ID;
1143     ConDesImport Import;
1144     /* Initialize to avoid gcc warnings: */
1145     int Type = -1;
1146     ConDesOrder Order = cdIncreasing;
1147
1148     /* Bitmask to remember the attributes we got already */
1149     enum {
1150         atNone          = 0x0000,
1151         atCount         = 0x0001,
1152         atImport        = 0x0002,
1153         atLabel         = 0x0004,
1154         atOrder         = 0x0008,
1155         atSegName       = 0x0010,
1156         atType          = 0x0020,
1157     };
1158     unsigned AttrFlags = atNone;
1159
1160     /* Parse the attributes */
1161     while (1) {
1162
1163         /* Map the identifier to a token */
1164         cfgtok_t AttrTok;
1165         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1166         AttrTok = CfgTok;
1167
1168         /* An optional assignment follows */
1169         CfgNextTok ();
1170         CfgOptionalAssign ();
1171
1172         /* Check which attribute was given */
1173         switch (AttrTok) {
1174
1175             case CFGTOK_COUNT:
1176                 /* Don't allow this twice */
1177                 FlagAttr (&AttrFlags, atCount, "COUNT");
1178                 /* We expect an identifier */
1179                 CfgAssureIdent ();
1180                 /* Remember the value for later */
1181                 Count = GetStrBufId (&CfgSVal);
1182                 break;
1183
1184             case CFGTOK_IMPORT:
1185                 /* Don't allow this twice */
1186                 FlagAttr (&AttrFlags, atImport, "IMPORT");
1187                 /* We expect an identifier */
1188                 CfgAssureIdent ();
1189                 /* Remember value and position for later */
1190                 Import.Name = GetStrBufId (&CfgSVal);
1191                 Import.Pos = CfgErrorPos;
1192                 Import.AddrSize = ADDR_SIZE_ABS;
1193                 break;
1194
1195             case CFGTOK_LABEL:
1196                 /* Don't allow this twice */
1197                 FlagAttr (&AttrFlags, atLabel, "LABEL");
1198                 /* We expect an identifier */
1199                 CfgAssureIdent ();
1200                 /* Remember the value for later */
1201                 Label = GetStrBufId (&CfgSVal);
1202                 break;
1203
1204             case CFGTOK_ORDER:
1205                 /* Don't allow this twice */
1206                 FlagAttr (&AttrFlags, atOrder, "ORDER");
1207                 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1208                 switch (CfgTok) {
1209                     case CFGTOK_DECREASING: Order = cdDecreasing;       break;
1210                     case CFGTOK_INCREASING: Order = cdIncreasing;       break;
1211                     default: FAIL ("Unexpected order token");
1212                 }
1213                 break;
1214
1215             case CFGTOK_SEGMENT:
1216                 /* Don't allow this twice */
1217                 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1218                 /* We expect an identifier */
1219                 CfgAssureIdent ();
1220                 /* Remember the value for later */
1221                 SegName = GetStrBufId (&CfgSVal);
1222                 break;
1223
1224             case CFGTOK_TYPE:
1225                 /* Don't allow this twice */
1226                 FlagAttr (&AttrFlags, atType, "TYPE");
1227                 /* The type may be given as id or numerical */
1228                 if (CfgTok == CFGTOK_INTCON) {
1229                     CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1230                     Type = (int) CfgIVal;
1231                 } else {
1232                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1233                     switch (CfgTok) {
1234                         case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON;    break;
1235                         case CFGTOK_DESTRUCTOR:  Type = CD_TYPE_DES;    break;
1236                         case CFGTOK_INTERRUPTOR: Type = CD_TYPE_INT;    break;
1237                         default: FAIL ("Unexpected type token");
1238                     }
1239                 }
1240                 break;
1241
1242             default:
1243                 FAIL ("Unexpected attribute token");
1244
1245         }
1246
1247         /* Skip the attribute value */
1248         CfgNextTok ();
1249
1250         /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1251         if (CfgTok == CFGTOK_SEMI) {
1252             break;
1253         } else if (CfgTok == CFGTOK_COMMA) {
1254             CfgNextTok ();
1255         }
1256     }
1257
1258     /* Check if we have all mandatory attributes */
1259     AttrCheck (AttrFlags, atSegName, "SEGMENT");
1260     AttrCheck (AttrFlags, atLabel, "LABEL");
1261     AttrCheck (AttrFlags, atType, "TYPE");
1262
1263     /* Check if the condes has already attributes defined */
1264     if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1265         CfgError (&CfgErrorPos,
1266                   "CONDES attributes for type %d are already defined",
1267                   Type);
1268     }
1269
1270     /* Define the attributes */
1271     ConDesSetSegName (Type, SegName);
1272     ConDesSetLabel (Type, Label);
1273     if (AttrFlags & atCount) {
1274         ConDesSetCountSym (Type, Count);
1275     }
1276     if (AttrFlags & atImport) {
1277         ConDesSetImport (Type, &Import);
1278     }
1279     if (AttrFlags & atOrder) {
1280         ConDesSetOrder (Type, Order);
1281     }
1282 }
1283
1284
1285
1286 static void ParseStartAddress (void)
1287 /* Parse the STARTADDRESS feature */
1288 {
1289     static const IdentTok Attributes [] = {
1290         {   "DEFAULT",  CFGTOK_DEFAULT },
1291     };
1292
1293
1294     /* Attribute values. */
1295     unsigned long DefStartAddr = 0;
1296
1297     /* Bitmask to remember the attributes we got already */
1298     enum {
1299         atNone          = 0x0000,
1300         atDefault       = 0x0001
1301     };
1302     unsigned AttrFlags = atNone;
1303
1304     /* Parse the attributes */
1305     while (1) {
1306
1307         /* Map the identifier to a token */
1308         cfgtok_t AttrTok;
1309         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1310         AttrTok = CfgTok;
1311
1312         /* An optional assignment follows */
1313         CfgNextTok ();
1314         CfgOptionalAssign ();
1315
1316         /* Check which attribute was given */
1317         switch (AttrTok) {
1318
1319             case CFGTOK_DEFAULT:
1320                 /* Don't allow this twice */
1321                 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1322                 /* We expect a numeric expression */
1323                 DefStartAddr = CfgCheckedConstExpr (0, 0xFFFFFF);
1324                 break;
1325
1326             default:
1327                 FAIL ("Unexpected attribute token");
1328
1329         }
1330
1331         /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1332         if (CfgTok == CFGTOK_SEMI) {
1333             break;
1334         } else if (CfgTok == CFGTOK_COMMA) {
1335             CfgNextTok ();
1336         }
1337     }
1338
1339     /* Check if we have all mandatory attributes */
1340     AttrCheck (AttrFlags, atDefault, "DEFAULT");
1341
1342     /* If no start address was given on the command line, use the one given
1343     ** here
1344     */
1345     if (!HaveStartAddr) {
1346         StartAddr = DefStartAddr;
1347     }
1348 }
1349
1350
1351
1352 static void ParseFeatures (void)
1353 /* Parse a features section */
1354 {
1355     static const IdentTok Features [] = {
1356         {   "CONDES",       CFGTOK_CONDES       },
1357         {   "STARTADDRESS", CFGTOK_STARTADDRESS },
1358     };
1359
1360     while (CfgTok == CFGTOK_IDENT) {
1361
1362         /* Map the identifier to a token */
1363         cfgtok_t FeatureTok;
1364         CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1365         FeatureTok = CfgTok;
1366
1367         /* Skip the name and the following colon */
1368         CfgNextTok ();
1369         CfgConsumeColon ();
1370
1371         /* Parse the format options */
1372         switch (FeatureTok) {
1373
1374             case CFGTOK_CONDES:
1375                 ParseConDes ();
1376                 break;
1377
1378             case CFGTOK_STARTADDRESS:
1379                 ParseStartAddress ();
1380                 break;
1381
1382
1383             default:
1384                 FAIL ("Unexpected feature token");
1385         }
1386
1387         /* Skip the semicolon */
1388         CfgConsumeSemi ();
1389     }
1390
1391     /* Remember we had this section */
1392     SectionsEncountered |= SE_FEATURES;
1393 }
1394
1395
1396
1397 static void ParseSymbols (void)
1398 /* Parse a symbols section */
1399 {
1400     static const IdentTok Attributes[] = {
1401         {   "ADDRSIZE", CFGTOK_ADDRSIZE },
1402         {   "TYPE",     CFGTOK_TYPE     },
1403         {   "VALUE",    CFGTOK_VALUE    },
1404     };
1405
1406     static const IdentTok AddrSizes [] = {
1407         {   "ABS",      CFGTOK_ABS      },
1408         {   "ABSOLUTE", CFGTOK_ABS      },
1409         {   "DIRECT",   CFGTOK_ZP       },
1410         {   "DWORD",    CFGTOK_LONG     },
1411         {   "FAR",      CFGTOK_FAR      },
1412         {   "LONG",     CFGTOK_LONG     },
1413         {   "NEAR",     CFGTOK_ABS      },
1414         {   "ZEROPAGE", CFGTOK_ZP       },
1415         {   "ZP",       CFGTOK_ZP       },
1416     };
1417
1418     static const IdentTok Types [] = {
1419         {   "EXPORT",   CFGTOK_EXPORT   },
1420         {   "IMPORT",   CFGTOK_IMPORT   },
1421         {   "WEAK",     CFGTOK_WEAK     },
1422     };
1423
1424     while (CfgTok == CFGTOK_IDENT) {
1425
1426         /* Bitmask to remember the attributes we got already */
1427         enum {
1428             atNone      = 0x0000,
1429             atAddrSize  = 0x0001,
1430             atType      = 0x0002,
1431             atValue     = 0x0004,
1432         };
1433         unsigned AttrFlags = atNone;
1434
1435         ExprNode* Value = 0;
1436         CfgSymType Type = CfgSymExport;
1437         unsigned char AddrSize = ADDR_SIZE_ABS;
1438         Import* Imp;
1439         Export* Exp;
1440         CfgSymbol* Sym;
1441
1442         /* Remember the name */
1443         unsigned Name = GetStrBufId (&CfgSVal);
1444         CfgNextTok ();
1445
1446         /* New syntax - skip the colon */
1447         CfgNextTok ();
1448
1449         /* Parse the attributes */
1450         while (1) {
1451
1452             /* Map the identifier to a token */
1453             cfgtok_t AttrTok;
1454             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1455             AttrTok = CfgTok;
1456
1457             /* Skip the attribute name */
1458             CfgNextTok ();
1459
1460             /* An optional assignment follows */
1461             CfgOptionalAssign ();
1462
1463             /* Check which attribute was given */
1464             switch (AttrTok) {
1465
1466                 case CFGTOK_ADDRSIZE:
1467                     /* Don't allow this twice */
1468                     FlagAttr (&AttrFlags, atAddrSize, "ADDRSIZE");
1469                     /* Map the type to a token */
1470                     CfgSpecialToken (AddrSizes, ENTRY_COUNT (AddrSizes), "AddrSize");
1471                     switch (CfgTok) {
1472                         case CFGTOK_ABS:    AddrSize = ADDR_SIZE_ABS;   break;
1473                         case CFGTOK_FAR:    AddrSize = ADDR_SIZE_FAR;   break;
1474                         case CFGTOK_LONG:   AddrSize = ADDR_SIZE_LONG;  break;
1475                         case CFGTOK_ZP:     AddrSize = ADDR_SIZE_ZP;    break;
1476                         default:
1477                             Internal ("Unexpected token: %d", CfgTok);
1478                     }
1479                     CfgNextTok ();
1480                     break;
1481
1482                 case CFGTOK_TYPE:
1483                     /* Don't allow this twice */
1484                     FlagAttr (&AttrFlags, atType, "TYPE");
1485                     /* Map the type to a token */
1486                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1487                     switch (CfgTok) {
1488                         case CFGTOK_EXPORT:     Type = CfgSymExport;    break;
1489                         case CFGTOK_IMPORT:     Type = CfgSymImport;    break;
1490                         case CFGTOK_WEAK:       Type = CfgSymWeak;      break;
1491                         default:
1492                             Internal ("Unexpected token: %d", CfgTok);
1493                     }
1494                     CfgNextTok ();
1495                     break;
1496
1497                 case CFGTOK_VALUE:
1498                     /* Don't allow this twice */
1499                     FlagAttr (&AttrFlags, atValue, "VALUE");
1500                     /* Value is an expression */
1501                     Value = CfgExpr ();
1502                     break;
1503
1504                 default:
1505                     FAIL ("Unexpected attribute token");
1506
1507             }
1508
1509             /* Semicolon ends the decl, otherwise accept an optional comma */
1510             if (CfgTok == CFGTOK_SEMI) {
1511                 break;
1512             } else if (CfgTok == CFGTOK_COMMA) {
1513                 CfgNextTok ();
1514             }
1515         }
1516
1517         /* We must have a type */
1518         AttrCheck (AttrFlags, atType, "TYPE");
1519
1520         /* Further actions depend on the type */
1521         switch (Type) {
1522
1523             case CfgSymExport:
1524                 /* We must have a value */
1525                 AttrCheck (AttrFlags, atValue, "VALUE");
1526                 /* Create the export */
1527                 Exp = CreateExprExport (Name, Value, AddrSize);
1528                 CollAppend (&Exp->DefLines, GenLineInfo (&CfgErrorPos));
1529                 break;
1530
1531             case CfgSymImport:
1532                 /* An import must not have a value */
1533                 if (AttrFlags & atValue) {
1534                     CfgError (&CfgErrorPos, "Imports must not have a value");
1535                 }
1536                 /* Generate the import */
1537                 Imp = InsertImport (GenImport (Name, AddrSize));
1538                 /* Remember the file position */
1539                 CollAppend (&Imp->RefLines, GenLineInfo (&CfgErrorPos));
1540                 break;
1541
1542             case CfgSymWeak:
1543                 /* We must have a value */
1544                 AttrCheck (AttrFlags, atValue, "VALUE");
1545                 /* Remember the symbol for later */
1546                 Sym = NewCfgSymbol (CfgSymWeak, Name);
1547                 Sym->Value = Value;
1548                 Sym->AddrSize = AddrSize;
1549                 break;
1550
1551             default:
1552                 Internal ("Unexpected symbol type %d", Type);
1553         }
1554
1555         /* Skip the semicolon */
1556         CfgConsumeSemi ();
1557     }
1558
1559     /* Remember we had this section */
1560     SectionsEncountered |= SE_SYMBOLS;
1561 }
1562
1563
1564
1565 static void ParseConfig (void)
1566 /* Parse the config file */
1567 {
1568     static const IdentTok BlockNames [] = {
1569         {   "MEMORY",   CFGTOK_MEMORY   },
1570         {   "FILES",    CFGTOK_FILES    },
1571         {   "SEGMENTS", CFGTOK_SEGMENTS },
1572         {   "FORMATS",  CFGTOK_FORMATS  },
1573         {   "FEATURES", CFGTOK_FEATURES },
1574         {   "SYMBOLS",  CFGTOK_SYMBOLS  },
1575     };
1576     cfgtok_t BlockTok;
1577
1578     do {
1579
1580         /* Read the block ident */
1581         CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1582         BlockTok = CfgTok;
1583         CfgNextTok ();
1584
1585         /* Expected a curly brace */
1586         CfgConsume (CFGTOK_LCURLY, "'{' expected");
1587
1588         /* Read the block */
1589         switch (BlockTok) {
1590
1591             case CFGTOK_MEMORY:
1592                 ParseMemory ();
1593                 break;
1594
1595             case CFGTOK_FILES:
1596                 ParseFiles ();
1597                 break;
1598
1599             case CFGTOK_SEGMENTS:
1600                 ParseSegments ();
1601                 break;
1602
1603             case CFGTOK_FORMATS:
1604                 ParseFormats ();
1605                 break;
1606
1607             case CFGTOK_FEATURES:
1608                 ParseFeatures ();
1609                 break;
1610
1611             case CFGTOK_SYMBOLS:
1612                 ParseSymbols ();
1613                 break;
1614
1615             default:
1616                 FAIL ("Unexpected block token");
1617
1618         }
1619
1620         /* Skip closing brace */
1621         CfgConsume (CFGTOK_RCURLY, "'}' expected");
1622
1623     } while (CfgTok != CFGTOK_EOF);
1624 }
1625
1626
1627
1628 void CfgRead (void)
1629 /* Read the configuration */
1630 {
1631     /* Create the descriptors for the binary formats */
1632     BinFmtDesc = NewBinDesc ();
1633     O65FmtDesc = NewO65Desc ();
1634     XexFmtDesc = NewXexDesc ();
1635
1636     /* If we have a config name given, open the file, otherwise we will read
1637     ** from a buffer.
1638     */
1639     CfgOpenInput ();
1640
1641     /* Parse the file */
1642     ParseConfig ();
1643
1644     /* Close the input file */
1645     CfgCloseInput ();
1646 }
1647
1648
1649
1650 /*****************************************************************************/
1651 /*                          Config file processing                           */
1652 /*****************************************************************************/
1653
1654
1655
1656 static void ProcessSegments (void)
1657 /* Process the SEGMENTS section */
1658 {
1659     unsigned I;
1660
1661     /* Walk over the list of segment descriptors */
1662     I = 0;
1663     while (I < CollCount (&SegDescList)) {
1664
1665         /* Get the next segment descriptor */
1666         SegDesc* S = CollAtUnchecked (&SegDescList, I);
1667
1668         /* Search for the actual segment in the input files. The function may
1669         ** return NULL (no such segment), this is checked later.
1670         */
1671         S->Seg = SegFind (S->Name);
1672
1673         /* If the segment is marked as BSS style, and if the segment exists
1674         ** in any of the object file, check that there's no initialized data
1675         ** in the segment.
1676         */
1677         if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
1678             CfgWarning (GetSourcePos (S->LI),
1679                         "Segment '%s' with type 'bss' contains initialized data",
1680                         GetString (S->Name));
1681         }
1682
1683         /* If this segment does exist in any of the object files, insert the
1684         ** segment into the load/run memory areas. Otherwise print a warning
1685         ** and discard it, because the segment pointer in the descriptor is
1686         ** invalid.
1687         */
1688         if (S->Seg != 0) {
1689
1690             /* Insert the segment into the memory area list */
1691             MemoryInsert (S->Run, S);
1692             if (S->Load != S->Run) {
1693                 /* We have separate RUN and LOAD areas */
1694                 MemoryInsert (S->Load, S);
1695             }
1696
1697             /* Use the fill value from the config */
1698             S->Seg->FillVal = S->FillVal;
1699
1700             /* Process the next segment descriptor in the next run */
1701             ++I;
1702
1703         } else {
1704
1705             /* Print a warning if the segment is not optional */
1706             if ((S->Flags & SF_OPTIONAL) == 0) {
1707                 CfgWarning (&CfgErrorPos,
1708                             "Segment '%s' does not exist",
1709                             GetString (S->Name));
1710             }
1711
1712             /* Discard the descriptor and remove it from the collection */
1713             FreeSegDesc (S);
1714             CollDelete (&SegDescList, I);
1715         }
1716     }
1717 }
1718
1719
1720
1721 static void ProcessSymbols (void)
1722 /* Process the SYMBOLS section */
1723 {
1724     Export* E;
1725
1726     /* Walk over all symbols */
1727     unsigned I;
1728     for (I = 0; I < CollCount (&CfgSymbols); ++I) {
1729
1730         /* Get the next symbol */
1731         CfgSymbol* Sym = CollAtUnchecked (&CfgSymbols, I);
1732
1733         /* Check what it is. */
1734         switch (Sym->Type) {
1735
1736             case CfgSymO65Export:
1737                 /* Check if the export symbol is also defined as an import. */
1738                 if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1739                     CfgError (
1740                         GetSourcePos (Sym->LI),
1741                         "Exported o65 symbol '%s' cannot also be an o65 import",
1742                         GetString (Sym->Name)
1743                     );
1744                 }
1745
1746                 /* Check if we have this symbol defined already. The entry
1747                 ** routine will check this also, but we get a more verbose
1748                 ** error message when checking it here.
1749                 */
1750                 if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
1751                     CfgError (
1752                         GetSourcePos (Sym->LI),
1753                         "Duplicate exported o65 symbol: '%s'",
1754                         GetString (Sym->Name)
1755                     );
1756                 }
1757
1758                 /* Insert the symbol into the table */
1759                 O65SetExport (O65FmtDesc, Sym->Name);
1760                 break;
1761
1762             case CfgSymO65Import:
1763                 /* Check if the import symbol is also defined as an export. */
1764                 if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
1765                     CfgError (
1766                         GetSourcePos (Sym->LI),
1767                         "Imported o65 symbol '%s' cannot also be an o65 export",
1768                         GetString (Sym->Name)
1769                     );
1770                 }
1771
1772                 /* Check if we have this symbol defined already. The entry
1773                 ** routine will check this also, but we get a more verbose
1774                 ** error message when checking it here.
1775                 */
1776                 if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1777                     CfgError (
1778                         GetSourcePos (Sym->LI),
1779                         "Duplicate imported o65 symbol: '%s'",
1780                         GetString (Sym->Name)
1781                     );
1782                 }
1783
1784                 /* Insert the symbol into the table */
1785                 O65SetImport (O65FmtDesc, Sym->Name);
1786                 break;
1787
1788             case CfgSymWeak:
1789                 /* If the symbol is not defined until now, define it */
1790                 if ((E = FindExport (Sym->Name)) == 0 || IsUnresolvedExport (E)) {
1791                     /* The symbol is undefined, generate an export */
1792                     E = CreateExprExport (Sym->Name, Sym->Value, Sym->AddrSize);
1793                     CollAppend (&E->DefLines, Sym->LI);
1794                 }
1795                 break;
1796
1797             default:
1798                 Internal ("Unexpected symbol type %d", Sym->Type);
1799                 break;
1800         }
1801     }
1802
1803 }
1804
1805
1806
1807 static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
1808 /* Create the defines for a RUN segment */
1809 {
1810     Export* E;
1811     StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1812
1813     /* Define the run address of the segment */
1814     SB_Printf (&Buf, "__%s_RUN__", GetString (S->Name));
1815     E = CreateMemoryExport (GetStrBufId (&Buf), S->Run, SegAddr - S->Run->Start);
1816     CollAppend (&E->DefLines, S->LI);
1817
1818     /* Define the size of the segment */
1819     SB_Printf (&Buf, "__%s_SIZE__", GetString (S->Name));
1820     E = CreateConstExport (GetStrBufId (&Buf), S->Seg->Size);
1821     CollAppend (&E->DefLines, S->LI);
1822
1823     S->Flags |= SF_RUN_DEF;
1824     SB_Done (&Buf);
1825 }
1826
1827
1828
1829 static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
1830 /* Create the defines for a LOAD segment */
1831 {
1832     Export* E;
1833     StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1834
1835     /* Define the load address of the segment */
1836     SB_Printf (&Buf, "__%s_LOAD__", GetString (S->Name));
1837     E = CreateMemoryExport (GetStrBufId (&Buf), S->Load, SegAddr - S->Load->Start);
1838     CollAppend (&E->DefLines, S->LI);
1839
1840     S->Flags |= SF_LOAD_DEF;
1841     SB_Done (&Buf);
1842 }
1843
1844
1845
1846 unsigned CfgProcess (void)
1847 /* Process the config file, after reading in object files and libraries. This
1848 ** includes postprocessing of the config file data; but also assigning segments,
1849 ** and defining segment/memory-area related symbols. The function will return
1850 ** the number of memory area overflows (so, zero means everything went OK).
1851 ** In case of overflows, a short mapfile can be generated later, to ease the
1852 ** user's task of re-arranging segments.
1853 */
1854 {
1855     unsigned Overflows = 0;
1856     unsigned I;
1857
1858     /* Postprocess symbols. We must do that first, since weak symbols are
1859     ** defined here, which may be needed later.
1860     */
1861     ProcessSymbols ();
1862
1863     /* Postprocess segments */
1864     ProcessSegments ();
1865
1866     /* Walk through each of the memory sections. Add up the sizes; and, check
1867     ** for an overflow of the section. Assign the start addresses of the
1868     ** segments while doing that.
1869     */
1870     for (I = 0; I < CollCount (&MemoryAreas); ++I) {
1871         unsigned J;
1872         unsigned long Addr;
1873         unsigned Overwrites = 0;
1874
1875         /* Get the next memory area */
1876         MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
1877
1878         /* Remember the offset in the output file */
1879         M->FileOffs = M->F->Size;
1880
1881         /* Remember if this is a relocatable memory area */
1882         M->Relocatable = RelocatableBinFmt (M->F->Format);
1883
1884         /* Resolve the start address expression, remember the start address,
1885         ** and mark the memory area as placed.
1886         */
1887         if (!IsConstExpr (M->StartExpr)) {
1888             CfgError (GetSourcePos (M->LI),
1889                       "Start address of memory area '%s' is not constant",
1890                       GetString (M->Name));
1891         }
1892         Addr = M->Start = GetExprVal (M->StartExpr);
1893         M->Flags |= MF_PLACED;
1894
1895         /* If requested, define the symbol for the start of the memory area.
1896         ** Doing it here means that the expression for the size of the area
1897         ** may reference this symbol.
1898         */
1899         if (M->Flags & MF_DEFINE) {
1900             Export* E;
1901             StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1902
1903             /* Define the start of the memory area */
1904             SB_Printf (&Buf, "__%s_START__", GetString (M->Name));
1905             E = CreateMemoryExport (GetStrBufId (&Buf), M, 0);
1906             CollAppend (&E->DefLines, M->LI);
1907
1908             SB_Done (&Buf);
1909         }
1910
1911         /* Resolve the size expression */
1912         if (!IsConstExpr (M->SizeExpr)) {
1913             CfgError (GetSourcePos (M->LI),
1914                       "Size of memory area '%s' is not constant",
1915                       GetString (M->Name));
1916         }
1917         M->Size = GetExprVal (M->SizeExpr);
1918
1919         /* Walk through the segments in this memory area */
1920         for (J = 0; J < CollCount (&M->SegList); ++J) {
1921             /* Get the segment */
1922             SegDesc* S = CollAtUnchecked (&M->SegList, J);
1923
1924             /* Remember the start address before handling this segment */
1925             unsigned long StartAddr = Addr;
1926
1927             /* Take note of "overwrite" segments and make sure there are no
1928             ** other segment types following them in current memory region.
1929             */
1930             if (S->Flags & SF_OVERWRITE) {
1931                 if (S->Flags & (SF_OFFSET | SF_START)) {
1932                     ++Overwrites;
1933                 } else {
1934                     CfgError (GetSourcePos (M->LI),
1935                               "Segment '%s' of type 'overwrite' requires either"
1936                               " 'Start' or 'Offset' attribute to be specified",
1937                               GetString (S->Name));
1938                 }
1939             } else {
1940                 if (Overwrites > 0) {
1941                     CfgError (GetSourcePos (M->LI),
1942                               "Segment '%s' is preceded by at least one segment"
1943                               " of type 'overwrite'",
1944                               GetString (S->Name));
1945                 }
1946             }
1947
1948             /* Some actions depend on whether this is the load or run memory
1949             ** area.
1950             */
1951             if (S->Run == M) {
1952                 /* This is the run (and maybe load) memory area. Handle
1953                 ** alignment and explict start address and offset.
1954                 */
1955
1956                 /* Check if the alignment for the segment from the linker
1957                 ** config is a multiple for that of the segment.
1958                 ** If START or OFFSET is provided instead of ALIGN, check
1959                 ** if its address fits alignment requirements.
1960                 */
1961                 unsigned long AlignedBy = (S->Flags & SF_START) ? S->Addr
1962                     : (S->Flags & SF_OFFSET) ? (S->Addr + M->Start)
1963                     : S->RunAlignment;
1964                 if ((AlignedBy % S->Seg->Alignment) != 0) {
1965                     /* Segment requires another alignment than configured
1966                     ** in the linker.
1967                     */
1968                     CfgWarning (GetSourcePos (S->LI),
1969                                 "Segment '%s' isn't aligned properly; the"
1970                                 " resulting executable might not be functional.",
1971                                 GetString (S->Name));
1972                 }
1973
1974                 if (S->Flags & SF_ALIGN) {
1975                     /* Align the address */
1976                     unsigned long NewAddr = AlignAddr (Addr, S->RunAlignment);
1977
1978                     /* If the first segment placed in the memory area needs
1979                     ** fill bytes for the alignment, emit a warning, since
1980                     ** that is somewhat suspicious.
1981                     */
1982                     if (M->FillLevel == 0 && NewAddr > Addr) {
1983                         CfgWarning (GetSourcePos (S->LI),
1984                                     "The first segment in memory area '%s' "
1985                                     "needs fill bytes for alignment.",
1986                                     GetString (M->Name));
1987                     }
1988
1989                     /* Use the aligned address */
1990                     Addr = NewAddr;
1991
1992                 } else if ((S->Flags & (SF_OFFSET | SF_START)) != 0 &&
1993                            (M->Flags & MF_OVERFLOW) == 0) {
1994                     /* Give the segment a fixed starting address */
1995                     unsigned long NewAddr = S->Addr;
1996
1997                     if (S->Flags & SF_OFFSET) {
1998                         /* An offset was given, no address, make an address */
1999                         NewAddr += M->Start;
2000                     }
2001
2002                     if (S->Flags & SF_OVERWRITE) {
2003                         if (NewAddr < M->Start) {
2004                             CfgError (GetSourcePos (S->LI),
2005                                       "Segment '%s' begins before memory area '%s'",
2006                                       GetString (S->Name), GetString (M->Name));
2007                         } else {
2008                             Addr = NewAddr;
2009                         }
2010                     } else {
2011                         if (NewAddr < Addr) {
2012                             /* Offset already too large */
2013                             ++Overflows;
2014                             if (S->Flags & SF_OFFSET) {
2015                                 CfgWarning (GetSourcePos (S->LI),
2016                                             "Segment '%s' offset is too small in '%s' by %lu byte%c",
2017                                             GetString (S->Name), GetString (M->Name),
2018                                             Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
2019                             } else {
2020                                 CfgWarning (GetSourcePos (S->LI),
2021                                             "Segment '%s' start address is too low in '%s' by %lu byte%c",
2022                                             GetString (S->Name), GetString (M->Name),
2023                                             Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
2024                             }
2025                         } else {
2026                             Addr = NewAddr;
2027                         }
2028                     }
2029                 }
2030
2031                 /* Set the start address of this segment, set the readonly flag
2032                 ** in the segment, and remember if the segment is in a
2033                 ** relocatable file or not.
2034                 */
2035                 S->Seg->PC = Addr;
2036                 S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
2037
2038                 /* Remember the run memory for this segment, which is also a
2039                 ** flag that the segment has been placed.
2040                 */
2041                 S->Seg->MemArea = M;
2042
2043             } else if (S->Load == M) {
2044                 /* This is the load memory area; *and*, run and load are
2045                 ** different (because of the "else" above). Handle alignment.
2046                 */
2047                 if (S->Flags & SF_ALIGN_LOAD) {
2048                     /* Align the address */
2049                     Addr = AlignAddr (Addr, S->LoadAlignment);
2050                 }
2051             }
2052
2053             /* If this is the load memory area, and the segment doesn't have a
2054             ** fill value defined, use the one from the memory area.
2055             */
2056             if (S->Load == M && (S->Flags & SF_FILLVAL) == 0) {
2057                 S->Seg->FillVal = M->FillVal;
2058             }
2059
2060             /* Increment the fill level of the memory area; and, check for an
2061             ** overflow.
2062             */
2063             M->FillLevel = Addr + S->Seg->Size - M->Start;
2064             if (M->FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) {
2065                 ++Overflows;
2066                 M->Flags |= MF_OVERFLOW;
2067                 CfgWarning (GetSourcePos (M->LI),
2068                             "Segment '%s' overflows memory area '%s' by %lu byte%c",
2069                             GetString (S->Name), GetString (M->Name),
2070                             M->FillLevel - M->Size, (M->FillLevel - M->Size == 1) ? ' ' : 's');
2071             }
2072
2073             /* If requested, define symbols for the start and size of the
2074             ** segment.
2075             */
2076             if (S->Flags & SF_DEFINE) {
2077                 if (S->Run == M && (S->Flags & SF_RUN_DEF) == 0) {
2078                     CreateRunDefines (S, Addr);
2079                 }
2080                 if (S->Load == M && (S->Flags & SF_LOAD_DEF) == 0) {
2081                     CreateLoadDefines (S, Addr);
2082                 }
2083             }
2084
2085             /* Calculate the new address */
2086             Addr += S->Seg->Size;
2087
2088             /* If this segment will go out to the file, or its place
2089             ** in the file will be filled, then increase the file size.
2090             */
2091             if (S->Load == M &&
2092                 ((S->Flags & SF_BSS) == 0 || (M->Flags & MF_FILL) != 0)) {
2093                 M->F->Size += Addr - StartAddr;
2094             }
2095         }
2096
2097         /* If requested, define symbols for start, size, and offset of the
2098         ** memory area
2099         */
2100         if (M->Flags & MF_DEFINE) {
2101             Export* E;
2102             StrBuf Buf = STATIC_STRBUF_INITIALIZER;
2103
2104             /* Define the size of the memory area */
2105             SB_Printf (&Buf, "__%s_SIZE__", GetString (M->Name));
2106             E = CreateConstExport (GetStrBufId (&Buf), M->Size);
2107             CollAppend (&E->DefLines, M->LI);
2108
2109             /* Define the fill level of the memory area */
2110             SB_Printf (&Buf, "__%s_LAST__", GetString (M->Name));
2111             E = CreateMemoryExport (GetStrBufId (&Buf), M, M->FillLevel);
2112             CollAppend (&E->DefLines, M->LI);
2113
2114             /* Define the file offset of the memory area. This isn't of much
2115             ** use for relocatable output files.
2116             */
2117             if (!M->Relocatable) {
2118                 SB_Printf (&Buf, "__%s_FILEOFFS__", GetString (M->Name));
2119                 E = CreateConstExport (GetStrBufId (&Buf), M->FileOffs);
2120                 CollAppend (&E->DefLines, M->LI);
2121             }
2122
2123             /* Throw away the string buffer */
2124             SB_Done (&Buf);
2125         }
2126
2127         /* If we didn't have an overflow, and are requested to fill the memory
2128         ** area, account for that in the file size.
2129         */
2130         if ((M->Flags & MF_OVERFLOW) == 0 && (M->Flags & MF_FILL) != 0) {
2131             M->F->Size += (M->Size - M->FillLevel);
2132         }
2133     }
2134
2135     /* Return the number of memory area overflows */
2136     return Overflows;
2137 }
2138
2139
2140
2141 void CfgWriteTarget (void)
2142 /* Write the target file(s) */
2143 {
2144     unsigned I;
2145
2146     /* Walk through the files list */
2147     for (I = 0; I < CollCount (&FileList); ++I) {
2148
2149         /* Get this entry */
2150         File* F = CollAtUnchecked (&FileList, I);
2151
2152         /* We don't need to look at files with no memory areas */
2153         if (CollCount (&F->MemoryAreas) > 0) {
2154
2155             /* Is there an output file? */
2156             if (SB_GetLen (GetStrBuf (F->Name)) > 0) {
2157
2158                 /* Assign a proper binary format */
2159                 if (F->Format == BINFMT_DEFAULT) {
2160                     F->Format = DefaultBinFmt;
2161                 }
2162
2163                 /* Call the apropriate routine for the binary format */
2164                 switch (F->Format) {
2165
2166                     case BINFMT_BINARY:
2167                         BinWriteTarget (BinFmtDesc, F);
2168                         break;
2169
2170                     case BINFMT_O65:
2171                         O65WriteTarget (O65FmtDesc, F);
2172                         break;
2173
2174                     case BINFMT_ATARIEXE:
2175                         XexWriteTarget (XexFmtDesc, F);
2176                         break;
2177
2178                     default:
2179                         Internal ("Invalid binary format: %u", F->Format);
2180
2181                 }
2182
2183             } else {
2184
2185                 /* No output file. Walk through the list and mark all segments
2186                 ** loading into these memory areas in this file as dumped.
2187                 */
2188                 unsigned J;
2189                 for (J = 0; J < CollCount (&F->MemoryAreas); ++J) {
2190
2191                     unsigned K;
2192
2193                     /* Get this entry */
2194                     MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, J);
2195
2196                     /* Debugging */
2197                     Print (stdout, 2, "Skipping '%s'...\n", GetString (M->Name));
2198
2199                     /* Walk throught the segments */
2200                     for (K = 0; K < CollCount (&M->SegList); ++K) {
2201                         SegDesc* S = CollAtUnchecked (&M->SegList, K);
2202                         if (S->Load == M) {
2203                             /* Load area - mark the segment as dumped */
2204                             S->Seg->Dumped = 1;
2205                         }
2206                     }
2207                 }
2208             }
2209         }
2210     }
2211 }