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