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