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