]> git.sur5r.net Git - cc65/blob - src/ld65/config.c
Allow to define symbols in the linker config
[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-2000 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
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
47 /* ld65 */
48 #include "bin.h"
49 #include "binfmt.h"
50 #include "condes.h"
51 #include "error.h"
52 #include "exports.h"
53 #include "global.h"
54 #include "o65.h"
55 #include "scanner.h"
56 #include "config.h"
57
58
59
60 /*****************************************************************************/
61 /*                                   Data                                    */
62 /*****************************************************************************/
63
64
65
66 /* File list */
67 static File*            FileList;       /* Single linked list */
68 static unsigned         FileCount;      /* Number of entries in the list */
69
70
71
72 /* Memory list */
73 static Memory*          MemoryList;     /* Single linked list */
74 static Memory*          MemoryLast;     /* Last element in list */
75 static unsigned         MemoryCount;    /* Number of entries in the list */
76
77 /* Memory attributes */
78 #define MA_START        0x0001
79 #define MA_SIZE         0x0002
80 #define MA_TYPE         0x0004
81 #define MA_FILE         0x0008
82 #define MA_DEFINE       0x0010
83 #define MA_FILL         0x0020
84 #define MA_FILLVAL      0x0040
85
86
87
88 /* Segment list */
89 SegDesc*                SegDescList;    /* Single linked list */
90 unsigned                SegDescCount;   /* Number of entries in list */
91
92 /* Segment attributes */
93 #define SA_TYPE         0x0001
94 #define SA_LOAD         0x0002
95 #define SA_RUN          0x0004
96 #define SA_ALIGN        0x0008
97 #define SA_DEFINE       0x0010
98 #define SA_OFFSET       0x0020
99 #define SA_START        0x0040
100
101
102
103 /* Descriptor holding information about the binary formats */
104 static BinDesc* BinFmtDesc      = 0;
105 static O65Desc* O65FmtDesc      = 0;
106
107 /* Attributes for the o65 format */
108 static unsigned O65Attr = 0;
109 #define OA_OS           0x0001
110 #define OA_TYPE         0x0002
111 #define OA_VERSION      0x0004
112 #define OA_OSVERSION    0x0008
113 #define OA_TEXT         0x0010
114 #define OA_DATA         0x0020
115 #define OA_BSS          0x0040
116 #define OA_ZP           0x0080
117
118
119
120 /*****************************************************************************/
121 /*                                 Forwards                                  */
122 /*****************************************************************************/
123
124
125
126 static File* NewFile (const char* Name);
127 /* Create a new file descriptor and insert it into the list */
128
129
130
131 /*****************************************************************************/
132 /*                              List management                              */
133 /*****************************************************************************/
134
135
136
137 static File* FindFile (const char* Name)
138 /* Find a file with a given name. */
139 {
140     File* F = FileList;
141     while (F) {
142         if (strcmp (F->Name, Name) == 0) {
143             return F;
144         }
145         F = F->Next;
146     }
147     return 0;
148 }
149
150
151
152 static File* GetFile (const char* Name)
153 /* Get a file entry with the given name. Create a new one if needed. */
154 {
155     File* F = FindFile (Name);
156     if (F == 0) {
157         /* Create a new one */
158         F = NewFile (Name);
159     }
160     return F;
161 }
162
163
164
165 static void FileInsert (File* F, Memory* M)
166 /* Insert the memory area into the files list */
167 {
168     M->F = F;
169     if (F->MemList == 0) {
170         /* First entry */
171         F->MemList = M;
172     } else {
173         F->MemLast->FNext = M;
174     }
175     F->MemLast = M;
176 }
177
178
179
180 static Memory* CfgFindMemory (const char* Name)
181 /* Find the memory are with the given name. Return NULL if not found */
182 {
183     Memory* M = MemoryList;
184     while (M) {
185         if (strcmp (M->Name, Name) == 0) {
186             return M;
187         }
188         M = M->Next;
189     }
190     return 0;
191 }
192
193
194
195 static Memory* CfgGetMemory (const char* Name)
196 /* Find the memory are with the given name. Print an error on an invalid name */
197 {
198     Memory* M = CfgFindMemory (Name);
199     if (M == 0) {
200         CfgError ("Invalid memory area `%s'", Name);
201     }
202     return M;
203 }
204
205
206
207 static SegDesc* CfgFindSegDesc (const char* Name)
208 /* Find the segment descriptor with the given name, return NULL if not found. */
209 {
210     SegDesc* S = SegDescList;
211     while (S) {
212         if (strcmp (S->Name, Name) == 0) {
213             /* Found */
214             return S;
215         }
216         S = S->Next;
217     }
218
219     /* Not found */
220     return 0;
221 }
222
223
224
225 static void SegDescInsert (SegDesc* S)
226 /* Insert a segment descriptor into the list of segment descriptors */
227 {
228     /* Insert the struct into the list */
229     S->Next = SegDescList;
230     SegDescList = S;
231     ++SegDescCount;
232 }
233
234
235
236 static void MemoryInsert (Memory* M, SegDesc* S)
237 /* Insert the segment descriptor into the memory area list */
238 {
239     /* Create a new node for the entry */
240     MemListNode* N = xmalloc (sizeof (MemListNode));
241     N->Seg  = S;
242     N->Next = 0;
243
244     if (M->SegLast == 0) {
245         /* First entry */
246         M->SegList = N;
247     } else {
248         M->SegLast->Next = N;
249     }
250     M->SegLast = N;
251 }
252
253
254
255 /*****************************************************************************/
256 /*                         Constructors/Destructors                          */
257 /*****************************************************************************/
258
259
260
261 static File* NewFile (const char* Name)
262 /* Create a new file descriptor and insert it into the list */
263 {
264     /* Get the length of the name */
265     unsigned Len = strlen (Name);
266
267     /* Allocate memory */
268     File* F = xmalloc (sizeof (File) + Len);
269
270     /* Initialize the fields */
271     F->Flags   = 0;
272     F->Format  = BINFMT_DEFAULT;
273     F->MemList = 0;
274     F->MemLast = 0;
275     memcpy (F->Name, Name, Len);
276     F->Name [Len] = '\0';
277
278     /* Insert the struct into the list */
279     F->Next  = FileList;
280     FileList = F;
281     ++FileCount;
282
283     /* ...and return it */
284     return F;
285 }
286
287
288
289 static Memory* NewMemory (const char* Name)
290 /* Create a new memory section and insert it into the list */
291 {
292     /* Get the length of the name */
293     unsigned Len = strlen (Name);
294
295     /* Check for duplicate names */
296     Memory* M = CfgFindMemory (Name);
297     if (M) {
298         CfgError ("Memory area `%s' defined twice", Name);
299     }
300
301     /* Allocate memory */
302     M = xmalloc (sizeof (Memory) + Len);
303
304     /* Initialize the fields */
305     M->Next      = 0;
306     M->FNext     = 0;
307     M->Attr      = 0;
308     M->Flags     = 0;
309     M->Start     = 0;
310     M->Size      = 0;
311     M->FillLevel = 0;
312     M->FillVal   = 0;
313     M->SegList   = 0;
314     M->SegLast   = 0;
315     M->F         = 0;
316     memcpy (M->Name, Name, Len);
317     M->Name [Len] = '\0';
318
319     /* Insert the struct into the list */
320     if (MemoryLast == 0) {
321         /* First element */
322         MemoryList = M;
323     } else {
324         MemoryLast->Next = M;
325     }
326     MemoryLast = M;
327     ++MemoryCount;
328
329     /* ...and return it */
330     return M;
331 }
332
333
334
335 static SegDesc* NewSegDesc (const char* Name)
336 /* Create a segment descriptor */
337 {
338     Segment* Seg;
339
340     /* Get the length of the name */
341     unsigned Len = strlen (Name);
342
343     /* Check for duplicate names */
344     SegDesc* S = CfgFindSegDesc (Name);
345     if (S) {
346         CfgError ("Segment `%s' defined twice", Name);
347     }
348
349     /* Verify that the given segment does really exist */
350     Seg = SegFind (Name);
351     if (Seg == 0) {
352         CfgWarning ("Segment `%s' does not exist", Name);
353     }
354
355     /* Allocate memory */
356     S = xmalloc (sizeof (SegDesc) + Len);
357
358     /* Initialize the fields */
359     S->Next    = 0;
360     S->Seg     = Seg;
361     S->Attr    = 0;
362     S->Flags   = 0;
363     S->Align   = 0;
364     memcpy (S->Name, Name, Len);
365     S->Name [Len] = '\0';
366
367     /* ...and return it */
368     return S;
369 }
370
371
372
373 static void FreeSegDesc (SegDesc* S)
374 /* Free a segment descriptor */
375 {
376     xfree (S);
377 }
378
379
380
381 /*****************************************************************************/
382 /*                                   Code                                    */
383 /*****************************************************************************/
384
385
386
387 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
388 /* Check if the item is already defined. Print an error if so. If not, set
389  * the marker that we have a definition now.
390  */
391 {
392     if (*Flags & Mask) {
393         CfgError ("%s is already defined", Name);
394     }
395     *Flags |= Mask;
396 }
397
398
399
400 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
401 /* Check that a mandatory attribute was given */
402 {
403     if ((Attr & Mask) == 0) {
404         CfgError ("%s attribute is missing", Name);
405     }
406 }
407
408
409
410 static void ParseMemory (void)
411 /* Parse a MEMORY section */
412 {
413     static const IdentTok Attributes [] = {
414         {   "START",    CFGTOK_START    },
415         {   "SIZE",     CFGTOK_SIZE     },
416         {   "TYPE",     CFGTOK_TYPE     },
417         {   "FILE",     CFGTOK_FILE     },
418         {   "DEFINE",   CFGTOK_DEFINE   },
419         {   "FILL",     CFGTOK_FILL     },
420         {   "FILLVAL",  CFGTOK_FILLVAL  },
421     };
422     static const IdentTok Types [] = {
423         {   "RO",       CFGTOK_RO       },
424         {   "RW",       CFGTOK_RW       },
425     };
426
427     while (CfgTok == CFGTOK_IDENT) {
428
429         /* Create a new entry on the heap */
430         Memory* M = NewMemory (CfgSVal);
431
432         /* Skip the name and the following colon */
433         CfgNextTok ();
434         CfgConsumeColon ();
435
436         /* Read the attributes */
437         while (CfgTok == CFGTOK_IDENT) {
438
439             /* Map the identifier to a token */
440             cfgtok_t AttrTok;
441             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
442             AttrTok = CfgTok;
443
444             /* An optional assignment follows */
445             CfgNextTok ();
446             CfgOptionalAssign ();
447
448             /* Check which attribute was given */
449             switch (AttrTok) {
450
451                 case CFGTOK_START:
452                     FlagAttr (&M->Attr, MA_START, "START");
453                     CfgAssureInt ();
454                     M->Start = CfgIVal;
455                     break;
456
457                 case CFGTOK_SIZE:
458                     FlagAttr (&M->Attr, MA_SIZE, "SIZE");
459                     CfgAssureInt ();
460                     M->Size = CfgIVal;
461                     break;
462
463                 case CFGTOK_TYPE:
464                     FlagAttr (&M->Attr, MA_TYPE, "TYPE");
465                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
466                     if (CfgTok == CFGTOK_RO) {
467                         M->Flags |= MF_RO;
468                     }
469                     break;
470
471                 case CFGTOK_FILE:
472                     FlagAttr (&M->Attr, MA_FILE, "FILE");
473                     CfgAssureStr ();
474                     /* Get the file entry and insert the memory area */
475                     FileInsert (GetFile (CfgSVal), M);
476                     break;
477
478                 case CFGTOK_DEFINE:
479                     FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
480                     /* Map the token to a boolean */
481                     CfgBoolToken ();
482                     if (CfgTok == CFGTOK_TRUE) {
483                         M->Flags |= MF_DEFINE;
484                     }
485                     break;
486
487                 case CFGTOK_FILL:
488                     FlagAttr (&M->Attr, MA_FILL, "FILL");
489                     /* Map the token to a boolean */
490                     CfgBoolToken ();
491                     if (CfgTok == CFGTOK_TRUE) {
492                         M->Flags |= MF_FILL;
493                     }
494                     break;
495
496                 case CFGTOK_FILLVAL:
497                     FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
498                     CfgAssureInt ();
499                     CfgRangeCheck (0, 0xFF);
500                     M->FillVal = (unsigned char) CfgIVal;
501                     break;
502
503                 default:
504                     FAIL ("Unexpected attribute token");
505
506             }
507
508             /* Skip the attribute value and an optional comma */
509             CfgNextTok ();
510             CfgOptionalComma ();
511         }
512
513         /* Skip the semicolon */
514         CfgConsumeSemi ();
515
516         /* Check for mandatory parameters */
517         AttrCheck (M->Attr, MA_START, "START");
518         AttrCheck (M->Attr, MA_SIZE, "SIZE");
519
520         /* If we don't have a file name for output given, use the default
521          * file name.
522          */
523         if ((M->Attr & MA_FILE) == 0) {
524             FileInsert (GetFile (OutputName), M);
525         }
526     }
527 }
528
529
530
531 static void ParseFiles (void)
532 /* Parse a FILES section */
533 {
534     static const IdentTok Attributes [] = {
535         {   "FORMAT",   CFGTOK_FORMAT   },
536     };
537     static const IdentTok Formats [] = {
538         {   "O65",      CFGTOK_O65           },
539         {   "BIN",      CFGTOK_BIN      },
540         {   "BINARY",   CFGTOK_BIN      },
541     };
542
543
544     /* Parse all files */
545     while (CfgTok != CFGTOK_RCURLY) {
546
547         File* F;
548
549         /* We expect a string value here */
550         CfgAssureStr ();
551
552         /* Search for the file, it must exist */
553         F = FindFile (CfgSVal);
554         if (F == 0) {
555             CfgError ("No such file: `%s'", CfgSVal);
556         }
557
558         /* Skip the token and the following colon */
559         CfgNextTok ();
560         CfgConsumeColon ();
561
562         /* Read the attributes */
563         while (CfgTok == CFGTOK_IDENT) {
564
565             /* Map the identifier to a token */
566             cfgtok_t AttrTok;
567             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
568             AttrTok = CfgTok;
569
570             /* An optional assignment follows */
571             CfgNextTok ();
572             CfgOptionalAssign ();
573
574             /* Check which attribute was given */
575             switch (AttrTok) {
576
577                 case CFGTOK_FORMAT:
578                     if (F->Format != BINFMT_DEFAULT) {
579                         /* We've set the format already! */
580                         Error ("Cannot set a file format twice");
581                     }
582                     /* Read the format token */
583                     CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
584                     switch (CfgTok) {
585
586                         case CFGTOK_BIN:
587                             F->Format = BINFMT_BINARY;
588                             break;
589
590                         case CFGTOK_O65:
591                             F->Format = BINFMT_O65;
592                             break;
593
594                         default:
595                             Error ("Unexpected format token");
596                     }
597                     break;
598
599                 default:
600                     FAIL ("Unexpected attribute token");
601
602             }
603
604             /* Skip the attribute value and an optional comma */
605             CfgNextTok ();
606             CfgOptionalComma ();
607         }
608
609         /* Skip the semicolon */
610         CfgConsumeSemi ();
611
612     }
613 }
614
615
616
617 static void ParseSegments (void)
618 /* Parse a SEGMENTS section */
619 {
620     static const IdentTok Attributes [] = {
621         {   "LOAD",     CFGTOK_LOAD     },
622         {   "RUN",      CFGTOK_RUN      },
623         {   "TYPE",     CFGTOK_TYPE     },
624         {   "ALIGN",    CFGTOK_ALIGN    },
625         {   "DEFINE",   CFGTOK_DEFINE   },
626         {   "OFFSET",   CFGTOK_OFFSET   },
627         {   "START",    CFGTOK_START    },
628     };
629     static const IdentTok Types [] = {
630         {   "RO",       CFGTOK_RO       },
631         {   "RW",       CFGTOK_RW       },
632         {   "BSS",      CFGTOK_BSS      },
633         {   "ZP",       CFGTOK_ZP       },
634         {   "WP",       CFGTOK_WPROT    },
635         {   "WPROT",    CFGTOK_WPROT    },
636     };
637
638     unsigned Count;
639
640     while (CfgTok == CFGTOK_IDENT) {
641
642         SegDesc* S;
643
644         /* Create a new entry on the heap */
645         S = NewSegDesc (CfgSVal);
646
647         /* Skip the name and the following colon */
648         CfgNextTok ();
649         CfgConsumeColon ();
650
651         /* Read the attributes */
652         while (CfgTok == CFGTOK_IDENT) {
653
654             /* Map the identifier to a token */
655             cfgtok_t AttrTok;
656             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
657             AttrTok = CfgTok;
658
659             /* An optional assignment follows */
660             CfgNextTok ();
661             CfgOptionalAssign ();
662
663             /* Check which attribute was given */
664             switch (AttrTok) {
665
666                 case CFGTOK_LOAD:
667                     FlagAttr (&S->Attr, SA_LOAD, "LOAD");
668                     S->Load = CfgGetMemory (CfgSVal);
669                     break;
670
671                 case CFGTOK_RUN:
672                     FlagAttr (&S->Attr, SA_RUN, "RUN");
673                     S->Run = CfgGetMemory (CfgSVal);
674                     break;
675
676                 case CFGTOK_TYPE:
677                     FlagAttr (&S->Attr, SA_TYPE, "TYPE");
678                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
679                     switch (CfgTok) {
680                         case CFGTOK_RO:    S->Flags |= SF_RO;               break;
681                         case CFGTOK_RW:    /* Default */                    break;
682                         case CFGTOK_BSS:   S->Flags |= SF_BSS;              break;
683                         case CFGTOK_ZP:    S->Flags |= (SF_BSS | SF_ZP);    break;
684                         case CFGTOK_WPROT: S->Flags |= (SF_RO | SF_WPROT);  break;
685                         default:           Internal ("Unexpected token: %d", CfgTok);
686                     }
687                     break;
688
689                 case CFGTOK_ALIGN:
690                     CfgAssureInt ();
691                     FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
692                     CfgRangeCheck (1, 0x10000);
693                     S->Align = BitFind (CfgIVal);
694                     if ((0x01UL << S->Align) != CfgIVal) {
695                         CfgError ("Alignment must be a power of 2");
696                     }
697                     S->Flags |= SF_ALIGN;
698                     break;
699
700                 case CFGTOK_DEFINE:
701                     FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
702                     /* Map the token to a boolean */
703                     CfgBoolToken ();
704                     if (CfgTok == CFGTOK_TRUE) {
705                         S->Flags |= SF_DEFINE;
706                     }
707                     break;
708
709                 case CFGTOK_OFFSET:
710                     CfgAssureInt ();
711                     FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
712                     CfgRangeCheck (1, 0x1000000);
713                     S->Addr   = CfgIVal;
714                     S->Flags |= SF_OFFSET;
715                     break;
716
717                 case CFGTOK_START:
718                     CfgAssureInt ();
719                     FlagAttr (&S->Attr, SA_START, "START");
720                     CfgRangeCheck (1, 0x1000000);
721                     S->Addr   = CfgIVal;
722                     S->Flags |= SF_START;
723                     break;
724
725                 default:
726                     FAIL ("Unexpected attribute token");
727
728             }
729
730             /* Skip the attribute value and an optional comma */
731             CfgNextTok ();
732             CfgOptionalComma ();
733         }
734
735         /* Skip the semicolon */
736         CfgConsumeSemi ();
737
738         /* Check for mandatory parameters */
739         AttrCheck (S->Attr, SA_LOAD, "LOAD");
740
741         /* Set defaults for stuff not given */
742         if ((S->Attr & SA_RUN) == 0) {
743             S->Attr |= SA_RUN;
744             S->Run = S->Load;
745         } else {
746             /* Both attributes given */
747             S->Flags |= SF_LOAD_AND_RUN;
748         }
749         if ((S->Attr & SA_ALIGN) == 0) {
750             S->Attr |= SA_ALIGN;
751             S->Align = 0;
752         }
753
754         /* If the segment is marked as BSS style, check that there's no
755          * initialized data in the segment.
756          */
757         if ((S->Flags & SF_BSS) != 0 && !IsBSSType (S->Seg)) {
758             Warning ("%s(%u): Segment with type `bss' contains initialized data",
759                      CfgGetName (), CfgErrorLine);
760         }
761
762         /* Don't allow read/write data to be put into a readonly area */
763         if ((S->Flags & SF_RO) == 0) {
764             if (S->Run->Flags & MF_RO) {
765                 CfgError ("Cannot put r/w segment `%s' in r/o memory area `%s'",
766                           S->Name, S->Run->Name);
767             }
768         }
769
770         /* Only one of ALIGN, START and OFFSET may be used */
771         Count = ((S->Flags & SF_ALIGN)  != 0) +
772                 ((S->Flags & SF_OFFSET) != 0) +
773                 ((S->Flags & SF_START)  != 0);
774         if (Count > 1) {
775             CfgError ("Only one of ALIGN, START, OFFSET may be used");
776         }
777
778         /* If this segment does exist in any of the object files, insert the
779          * descriptor into the list of segment descriptors. Otherwise discard
780          * it silently, because the segment pointer in the descriptor is
781          * invalid.
782          */
783         if (S->Seg != 0) {
784             /* Insert the descriptor into the list of all descriptors */
785             SegDescInsert (S);
786             /* Insert the segment into the memory area list */
787             MemoryInsert (S->Run, S);
788             if ((S->Flags & SF_LOAD_AND_RUN) != 0) {
789                 /* We have a separate RUN area given */
790                 MemoryInsert (S->Load, S);
791             }
792         } else {
793             /* Segment does not exist, discard the descriptor */
794             FreeSegDesc (S);
795         }
796     }
797 }
798
799
800
801 static void ParseO65 (void)
802 /* Parse the o65 format section */
803 {
804     static const IdentTok Attributes [] = {
805         {   "EXPORT",    CFGTOK_EXPORT          },
806         {   "IMPORT",    CFGTOK_IMPORT          },
807         {   "TYPE",      CFGTOK_TYPE            },
808         {   "OS",        CFGTOK_OS              },
809     };
810     static const IdentTok Types [] = {
811         {   "SMALL",     CFGTOK_SMALL           },
812         {   "LARGE",     CFGTOK_LARGE           },
813     };
814     static const IdentTok OperatingSystems [] = {
815         {   "LUNIX",     CFGTOK_LUNIX           },
816         {   "OSA65",     CFGTOK_OSA65           },
817     };
818
819     while (CfgTok == CFGTOK_IDENT) {
820
821         /* Map the identifier to a token */
822         cfgtok_t AttrTok;
823         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
824         AttrTok = CfgTok;
825
826         /* An optional assignment follows */
827         CfgNextTok ();
828         CfgOptionalAssign ();
829
830         /* Check which attribute was given */
831         switch (AttrTok) {
832
833             case CFGTOK_EXPORT:
834                 /* We expect an identifier */
835                 CfgAssureIdent ();
836                 /* Check if we have this symbol defined already. The entry
837                  * routine will check this also, but we get a more verbose
838                  * error message when checking it here.
839                  */
840                 if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
841                     CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
842                 }
843                 /* Insert the symbol into the table */
844                 O65SetExport (O65FmtDesc, CfgSVal);
845                 break;
846
847             case CFGTOK_IMPORT:
848                 /* We expect an identifier */
849                 CfgAssureIdent ();
850                 /* Check if we have this symbol defined already. The entry
851                  * routine will check this also, but we get a more verbose
852                  * error message when checking it here.
853                  */
854                 if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
855                     CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
856                 }
857                 /* Insert the symbol into the table */
858                 O65SetImport (O65FmtDesc, CfgSVal);
859                 break;
860
861             case CFGTOK_TYPE:
862                 /* Cannot have this attribute twice */
863                 FlagAttr (&O65Attr, OA_TYPE, "TYPE");
864                 /* Get the type of the executable */
865                 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
866                 switch (CfgTok) {
867
868                     case CFGTOK_SMALL:
869                         /* Default, nothing to do */
870                         break;
871
872                     case CFGTOK_LARGE:
873                         O65SetLargeModel (O65FmtDesc);
874                         break;
875
876                     default:
877                         CfgError ("Unexpected type token");
878                 }
879                 break;
880
881             case CFGTOK_OS:
882                 /* Cannot use this attribute twice */
883                 FlagAttr (&O65Attr, OA_OS, "OS");
884                 /* Get the operating system */
885                 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
886                 switch (CfgTok) {
887
888                     case CFGTOK_LUNIX:
889                         O65SetOS (O65FmtDesc, O65OS_LUNIX);
890                         break;
891
892                     case CFGTOK_OSA65:
893                         O65SetOS (O65FmtDesc, O65OS_OSA65);
894                         break;
895
896                     default:
897                         CfgError ("Unexpected OS token");
898                 }
899                 break;
900
901             default:
902                 FAIL ("Unexpected attribute token");
903
904         }
905
906         /* Skip the attribute value and an optional comma */
907         CfgNextTok ();
908         CfgOptionalComma ();
909     }
910 }
911
912
913
914 static void ParseFormats (void)
915 /* Parse a target format section */
916 {
917     static const IdentTok Formats [] = {
918         {   "O65",      CFGTOK_O65      },
919         {   "BIN",      CFGTOK_BIN      },
920         {   "BINARY",   CFGTOK_BIN      },
921     };
922
923     while (CfgTok == CFGTOK_IDENT) {
924
925         /* Map the identifier to a token */
926         cfgtok_t FormatTok;
927         CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
928         FormatTok = CfgTok;
929
930         /* Skip the name and the following colon */
931         CfgNextTok ();
932         CfgConsumeColon ();
933
934         /* Parse the format options */
935         switch (FormatTok) {
936
937             case CFGTOK_O65:
938                 ParseO65 ();
939                 break;
940
941             case CFGTOK_BIN:
942                 /* No attribibutes available */
943                 break;
944
945             default:
946                 Error ("Unexpected format token");
947         }
948
949         /* Skip the semicolon */
950         CfgConsumeSemi ();
951     }
952 }
953
954
955
956 static void ParseConDes (void)
957 /* Parse the CONDES feature */
958 {
959     static const IdentTok Attributes [] = {
960         {   "SEGMENT",          CFGTOK_SEGMENT          },
961         {   "LABEL",            CFGTOK_LABEL            },
962         {   "COUNT",            CFGTOK_COUNT            },
963         {   "TYPE",             CFGTOK_TYPE             },
964         {   "ORDER",            CFGTOK_ORDER            },
965     };
966
967     static const IdentTok Types [] = {
968         {   "CONSTRUCTOR",      CFGTOK_CONSTRUCTOR      },
969         {   "DESTRUCTOR",       CFGTOK_DESTRUCTOR       },
970     };
971
972     static const IdentTok Orders [] = {
973         {   "DECREASING",       CFGTOK_DECREASING       },
974         {   "INCREASING",       CFGTOK_INCREASING       },
975     };
976
977     /* Attribute values. */
978     char SegName[sizeof (CfgSVal)];
979     char Label[sizeof (CfgSVal)];
980     char Count[sizeof (CfgSVal)];
981     /* Initialize to avoid gcc warnings: */
982     int Type = -1;
983     ConDesOrder Order = cdIncreasing;
984
985     /* Bitmask to remember the attributes we got already */
986     enum {
987         atNone          = 0x0000,
988         atSegName       = 0x0001,
989         atLabel         = 0x0002,
990         atCount         = 0x0004,
991         atType          = 0x0008,
992         atOrder         = 0x0010
993     };
994     unsigned AttrFlags = atNone;
995
996     /* Parse the attributes */
997     while (1) {
998
999         /* Map the identifier to a token */
1000         cfgtok_t AttrTok;
1001         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1002         AttrTok = CfgTok;
1003
1004         /* An optional assignment follows */
1005         CfgNextTok ();
1006         CfgOptionalAssign ();
1007
1008         /* Check which attribute was given */
1009         switch (AttrTok) {
1010
1011             case CFGTOK_SEGMENT:
1012                 /* Don't allow this twice */
1013                 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1014                 /* We expect an identifier */
1015                 CfgAssureIdent ();
1016                 /* Remember the value for later */
1017                 strcpy (SegName, CfgSVal);
1018                 break;
1019
1020             case CFGTOK_LABEL:
1021                 /* Don't allow this twice */
1022                 FlagAttr (&AttrFlags, atLabel, "LABEL");
1023                 /* We expect an identifier */
1024                 CfgAssureIdent ();
1025                 /* Remember the value for later */
1026                 strcpy (Label, CfgSVal);
1027                 break;
1028
1029             case CFGTOK_COUNT:
1030                 /* Don't allow this twice */
1031                 FlagAttr (&AttrFlags, atCount, "COUNT");
1032                 /* We expect an identifier */
1033                 CfgAssureIdent ();
1034                 /* Remember the value for later */
1035                 strcpy (Count, CfgSVal);
1036                 break;
1037
1038             case CFGTOK_TYPE:
1039                 /* Don't allow this twice */
1040                 FlagAttr (&AttrFlags, atType, "TYPE");
1041                 /* The type may be given as id or numerical */
1042                 if (CfgTok == CFGTOK_INTCON) {
1043                     CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1044                     Type = (int) CfgIVal;
1045                 } else {
1046                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1047                     switch (CfgTok) {
1048                         case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON;    break;
1049                         case CFGTOK_DESTRUCTOR:  Type = CD_TYPE_DES;    break;
1050                         default: FAIL ("Unexpected type token");
1051                     }
1052                 }
1053                 break;
1054
1055             case CFGTOK_ORDER:
1056                 /* Don't allow this twice */
1057                 FlagAttr (&AttrFlags, atOrder, "ORDER");
1058                 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1059                 switch (CfgTok) {
1060                     case CFGTOK_DECREASING: Order = cdDecreasing;       break;
1061                     case CFGTOK_INCREASING: Order = cdIncreasing;       break;
1062                     default: FAIL ("Unexpected order token");
1063                 }
1064                 break;
1065
1066             default:
1067                 FAIL ("Unexpected attribute token");
1068
1069         }
1070
1071         /* Skip the attribute value */
1072         CfgNextTok ();
1073
1074         /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1075         if (CfgTok == CFGTOK_SEMI) {
1076             break;
1077         } else if (CfgTok == CFGTOK_COMMA) {
1078             CfgNextTok ();
1079         }
1080     }
1081
1082     /* Check if we have all mandatory attributes */
1083     AttrCheck (AttrFlags, atSegName, "SEGMENT");
1084     AttrCheck (AttrFlags, atLabel, "LABEL");
1085     AttrCheck (AttrFlags, atType, "TYPE");
1086
1087     /* Check if the condes has already attributes defined */
1088     if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1089         CfgError ("CONDES attributes for type %d are already defined", Type);
1090     }
1091
1092     /* Define the attributes */
1093     ConDesSetSegName (Type, SegName);
1094     ConDesSetLabel (Type, Label);
1095     if (AttrFlags & atCount) {
1096         ConDesSetCountSym (Type, Count);
1097     }
1098     if (AttrFlags & atOrder) {
1099         ConDesSetOrder (Type, Order);
1100     }
1101 }
1102
1103
1104
1105 static void ParseFeatures (void)
1106 /* Parse a features section */
1107 {
1108     static const IdentTok Features [] = {
1109         {   "CONDES",   CFGTOK_CONDES   },
1110     };
1111
1112     while (CfgTok == CFGTOK_IDENT) {
1113
1114         /* Map the identifier to a token */
1115         cfgtok_t FeatureTok;
1116         CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1117         FeatureTok = CfgTok;
1118
1119         /* Skip the name and the following colon */
1120         CfgNextTok ();
1121         CfgConsumeColon ();
1122
1123         /* Parse the format options */
1124         switch (FeatureTok) {
1125
1126             case CFGTOK_CONDES:
1127                 ParseConDes ();
1128                 break;
1129
1130             default:
1131                 Error ("Unexpected feature token");
1132         }
1133
1134         /* Skip the semicolon */
1135         CfgConsumeSemi ();
1136     }
1137 }
1138
1139
1140
1141 static void ParseSymbols (void)
1142 /* Parse a symbols section */
1143 {
1144     while (CfgTok == CFGTOK_IDENT) {
1145
1146         long Val;
1147
1148         /* Remember the name */
1149         char Name [sizeof (CfgSVal)];
1150         strcpy (Name, CfgSVal);
1151         CfgNextTok ();
1152
1153         /* Allow an optional assignment */
1154         CfgOptionalAssign ();
1155
1156         /* Make sure the next token is an integer, read and skip it */
1157         CfgAssureInt ();
1158         Val = CfgIVal;
1159         CfgNextTok ();
1160
1161         /* Generate an export with the given value */
1162         CreateConstExport (Name, Val);
1163
1164         /* Skip the semicolon */
1165         CfgConsumeSemi ();
1166     }
1167 }
1168
1169
1170
1171 static void ParseConfig (void)
1172 /* Parse the config file */
1173 {
1174     static const IdentTok BlockNames [] = {
1175         {   "MEMORY",   CFGTOK_MEMORY   },
1176         {   "FILES",    CFGTOK_FILES    },
1177         {   "SEGMENTS", CFGTOK_SEGMENTS },
1178         {   "FORMATS",  CFGTOK_FORMATS  },
1179         {   "FEATURES", CFGTOK_FEATURES },
1180         {   "SYMBOLS",  CFGTOK_SYMBOLS  },
1181     };
1182     cfgtok_t BlockTok;
1183
1184     do {
1185
1186         /* Read the block ident */
1187         CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1188         BlockTok = CfgTok;
1189         CfgNextTok ();
1190
1191         /* Expected a curly brace */
1192         CfgConsume (CFGTOK_LCURLY, "`{' expected");
1193
1194         /* Read the block */
1195         switch (BlockTok) {
1196
1197             case CFGTOK_MEMORY:
1198                 ParseMemory ();
1199                 break;
1200
1201             case CFGTOK_FILES:
1202                 ParseFiles ();
1203                 break;
1204
1205             case CFGTOK_SEGMENTS:
1206                 ParseSegments ();
1207                 break;
1208
1209             case CFGTOK_FORMATS:
1210                 ParseFormats ();
1211                 break;
1212
1213             case CFGTOK_FEATURES:
1214                 ParseFeatures ();
1215                 break;
1216
1217             case CFGTOK_SYMBOLS:
1218                 ParseSymbols ();
1219                 break;
1220
1221             default:
1222                 FAIL ("Unexpected block token");
1223
1224         }
1225
1226         /* Skip closing brace */
1227         CfgConsume (CFGTOK_RCURLY, "`}' expected");
1228
1229     } while (CfgTok != CFGTOK_EOF);
1230 }
1231
1232
1233
1234 void CfgRead (void)
1235 /* Read the configuration */
1236 {
1237     /* Create the descriptors for the binary formats */
1238     BinFmtDesc = NewBinDesc ();
1239     O65FmtDesc = NewO65Desc ();
1240
1241     /* If we have a config name given, open the file, otherwise we will read
1242      * from a buffer.
1243      */
1244     CfgOpenInput ();
1245
1246     /* Parse the file */
1247     ParseConfig ();
1248
1249     /* Close the input file */
1250     CfgCloseInput ();
1251 }
1252
1253
1254
1255 static void CreateRunDefines (Memory* M, SegDesc* S, unsigned long Addr)
1256 /* Create the defines for a RUN segment */
1257 {
1258     char Buf [256];
1259
1260     sprintf (Buf, "__%s_RUN__", S->Name);
1261     CreateMemExport (Buf, M, Addr - M->Start);
1262     sprintf (Buf, "__%s_SIZE__", S->Name);
1263     CreateConstExport (Buf, S->Seg->Size);
1264     S->Flags |= SF_RUN_DEF;
1265 }
1266
1267
1268
1269 static void CreateLoadDefines (Memory* M, SegDesc* S, unsigned long Addr)
1270 /* Create the defines for a LOAD segment */
1271 {
1272     char Buf [256];
1273
1274     sprintf (Buf, "__%s_LOAD__", S->Name);
1275     CreateMemExport (Buf, M, Addr - M->Start);
1276     S->Flags |= SF_LOAD_DEF;
1277 }
1278
1279
1280
1281 void CfgAssignSegments (void)
1282 /* Assign segments, define linker symbols where requested */
1283 {
1284     /* Walk through each of the memory sections. Add up the sizes and check
1285      * for an overflow of the section. Assign the start addresses of the
1286      * segments while doing this.
1287      */
1288     Memory* M = MemoryList;
1289     while (M) {
1290
1291         /* Get the start address of this memory area */
1292         unsigned long Addr = M->Start;
1293
1294         /* Walk through the segments in this memory area */
1295         MemListNode* N = M->SegList;
1296         while (N) {
1297
1298             /* Get the segment from the node */
1299             SegDesc* S = N->Seg;
1300
1301             /* Handle ALIGN and OFFSET/START */
1302             if (S->Flags & SF_ALIGN) {
1303                 /* Align the address */
1304                 unsigned long Val = (0x01UL << S->Align) - 1;
1305                 Addr = (Addr + Val) & ~Val;
1306             } else if (S->Flags & (SF_OFFSET | SF_START)) {
1307                 /* Give the segment a fixed starting address */
1308                 unsigned long NewAddr = S->Addr;
1309                 if (S->Flags & SF_OFFSET) {
1310                     /* An offset was given, no address, make an address */
1311                     NewAddr += M->Start;
1312                 }
1313                 if (Addr > NewAddr) {
1314                     /* Offset already too large */
1315                     if (S->Flags & SF_OFFSET) {
1316                         Error ("Offset too small in `%s', segment `%s'",
1317                                M->Name, S->Name);
1318                     } else {
1319                         Error ("Start address too low in `%s', segment `%s'",
1320                                M->Name, S->Name);
1321                     }
1322                 }
1323                 Addr = NewAddr;
1324             }
1325
1326             /* If this is the run area, set the start address of this segment */
1327             if (S->Run == M) {
1328                 S->Seg->PC = Addr;
1329             }
1330
1331             /* Increment the fill level of the memory area and check for an
1332              * overflow.
1333              */
1334             M->FillLevel = Addr + S->Seg->Size - M->Start;
1335             if (M->FillLevel > M->Size) {
1336                 Error ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
1337                        M->Name, S->Name, M->FillLevel - M->Size);
1338             }
1339
1340             /* If requested, define symbols for the start and size of the
1341              * segment.
1342              */
1343             if (S->Flags & SF_DEFINE) {
1344                 if ((S->Flags & SF_LOAD_AND_RUN) && S->Run == S->Load) {
1345                     /* RUN and LOAD given and in one memory area.
1346                      * Be careful: We will encounter this code twice, the
1347                      * first time when walking the RUN list, second time when
1348                      * walking the LOAD list. Be sure to define only the
1349                      * relevant symbols on each walk.
1350                      */
1351                     if (S->Load == M) {
1352                         if ((S->Flags & SF_LOAD_DEF) == 0) {
1353                             CreateLoadDefines (M, S, Addr);
1354                         } else {
1355                             CHECK ((S->Flags & SF_RUN_DEF) == 0);
1356                             CreateRunDefines (M, S, Addr);
1357                         }
1358                     }
1359                 } else {
1360                     /* RUN and LOAD in different memory areas, or RUN not
1361                      * given, so RUN defaults to LOAD. In the latter case, we
1362                      * have only one copy of the segment in the area.
1363                      */
1364                     if (S->Run == M) {
1365                         CreateRunDefines (M, S, Addr);
1366                     }
1367                     if (S->Load == M) {
1368                         CreateLoadDefines (M, S, Addr);
1369                     }
1370                 }
1371             }
1372
1373             /* Calculate the new address */
1374             Addr += S->Seg->Size;
1375
1376             /* Next segment */
1377             N = N->Next;
1378         }
1379
1380         /* If requested, define symbols for start and size of the memory area */
1381         if (M->Flags & MF_DEFINE) {
1382             char Buf [256];
1383             sprintf (Buf, "__%s_START__", M->Name);
1384             CreateMemExport (Buf, M, 0);
1385             sprintf (Buf, "__%s_SIZE__", M->Name);
1386             CreateConstExport (Buf, M->Size);
1387             sprintf (Buf, "__%s_LAST__", M->Name);
1388             CreateConstExport (Buf, M->FillLevel);
1389         }
1390
1391         /* Next memory area */
1392         M = M->Next;
1393     }
1394 }
1395
1396
1397
1398 void CfgWriteTarget (void)
1399 /* Write the target file(s) */
1400 {
1401     Memory* M;
1402
1403     /* Walk through the files list */
1404     File* F = FileList;
1405     while (F) {
1406         /* We don't need to look at files with no memory areas */
1407         if (F->MemList) {
1408
1409             /* Is there an output file? */
1410             if (strlen (F->Name) > 0) {
1411
1412                 /* Assign a proper binary format */
1413                 if (F->Format == BINFMT_DEFAULT) {
1414                     F->Format = DefaultBinFmt;
1415                 }
1416
1417                 /* Call the apropriate routine for the binary format */
1418                 switch (F->Format) {
1419
1420                     case BINFMT_BINARY:
1421                         BinWriteTarget (BinFmtDesc, F);
1422                         break;
1423
1424                     case BINFMT_O65:
1425                         O65WriteTarget (O65FmtDesc, F);
1426                         break;
1427
1428                     default:
1429                         Internal ("Invalid binary format: %u", F->Format);
1430
1431                 }
1432
1433             } else {
1434
1435                 /* No output file. Walk through the list and mark all segments
1436                  * loading into these memory areas in this file as dumped.
1437                  */
1438                 M = F->MemList;
1439                 while (M) {
1440
1441                     MemListNode* N;
1442
1443                     /* Debugging */
1444                     Print (stdout, 2, "Skipping `%s'...\n", M->Name);
1445
1446                     /* Walk throught the segments */
1447                     N = M->SegList;
1448                     while (N) {
1449                         if (N->Seg->Load == M) {
1450                             /* Load area - mark the segment as dumped */
1451                             N->Seg->Seg->Dumped = 1;
1452                         }
1453
1454                         /* Next segment node */
1455                         N = N->Next;
1456                     }
1457                     /* Next memory area */
1458                     M = M->FNext;
1459                 }
1460             }
1461         }
1462
1463         /* Next file */
1464         F = F->Next;
1465     }
1466 }
1467
1468
1469