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