]> git.sur5r.net Git - cc65/blob - src/ld65/config.c
Keep the config file position in a FilePos structure.
[cc65] / src / ld65 / config.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 config.c                                  */
4 /*                                                                           */
5 /*               Target configuration file for the ld65 linker               */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2010, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <errno.h>
40
41 /* common */
42 #include "bitops.h"
43 #include "check.h"
44 #include "print.h"
45 #include "xmalloc.h"
46 #include "xsprintf.h"
47
48 /* ld65 */
49 #include "bin.h"
50 #include "binfmt.h"
51 #include "cfgexpr.h"
52 #include "condes.h"
53 #include "config.h"
54 #include "error.h"
55 #include "exports.h"
56 #include "expr.h"
57 #include "global.h"
58 #include "memarea.h"
59 #include "o65.h"
60 #include "objdata.h"
61 #include "scanner.h"
62 #include "spool.h"
63
64
65
66 /*****************************************************************************/
67 /*                                   Data                                    */
68 /*****************************************************************************/
69
70
71
72 /* Remember which sections we had encountered */
73 static enum {
74     SE_NONE     = 0x0000,
75     SE_MEMORY   = 0x0001,
76     SE_SEGMENTS = 0x0002,
77     SE_FEATURES = 0x0004,
78     SE_FILES    = 0x0008,
79     SE_FORMATS  = 0x0010,
80     SE_SYMBOLS  = 0x0020
81 } SectionsEncountered = SE_NONE;
82
83
84
85 /* File list */
86 static Collection       FileList = STATIC_COLLECTION_INITIALIZER;
87
88 /* Memory list */
89 static Collection       MemoryAreas = STATIC_COLLECTION_INITIALIZER;
90
91 /* Memory attributes */
92 #define MA_START        0x0001
93 #define MA_SIZE         0x0002
94 #define MA_TYPE         0x0004
95 #define MA_FILE         0x0008
96 #define MA_DEFINE       0x0010
97 #define MA_FILL         0x0020
98 #define MA_FILLVAL      0x0040
99
100 /* Segment list */
101 static Collection       SegDescList = STATIC_COLLECTION_INITIALIZER;
102
103 /* Segment attributes */
104 #define SA_TYPE         0x0001
105 #define SA_LOAD         0x0002
106 #define SA_RUN          0x0004
107 #define SA_ALIGN        0x0008
108 #define SA_ALIGN_LOAD   0x0010
109 #define SA_DEFINE       0x0020
110 #define SA_OFFSET       0x0040
111 #define SA_START        0x0080
112 #define SA_OPTIONAL     0x0100
113
114 /* Symbol structure. It is used for o65 imports and exports, but also for
115  * symbols from the SYMBOLS sections (symbols defined in the config file or
116  * forced imports).
117  */
118 typedef struct Symbol Symbol;
119 struct Symbol {
120     FilePos     Pos;            /* Config file position */
121     unsigned    Name;           /* Symbol name */
122     unsigned    Flags;          /* Symbol flags */
123     long        Val;            /* Symbol value if any */
124 };
125
126 /* Collections with symbols */
127 static Collection       O65Imports = STATIC_COLLECTION_INITIALIZER;
128 static Collection       O65Exports = STATIC_COLLECTION_INITIALIZER;
129 static Collection       Symbols    = STATIC_COLLECTION_INITIALIZER;
130
131 /* Symbol flags */
132 #define SYM_NONE        0x00    /* No special meaning */
133 #define SYM_DEF         0x01    /* Symbol defined in the config file */
134 #define SYM_WEAK        0x02    /* Defined symbol is weak */
135 #define SYM_IMPORT      0x04    /* A forced import */
136
137 /* Descriptor holding information about the binary formats */
138 static BinDesc* BinFmtDesc      = 0;
139 static O65Desc* O65FmtDesc      = 0;
140
141
142
143 /*****************************************************************************/
144 /*                                 Forwards                                  */
145 /*****************************************************************************/
146
147
148
149 static File* NewFile (unsigned Name);
150 /* Create a new file descriptor and insert it into the list */
151
152
153
154 /*****************************************************************************/
155 /*                              List management                              */
156 /*****************************************************************************/
157
158
159
160 static File* FindFile (unsigned Name)
161 /* Find a file with a given name. */
162 {
163     unsigned I;
164     for (I = 0; I < CollCount (&FileList); ++I) {
165         File* F = CollAtUnchecked (&FileList, I);
166         if (F->Name == Name) {
167             return F;
168         }
169     }
170     return 0;
171 }
172
173
174
175 static File* GetFile (unsigned Name)
176 /* Get a file entry with the given name. Create a new one if needed. */
177 {
178     File* F = FindFile (Name);
179     if (F == 0) {
180         /* Create a new one */
181         F = NewFile (Name);
182     }
183     return F;
184 }
185
186
187
188 static void FileInsert (File* F, MemoryArea* M)
189 /* Insert the memory area into the files list */
190 {
191     M->F = F;
192     CollAppend (&F->MemoryAreas, M);
193 }
194
195
196
197 static MemoryArea* CfgFindMemory (unsigned Name)
198 /* Find the memory are with the given name. Return NULL if not found */
199 {
200     unsigned I;
201     for (I = 0; I < CollCount (&MemoryAreas); ++I) {
202         MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
203         if (M->Name == Name) {
204             return M;
205         }
206     }
207     return 0;
208 }
209
210
211
212 static MemoryArea* CfgGetMemory (unsigned Name)
213 /* Find the memory are with the given name. Print an error on an invalid name */
214 {
215     MemoryArea* M = CfgFindMemory (Name);
216     if (M == 0) {
217         CfgError (&CfgErrorPos, "Invalid memory area `%s'", GetString (Name));
218     }
219     return M;
220 }
221
222
223
224 static SegDesc* CfgFindSegDesc (unsigned Name)
225 /* Find the segment descriptor with the given name, return NULL if not found. */
226 {
227     unsigned I;
228     for (I = 0; I < CollCount (&SegDescList); ++I) {
229         SegDesc* S = CollAtUnchecked (&SegDescList, I);
230         if (S->Name == Name) {
231             /* Found */
232             return S;
233         }
234     }
235
236     /* Not found */
237     return 0;
238 }
239
240
241
242 static void MemoryInsert (MemoryArea* M, SegDesc* S)
243 /* Insert the segment descriptor into the memory area list */
244 {
245     /* Insert the segment into the segment list of the memory area */
246     CollAppend (&M->SegList, S);
247 }
248
249
250
251 /*****************************************************************************/
252 /*                         Constructors/Destructors                          */
253 /*****************************************************************************/
254
255
256
257 static Symbol* NewSymbol (unsigned Name, unsigned Flags, long Val)
258 /* Create a new Symbol structure with the given name name and flags. The
259  * current config file position is recorded in the returned struct.
260  */
261 {
262     /* Allocate memory */
263     Symbol* Sym = xmalloc (sizeof (Symbol));
264
265     /* Initialize the fields */
266     Sym->Pos    = CfgErrorPos;
267     Sym->Name   = Name;
268     Sym->Flags  = Flags;
269     Sym->Val    = Val;
270
271     /* Return the initialized struct */
272     return Sym;
273 }
274
275
276
277 static Symbol* NewO65Symbol (void)
278 /* Create a new Symbol structure with the name in the current CfgSVal variable
279  * ready for use as an o65 symbol. The current config file position is recorded
280  * in the returned struct.
281  */
282 {
283     return NewSymbol (GetStrBufId (&CfgSVal), SYM_NONE, 0);
284 }
285
286
287
288 static File* NewFile (unsigned Name)
289 /* Create a new file descriptor and insert it into the list */
290 {
291     /* Allocate memory */
292     File* F = xmalloc (sizeof (File));
293
294     /* Initialize the fields */
295     F->Name    = Name;
296     F->Flags   = 0;
297     F->Format  = BINFMT_DEFAULT;
298     InitCollection (&F->MemoryAreas);
299
300     /* Insert the struct into the list */
301     CollAppend (&FileList, F);
302
303     /* ...and return it */
304     return F;
305 }
306
307
308
309 static MemoryArea* CreateMemoryArea (const FilePos* Pos, unsigned Name)
310 /* Create a new memory area and insert it into the list */
311 {
312     /* Check for duplicate names */
313     MemoryArea* M = CfgFindMemory (Name);
314     if (M) {
315         CfgError (&CfgErrorPos,
316                   "Memory area `%s' defined twice",
317                   GetString (Name));
318     }
319
320     /* Create a new memory area */
321     M = NewMemoryArea (Pos, Name);
322
323     /* Insert the struct into the list ... */
324     CollAppend (&MemoryAreas, M);
325
326     /* ...and return it */
327     return M;
328 }
329
330
331
332 static SegDesc* NewSegDesc (unsigned Name)
333 /* Create a segment descriptor and insert it into the list */
334 {
335
336     /* Check for duplicate names */
337     SegDesc* S = CfgFindSegDesc (Name);
338     if (S) {
339         CfgError (&CfgErrorPos, "Segment `%s' defined twice", GetString (Name));
340     }
341
342     /* Allocate memory */
343     S = xmalloc (sizeof (SegDesc));
344
345     /* Initialize the fields */
346     S->Name    = Name;
347     S->Seg     = 0;
348     S->Attr    = 0;
349     S->Flags   = 0;
350     S->Align   = 0;
351
352     /* Insert the struct into the list ... */
353     CollAppend (&SegDescList, S);
354
355     /* ...and return it */
356     return S;
357 }
358
359
360
361 static void FreeSegDesc (SegDesc* S)
362 /* Free a segment descriptor */
363 {
364     xfree (S);
365 }
366
367
368
369 /*****************************************************************************/
370 /*                            Config file parsing                            */
371 /*****************************************************************************/
372
373
374
375 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
376 /* Check if the item is already defined. Print an error if so. If not, set
377  * the marker that we have a definition now.
378  */
379 {
380     if (*Flags & Mask) {
381         CfgError (&CfgErrorPos, "%s is already defined", Name);
382     }
383     *Flags |= Mask;
384 }
385
386
387
388 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
389 /* Check that a mandatory attribute was given */
390 {
391     if ((Attr & Mask) == 0) {
392         CfgError (&CfgErrorPos, "%s attribute is missing", Name);
393     }
394 }
395
396
397
398 static void ParseMemory (void)
399 /* Parse a MEMORY section */
400 {
401     static const IdentTok Attributes [] = {
402         {   "START",    CFGTOK_START    },
403         {   "SIZE",     CFGTOK_SIZE     },
404         {   "TYPE",     CFGTOK_TYPE     },
405         {   "FILE",     CFGTOK_FILE     },
406         {   "DEFINE",   CFGTOK_DEFINE   },
407         {   "FILL",     CFGTOK_FILL     },
408         {   "FILLVAL",  CFGTOK_FILLVAL  },
409     };
410     static const IdentTok Types [] = {
411         {   "RO",       CFGTOK_RO       },
412         {   "RW",       CFGTOK_RW       },
413     };
414
415     while (CfgTok == CFGTOK_IDENT) {
416
417         /* Create a new entry on the heap */
418         MemoryArea* M = CreateMemoryArea (&CfgErrorPos, GetStrBufId (&CfgSVal));
419
420         /* Skip the name and the following colon */
421         CfgNextTok ();
422         CfgConsumeColon ();
423
424         /* Read the attributes */
425         while (CfgTok == CFGTOK_IDENT) {
426
427             /* Map the identifier to a token */
428             cfgtok_t AttrTok;
429             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
430             AttrTok = CfgTok;
431
432             /* An optional assignment follows */
433             CfgNextTok ();
434             CfgOptionalAssign ();
435
436             /* Check which attribute was given */
437             switch (AttrTok) {
438
439                 case CFGTOK_START:
440                     FlagAttr (&M->Attr, MA_START, "START");
441                     M->StartExpr = CfgExpr ();
442                     break;
443
444                 case CFGTOK_SIZE:
445                     FlagAttr (&M->Attr, MA_SIZE, "SIZE");
446                     M->SizeExpr = CfgExpr ();
447                     break;
448
449                 case CFGTOK_TYPE:
450                     FlagAttr (&M->Attr, MA_TYPE, "TYPE");
451                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
452                     if (CfgTok == CFGTOK_RO) {
453                         M->Flags |= MF_RO;
454                     }
455                     CfgNextTok ();
456                     break;
457
458                 case CFGTOK_FILE:
459                     FlagAttr (&M->Attr, MA_FILE, "FILE");
460                     CfgAssureStr ();
461                     /* Get the file entry and insert the memory area */
462                     FileInsert (GetFile (GetStrBufId (&CfgSVal)), M);
463                     CfgNextTok ();
464                     break;
465
466                 case CFGTOK_DEFINE:
467                     FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
468                     /* Map the token to a boolean */
469                     CfgBoolToken ();
470                     if (CfgTok == CFGTOK_TRUE) {
471                         M->Flags |= MF_DEFINE;
472                     }
473                     CfgNextTok ();
474                     break;
475
476                 case CFGTOK_FILL:
477                     FlagAttr (&M->Attr, MA_FILL, "FILL");
478                     /* Map the token to a boolean */
479                     CfgBoolToken ();
480                     if (CfgTok == CFGTOK_TRUE) {
481                         M->Flags |= MF_FILL;
482                     }
483                     CfgNextTok ();
484                     break;
485
486                 case CFGTOK_FILLVAL:
487                     FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
488                     M->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
489                     break;
490
491                 default:
492                     FAIL ("Unexpected attribute token");
493
494             }
495
496             /* Skip an optional comma */
497             CfgOptionalComma ();
498         }
499
500         /* Skip the semicolon */
501         CfgConsumeSemi ();
502
503         /* Check for mandatory parameters */
504         AttrCheck (M->Attr, MA_START, "START");
505         AttrCheck (M->Attr, MA_SIZE, "SIZE");
506
507         /* If we don't have a file name for output given, use the default
508          * file name.
509          */
510         if ((M->Attr & MA_FILE) == 0) {
511             FileInsert (GetFile (GetStringId (OutputName)), M);
512             OutputNameUsed = 1;
513         }
514     }
515
516     /* Remember we had this section */
517     SectionsEncountered |= SE_MEMORY;
518 }
519
520
521
522 static void ParseFiles (void)
523 /* Parse a FILES section */
524 {
525     static const IdentTok Attributes [] = {
526         {   "FORMAT",   CFGTOK_FORMAT   },
527     };
528     static const IdentTok Formats [] = {
529         {   "O65",      CFGTOK_O65      },
530         {   "BIN",      CFGTOK_BIN      },
531         {   "BINARY",   CFGTOK_BIN      },
532     };
533
534
535     /* The MEMORY section must preceed the FILES section */
536     if ((SectionsEncountered & SE_MEMORY) == 0) {
537         CfgError (&CfgErrorPos, "MEMORY must precede FILES");
538     }
539
540     /* Parse all files */
541     while (CfgTok != CFGTOK_RCURLY) {
542
543         File* F;
544
545         /* We expect a string value here */
546         CfgAssureStr ();
547
548         /* Search for the file, it must exist */
549         F = FindFile (GetStrBufId (&CfgSVal));
550         if (F == 0) {
551             CfgError (&CfgErrorPos,
552                       "File `%s' not found in MEMORY section",
553                       SB_GetConstBuf (&CfgSVal));
554         }
555
556         /* Skip the token and the following colon */
557         CfgNextTok ();
558         CfgConsumeColon ();
559
560         /* Read the attributes */
561         while (CfgTok == CFGTOK_IDENT) {
562
563             /* Map the identifier to a token */
564             cfgtok_t AttrTok;
565             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
566             AttrTok = CfgTok;
567
568             /* An optional assignment follows */
569             CfgNextTok ();
570             CfgOptionalAssign ();
571
572             /* Check which attribute was given */
573             switch (AttrTok) {
574
575                 case CFGTOK_FORMAT:
576                     if (F->Format != BINFMT_DEFAULT) {
577                         /* We've set the format already! */
578                         CfgError (&CfgErrorPos,
579                                   "Cannot set a file format twice");
580                     }
581                     /* Read the format token */
582                     CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
583                     switch (CfgTok) {
584
585                         case CFGTOK_BIN:
586                             F->Format = BINFMT_BINARY;
587                             break;
588
589                         case CFGTOK_O65:
590                             F->Format = BINFMT_O65;
591                             break;
592
593                         default:
594                             Error ("Unexpected format token");
595                     }
596                     break;
597
598                 default:
599                     FAIL ("Unexpected attribute token");
600
601             }
602
603             /* Skip the attribute value and an optional comma */
604             CfgNextTok ();
605             CfgOptionalComma ();
606         }
607
608         /* Skip the semicolon */
609         CfgConsumeSemi ();
610
611     }
612
613     /* Remember we had this section */
614     SectionsEncountered |= SE_FILES;
615 }
616
617
618
619 static void ParseSegments (void)
620 /* Parse a SEGMENTS section */
621 {
622     static const IdentTok Attributes [] = {
623         {   "ALIGN",            CFGTOK_ALIGN            },
624         {   "ALIGN_LOAD",       CFGTOK_ALIGN_LOAD       },
625         {   "DEFINE",           CFGTOK_DEFINE           },
626         {   "LOAD",             CFGTOK_LOAD             },
627         {   "OFFSET",           CFGTOK_OFFSET           },
628         {   "OPTIONAL",         CFGTOK_OPTIONAL         },
629         {   "RUN",              CFGTOK_RUN              },
630         {   "START",            CFGTOK_START            },
631         {   "TYPE",             CFGTOK_TYPE             },
632     };
633     static const IdentTok Types [] = {
634         {   "RO",               CFGTOK_RO               },
635         {   "RW",               CFGTOK_RW               },
636         {   "BSS",              CFGTOK_BSS              },
637         {   "ZP",               CFGTOK_ZP               },
638     };
639
640     unsigned Count;
641     long     Val;
642
643     /* The MEMORY section must preceed the SEGMENTS section */
644     if ((SectionsEncountered & SE_MEMORY) == 0) {
645         CfgError (&CfgErrorPos, "MEMORY must precede SEGMENTS");
646     }
647
648     while (CfgTok == CFGTOK_IDENT) {
649
650         SegDesc* S;
651
652         /* Create a new entry on the heap */
653         S = NewSegDesc (GetStrBufId (&CfgSVal));
654
655         /* Skip the name and the following colon */
656         CfgNextTok ();
657         CfgConsumeColon ();
658
659         /* Read the attributes */
660         while (CfgTok == CFGTOK_IDENT) {
661
662             /* Map the identifier to a token */
663             cfgtok_t AttrTok;
664             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
665             AttrTok = CfgTok;
666
667             /* An optional assignment follows */
668             CfgNextTok ();
669             CfgOptionalAssign ();
670
671             /* Check which attribute was given */
672             switch (AttrTok) {
673
674                 case CFGTOK_ALIGN:
675                     FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
676                     Val = CfgCheckedConstExpr (1, 0x10000);
677                     S->Align = BitFind (Val);
678                     if ((0x01L << S->Align) != Val) {
679                         CfgError (&CfgErrorPos, "Alignment must be a power of 2");
680                     }
681                     S->Flags |= SF_ALIGN;
682                     break;
683
684                 case CFGTOK_ALIGN_LOAD:
685                     FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
686                     Val = CfgCheckedConstExpr (1, 0x10000);
687                     S->AlignLoad = BitFind (Val);
688                     if ((0x01L << S->AlignLoad) != Val) {
689                         CfgError (&CfgErrorPos, "Alignment must be a power of 2");
690                     }
691                     S->Flags |= SF_ALIGN_LOAD;
692                     break;
693
694                 case CFGTOK_DEFINE:
695                     FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
696                     /* Map the token to a boolean */
697                     CfgBoolToken ();
698                     if (CfgTok == CFGTOK_TRUE) {
699                         S->Flags |= SF_DEFINE;
700                     }
701                     CfgNextTok ();
702                     break;
703
704                 case CFGTOK_LOAD:
705                     FlagAttr (&S->Attr, SA_LOAD, "LOAD");
706                     S->Load = CfgGetMemory (GetStrBufId (&CfgSVal));
707                     CfgNextTok ();
708                     break;
709
710                 case CFGTOK_OFFSET:
711                     FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
712                     S->Addr   = CfgCheckedConstExpr (1, 0x1000000);
713                     S->Flags |= SF_OFFSET;
714                     break;
715
716                 case CFGTOK_OPTIONAL:
717                     FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL");
718                     CfgBoolToken ();
719                     if (CfgTok == CFGTOK_TRUE) {
720                         S->Flags |= SF_OPTIONAL;
721                     }
722                     CfgNextTok ();
723                     break;
724
725                 case CFGTOK_RUN:
726                     FlagAttr (&S->Attr, SA_RUN, "RUN");
727                     S->Run = CfgGetMemory (GetStrBufId (&CfgSVal));
728                     CfgNextTok ();
729                     break;
730
731                 case CFGTOK_START:
732                     FlagAttr (&S->Attr, SA_START, "START");
733                     S->Addr   = CfgCheckedConstExpr (1, 0x1000000);
734                     S->Flags |= SF_START;
735                     break;
736
737                 case CFGTOK_TYPE:
738                     FlagAttr (&S->Attr, SA_TYPE, "TYPE");
739                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
740                     switch (CfgTok) {
741                         case CFGTOK_RO:    S->Flags |= SF_RO;               break;
742                         case CFGTOK_RW:    /* Default */                    break;
743                         case CFGTOK_BSS:   S->Flags |= SF_BSS;              break;
744                         case CFGTOK_ZP:    S->Flags |= (SF_BSS | SF_ZP);    break;
745                         default:           Internal ("Unexpected token: %d", CfgTok);
746                     }
747                     CfgNextTok ();
748                     break;
749
750                 default:
751                     FAIL ("Unexpected attribute token");
752
753             }
754
755             /* Skip an optional comma */
756             CfgOptionalComma ();
757         }
758
759         /* Check for mandatory parameters */
760         AttrCheck (S->Attr, SA_LOAD, "LOAD");
761
762         /* Set defaults for stuff not given */
763         if ((S->Attr & SA_RUN) == 0) {
764             S->Attr |= SA_RUN;
765             S->Run = S->Load;
766         }
767
768         /* An attribute of ALIGN_LOAD doesn't make sense if there are no
769          * separate run and load memory areas.
770          */
771         if ((S->Flags & SF_ALIGN_LOAD) != 0 && (S->Load == S->Run)) {
772             Warning ("%s(%lu): ALIGN_LOAD attribute specified, but no separate "
773                      "LOAD and RUN memory areas assigned",
774                      CfgGetName (), CfgErrorPos.Line);
775             /* Remove the flag */
776             S->Flags &= ~SF_ALIGN_LOAD;
777         }
778
779         /* If the segment is marked as BSS style, it may not have separate
780          * load and run memory areas, because it's is never written to disk.
781          */
782         if ((S->Flags & SF_BSS) != 0 && (S->Load != S->Run)) {
783             Warning ("%s(%lu): Segment with type `bss' has both LOAD and RUN "
784                      "memory areas assigned", CfgGetName (), CfgErrorPos.Line);
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                 CollAppend (&O65Exports, NewO65Symbol ());
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                 CollAppend (&O65Imports, NewO65Symbol ());
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         {   "VALUE",    CFGTOK_VALUE    },
1295         {   "WEAK",     CFGTOK_WEAK     },
1296     };
1297
1298     while (CfgTok == CFGTOK_IDENT) {
1299
1300         long Val = 0L;
1301         unsigned Flags = SYM_NONE;
1302
1303         /* Remember the name */
1304         unsigned Name = GetStrBufId (&CfgSVal);
1305         CfgNextTok ();
1306
1307         /* Support both, old and new syntax here. New syntax is a colon
1308          * followed by an attribute list, old syntax is an optional equal
1309          * sign plus a value.
1310          */
1311         if (CfgTok != CFGTOK_COLON) {
1312
1313             /* Old syntax */
1314
1315             /* Allow an optional assignment */
1316             CfgOptionalAssign ();
1317
1318             /* Make sure the next token is an integer expression, read and
1319              * skip it.
1320              */
1321             Val = CfgConstExpr ();
1322
1323             /* This is a defined symbol */
1324             Flags = SYM_DEF;
1325
1326         } else {
1327
1328             /* Bitmask to remember the attributes we got already */
1329             enum {
1330                 atNone          = 0x0000,
1331                 atValue         = 0x0001,
1332                 atWeak          = 0x0002
1333             };
1334             unsigned AttrFlags = atNone;
1335
1336
1337             /* New syntax - skip the colon */
1338             CfgNextTok ();
1339
1340             /* Parse the attributes */
1341             while (1) {
1342
1343                 /* Map the identifier to a token */
1344                 cfgtok_t AttrTok;
1345                 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1346                 AttrTok = CfgTok;
1347
1348                 /* Skip the attribute name */
1349                 CfgNextTok ();
1350
1351                 /* An optional assignment follows */
1352                 CfgOptionalAssign ();
1353
1354                 /* Check which attribute was given */
1355                 switch (AttrTok) {
1356
1357                     case CFGTOK_VALUE:
1358                         /* Don't allow this twice */
1359                         FlagAttr (&AttrFlags, atValue, "VALUE");
1360                         /* We expect a numeric expression */
1361                         Val = CfgConstExpr ();
1362                         /* Symbol is defined */
1363                         Flags |= SYM_DEF;
1364                         break;
1365
1366                     case CFGTOK_WEAK:
1367                         /* Don't allow this twice */
1368                         FlagAttr (&AttrFlags, atWeak, "WEAK");
1369                         CfgBoolToken ();
1370                         if (CfgTok == CFGTOK_TRUE) {
1371                             Flags |= SYM_WEAK;
1372                         }
1373                         CfgNextTok ();
1374                         break;
1375
1376                     default:
1377                         FAIL ("Unexpected attribute token");
1378
1379                 }
1380
1381                 /* Semicolon ends the decl, otherwise accept an optional comma */
1382                 if (CfgTok == CFGTOK_SEMI) {
1383                     break;
1384                 } else if (CfgTok == CFGTOK_COMMA) {
1385                     CfgNextTok ();
1386                 }
1387             }
1388
1389             /* Check if we have all mandatory attributes */
1390             AttrCheck (AttrFlags, atValue, "VALUE");
1391         }
1392
1393         /* Remember the symbol for later */
1394         CollAppend (&Symbols, NewSymbol (Name, Flags, Val));
1395
1396         /* Skip the semicolon */
1397         CfgConsumeSemi ();
1398     }
1399
1400     /* Remember we had this section */
1401     SectionsEncountered |= SE_SYMBOLS;
1402 }
1403
1404
1405
1406 static void ParseConfig (void)
1407 /* Parse the config file */
1408 {
1409     static const IdentTok BlockNames [] = {
1410         {   "MEMORY",   CFGTOK_MEMORY   },
1411         {   "FILES",    CFGTOK_FILES    },
1412         {   "SEGMENTS", CFGTOK_SEGMENTS },
1413         {   "FORMATS",  CFGTOK_FORMATS  },
1414         {   "FEATURES", CFGTOK_FEATURES },
1415         {   "SYMBOLS",  CFGTOK_SYMBOLS  },
1416     };
1417     cfgtok_t BlockTok;
1418
1419     do {
1420
1421         /* Read the block ident */
1422         CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1423         BlockTok = CfgTok;
1424         CfgNextTok ();
1425
1426         /* Expected a curly brace */
1427         CfgConsume (CFGTOK_LCURLY, "`{' expected");
1428
1429         /* Read the block */
1430         switch (BlockTok) {
1431
1432             case CFGTOK_MEMORY:
1433                 ParseMemory ();
1434                 break;
1435
1436             case CFGTOK_FILES:
1437                 ParseFiles ();
1438                 break;
1439
1440             case CFGTOK_SEGMENTS:
1441                 ParseSegments ();
1442                 break;
1443
1444             case CFGTOK_FORMATS:
1445                 ParseFormats ();
1446                 break;
1447
1448             case CFGTOK_FEATURES:
1449                 ParseFeatures ();
1450                 break;
1451
1452             case CFGTOK_SYMBOLS:
1453                 ParseSymbols ();
1454                 break;
1455
1456             default:
1457                 FAIL ("Unexpected block token");
1458
1459         }
1460
1461         /* Skip closing brace */
1462         CfgConsume (CFGTOK_RCURLY, "`}' expected");
1463
1464     } while (CfgTok != CFGTOK_EOF);
1465 }
1466
1467
1468
1469 void CfgRead (void)
1470 /* Read the configuration */
1471 {
1472     /* Create the descriptors for the binary formats */
1473     BinFmtDesc = NewBinDesc ();
1474     O65FmtDesc = NewO65Desc ();
1475
1476     /* If we have a config name given, open the file, otherwise we will read
1477      * from a buffer.
1478      */
1479     CfgOpenInput ();
1480
1481     /* Parse the file */
1482     ParseConfig ();
1483
1484     /* Close the input file */
1485     CfgCloseInput ();
1486 }
1487
1488
1489
1490 /*****************************************************************************/
1491 /*                          Config file processing                           */
1492 /*****************************************************************************/
1493
1494
1495
1496 static void ProcessMemory (void)
1497 /* Process the MEMORY section */
1498 {
1499     /* Walk over the list with the memory areas */
1500     unsigned I;
1501     for (I = 0; I < CollCount (&MemoryAreas); ++I) {
1502
1503         /* Get the next memory area */
1504         MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
1505
1506         /* Remember if this is a relocatable memory area */
1507         M->Relocatable = RelocatableBinFmt (M->F->Format);
1508
1509         /* Resolve the expressions */
1510         if (!IsConstExpr (M->StartExpr)) {
1511             CfgError (&M->Pos,
1512                       "Start address of memory area `%s' is not constant",
1513                       GetString (M->Name));
1514         }
1515         M->Start = GetExprVal (M->StartExpr);
1516
1517         if (!IsConstExpr (M->SizeExpr)) {
1518             CfgError (&M->Pos,
1519                       "Size of memory area `%s' is not constant",
1520                       GetString (M->Name));
1521         }
1522         M->Size = GetExprVal (M->SizeExpr);
1523
1524         /* Mark the memory area as placed */
1525         M->Flags |= MF_PLACED;
1526     }
1527 }
1528
1529
1530
1531 static void ProcessSegments (void)
1532 /* Process the SEGMENTS section */
1533 {
1534     unsigned I;
1535
1536     /* Walk over the list of segment descriptors */
1537     I = 0;
1538     while (I < CollCount (&SegDescList)) {
1539
1540         /* Get the next segment descriptor */
1541         SegDesc* S = CollAtUnchecked (&SegDescList, I);
1542
1543         /* Search for the actual segment in the input files. The function may
1544          * return NULL (no such segment), this is checked later.
1545          */
1546         S->Seg = SegFind (S->Name);
1547
1548         /* If the segment is marked as BSS style, and if the segment exists
1549          * in any of the object file, check that there's no initialized data
1550          * in the segment.
1551          */
1552         if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
1553             Warning ("Segment `%s' with type `bss' contains initialized data",
1554                      GetString (S->Name));
1555         }
1556
1557         /* If this segment does exist in any of the object files, insert the
1558          * segment into the load/run memory areas. Otherwise print a warning
1559          * and discard it, because the segment pointer in the descriptor is
1560          * invalid.
1561          */
1562         if (S->Seg != 0) {
1563
1564             /* Insert the segment into the memory area list */
1565             MemoryInsert (S->Run, S);
1566             if (S->Load != S->Run) {
1567                 /* We have separate RUN and LOAD areas */
1568                 MemoryInsert (S->Load, S);
1569             }
1570
1571             /* Process the next segment descriptor in the next run */
1572             ++I;
1573
1574         } else {
1575
1576             /* Print a warning if the segment is not optional */
1577             if ((S->Flags & SF_OPTIONAL) == 0) {
1578                 CfgWarning (&CfgErrorPos,
1579                             "Segment `%s' does not exist",
1580                             GetString (S->Name));
1581             }
1582
1583             /* Discard the descriptor and remove it from the collection */
1584             FreeSegDesc (S);
1585             CollDelete (&SegDescList, I);
1586         }
1587     }
1588 }
1589
1590
1591
1592 static void ProcessO65 (void)
1593 /* Process the o65 format section */
1594 {
1595     unsigned I;
1596
1597     /* Walk over the imports, check and add them to the o65 data */
1598     for (I = 0; I < CollCount (&O65Imports); ++I) {
1599
1600         /* Get the import */
1601         Symbol* Sym = CollAtUnchecked (&O65Imports, I);
1602
1603         /* Check if we have this symbol defined already. The entry
1604          * routine will check this also, but we get a more verbose
1605          * error message when checking it here.
1606          */
1607         if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1608             CfgError (&Sym->Pos,
1609                       "Duplicate imported o65 symbol: `%s'",
1610                       GetString (Sym->Name));
1611         }
1612
1613         /* Insert the symbol into the table */
1614         O65SetImport (O65FmtDesc, Sym->Name);
1615     }
1616
1617     /* Walk over the exports, check and add them to the o65 data */
1618     for (I = 0; I < CollCount (&O65Exports); ++I) {
1619
1620         /* Get the export */
1621         Symbol* Sym = CollAtUnchecked (&O65Exports, I);
1622
1623         /* Check if the export symbol is also defined as an import. */
1624         if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1625             CfgError (&Sym->Pos,
1626                       "Exported o65 symbol `%s' cannot also be an o65 import",
1627                       GetString (Sym->Name));
1628         }
1629
1630         /* Check if we have this symbol defined already. The entry
1631          * routine will check this also, but we get a more verbose
1632          * error message when checking it here.
1633          */
1634         if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
1635             CfgError (&Sym->Pos,
1636                       "Duplicate exported o65 symbol: `%s'",
1637                       GetString (Sym->Name));
1638         }
1639
1640         /* Insert the symbol into the table */
1641         O65SetExport (O65FmtDesc, Sym->Name);
1642     }
1643 }
1644
1645
1646
1647 static void ProcessBin (void)
1648 /* Process the bin format section */
1649 {
1650 }
1651
1652
1653
1654 static void ProcessFormats (void)
1655 /* Process the target format section */
1656 {
1657     ProcessO65 ();
1658     ProcessBin ();
1659 }
1660
1661
1662
1663 static void ProcessSymbols (void)
1664 /* Process the SYMBOLS section */
1665 {
1666     Export* E;
1667
1668     /* Walk over all symbols */
1669     unsigned I;
1670     for (I = 0; I < CollCount (&Symbols); ++I) {
1671
1672         /* Get the next symbol */
1673         Symbol* Sym = CollAtUnchecked (&Symbols, I);
1674
1675         /* Do we define this symbol? */
1676         if ((Sym->Flags & SYM_DEF) != 0) {
1677             /* Check if the symbol is already defined somewhere else */
1678             if ((E = FindExport (Sym->Name)) != 0 && !IsUnresolvedExport (E)) {
1679                 /* If the symbol is not marked as weak, this is an error.
1680                  * Otherwise ignore the symbol from the config.
1681                  */
1682                 if ((Sym->Flags & SYM_WEAK) == 0) {
1683                     CfgError (&CfgErrorPos,
1684                               "Symbol `%s' is already defined",
1685                               GetString (Sym->Name));
1686                 }
1687             } else {
1688                 /* The symbol is undefined, generate an export */
1689                 CreateConstExport (Sym->Name, Sym->Val);
1690             }
1691
1692         } else {
1693
1694
1695         }
1696     }
1697 }
1698
1699
1700
1701 static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
1702 /* Create the defines for a RUN segment */
1703 {
1704     StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1705
1706     SB_Printf (&Buf, "__%s_RUN__", GetString (S->Name));
1707     CreateMemoryExport (GetStrBufId (&Buf), S->Run, SegAddr - S->Run->Start);
1708     SB_Printf (&Buf, "__%s_SIZE__", GetString (S->Name));
1709     CreateConstExport (GetStrBufId (&Buf), S->Seg->Size);
1710     S->Flags |= SF_RUN_DEF;
1711     SB_Done (&Buf);
1712 }
1713
1714
1715
1716 static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
1717 /* Create the defines for a LOAD segment */
1718 {
1719     StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1720
1721     SB_Printf (&Buf, "__%s_LOAD__", GetString (S->Name));
1722     CreateMemoryExport (GetStrBufId (&Buf), S->Load, SegAddr - S->Load->Start);
1723     S->Flags |= SF_LOAD_DEF;
1724     SB_Done (&Buf);
1725 }
1726
1727
1728
1729 unsigned CfgProcess (void)
1730 /* Process the config file after reading in object files and libraries. This
1731  * includes postprocessing of the config file data but also assigning segments
1732  * and defining segment/memory area related symbols. The function will return
1733  * the number of memory area overflows (so zero means anything went ok).
1734  * In case of overflows, a short mapfile can be generated later, to ease the
1735  * task of rearranging segments for the user.
1736  */
1737 {
1738     unsigned Overflows = 0;
1739     unsigned I;
1740
1741     /* Do postprocessing of the config file data */
1742     ProcessSymbols (); /* ######## */
1743     ProcessMemory ();
1744     ProcessSegments ();
1745     ProcessFormats ();
1746
1747     /* Walk through each of the memory sections. Add up the sizes and check
1748      * for an overflow of the section. Assign the start addresses of the
1749      * segments while doing this.
1750      */
1751     for (I = 0; I < CollCount (&MemoryAreas); ++I) {
1752
1753         unsigned J;
1754
1755         /* Get this entry */
1756         MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
1757
1758         /* Get the start address of this memory area */
1759         unsigned long Addr = M->Start;
1760
1761         /* Walk through the segments in this memory area */
1762         for (J = 0; J < CollCount (&M->SegList); ++J) {
1763
1764             /* Get the segment */
1765             SegDesc* S = CollAtUnchecked (&M->SegList, J);
1766
1767             /* Some actions depend on wether this is the load or run memory
1768              * area.
1769              */
1770             if (S->Run == M) {
1771
1772                 /* This is the run (and maybe load) memory area. Handle
1773                  * alignment and explict start address and offset.
1774                  */
1775                 if (S->Flags & SF_ALIGN) {
1776                     /* Align the address */
1777                     unsigned long Val = (0x01UL << S->Align) - 1;
1778                     Addr = (Addr + Val) & ~Val;
1779                 } else if (S->Flags & (SF_OFFSET | SF_START)) {
1780                     /* Give the segment a fixed starting address */
1781                     unsigned long NewAddr = S->Addr;
1782                     if (S->Flags & SF_OFFSET) {
1783                         /* An offset was given, no address, make an address */
1784                         NewAddr += M->Start;
1785                     }
1786                     if (Addr > NewAddr) {
1787                         /* Offset already too large */
1788                         if (S->Flags & SF_OFFSET) {
1789                             CfgError (&M->Pos,
1790                                       "Offset too small in `%s', segment `%s'",
1791                                       GetString (M->Name),
1792                                       GetString (S->Name));
1793                         } else {
1794                             CfgError (&M->Pos,
1795                                       "Start address too low in `%s', segment `%s'",
1796                                       GetString (M->Name),
1797                                       GetString (S->Name));
1798                         }
1799                     }
1800                     Addr = NewAddr;
1801                 }
1802
1803                 /* Set the start address of this segment, set the readonly flag
1804                  * in the segment and and remember if the segment is in a
1805                  * relocatable file or not.
1806                  */
1807                 S->Seg->PC = Addr;
1808                 S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
1809                 S->Seg->Relocatable = M->Relocatable;
1810
1811                 /* Remember that this segment is placed */
1812                 S->Seg->Placed = 1;
1813
1814             } else if (S->Load == M) {
1815
1816                 /* This is the load memory area, *and* run and load are
1817                  * different (because of the "else" above). Handle alignment.
1818                  */
1819                 if (S->Flags & SF_ALIGN_LOAD) {
1820                     /* Align the address */
1821                     unsigned long Val = (0x01UL << S->AlignLoad) - 1;
1822                     Addr = (Addr + Val) & ~Val;
1823                 }
1824
1825             }
1826
1827             /* Increment the fill level of the memory area and check for an
1828              * overflow.
1829              */
1830             M->FillLevel = Addr + S->Seg->Size - M->Start;
1831             if (M->FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) {
1832                 ++Overflows;
1833                 M->Flags |= MF_OVERFLOW;
1834                 Warning ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
1835                          GetString (M->Name), GetString (S->Name),
1836                          M->FillLevel - M->Size);
1837             }
1838
1839             /* If requested, define symbols for the start and size of the
1840              * segment.
1841              */
1842             if (S->Flags & SF_DEFINE) {
1843                 if (S->Run == M && (S->Flags & SF_RUN_DEF) == 0) {
1844                     CreateRunDefines (S, Addr);
1845                 }
1846                 if (S->Load == M && (S->Flags & SF_LOAD_DEF) == 0) {
1847                     CreateLoadDefines (S, Addr);
1848                 }
1849             }
1850
1851             /* Calculate the new address */
1852             Addr += S->Seg->Size;
1853
1854         }
1855
1856         /* If requested, define symbols for start and size of the memory area */
1857         if (M->Flags & MF_DEFINE) {
1858             StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1859             SB_Printf (&Buf, "__%s_START__", GetString (M->Name));
1860             CreateMemoryExport (GetStrBufId (&Buf), M, 0);
1861             SB_Printf (&Buf, "__%s_SIZE__", GetString (M->Name));
1862             CreateConstExport (GetStrBufId (&Buf), M->Size);
1863             SB_Printf (&Buf, "__%s_LAST__", GetString (M->Name));
1864             CreateMemoryExport (GetStrBufId (&Buf), M, M->FillLevel);
1865             SB_Done (&Buf);
1866         }
1867
1868     }
1869
1870     /* Return the number of memory area overflows */
1871     return Overflows;
1872 }
1873
1874
1875
1876 void CfgWriteTarget (void)
1877 /* Write the target file(s) */
1878 {
1879     unsigned I;
1880
1881     /* Walk through the files list */
1882     for (I = 0; I < CollCount (&FileList); ++I) {
1883
1884         /* Get this entry */
1885         File* F = CollAtUnchecked (&FileList, I);
1886
1887         /* We don't need to look at files with no memory areas */
1888         if (CollCount (&F->MemoryAreas) > 0) {
1889
1890             /* Is there an output file? */
1891             if (SB_GetLen (GetStrBuf (F->Name)) > 0) {
1892
1893                 /* Assign a proper binary format */
1894                 if (F->Format == BINFMT_DEFAULT) {
1895                     F->Format = DefaultBinFmt;
1896                 }
1897
1898                 /* Call the apropriate routine for the binary format */
1899                 switch (F->Format) {
1900
1901                     case BINFMT_BINARY:
1902                         BinWriteTarget (BinFmtDesc, F);
1903                         break;
1904
1905                     case BINFMT_O65:
1906                         O65WriteTarget (O65FmtDesc, F);
1907                         break;
1908
1909                     default:
1910                         Internal ("Invalid binary format: %u", F->Format);
1911
1912                 }
1913
1914             } else {
1915
1916                 /* No output file. Walk through the list and mark all segments
1917                  * loading into these memory areas in this file as dumped.
1918                  */
1919                 unsigned J;
1920                 for (J = 0; J < CollCount (&F->MemoryAreas); ++J) {
1921
1922                     unsigned K;
1923
1924                     /* Get this entry */
1925                     MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, J);
1926
1927                     /* Debugging */
1928                     Print (stdout, 2, "Skipping `%s'...\n", GetString (M->Name));
1929
1930                     /* Walk throught the segments */
1931                     for (K = 0; K < CollCount (&M->SegList); ++K) {
1932                         SegDesc* S = CollAtUnchecked (&M->SegList, K);
1933                         if (S->Load == M) {
1934                             /* Load area - mark the segment as dumped */
1935                             S->Seg->Dumped = 1;
1936                         }
1937                     }
1938                 }
1939             }
1940         }
1941     }
1942 }
1943
1944
1945