]> git.sur5r.net Git - cc65/blob - src/ld65/config.c
Added o65 symbol export capability
[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 the export symbol is also defined as an import. */
837                 if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
838                     CfgError ("Exported symbol `%s' cannot be an import", CfgSVal);
839                 }
840                 /* Check if we have this symbol defined already. The entry
841                  * routine will check this also, but we get a more verbose
842                  * error message when checking it here.
843                  */
844                 if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
845                     CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
846                 }
847                 /* Insert the symbol into the table */
848                 O65SetExport (O65FmtDesc, CfgSVal);
849                 break;
850
851             case CFGTOK_IMPORT:
852                 /* We expect an identifier */
853                 CfgAssureIdent ();
854                 /* Check if the imported symbol is also defined as an export. */
855                 if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
856                     CfgError ("Imported symbol `%s' cannot be an export", CfgSVal);
857                 }
858                 /* Check if we have this symbol defined already. The entry
859                  * routine will check this also, but we get a more verbose
860                  * error message when checking it here.
861                  */
862                 if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
863                     CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
864                 }
865                 /* Insert the symbol into the table */
866                 O65SetImport (O65FmtDesc, CfgSVal);
867                 break;
868
869             case CFGTOK_TYPE:
870                 /* Cannot have this attribute twice */
871                 FlagAttr (&O65Attr, OA_TYPE, "TYPE");
872                 /* Get the type of the executable */
873                 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
874                 switch (CfgTok) {
875
876                     case CFGTOK_SMALL:
877                         O65SetSmallModel (O65FmtDesc);
878                         break;
879
880                     case CFGTOK_LARGE:
881                         O65SetLargeModel (O65FmtDesc);
882                         break;
883
884                     default:
885                         CfgError ("Unexpected type token");
886                 }
887                 break;
888
889             case CFGTOK_OS:
890                 /* Cannot use this attribute twice */
891                 FlagAttr (&O65Attr, OA_OS, "OS");
892                 /* Get the operating system */
893                 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
894                 switch (CfgTok) {
895
896                     case CFGTOK_LUNIX:
897                         O65SetOS (O65FmtDesc, O65OS_LUNIX);
898                         break;
899
900                     case CFGTOK_OSA65:
901                         O65SetOS (O65FmtDesc, O65OS_OSA65);
902                         break;
903
904                     default:
905                         CfgError ("Unexpected OS token");
906                 }
907                 break;
908
909             default:
910                 FAIL ("Unexpected attribute token");
911
912         }
913
914         /* Skip the attribute value and an optional comma */
915         CfgNextTok ();
916         CfgOptionalComma ();
917     }
918 }
919
920
921
922 static void ParseFormats (void)
923 /* Parse a target format section */
924 {
925     static const IdentTok Formats [] = {
926         {   "O65",      CFGTOK_O65      },
927         {   "BIN",      CFGTOK_BIN      },
928         {   "BINARY",   CFGTOK_BIN      },
929     };
930
931     while (CfgTok == CFGTOK_IDENT) {
932
933         /* Map the identifier to a token */
934         cfgtok_t FormatTok;
935         CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
936         FormatTok = CfgTok;
937
938         /* Skip the name and the following colon */
939         CfgNextTok ();
940         CfgConsumeColon ();
941
942         /* Parse the format options */
943         switch (FormatTok) {
944
945             case CFGTOK_O65:
946                 ParseO65 ();
947                 break;
948
949             case CFGTOK_BIN:
950                 /* No attribibutes available */
951                 break;
952
953             default:
954                 Error ("Unexpected format token");
955         }
956
957         /* Skip the semicolon */
958         CfgConsumeSemi ();
959     }
960 }
961
962
963
964 static void ParseConDes (void)
965 /* Parse the CONDES feature */
966 {
967     static const IdentTok Attributes [] = {
968         {   "SEGMENT",          CFGTOK_SEGMENT          },
969         {   "LABEL",            CFGTOK_LABEL            },
970         {   "COUNT",            CFGTOK_COUNT            },
971         {   "TYPE",             CFGTOK_TYPE             },
972         {   "ORDER",            CFGTOK_ORDER            },
973     };
974
975     static const IdentTok Types [] = {
976         {   "CONSTRUCTOR",      CFGTOK_CONSTRUCTOR      },
977         {   "DESTRUCTOR",       CFGTOK_DESTRUCTOR       },
978     };
979
980     static const IdentTok Orders [] = {
981         {   "DECREASING",       CFGTOK_DECREASING       },
982         {   "INCREASING",       CFGTOK_INCREASING       },
983     };
984
985     /* Attribute values. */
986     char SegName[sizeof (CfgSVal)];
987     char Label[sizeof (CfgSVal)];
988     char Count[sizeof (CfgSVal)];
989     /* Initialize to avoid gcc warnings: */
990     int Type = -1;
991     ConDesOrder Order = cdIncreasing;
992
993     /* Bitmask to remember the attributes we got already */
994     enum {
995         atNone          = 0x0000,
996         atSegName       = 0x0001,
997         atLabel         = 0x0002,
998         atCount         = 0x0004,
999         atType          = 0x0008,
1000         atOrder         = 0x0010
1001     };
1002     unsigned AttrFlags = atNone;
1003
1004     /* Parse the attributes */
1005     while (1) {
1006
1007         /* Map the identifier to a token */
1008         cfgtok_t AttrTok;
1009         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1010         AttrTok = CfgTok;
1011
1012         /* An optional assignment follows */
1013         CfgNextTok ();
1014         CfgOptionalAssign ();
1015
1016         /* Check which attribute was given */
1017         switch (AttrTok) {
1018
1019             case CFGTOK_SEGMENT:
1020                 /* Don't allow this twice */
1021                 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1022                 /* We expect an identifier */
1023                 CfgAssureIdent ();
1024                 /* Remember the value for later */
1025                 strcpy (SegName, CfgSVal);
1026                 break;
1027
1028             case CFGTOK_LABEL:
1029                 /* Don't allow this twice */
1030                 FlagAttr (&AttrFlags, atLabel, "LABEL");
1031                 /* We expect an identifier */
1032                 CfgAssureIdent ();
1033                 /* Remember the value for later */
1034                 strcpy (Label, CfgSVal);
1035                 break;
1036
1037             case CFGTOK_COUNT:
1038                 /* Don't allow this twice */
1039                 FlagAttr (&AttrFlags, atCount, "COUNT");
1040                 /* We expect an identifier */
1041                 CfgAssureIdent ();
1042                 /* Remember the value for later */
1043                 strcpy (Count, CfgSVal);
1044                 break;
1045
1046             case CFGTOK_TYPE:
1047                 /* Don't allow this twice */
1048                 FlagAttr (&AttrFlags, atType, "TYPE");
1049                 /* The type may be given as id or numerical */
1050                 if (CfgTok == CFGTOK_INTCON) {
1051                     CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1052                     Type = (int) CfgIVal;
1053                 } else {
1054                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1055                     switch (CfgTok) {
1056                         case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON;    break;
1057                         case CFGTOK_DESTRUCTOR:  Type = CD_TYPE_DES;    break;
1058                         default: FAIL ("Unexpected type token");
1059                     }
1060                 }
1061                 break;
1062
1063             case CFGTOK_ORDER:
1064                 /* Don't allow this twice */
1065                 FlagAttr (&AttrFlags, atOrder, "ORDER");
1066                 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1067                 switch (CfgTok) {
1068                     case CFGTOK_DECREASING: Order = cdDecreasing;       break;
1069                     case CFGTOK_INCREASING: Order = cdIncreasing;       break;
1070                     default: FAIL ("Unexpected order token");
1071                 }
1072                 break;
1073
1074             default:
1075                 FAIL ("Unexpected attribute token");
1076
1077         }
1078
1079         /* Skip the attribute value */
1080         CfgNextTok ();
1081
1082         /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1083         if (CfgTok == CFGTOK_SEMI) {
1084             break;
1085         } else if (CfgTok == CFGTOK_COMMA) {
1086             CfgNextTok ();
1087         }
1088     }
1089
1090     /* Check if we have all mandatory attributes */
1091     AttrCheck (AttrFlags, atSegName, "SEGMENT");
1092     AttrCheck (AttrFlags, atLabel, "LABEL");
1093     AttrCheck (AttrFlags, atType, "TYPE");
1094
1095     /* Check if the condes has already attributes defined */
1096     if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1097         CfgError ("CONDES attributes for type %d are already defined", Type);
1098     }
1099
1100     /* Define the attributes */
1101     ConDesSetSegName (Type, SegName);
1102     ConDesSetLabel (Type, Label);
1103     if (AttrFlags & atCount) {
1104         ConDesSetCountSym (Type, Count);
1105     }
1106     if (AttrFlags & atOrder) {
1107         ConDesSetOrder (Type, Order);
1108     }
1109 }
1110
1111
1112
1113 static void ParseFeatures (void)
1114 /* Parse a features section */
1115 {
1116     static const IdentTok Features [] = {
1117         {   "CONDES",   CFGTOK_CONDES   },
1118     };
1119
1120     while (CfgTok == CFGTOK_IDENT) {
1121
1122         /* Map the identifier to a token */
1123         cfgtok_t FeatureTok;
1124         CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1125         FeatureTok = CfgTok;
1126
1127         /* Skip the name and the following colon */
1128         CfgNextTok ();
1129         CfgConsumeColon ();
1130
1131         /* Parse the format options */
1132         switch (FeatureTok) {
1133
1134             case CFGTOK_CONDES:
1135                 ParseConDes ();
1136                 break;
1137
1138             default:
1139                 Error ("Unexpected feature token");
1140         }
1141
1142         /* Skip the semicolon */
1143         CfgConsumeSemi ();
1144     }
1145 }
1146
1147
1148
1149 static void ParseSymbols (void)
1150 /* Parse a symbols section */
1151 {
1152     while (CfgTok == CFGTOK_IDENT) {
1153
1154         long Val;
1155
1156         /* Remember the name */
1157         char Name [sizeof (CfgSVal)];
1158         strcpy (Name, CfgSVal);
1159         CfgNextTok ();
1160
1161         /* Allow an optional assignment */
1162         CfgOptionalAssign ();
1163
1164         /* Make sure the next token is an integer, read and skip it */
1165         CfgAssureInt ();
1166         Val = CfgIVal;
1167         CfgNextTok ();
1168
1169         /* Generate an export with the given value */
1170         CreateConstExport (Name, Val);
1171
1172         /* Skip the semicolon */
1173         CfgConsumeSemi ();
1174     }
1175 }
1176
1177
1178
1179 static void ParseConfig (void)
1180 /* Parse the config file */
1181 {
1182     static const IdentTok BlockNames [] = {
1183         {   "MEMORY",   CFGTOK_MEMORY   },
1184         {   "FILES",    CFGTOK_FILES    },
1185         {   "SEGMENTS", CFGTOK_SEGMENTS },
1186         {   "FORMATS",  CFGTOK_FORMATS  },
1187         {   "FEATURES", CFGTOK_FEATURES },
1188         {   "SYMBOLS",  CFGTOK_SYMBOLS  },
1189     };
1190     cfgtok_t BlockTok;
1191
1192     do {
1193
1194         /* Read the block ident */
1195         CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1196         BlockTok = CfgTok;
1197         CfgNextTok ();
1198
1199         /* Expected a curly brace */
1200         CfgConsume (CFGTOK_LCURLY, "`{' expected");
1201
1202         /* Read the block */
1203         switch (BlockTok) {
1204
1205             case CFGTOK_MEMORY:
1206                 ParseMemory ();
1207                 break;
1208
1209             case CFGTOK_FILES:
1210                 ParseFiles ();
1211                 break;
1212
1213             case CFGTOK_SEGMENTS:
1214                 ParseSegments ();
1215                 break;
1216
1217             case CFGTOK_FORMATS:
1218                 ParseFormats ();
1219                 break;
1220
1221             case CFGTOK_FEATURES:
1222                 ParseFeatures ();
1223                 break;
1224
1225             case CFGTOK_SYMBOLS:
1226                 ParseSymbols ();
1227                 break;
1228
1229             default:
1230                 FAIL ("Unexpected block token");
1231
1232         }
1233
1234         /* Skip closing brace */
1235         CfgConsume (CFGTOK_RCURLY, "`}' expected");
1236
1237     } while (CfgTok != CFGTOK_EOF);
1238 }
1239
1240
1241
1242 void CfgRead (void)
1243 /* Read the configuration */
1244 {
1245     /* Create the descriptors for the binary formats */
1246     BinFmtDesc = NewBinDesc ();
1247     O65FmtDesc = NewO65Desc ();
1248
1249     /* If we have a config name given, open the file, otherwise we will read
1250      * from a buffer.
1251      */
1252     CfgOpenInput ();
1253
1254     /* Parse the file */
1255     ParseConfig ();
1256
1257     /* Close the input file */
1258     CfgCloseInput ();
1259 }
1260
1261
1262
1263 static void CreateRunDefines (Memory* M, SegDesc* S, unsigned long Addr)
1264 /* Create the defines for a RUN segment */
1265 {
1266     char Buf [256];
1267
1268     sprintf (Buf, "__%s_RUN__", S->Name);
1269     CreateMemExport (Buf, M, Addr - M->Start);
1270     sprintf (Buf, "__%s_SIZE__", S->Name);
1271     CreateConstExport (Buf, S->Seg->Size);
1272     S->Flags |= SF_RUN_DEF;
1273 }
1274
1275
1276
1277 static void CreateLoadDefines (Memory* M, SegDesc* S, unsigned long Addr)
1278 /* Create the defines for a LOAD segment */
1279 {
1280     char Buf [256];
1281
1282     sprintf (Buf, "__%s_LOAD__", S->Name);
1283     CreateMemExport (Buf, M, Addr - M->Start);
1284     S->Flags |= SF_LOAD_DEF;
1285 }
1286
1287
1288
1289 void CfgAssignSegments (void)
1290 /* Assign segments, define linker symbols where requested */
1291 {
1292     /* Walk through each of the memory sections. Add up the sizes and check
1293      * for an overflow of the section. Assign the start addresses of the
1294      * segments while doing this.
1295      */
1296     Memory* M = MemoryList;
1297     while (M) {
1298
1299         /* Get the start address of this memory area */
1300         unsigned long Addr = M->Start;
1301
1302         /* Walk through the segments in this memory area */
1303         MemListNode* N = M->SegList;
1304         while (N) {
1305
1306             /* Get the segment from the node */
1307             SegDesc* S = N->Seg;
1308
1309             /* Handle ALIGN and OFFSET/START */
1310             if (S->Flags & SF_ALIGN) {
1311                 /* Align the address */
1312                 unsigned long Val = (0x01UL << S->Align) - 1;
1313                 Addr = (Addr + Val) & ~Val;
1314             } else if (S->Flags & (SF_OFFSET | SF_START)) {
1315                 /* Give the segment a fixed starting address */
1316                 unsigned long NewAddr = S->Addr;
1317                 if (S->Flags & SF_OFFSET) {
1318                     /* An offset was given, no address, make an address */
1319                     NewAddr += M->Start;
1320                 }
1321                 if (Addr > NewAddr) {
1322                     /* Offset already too large */
1323                     if (S->Flags & SF_OFFSET) {
1324                         Error ("Offset too small in `%s', segment `%s'",
1325                                M->Name, S->Name);
1326                     } else {
1327                         Error ("Start address too low in `%s', segment `%s'",
1328                                M->Name, S->Name);
1329                     }
1330                 }
1331                 Addr = NewAddr;
1332             }
1333
1334             /* If this is the run area, set the start address of this segment */
1335             if (S->Run == M) {
1336                 S->Seg->PC = Addr;
1337             }
1338
1339             /* Increment the fill level of the memory area and check for an
1340              * overflow.
1341              */
1342             M->FillLevel = Addr + S->Seg->Size - M->Start;
1343             if (M->FillLevel > M->Size) {
1344                 Error ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
1345                        M->Name, S->Name, M->FillLevel - M->Size);
1346             }
1347
1348             /* If requested, define symbols for the start and size of the
1349              * segment.
1350              */
1351             if (S->Flags & SF_DEFINE) {
1352                 if ((S->Flags & SF_LOAD_AND_RUN) && S->Run == S->Load) {
1353                     /* RUN and LOAD given and in one memory area.
1354                      * Be careful: We will encounter this code twice, the
1355                      * first time when walking the RUN list, second time when
1356                      * walking the LOAD list. Be sure to define only the
1357                      * relevant symbols on each walk.
1358                      */
1359                     if (S->Load == M) {
1360                         if ((S->Flags & SF_LOAD_DEF) == 0) {
1361                             CreateLoadDefines (M, S, Addr);
1362                         } else {
1363                             CHECK ((S->Flags & SF_RUN_DEF) == 0);
1364                             CreateRunDefines (M, S, Addr);
1365                         }
1366                     }
1367                 } else {
1368                     /* RUN and LOAD in different memory areas, or RUN not
1369                      * given, so RUN defaults to LOAD. In the latter case, we
1370                      * have only one copy of the segment in the area.
1371                      */
1372                     if (S->Run == M) {
1373                         CreateRunDefines (M, S, Addr);
1374                     }
1375                     if (S->Load == M) {
1376                         CreateLoadDefines (M, S, Addr);
1377                     }
1378                 }
1379             }
1380
1381             /* Calculate the new address */
1382             Addr += S->Seg->Size;
1383
1384             /* Next segment */
1385             N = N->Next;
1386         }
1387
1388         /* If requested, define symbols for start and size of the memory area */
1389         if (M->Flags & MF_DEFINE) {
1390             char Buf [256];
1391             sprintf (Buf, "__%s_START__", M->Name);
1392             CreateMemExport (Buf, M, 0);
1393             sprintf (Buf, "__%s_SIZE__", M->Name);
1394             CreateConstExport (Buf, M->Size);
1395             sprintf (Buf, "__%s_LAST__", M->Name);
1396             CreateConstExport (Buf, M->FillLevel);
1397         }
1398
1399         /* Next memory area */
1400         M = M->Next;
1401     }
1402 }
1403
1404
1405
1406 void CfgWriteTarget (void)
1407 /* Write the target file(s) */
1408 {
1409     Memory* M;
1410
1411     /* Walk through the files list */
1412     File* F = FileList;
1413     while (F) {
1414         /* We don't need to look at files with no memory areas */
1415         if (F->MemList) {
1416
1417             /* Is there an output file? */
1418             if (strlen (F->Name) > 0) {
1419
1420                 /* Assign a proper binary format */
1421                 if (F->Format == BINFMT_DEFAULT) {
1422                     F->Format = DefaultBinFmt;
1423                 }
1424
1425                 /* Call the apropriate routine for the binary format */
1426                 switch (F->Format) {
1427
1428                     case BINFMT_BINARY:
1429                         BinWriteTarget (BinFmtDesc, F);
1430                         break;
1431
1432                     case BINFMT_O65:
1433                         O65WriteTarget (O65FmtDesc, F);
1434                         break;
1435
1436                     default:
1437                         Internal ("Invalid binary format: %u", F->Format);
1438
1439                 }
1440
1441             } else {
1442
1443                 /* No output file. Walk through the list and mark all segments
1444                  * loading into these memory areas in this file as dumped.
1445                  */
1446                 M = F->MemList;
1447                 while (M) {
1448
1449                     MemListNode* N;
1450
1451                     /* Debugging */
1452                     Print (stdout, 2, "Skipping `%s'...\n", M->Name);
1453
1454                     /* Walk throught the segments */
1455                     N = M->SegList;
1456                     while (N) {
1457                         if (N->Seg->Load == M) {
1458                             /* Load area - mark the segment as dumped */
1459                             N->Seg->Seg->Dumped = 1;
1460                         }
1461
1462                         /* Next segment node */
1463                         N = N->Next;
1464                     }
1465                     /* Next memory area */
1466                     M = M->FNext;
1467                 }
1468             }
1469         }
1470
1471         /* Next file */
1472         F = F->Next;
1473     }
1474 }
1475
1476
1477