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