]> git.sur5r.net Git - cc65/blob - src/ld65/config.c
New segment type renamed to "overwrite".
[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-2013, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /* With contributions from:                                                  */
15 /*                                                                           */
16 /*      - "David M. Lloyd" <david.lloyd@redhat.com>                          */
17 /*                                                                           */
18 /*                                                                           */
19 /* This software is provided 'as-is', without any expressed or implied       */
20 /* warranty.  In no event will the authors be held liable for any damages    */
21 /* arising from the use of this software.                                    */
22 /*                                                                           */
23 /* Permission is granted to anyone to use this software for any purpose,     */
24 /* including commercial applications, and to alter it and redistribute it    */
25 /* freely, subject to the following restrictions:                            */
26 /*                                                                           */
27 /* 1. The origin of this software must not be misrepresented; you must not   */
28 /*    claim that you wrote the original software. If you use this software   */
29 /*    in a product, an acknowledgment in the product documentation would be  */
30 /*    appreciated but is not required.                                       */
31 /* 2. Altered source versions must be plainly marked as such, and must not   */
32 /*    be misrepresented as being the original software.                      */
33 /* 3. This notice may not be removed or altered from any source              */
34 /*    distribution.                                                          */
35 /*                                                                           */
36 /*****************************************************************************/
37
38
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <errno.h>
44
45 /* common */
46 #include "addrsize.h"
47 #include "bitops.h"
48 #include "check.h"
49 #include "print.h"
50 #include "segdefs.h"
51 #include "target.h"
52 #include "xmalloc.h"
53 #include "xsprintf.h"
54
55 /* ld65 */
56 #include "alignment.h"
57 #include "bin.h"
58 #include "binfmt.h"
59 #include "cfgexpr.h"
60 #include "condes.h"
61 #include "config.h"
62 #include "error.h"
63 #include "exports.h"
64 #include "expr.h"
65 #include "global.h"
66 #include "memarea.h"
67 #include "o65.h"
68 #include "objdata.h"
69 #include "scanner.h"
70 #include "spool.h"
71
72
73
74 /*****************************************************************************/
75 /*                                   Data                                    */
76 /*****************************************************************************/
77
78
79
80 /* Remember which sections we had encountered */
81 static enum {
82     SE_NONE     = 0x0000,
83     SE_MEMORY   = 0x0001,
84     SE_SEGMENTS = 0x0002,
85     SE_FEATURES = 0x0004,
86     SE_FILES    = 0x0008,
87     SE_FORMATS  = 0x0010,
88     SE_SYMBOLS  = 0x0020
89 } SectionsEncountered = SE_NONE;
90
91
92
93 /* File list */
94 static Collection       FileList = STATIC_COLLECTION_INITIALIZER;
95
96 /* Memory list */
97 static Collection       MemoryAreas = STATIC_COLLECTION_INITIALIZER;
98
99 /* Memory attributes */
100 #define MA_START        0x0001
101 #define MA_SIZE         0x0002
102 #define MA_TYPE         0x0004
103 #define MA_FILE         0x0008
104 #define MA_DEFINE       0x0010
105 #define MA_FILL         0x0020
106 #define MA_FILLVAL      0x0040
107 #define MA_BANK         0x0080
108
109 /* Segment list */
110 static Collection       SegDescList = STATIC_COLLECTION_INITIALIZER;
111
112 /* Segment attributes */
113 #define SA_TYPE         0x0001
114 #define SA_LOAD         0x0002
115 #define SA_RUN          0x0004
116 #define SA_ALIGN        0x0008
117 #define SA_ALIGN_LOAD   0x0010
118 #define SA_DEFINE       0x0020
119 #define SA_OFFSET       0x0040
120 #define SA_START        0x0080
121 #define SA_OPTIONAL     0x0100
122 #define SA_FILLVAL      0x0200
123
124 /* Symbol types used in the CfgSymbol structure */
125 typedef enum {
126     CfgSymExport,               /* Not really used in struct CfgSymbol */
127     CfgSymImport,               /* Dito */
128     CfgSymWeak,                 /* Like export but weak */
129     CfgSymO65Export,            /* An o65 export */
130     CfgSymO65Import,            /* An o65 import */
131 } CfgSymType;
132
133 /* Symbol structure. It is used for o65 imports and exports, but also for
134 ** symbols from the SYMBOLS sections (symbols defined in the config file or
135 ** forced imports).
136 */
137 typedef struct CfgSymbol CfgSymbol;
138 struct CfgSymbol {
139     CfgSymType  Type;           /* Type of symbol */
140     LineInfo*   LI;             /* Config file position */
141     unsigned    Name;           /* Symbol name */
142     ExprNode*   Value;          /* Symbol value if any */
143     unsigned    AddrSize;       /* Address size of symbol */
144 };
145
146 /* Collections with symbols */
147 static Collection       CfgSymbols = STATIC_COLLECTION_INITIALIZER;
148
149 /* Descriptor holding information about the binary formats */
150 static BinDesc* BinFmtDesc      = 0;
151 static O65Desc* O65FmtDesc      = 0;
152
153
154
155 /*****************************************************************************/
156 /*                                 Forwards                                  */
157 /*****************************************************************************/
158
159
160
161 static File* NewFile (unsigned Name);
162 /* Create a new file descriptor and insert it into the list */
163
164
165
166 /*****************************************************************************/
167 /*                              List management                              */
168 /*****************************************************************************/
169
170
171
172 static File* FindFile (unsigned Name)
173 /* Find a file with a given name. */
174 {
175     unsigned I;
176     for (I = 0; I < CollCount (&FileList); ++I) {
177         File* F = CollAtUnchecked (&FileList, I);
178         if (F->Name == Name) {
179             return F;
180         }
181     }
182     return 0;
183 }
184
185
186
187 static File* GetFile (unsigned Name)
188 /* Get a file entry with the given name. Create a new one if needed. */
189 {
190     File* F = FindFile (Name);
191     if (F == 0) {
192         /* Create a new one */
193         F = NewFile (Name);
194     }
195     return F;
196 }
197
198
199
200 static void FileInsert (File* F, MemoryArea* M)
201 /* Insert the memory area into the files list */
202 {
203     M->F = F;
204     CollAppend (&F->MemoryAreas, M);
205 }
206
207
208
209 static MemoryArea* CfgFindMemory (unsigned Name)
210 /* Find the memory are with the given name. Return NULL if not found */
211 {
212     unsigned I;
213     for (I = 0; I < CollCount (&MemoryAreas); ++I) {
214         MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
215         if (M->Name == Name) {
216             return M;
217         }
218     }
219     return 0;
220 }
221
222
223
224 static MemoryArea* CfgGetMemory (unsigned Name)
225 /* Find the memory are with the given name. Print an error on an invalid name */
226 {
227     MemoryArea* M = CfgFindMemory (Name);
228     if (M == 0) {
229         CfgError (&CfgErrorPos, "Invalid memory area `%s'", GetString (Name));
230     }
231     return M;
232 }
233
234
235
236 static SegDesc* CfgFindSegDesc (unsigned Name)
237 /* Find the segment descriptor with the given name, return NULL if not found. */
238 {
239     unsigned I;
240     for (I = 0; I < CollCount (&SegDescList); ++I) {
241         SegDesc* S = CollAtUnchecked (&SegDescList, I);
242         if (S->Name == Name) {
243             /* Found */
244             return S;
245         }
246     }
247
248     /* Not found */
249     return 0;
250 }
251
252
253
254 static void MemoryInsert (MemoryArea* M, SegDesc* S)
255 /* Insert the segment descriptor into the memory area list */
256 {
257     /* Insert the segment into the segment list of the memory area */
258     CollAppend (&M->SegList, S);
259 }
260
261
262
263 /*****************************************************************************/
264 /*                         Constructors/Destructors                          */
265 /*****************************************************************************/
266
267
268
269 static CfgSymbol* NewCfgSymbol (CfgSymType Type, unsigned Name)
270 /* Create a new CfgSymbol structure with the given type and name. The
271 ** current config file position is recorded in the returned struct. The
272 ** created struct is inserted into the CfgSymbols collection and returned.
273 */
274 {
275     /* Allocate memory */
276     CfgSymbol* Sym = xmalloc (sizeof (CfgSymbol));
277
278     /* Initialize the fields */
279     Sym->Type     = Type;
280     Sym->LI       = GenLineInfo (&CfgErrorPos);
281     Sym->Name     = Name;
282     Sym->Value    = 0;
283     Sym->AddrSize = ADDR_SIZE_INVALID;
284
285     /* Insert the symbol into the collection */
286     CollAppend (&CfgSymbols, Sym);
287
288     /* Return the initialized struct */
289     return Sym;
290 }
291
292
293
294 static File* NewFile (unsigned Name)
295 /* Create a new file descriptor and insert it into the list */
296 {
297     /* Allocate memory */
298     File* F = xmalloc (sizeof (File));
299
300     /* Initialize the fields */
301     F->Name    = Name;
302     F->Flags   = 0;
303     F->Format  = BINFMT_DEFAULT;
304     F->Size    = 0;
305     InitCollection (&F->MemoryAreas);
306
307     /* Insert the struct into the list */
308     CollAppend (&FileList, F);
309
310     /* ...and return it */
311     return F;
312 }
313
314
315
316 static MemoryArea* CreateMemoryArea (const FilePos* Pos, unsigned Name)
317 /* Create a new memory area and insert it into the list */
318 {
319     /* Check for duplicate names */
320     MemoryArea* M = CfgFindMemory (Name);
321     if (M) {
322         CfgError (&CfgErrorPos,
323                   "Memory area `%s' defined twice",
324                   GetString (Name));
325     }
326
327     /* Create a new memory area */
328     M = NewMemoryArea (Pos, Name);
329
330     /* Insert the struct into the list ... */
331     CollAppend (&MemoryAreas, M);
332
333     /* ...and return it */
334     return M;
335 }
336
337
338
339 static SegDesc* NewSegDesc (unsigned Name)
340 /* Create a segment descriptor and insert it into the list */
341 {
342
343     /* Check for duplicate names */
344     SegDesc* S = CfgFindSegDesc (Name);
345     if (S) {
346         CfgError (&CfgErrorPos, "Segment `%s' defined twice", GetString (Name));
347     }
348
349     /* Allocate memory */
350     S = xmalloc (sizeof (SegDesc));
351
352     /* Initialize the fields */
353     S->Name          = Name;
354     S->LI            = GenLineInfo (&CfgErrorPos);
355     S->Seg           = 0;
356     S->Attr          = 0;
357     S->Flags         = 0;
358     S->FillVal       = 0;
359     S->RunAlignment  = 1;
360     S->LoadAlignment = 1;
361
362     /* Insert the struct into the list ... */
363     CollAppend (&SegDescList, S);
364
365     /* ...and return it */
366     return S;
367 }
368
369
370
371 static void FreeSegDesc (SegDesc* S)
372 /* Free a segment descriptor */
373 {
374     FreeLineInfo (S->LI);
375     xfree (S);
376 }
377
378
379
380 /*****************************************************************************/
381 /*                            Config file parsing                            */
382 /*****************************************************************************/
383
384
385
386 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
387 /* Check if the item is already defined. Print an error if so. If not, set
388 ** the marker that we have a definition now.
389 */
390 {
391     if (*Flags & Mask) {
392         CfgError (&CfgErrorPos, "%s is already defined", Name);
393     }
394     *Flags |= Mask;
395 }
396
397
398
399 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
400 /* Check that a mandatory attribute was given */
401 {
402     if ((Attr & Mask) == 0) {
403         CfgError (&CfgErrorPos, "%s attribute is missing", Name);
404     }
405 }
406
407
408
409 static void ParseMemory (void)
410 /* Parse a MEMORY section */
411 {
412     static const IdentTok Attributes [] = {
413         {   "BANK",     CFGTOK_BANK     },
414         {   "DEFINE",   CFGTOK_DEFINE   },
415         {   "FILE",     CFGTOK_FILE     },
416         {   "FILL",     CFGTOK_FILL     },
417         {   "FILLVAL",  CFGTOK_FILLVAL  },
418         {   "SIZE",     CFGTOK_SIZE     },
419         {   "START",    CFGTOK_START    },
420         {   "TYPE",     CFGTOK_TYPE     },
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         MemoryArea* M = CreateMemoryArea (&CfgErrorPos, GetStrBufId (&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_BANK:
452                     FlagAttr (&M->Attr, MA_BANK, "BANK");
453                     M->BankExpr = CfgExpr ();
454                     break;
455
456                 case CFGTOK_DEFINE:
457                     FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
458                     /* Map the token to a boolean */
459                     CfgBoolToken ();
460                     if (CfgTok == CFGTOK_TRUE) {
461                         M->Flags |= MF_DEFINE;
462                     }
463                     CfgNextTok ();
464                     break;
465
466                 case CFGTOK_FILE:
467                     FlagAttr (&M->Attr, MA_FILE, "FILE");
468                     CfgAssureStr ();
469                     /* Get the file entry and insert the memory area */
470                     FileInsert (GetFile (GetStrBufId (&CfgSVal)), M);
471                     CfgNextTok ();
472                     break;
473
474                 case CFGTOK_FILL:
475                     FlagAttr (&M->Attr, MA_FILL, "FILL");
476                     /* Map the token to a boolean */
477                     CfgBoolToken ();
478                     if (CfgTok == CFGTOK_TRUE) {
479                         M->Flags |= MF_FILL;
480                     }
481                     CfgNextTok ();
482                     break;
483
484                 case CFGTOK_FILLVAL:
485                     FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
486                     M->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
487                     break;
488
489                 case CFGTOK_SIZE:
490                     FlagAttr (&M->Attr, MA_SIZE, "SIZE");
491                     M->SizeExpr = CfgExpr ();
492                     break;
493
494                 case CFGTOK_START:
495                     FlagAttr (&M->Attr, MA_START, "START");
496                     M->StartExpr = CfgExpr ();
497                     break;
498
499                 case CFGTOK_TYPE:
500                     FlagAttr (&M->Attr, MA_TYPE, "TYPE");
501                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "TYPE");
502                     if (CfgTok == CFGTOK_RO) {
503                         M->Flags |= MF_RO;
504                     }
505                     CfgNextTok ();
506                     break;
507
508                 default:
509                     FAIL ("Unexpected attribute token");
510
511             }
512
513             /* Skip an optional comma */
514             CfgOptionalComma ();
515         }
516
517         /* Skip the semicolon */
518         CfgConsumeSemi ();
519
520         /* Check for mandatory parameters */
521         AttrCheck (M->Attr, MA_START, "START");
522         AttrCheck (M->Attr, MA_SIZE, "SIZE");
523
524         /* If we don't have a file name for output given, use the default
525         ** file name.
526         */
527         if ((M->Attr & MA_FILE) == 0) {
528             FileInsert (GetFile (GetStringId (OutputName)), M);
529             OutputNameUsed = 1;
530         }
531     }
532
533     /* Remember we had this section */
534     SectionsEncountered |= SE_MEMORY;
535 }
536
537
538
539 static void ParseFiles (void)
540 /* Parse a FILES section */
541 {
542     static const IdentTok Attributes [] = {
543         {   "FORMAT",   CFGTOK_FORMAT   },
544     };
545     static const IdentTok Formats [] = {
546         {   "O65",      CFGTOK_O65      },
547         {   "BIN",      CFGTOK_BIN      },
548         {   "BINARY",   CFGTOK_BIN      },
549     };
550
551
552     /* The MEMORY section must preceed the FILES section */
553     if ((SectionsEncountered & SE_MEMORY) == 0) {
554         CfgError (&CfgErrorPos, "MEMORY must precede FILES");
555     }
556
557     /* Parse all files */
558     while (CfgTok != CFGTOK_RCURLY) {
559
560         File* F;
561
562         /* We expect a string value here */
563         CfgAssureStr ();
564
565         /* Search for the file, it must exist */
566         F = FindFile (GetStrBufId (&CfgSVal));
567         if (F == 0) {
568             CfgError (&CfgErrorPos,
569                       "File `%s' not found in MEMORY section",
570                       SB_GetConstBuf (&CfgSVal));
571         }
572
573         /* Skip the token and the following colon */
574         CfgNextTok ();
575         CfgConsumeColon ();
576
577         /* Read the attributes */
578         while (CfgTok == CFGTOK_IDENT) {
579
580             /* Map the identifier to a token */
581             cfgtok_t AttrTok;
582             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
583             AttrTok = CfgTok;
584
585             /* An optional assignment follows */
586             CfgNextTok ();
587             CfgOptionalAssign ();
588
589             /* Check which attribute was given */
590             switch (AttrTok) {
591
592                 case CFGTOK_FORMAT:
593                     if (F->Format != BINFMT_DEFAULT) {
594                         /* We've set the format already! */
595                         CfgError (&CfgErrorPos,
596                                   "Cannot set a file format twice");
597                     }
598                     /* Read the format token */
599                     CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
600                     switch (CfgTok) {
601
602                         case CFGTOK_BIN:
603                             F->Format = BINFMT_BINARY;
604                             break;
605
606                         case CFGTOK_O65:
607                             F->Format = BINFMT_O65;
608                             break;
609
610                         default:
611                             Error ("Unexpected format token");
612                     }
613                     break;
614
615                 default:
616                     FAIL ("Unexpected attribute token");
617
618             }
619
620             /* Skip the attribute value and an optional comma */
621             CfgNextTok ();
622             CfgOptionalComma ();
623         }
624
625         /* Skip the semicolon */
626         CfgConsumeSemi ();
627
628     }
629
630     /* Remember we had this section */
631     SectionsEncountered |= SE_FILES;
632 }
633
634
635
636 static void ParseSegments (void)
637 /* Parse a SEGMENTS section */
638 {
639     static const IdentTok Attributes [] = {
640         {   "ALIGN",            CFGTOK_ALIGN            },
641         {   "ALIGN_LOAD",       CFGTOK_ALIGN_LOAD       },
642         {   "DEFINE",           CFGTOK_DEFINE           },
643         {   "FILLVAL",          CFGTOK_FILLVAL          },
644         {   "LOAD",             CFGTOK_LOAD             },
645         {   "OFFSET",           CFGTOK_OFFSET           },
646         {   "OPTIONAL",         CFGTOK_OPTIONAL         },
647         {   "RUN",              CFGTOK_RUN              },
648         {   "START",            CFGTOK_START            },
649         {   "TYPE",             CFGTOK_TYPE             },
650     };
651     static const IdentTok Types [] = {
652         {   "RO",               CFGTOK_RO               },
653         {   "RW",               CFGTOK_RW               },
654         {   "BSS",              CFGTOK_BSS              },
655         {   "ZP",               CFGTOK_ZP               },
656         {   "OVERWRITE",        CFGTOK_OVERWRITE        },
657     };
658
659     unsigned Count;
660
661     /* The MEMORY section must preceed the SEGMENTS section */
662     if ((SectionsEncountered & SE_MEMORY) == 0) {
663         CfgError (&CfgErrorPos, "MEMORY must precede SEGMENTS");
664     }
665
666     while (CfgTok == CFGTOK_IDENT) {
667
668         SegDesc* S;
669
670         /* Create a new entry on the heap */
671         S = NewSegDesc (GetStrBufId (&CfgSVal));
672
673         /* Skip the name and the following colon */
674         CfgNextTok ();
675         CfgConsumeColon ();
676
677         /* Read the attributes */
678         while (CfgTok == CFGTOK_IDENT) {
679
680             /* Map the identifier to a token */
681             cfgtok_t AttrTok;
682             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
683             AttrTok = CfgTok;
684
685             /* An optional assignment follows */
686             CfgNextTok ();
687             CfgOptionalAssign ();
688
689             /* Check which attribute was given */
690             switch (AttrTok) {
691
692                 case CFGTOK_ALIGN:
693                     FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
694                     S->RunAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
695                     S->Flags |= SF_ALIGN;
696                     break;
697
698                 case CFGTOK_ALIGN_LOAD:
699                     FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
700                     S->LoadAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
701                     S->Flags |= SF_ALIGN_LOAD;
702                     break;
703
704                 case CFGTOK_DEFINE:
705                     FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
706                     /* Map the token to a boolean */
707                     CfgBoolToken ();
708                     if (CfgTok == CFGTOK_TRUE) {
709                         S->Flags |= SF_DEFINE;
710                     }
711                     CfgNextTok ();
712                     break;
713
714                 case CFGTOK_FILLVAL:
715                     FlagAttr (&S->Attr, SA_FILLVAL, "FILLVAL");
716                     S->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
717                     S->Flags |= SF_FILLVAL;
718                     break;
719
720                 case CFGTOK_LOAD:
721                     FlagAttr (&S->Attr, SA_LOAD, "LOAD");
722                     S->Load = CfgGetMemory (GetStrBufId (&CfgSVal));
723                     CfgNextTok ();
724                     break;
725
726                 case CFGTOK_OFFSET:
727                     FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
728                     S->Addr   = CfgCheckedConstExpr (1, 0x1000000);
729                     S->Flags |= SF_OFFSET;
730                     break;
731
732                 case CFGTOK_OPTIONAL:
733                     FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL");
734                     CfgBoolToken ();
735                     if (CfgTok == CFGTOK_TRUE) {
736                         S->Flags |= SF_OPTIONAL;
737                     }
738                     CfgNextTok ();
739                     break;
740
741                 case CFGTOK_RUN:
742                     FlagAttr (&S->Attr, SA_RUN, "RUN");
743                     S->Run = CfgGetMemory (GetStrBufId (&CfgSVal));
744                     CfgNextTok ();
745                     break;
746
747                 case CFGTOK_START:
748                     FlagAttr (&S->Attr, SA_START, "START");
749                     S->Addr   = CfgCheckedConstExpr (1, 0x1000000);
750                     S->Flags |= SF_START;
751                     break;
752
753                 case CFGTOK_TYPE:
754                     FlagAttr (&S->Attr, SA_TYPE, "TYPE");
755                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
756                     switch (CfgTok) {
757                         case CFGTOK_RO:        S->Flags |= SF_RO;                  break;
758                         case CFGTOK_RW:        /* Default */                       break;
759                         case CFGTOK_BSS:       S->Flags |= SF_BSS;                 break;
760                         case CFGTOK_ZP:        S->Flags |= (SF_BSS | SF_ZP);       break;
761                         case CFGTOK_OVERWRITE: S->Flags |= (SF_OVERWRITE | SF_RO); break;
762                         default:               Internal ("Unexpected token: %d", CfgTok);
763                     }
764                     CfgNextTok ();
765                     break;
766
767                 default:
768                     FAIL ("Unexpected attribute token");
769
770             }
771
772             /* Skip an optional comma */
773             CfgOptionalComma ();
774         }
775
776         /* Check for mandatory parameters */
777         AttrCheck (S->Attr, SA_LOAD, "LOAD");
778
779         /* Set defaults for stuff not given */
780         if ((S->Attr & SA_RUN) == 0) {
781             S->Attr |= SA_RUN;
782             S->Run = S->Load;
783         }
784
785         /* An attribute of ALIGN_LOAD doesn't make sense if there are no
786         ** separate run and load memory areas.
787         */
788         if ((S->Flags & SF_ALIGN_LOAD) != 0 && (S->Load == S->Run)) {
789             CfgWarning (&CfgErrorPos,
790                         "ALIGN_LOAD attribute specified, but no separate "
791                         "LOAD and RUN memory areas assigned");
792             /* Remove the flag */
793             S->Flags &= ~SF_ALIGN_LOAD;
794         }
795
796         /* If the segment is marked as BSS style, it may not have separate
797         ** load and run memory areas, because it's is never written to disk.
798         */
799         if ((S->Flags & SF_BSS) != 0 && (S->Load != S->Run)) {
800             CfgWarning (&CfgErrorPos,
801                         "Segment with type `bss' has both LOAD and RUN "
802                         "memory areas assigned");
803         }
804
805         /* Don't allow read/write data to be put into a readonly area */
806         if ((S->Flags & SF_RO) == 0) {
807             if (S->Run->Flags & MF_RO) {
808                 CfgError (&CfgErrorPos,
809                           "Cannot put r/w segment `%s' in r/o memory area `%s'",
810                           GetString (S->Name), GetString (S->Run->Name));
811             }
812         }
813
814         /* Only one of ALIGN, START and OFFSET may be used */
815         Count = ((S->Flags & SF_ALIGN)  != 0) +
816                 ((S->Flags & SF_OFFSET) != 0) +
817                 ((S->Flags & SF_START)  != 0);
818         if (Count > 1) {
819             CfgError (&CfgErrorPos,
820                       "Only one of ALIGN, START, OFFSET may be used");
821         }
822
823         /* Skip the semicolon */
824         CfgConsumeSemi ();
825     }
826
827     /* Remember we had this section */
828     SectionsEncountered |= SE_SEGMENTS;
829 }
830
831
832
833 static void ParseO65 (void)
834 /* Parse the o65 format section */
835 {
836     static const IdentTok Attributes [] = {
837         {   "EXPORT",   CFGTOK_EXPORT           },
838         {   "IMPORT",   CFGTOK_IMPORT           },
839         {   "TYPE",     CFGTOK_TYPE             },
840         {   "OS",       CFGTOK_OS               },
841         {   "ID",       CFGTOK_ID               },
842         {   "VERSION",  CFGTOK_VERSION          },
843     };
844     static const IdentTok Types [] = {
845         {   "SMALL",    CFGTOK_SMALL            },
846         {   "LARGE",    CFGTOK_LARGE            },
847     };
848     static const IdentTok OperatingSystems [] = {
849         {   "LUNIX",    CFGTOK_LUNIX            },
850         {   "OSA65",    CFGTOK_OSA65            },
851         {   "CC65",     CFGTOK_CC65             },
852         {   "OPENCBM",  CFGTOK_OPENCBM          },
853     };
854
855     /* Bitmask to remember the attributes we got already */
856     enum {
857         atNone          = 0x0000,
858         atOS            = 0x0001,
859         atOSVersion     = 0x0002,
860         atType          = 0x0004,
861         atImport        = 0x0008,
862         atExport        = 0x0010,
863         atID            = 0x0020,
864         atVersion       = 0x0040
865     };
866     unsigned AttrFlags = atNone;
867
868     /* Remember the attributes read */
869     unsigned OS = 0;            /* Initialize to keep gcc happy */
870     unsigned Version = 0;
871
872     /* Read the attributes */
873     while (CfgTok == CFGTOK_IDENT) {
874
875         /* Map the identifier to a token */
876         cfgtok_t AttrTok;
877         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
878         AttrTok = CfgTok;
879
880         /* An optional assignment follows */
881         CfgNextTok ();
882         CfgOptionalAssign ();
883
884         /* Check which attribute was given */
885         switch (AttrTok) {
886
887             case CFGTOK_EXPORT:
888                 /* Remember we had this token (maybe more than once) */
889                 AttrFlags |= atExport;
890                 /* We expect an identifier */
891                 CfgAssureIdent ();
892                 /* Remember it as an export for later */
893                 NewCfgSymbol (CfgSymO65Export, GetStrBufId (&CfgSVal));
894                 /* Eat the identifier token */
895                 CfgNextTok ();
896                 break;
897
898             case CFGTOK_IMPORT:
899                 /* Remember we had this token (maybe more than once) */
900                 AttrFlags |= atImport;
901                 /* We expect an identifier */
902                 CfgAssureIdent ();
903                 /* Remember it as an import for later */
904                 NewCfgSymbol (CfgSymO65Import, GetStrBufId (&CfgSVal));
905                 /* Eat the identifier token */
906                 CfgNextTok ();
907                 break;
908
909             case CFGTOK_TYPE:
910                 /* Cannot have this attribute twice */
911                 FlagAttr (&AttrFlags, atType, "TYPE");
912                 /* Get the type of the executable */
913                 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
914                 switch (CfgTok) {
915
916                     case CFGTOK_SMALL:
917                         O65SetSmallModel (O65FmtDesc);
918                         break;
919
920                     case CFGTOK_LARGE:
921                         O65SetLargeModel (O65FmtDesc);
922                         break;
923
924                     default:
925                         CfgError (&CfgErrorPos, "Unexpected type token");
926                 }
927                 /* Eat the attribute token */
928                 CfgNextTok ();
929                 break;
930
931             case CFGTOK_OS:
932                 /* Cannot use this attribute twice */
933                 FlagAttr (&AttrFlags, atOS, "OS");
934                 /* Get the operating system. It may be specified as name or
935                 ** as a number in the range 1..255.
936                 */
937                 if (CfgTok == CFGTOK_INTCON) {
938                     CfgRangeCheck (O65OS_MIN, O65OS_MAX);
939                     OS = (unsigned) CfgIVal;
940                 } else {
941                     CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
942                     switch (CfgTok) {
943                         case CFGTOK_LUNIX:    OS = O65OS_LUNIX;     break;
944                         case CFGTOK_OSA65:    OS = O65OS_OSA65;     break;
945                         case CFGTOK_CC65:     OS = O65OS_CC65;      break;
946                         case CFGTOK_OPENCBM:  OS = O65OS_OPENCBM;   break;
947                         default:              CfgError (&CfgErrorPos, "Unexpected OS token");
948                     }
949                 }
950                 CfgNextTok ();
951                 break;
952
953             case CFGTOK_ID:
954                 /* Cannot have this attribute twice */
955                 FlagAttr (&AttrFlags, atID, "ID");
956                 /* We're expecting a number in the 0..$FFFF range*/
957                 ModuleId = (unsigned) CfgCheckedConstExpr (0, 0xFFFF);
958                 break;
959
960             case CFGTOK_VERSION:
961                 /* Cannot have this attribute twice */
962                 FlagAttr (&AttrFlags, atVersion, "VERSION");
963                 /* We're expecting a number in byte range */
964                 Version = (unsigned) CfgCheckedConstExpr (0, 0xFF);
965                 break;
966
967             default:
968                 FAIL ("Unexpected attribute token");
969
970         }
971
972         /* Skip an optional comma */
973         CfgOptionalComma ();
974     }
975
976     /* Check if we have all mandatory attributes */
977     AttrCheck (AttrFlags, atOS, "OS");
978
979     /* Check for attributes that may not be combined */
980     if (OS == O65OS_CC65) {
981         if ((AttrFlags & (atImport | atExport)) != 0 && ModuleId < 0x8000) {
982             CfgError (&CfgErrorPos,
983                       "OS type CC65 may not have imports or exports for ids < $8000");
984         }
985     } else {
986         if (AttrFlags & atID) {
987             CfgError (&CfgErrorPos,
988                       "Operating system does not support the ID attribute");
989         }
990     }
991
992     /* Set the O65 operating system to use */
993     O65SetOS (O65FmtDesc, OS, Version, ModuleId);
994 }
995
996
997
998 static void ParseFormats (void)
999 /* Parse a target format section */
1000 {
1001     static const IdentTok Formats [] = {
1002         {   "O65",      CFGTOK_O65      },
1003         {   "BIN",      CFGTOK_BIN      },
1004         {   "BINARY",   CFGTOK_BIN      },
1005     };
1006
1007     while (CfgTok == CFGTOK_IDENT) {
1008
1009         /* Map the identifier to a token */
1010         cfgtok_t FormatTok;
1011         CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
1012         FormatTok = CfgTok;
1013
1014         /* Skip the name and the following colon */
1015         CfgNextTok ();
1016         CfgConsumeColon ();
1017
1018         /* Parse the format options */
1019         switch (FormatTok) {
1020
1021             case CFGTOK_O65:
1022                 ParseO65 ();
1023                 break;
1024
1025             case CFGTOK_BIN:
1026                 /* No attribibutes available */
1027                 break;
1028
1029             default:
1030                 Error ("Unexpected format token");
1031         }
1032
1033         /* Skip the semicolon */
1034         CfgConsumeSemi ();
1035     }
1036
1037
1038     /* Remember we had this section */
1039     SectionsEncountered |= SE_FORMATS;
1040 }
1041
1042
1043
1044 static void ParseConDes (void)
1045 /* Parse the CONDES feature */
1046 {
1047     static const IdentTok Attributes [] = {
1048         {   "COUNT",            CFGTOK_COUNT            },
1049         {   "IMPORT",           CFGTOK_IMPORT           },
1050         {   "LABEL",            CFGTOK_LABEL            },
1051         {   "ORDER",            CFGTOK_ORDER            },
1052         {   "SEGMENT",          CFGTOK_SEGMENT          },
1053         {   "TYPE",             CFGTOK_TYPE             },
1054     };
1055
1056     static const IdentTok Types [] = {
1057         {   "CONSTRUCTOR",      CFGTOK_CONSTRUCTOR      },
1058         {   "DESTRUCTOR",       CFGTOK_DESTRUCTOR       },
1059         {   "INTERRUPTOR",      CFGTOK_INTERRUPTOR      },
1060     };
1061
1062     static const IdentTok Orders [] = {
1063         {   "DECREASING",       CFGTOK_DECREASING       },
1064         {   "INCREASING",       CFGTOK_INCREASING       },
1065     };
1066
1067     /* Attribute values. */
1068     unsigned Count   = INVALID_STRING_ID;
1069     unsigned Label   = INVALID_STRING_ID;
1070     unsigned SegName = INVALID_STRING_ID;
1071     ConDesImport Import;
1072     /* Initialize to avoid gcc warnings: */
1073     int Type = -1;
1074     ConDesOrder Order = cdIncreasing;
1075
1076     /* Bitmask to remember the attributes we got already */
1077     enum {
1078         atNone          = 0x0000,
1079         atCount         = 0x0001,
1080         atImport        = 0x0002,
1081         atLabel         = 0x0004,
1082         atOrder         = 0x0008,
1083         atSegName       = 0x0010,
1084         atType          = 0x0020,
1085     };
1086     unsigned AttrFlags = atNone;
1087
1088     /* Parse the attributes */
1089     while (1) {
1090
1091         /* Map the identifier to a token */
1092         cfgtok_t AttrTok;
1093         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1094         AttrTok = CfgTok;
1095
1096         /* An optional assignment follows */
1097         CfgNextTok ();
1098         CfgOptionalAssign ();
1099
1100         /* Check which attribute was given */
1101         switch (AttrTok) {
1102
1103             case CFGTOK_COUNT:
1104                 /* Don't allow this twice */
1105                 FlagAttr (&AttrFlags, atCount, "COUNT");
1106                 /* We expect an identifier */
1107                 CfgAssureIdent ();
1108                 /* Remember the value for later */
1109                 Count = GetStrBufId (&CfgSVal);
1110                 break;
1111
1112             case CFGTOK_IMPORT:
1113                 /* Don't allow this twice */
1114                 FlagAttr (&AttrFlags, atImport, "IMPORT");
1115                 /* We expect an identifier */
1116                 CfgAssureIdent ();
1117                 /* Remember value and position for later */
1118                 Import.Name = GetStrBufId (&CfgSVal);
1119                 Import.Pos = CfgErrorPos;
1120                 Import.AddrSize = ADDR_SIZE_ABS;
1121                 break;
1122
1123             case CFGTOK_LABEL:
1124                 /* Don't allow this twice */
1125                 FlagAttr (&AttrFlags, atLabel, "LABEL");
1126                 /* We expect an identifier */
1127                 CfgAssureIdent ();
1128                 /* Remember the value for later */
1129                 Label = GetStrBufId (&CfgSVal);
1130                 break;
1131
1132             case CFGTOK_ORDER:
1133                 /* Don't allow this twice */
1134                 FlagAttr (&AttrFlags, atOrder, "ORDER");
1135                 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1136                 switch (CfgTok) {
1137                     case CFGTOK_DECREASING: Order = cdDecreasing;       break;
1138                     case CFGTOK_INCREASING: Order = cdIncreasing;       break;
1139                     default: FAIL ("Unexpected order token");
1140                 }
1141                 break;
1142
1143             case CFGTOK_SEGMENT:
1144                 /* Don't allow this twice */
1145                 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1146                 /* We expect an identifier */
1147                 CfgAssureIdent ();
1148                 /* Remember the value for later */
1149                 SegName = GetStrBufId (&CfgSVal);
1150                 break;
1151
1152             case CFGTOK_TYPE:
1153                 /* Don't allow this twice */
1154                 FlagAttr (&AttrFlags, atType, "TYPE");
1155                 /* The type may be given as id or numerical */
1156                 if (CfgTok == CFGTOK_INTCON) {
1157                     CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1158                     Type = (int) CfgIVal;
1159                 } else {
1160                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1161                     switch (CfgTok) {
1162                         case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON;    break;
1163                         case CFGTOK_DESTRUCTOR:  Type = CD_TYPE_DES;    break;
1164                         case CFGTOK_INTERRUPTOR: Type = CD_TYPE_INT;    break;
1165                         default: FAIL ("Unexpected type token");
1166                     }
1167                 }
1168                 break;
1169
1170             default:
1171                 FAIL ("Unexpected attribute token");
1172
1173         }
1174
1175         /* Skip the attribute value */
1176         CfgNextTok ();
1177
1178         /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1179         if (CfgTok == CFGTOK_SEMI) {
1180             break;
1181         } else if (CfgTok == CFGTOK_COMMA) {
1182             CfgNextTok ();
1183         }
1184     }
1185
1186     /* Check if we have all mandatory attributes */
1187     AttrCheck (AttrFlags, atSegName, "SEGMENT");
1188     AttrCheck (AttrFlags, atLabel, "LABEL");
1189     AttrCheck (AttrFlags, atType, "TYPE");
1190
1191     /* Check if the condes has already attributes defined */
1192     if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1193         CfgError (&CfgErrorPos,
1194                   "CONDES attributes for type %d are already defined",
1195                   Type);
1196     }
1197
1198     /* Define the attributes */
1199     ConDesSetSegName (Type, SegName);
1200     ConDesSetLabel (Type, Label);
1201     if (AttrFlags & atCount) {
1202         ConDesSetCountSym (Type, Count);
1203     }
1204     if (AttrFlags & atImport) {
1205         ConDesSetImport (Type, &Import);
1206     }
1207     if (AttrFlags & atOrder) {
1208         ConDesSetOrder (Type, Order);
1209     }
1210 }
1211
1212
1213
1214 static void ParseStartAddress (void)
1215 /* Parse the STARTADDRESS feature */
1216 {
1217     static const IdentTok Attributes [] = {
1218         {   "DEFAULT",  CFGTOK_DEFAULT },
1219     };
1220
1221
1222     /* Attribute values. */
1223     unsigned long DefStartAddr = 0;
1224
1225     /* Bitmask to remember the attributes we got already */
1226     enum {
1227         atNone          = 0x0000,
1228         atDefault       = 0x0001
1229     };
1230     unsigned AttrFlags = atNone;
1231
1232     /* Parse the attributes */
1233     while (1) {
1234
1235         /* Map the identifier to a token */
1236         cfgtok_t AttrTok;
1237         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1238         AttrTok = CfgTok;
1239
1240         /* An optional assignment follows */
1241         CfgNextTok ();
1242         CfgOptionalAssign ();
1243
1244         /* Check which attribute was given */
1245         switch (AttrTok) {
1246
1247             case CFGTOK_DEFAULT:
1248                 /* Don't allow this twice */
1249                 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1250                 /* We expect a numeric expression */
1251                 DefStartAddr = CfgCheckedConstExpr (0, 0xFFFFFF);
1252                 break;
1253
1254             default:
1255                 FAIL ("Unexpected attribute token");
1256
1257         }
1258
1259         /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1260         if (CfgTok == CFGTOK_SEMI) {
1261             break;
1262         } else if (CfgTok == CFGTOK_COMMA) {
1263             CfgNextTok ();
1264         }
1265     }
1266
1267     /* Check if we have all mandatory attributes */
1268     AttrCheck (AttrFlags, atDefault, "DEFAULT");
1269
1270     /* If no start address was given on the command line, use the one given
1271     ** here
1272     */
1273     if (!HaveStartAddr) {
1274         StartAddr = DefStartAddr;
1275     }
1276 }
1277
1278
1279
1280 static void ParseFeatures (void)
1281 /* Parse a features section */
1282 {
1283     static const IdentTok Features [] = {
1284         {   "CONDES",       CFGTOK_CONDES       },
1285         {   "STARTADDRESS", CFGTOK_STARTADDRESS },
1286     };
1287
1288     while (CfgTok == CFGTOK_IDENT) {
1289
1290         /* Map the identifier to a token */
1291         cfgtok_t FeatureTok;
1292         CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1293         FeatureTok = CfgTok;
1294
1295         /* Skip the name and the following colon */
1296         CfgNextTok ();
1297         CfgConsumeColon ();
1298
1299         /* Parse the format options */
1300         switch (FeatureTok) {
1301
1302             case CFGTOK_CONDES:
1303                 ParseConDes ();
1304                 break;
1305
1306             case CFGTOK_STARTADDRESS:
1307                 ParseStartAddress ();
1308                 break;
1309
1310
1311             default:
1312                 FAIL ("Unexpected feature token");
1313         }
1314
1315         /* Skip the semicolon */
1316         CfgConsumeSemi ();
1317     }
1318
1319     /* Remember we had this section */
1320     SectionsEncountered |= SE_FEATURES;
1321 }
1322
1323
1324
1325 static void ParseSymbols (void)
1326 /* Parse a symbols section */
1327 {
1328     static const IdentTok Attributes[] = {
1329         {   "ADDRSIZE", CFGTOK_ADDRSIZE },
1330         {   "TYPE",     CFGTOK_TYPE     },
1331         {   "VALUE",    CFGTOK_VALUE    },
1332     };
1333
1334     static const IdentTok AddrSizes [] = {
1335         {   "ABS",      CFGTOK_ABS      },
1336         {   "ABSOLUTE", CFGTOK_ABS      },
1337         {   "DIRECT",   CFGTOK_ZP       },
1338         {   "DWORD",    CFGTOK_LONG     },
1339         {   "FAR",      CFGTOK_FAR      },
1340         {   "LONG",     CFGTOK_LONG     },
1341         {   "NEAR",     CFGTOK_ABS      },
1342         {   "ZEROPAGE", CFGTOK_ZP       },
1343         {   "ZP",       CFGTOK_ZP       },
1344     };
1345
1346     static const IdentTok Types [] = {
1347         {   "EXPORT",   CFGTOK_EXPORT   },
1348         {   "IMPORT",   CFGTOK_IMPORT   },
1349         {   "WEAK",     CFGTOK_WEAK     },
1350     };
1351
1352     while (CfgTok == CFGTOK_IDENT) {
1353
1354         /* Bitmask to remember the attributes we got already */
1355         enum {
1356             atNone      = 0x0000,
1357             atAddrSize  = 0x0001,
1358             atType      = 0x0002,
1359             atValue     = 0x0004,
1360         };
1361         unsigned AttrFlags = atNone;
1362
1363         ExprNode* Value = 0;
1364         CfgSymType Type = CfgSymExport;
1365         unsigned char AddrSize = ADDR_SIZE_ABS;
1366         Import* Imp;
1367         Export* Exp;
1368         CfgSymbol* Sym;
1369
1370         /* Remember the name */
1371         unsigned Name = GetStrBufId (&CfgSVal);
1372         CfgNextTok ();
1373
1374         /* New syntax - skip the colon */
1375         CfgNextTok ();
1376
1377         /* Parse the attributes */
1378         while (1) {
1379
1380             /* Map the identifier to a token */
1381             cfgtok_t AttrTok;
1382             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1383             AttrTok = CfgTok;
1384
1385             /* Skip the attribute name */
1386             CfgNextTok ();
1387
1388             /* An optional assignment follows */
1389             CfgOptionalAssign ();
1390
1391             /* Check which attribute was given */
1392             switch (AttrTok) {
1393
1394                 case CFGTOK_ADDRSIZE:
1395                     /* Don't allow this twice */
1396                     FlagAttr (&AttrFlags, atAddrSize, "ADDRSIZE");
1397                     /* Map the type to a token */
1398                     CfgSpecialToken (AddrSizes, ENTRY_COUNT (AddrSizes), "AddrSize");
1399                     switch (CfgTok) {
1400                         case CFGTOK_ABS:    AddrSize = ADDR_SIZE_ABS;   break;
1401                         case CFGTOK_FAR:    AddrSize = ADDR_SIZE_FAR;   break;
1402                         case CFGTOK_LONG:   AddrSize = ADDR_SIZE_LONG;  break;
1403                         case CFGTOK_ZP:     AddrSize = ADDR_SIZE_ZP;    break;
1404                         default:
1405                             Internal ("Unexpected token: %d", CfgTok);
1406                     }
1407                     CfgNextTok ();
1408                     break;
1409
1410                 case CFGTOK_TYPE:
1411                     /* Don't allow this twice */
1412                     FlagAttr (&AttrFlags, atType, "TYPE");
1413                     /* Map the type to a token */
1414                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1415                     switch (CfgTok) {
1416                         case CFGTOK_EXPORT:     Type = CfgSymExport;    break;
1417                         case CFGTOK_IMPORT:     Type = CfgSymImport;    break;
1418                         case CFGTOK_WEAK:       Type = CfgSymWeak;      break;
1419                         default:
1420                             Internal ("Unexpected token: %d", CfgTok);
1421                     }
1422                     CfgNextTok ();
1423                     break;
1424
1425                 case CFGTOK_VALUE:
1426                     /* Don't allow this twice */
1427                     FlagAttr (&AttrFlags, atValue, "VALUE");
1428                     /* Value is an expression */
1429                     Value = CfgExpr ();
1430                     break;
1431
1432                 default:
1433                     FAIL ("Unexpected attribute token");
1434
1435             }
1436
1437             /* Semicolon ends the decl, otherwise accept an optional comma */
1438             if (CfgTok == CFGTOK_SEMI) {
1439                 break;
1440             } else if (CfgTok == CFGTOK_COMMA) {
1441                 CfgNextTok ();
1442             }
1443         }
1444
1445         /* We must have a type */
1446         AttrCheck (AttrFlags, atType, "TYPE");
1447
1448         /* Further actions depend on the type */
1449         switch (Type) {
1450
1451             case CfgSymExport:
1452                 /* We must have a value */
1453                 AttrCheck (AttrFlags, atValue, "VALUE");
1454                 /* Create the export */
1455                 Exp = CreateExprExport (Name, Value, AddrSize);
1456                 CollAppend (&Exp->DefLines, GenLineInfo (&CfgErrorPos));
1457                 break;
1458
1459             case CfgSymImport:
1460                 /* An import must not have a value */
1461                 if (AttrFlags & atValue) {
1462                     CfgError (&CfgErrorPos, "Imports must not have a value");
1463                 }
1464                 /* Generate the import */
1465                 Imp = InsertImport (GenImport (Name, AddrSize));
1466                 /* Remember the file position */
1467                 CollAppend (&Imp->RefLines, GenLineInfo (&CfgErrorPos));
1468                 break;
1469
1470             case CfgSymWeak:
1471                 /* We must have a value */
1472                 AttrCheck (AttrFlags, atValue, "VALUE");
1473                 /* Remember the symbol for later */
1474                 Sym = NewCfgSymbol (CfgSymWeak, Name);
1475                 Sym->Value = Value;
1476                 Sym->AddrSize = AddrSize;
1477                 break;
1478
1479             default:
1480                 Internal ("Unexpected symbol type %d", Type);
1481         }
1482
1483         /* Skip the semicolon */
1484         CfgConsumeSemi ();
1485     }
1486
1487     /* Remember we had this section */
1488     SectionsEncountered |= SE_SYMBOLS;
1489 }
1490
1491
1492
1493 static void ParseConfig (void)
1494 /* Parse the config file */
1495 {
1496     static const IdentTok BlockNames [] = {
1497         {   "MEMORY",   CFGTOK_MEMORY   },
1498         {   "FILES",    CFGTOK_FILES    },
1499         {   "SEGMENTS", CFGTOK_SEGMENTS },
1500         {   "FORMATS",  CFGTOK_FORMATS  },
1501         {   "FEATURES", CFGTOK_FEATURES },
1502         {   "SYMBOLS",  CFGTOK_SYMBOLS  },
1503     };
1504     cfgtok_t BlockTok;
1505
1506     do {
1507
1508         /* Read the block ident */
1509         CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1510         BlockTok = CfgTok;
1511         CfgNextTok ();
1512
1513         /* Expected a curly brace */
1514         CfgConsume (CFGTOK_LCURLY, "`{' expected");
1515
1516         /* Read the block */
1517         switch (BlockTok) {
1518
1519             case CFGTOK_MEMORY:
1520                 ParseMemory ();
1521                 break;
1522
1523             case CFGTOK_FILES:
1524                 ParseFiles ();
1525                 break;
1526
1527             case CFGTOK_SEGMENTS:
1528                 ParseSegments ();
1529                 break;
1530
1531             case CFGTOK_FORMATS:
1532                 ParseFormats ();
1533                 break;
1534
1535             case CFGTOK_FEATURES:
1536                 ParseFeatures ();
1537                 break;
1538
1539             case CFGTOK_SYMBOLS:
1540                 ParseSymbols ();
1541                 break;
1542
1543             default:
1544                 FAIL ("Unexpected block token");
1545
1546         }
1547
1548         /* Skip closing brace */
1549         CfgConsume (CFGTOK_RCURLY, "`}' expected");
1550
1551     } while (CfgTok != CFGTOK_EOF);
1552 }
1553
1554
1555
1556 void CfgRead (void)
1557 /* Read the configuration */
1558 {
1559     /* Create the descriptors for the binary formats */
1560     BinFmtDesc = NewBinDesc ();
1561     O65FmtDesc = NewO65Desc ();
1562
1563     /* If we have a config name given, open the file, otherwise we will read
1564     ** from a buffer.
1565     */
1566     CfgOpenInput ();
1567
1568     /* Parse the file */
1569     ParseConfig ();
1570
1571     /* Close the input file */
1572     CfgCloseInput ();
1573 }
1574
1575
1576
1577 /*****************************************************************************/
1578 /*                          Config file processing                           */
1579 /*****************************************************************************/
1580
1581
1582
1583 static void ProcessSegments (void)
1584 /* Process the SEGMENTS section */
1585 {
1586     unsigned I;
1587
1588     /* Walk over the list of segment descriptors */
1589     I = 0;
1590     while (I < CollCount (&SegDescList)) {
1591
1592         /* Get the next segment descriptor */
1593         SegDesc* S = CollAtUnchecked (&SegDescList, I);
1594
1595         /* Search for the actual segment in the input files. The function may
1596         ** return NULL (no such segment), this is checked later.
1597         */
1598         S->Seg = SegFind (S->Name);
1599
1600         /* If the segment is marked as BSS style, and if the segment exists
1601         ** in any of the object file, check that there's no initialized data
1602         ** in the segment.
1603         */
1604         if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
1605             CfgWarning (GetSourcePos (S->LI),
1606                         "Segment `%s' with type `bss' contains initialized data",
1607                         GetString (S->Name));
1608         }
1609
1610         /* If this segment does exist in any of the object files, insert the
1611         ** segment into the load/run memory areas. Otherwise print a warning
1612         ** and discard it, because the segment pointer in the descriptor is
1613         ** invalid.
1614         */
1615         if (S->Seg != 0) {
1616
1617             /* Insert the segment into the memory area list */
1618             MemoryInsert (S->Run, S);
1619             if (S->Load != S->Run) {
1620                 /* We have separate RUN and LOAD areas */
1621                 MemoryInsert (S->Load, S);
1622             }
1623
1624             /* Use the fill value from the config */
1625             S->Seg->FillVal = S->FillVal;
1626
1627             /* Process the next segment descriptor in the next run */
1628             ++I;
1629
1630         } else {
1631
1632             /* Print a warning if the segment is not optional */
1633             if ((S->Flags & SF_OPTIONAL) == 0) {
1634                 CfgWarning (&CfgErrorPos,
1635                             "Segment `%s' does not exist",
1636                             GetString (S->Name));
1637             }
1638
1639             /* Discard the descriptor and remove it from the collection */
1640             FreeSegDesc (S);
1641             CollDelete (&SegDescList, I);
1642         }
1643     }
1644 }
1645
1646
1647
1648 static void ProcessSymbols (void)
1649 /* Process the SYMBOLS section */
1650 {
1651     Export* E;
1652
1653     /* Walk over all symbols */
1654     unsigned I;
1655     for (I = 0; I < CollCount (&CfgSymbols); ++I) {
1656
1657         /* Get the next symbol */
1658         CfgSymbol* Sym = CollAtUnchecked (&CfgSymbols, I);
1659
1660         /* Check what it is. */
1661         switch (Sym->Type) {
1662
1663             case CfgSymO65Export:
1664                 /* Check if the export symbol is also defined as an import. */
1665                 if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1666                     CfgError (
1667                         GetSourcePos (Sym->LI),
1668                         "Exported o65 symbol `%s' cannot also be an o65 import",
1669                         GetString (Sym->Name)
1670                     );
1671                 }
1672
1673                 /* Check if we have this symbol defined already. The entry
1674                 ** routine will check this also, but we get a more verbose
1675                 ** error message when checking it here.
1676                 */
1677                 if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
1678                     CfgError (
1679                         GetSourcePos (Sym->LI),
1680                         "Duplicate exported o65 symbol: `%s'",
1681                         GetString (Sym->Name)
1682                     );
1683                 }
1684
1685                 /* Insert the symbol into the table */
1686                 O65SetExport (O65FmtDesc, Sym->Name);
1687                 break;
1688
1689             case CfgSymO65Import:
1690                 /* Check if the import symbol is also defined as an export. */
1691                 if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
1692                     CfgError (
1693                         GetSourcePos (Sym->LI),
1694                         "Imported o65 symbol `%s' cannot also be an o65 export",
1695                         GetString (Sym->Name)
1696                     );
1697                 }
1698
1699                 /* Check if we have this symbol defined already. The entry
1700                 ** routine will check this also, but we get a more verbose
1701                 ** error message when checking it here.
1702                 */
1703                 if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1704                     CfgError (
1705                         GetSourcePos (Sym->LI),
1706                         "Duplicate imported o65 symbol: `%s'",
1707                         GetString (Sym->Name)
1708                     );
1709                 }
1710
1711                 /* Insert the symbol into the table */
1712                 O65SetImport (O65FmtDesc, Sym->Name);
1713                 break;
1714
1715             case CfgSymWeak:
1716                 /* If the symbol is not defined until now, define it */
1717                 if ((E = FindExport (Sym->Name)) == 0 || IsUnresolvedExport (E)) {
1718                     /* The symbol is undefined, generate an export */
1719                     E = CreateExprExport (Sym->Name, Sym->Value, Sym->AddrSize);
1720                     CollAppend (&E->DefLines, Sym->LI);
1721                 }
1722                 break;
1723
1724             default:
1725                 Internal ("Unexpected symbol type %d", Sym->Type);
1726                 break;
1727         }
1728     }
1729
1730 }
1731
1732
1733
1734 static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
1735 /* Create the defines for a RUN segment */
1736 {
1737     Export* E;
1738     StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1739
1740     /* Define the run address of the segment */
1741     SB_Printf (&Buf, "__%s_RUN__", GetString (S->Name));
1742     E = CreateMemoryExport (GetStrBufId (&Buf), S->Run, SegAddr - S->Run->Start);
1743     CollAppend (&E->DefLines, S->LI);
1744
1745     /* Define the size of the segment */
1746     SB_Printf (&Buf, "__%s_SIZE__", GetString (S->Name));
1747     E = CreateConstExport (GetStrBufId (&Buf), S->Seg->Size);
1748     CollAppend (&E->DefLines, S->LI);
1749
1750     S->Flags |= SF_RUN_DEF;
1751     SB_Done (&Buf);
1752 }
1753
1754
1755
1756 static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
1757 /* Create the defines for a LOAD segment */
1758 {
1759     Export* E;
1760     StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1761
1762     /* Define the load address of the segment */
1763     SB_Printf (&Buf, "__%s_LOAD__", GetString (S->Name));
1764     E = CreateMemoryExport (GetStrBufId (&Buf), S->Load, SegAddr - S->Load->Start);
1765     CollAppend (&E->DefLines, S->LI);
1766
1767     S->Flags |= SF_LOAD_DEF;
1768     SB_Done (&Buf);
1769 }
1770
1771
1772
1773 unsigned CfgProcess (void)
1774 /* Process the config file, after reading in object files and libraries. This
1775 ** includes postprocessing of the config file data; but also assigning segments,
1776 ** and defining segment/memory-area related symbols. The function will return
1777 ** the number of memory area overflows (so, zero means everything went OK).
1778 ** In case of overflows, a short mapfile can be generated later, to ease the
1779 ** user's task of re-arranging segments.
1780 */
1781 {
1782     unsigned Overflows = 0;
1783     unsigned I;
1784
1785     /* Postprocess symbols. We must do that first, since weak symbols are
1786     ** defined here, which may be needed later.
1787     */
1788     ProcessSymbols ();
1789
1790     /* Postprocess segments */
1791     ProcessSegments ();
1792
1793     /* Walk through each of the memory sections. Add up the sizes; and, check
1794     ** for an overflow of the section. Assign the start addresses of the
1795     ** segments while doing that.
1796     */
1797     for (I = 0; I < CollCount (&MemoryAreas); ++I) {
1798         unsigned J;
1799         unsigned long Addr;
1800         unsigned Overwrites = 0;
1801
1802         /* Get the next memory area */
1803         MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
1804
1805         /* Remember the offset in the output file */
1806         M->FileOffs = M->F->Size;
1807
1808         /* Remember if this is a relocatable memory area */
1809         M->Relocatable = RelocatableBinFmt (M->F->Format);
1810
1811         /* Resolve the start address expression, remember the start address,
1812         ** and mark the memory area as placed.
1813         */
1814         if (!IsConstExpr (M->StartExpr)) {
1815             CfgError (GetSourcePos (M->LI),
1816                       "Start address of memory area `%s' is not constant",
1817                       GetString (M->Name));
1818         }
1819         Addr = M->Start = GetExprVal (M->StartExpr);
1820         M->Flags |= MF_PLACED;
1821
1822         /* If requested, define the symbol for the start of the memory area.
1823         ** Doing it here means that the expression for the size of the area
1824         ** may reference this symbol.
1825         */
1826         if (M->Flags & MF_DEFINE) {
1827             Export* E;
1828             StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1829
1830             /* Define the start of the memory area */
1831             SB_Printf (&Buf, "__%s_START__", GetString (M->Name));
1832             E = CreateMemoryExport (GetStrBufId (&Buf), M, 0);
1833             CollAppend (&E->DefLines, M->LI);
1834
1835             SB_Done (&Buf);
1836         }
1837
1838         /* Resolve the size expression */
1839         if (!IsConstExpr (M->SizeExpr)) {
1840             CfgError (GetSourcePos (M->LI),
1841                       "Size of memory area `%s' is not constant",
1842                       GetString (M->Name));
1843         }
1844         M->Size = GetExprVal (M->SizeExpr);
1845
1846         /* Walk through the segments in this memory area */
1847         for (J = 0; J < CollCount (&M->SegList); ++J) {
1848             /* Get the segment */
1849             SegDesc* S = CollAtUnchecked (&M->SegList, J);
1850
1851             /* Remember the start address before handling this segment */
1852             unsigned long StartAddr = Addr;
1853
1854             /* Take note of "overwrite" segments and make sure there are no
1855             ** other segment types following them in current memory region.
1856             */
1857             if (S->Flags & SF_OVERWRITE) {
1858                 if (S->Flags & (SF_OFFSET | SF_START)) {
1859                     ++Overwrites;
1860                 } else {
1861                     CfgError (GetSourcePos (M->LI),
1862                               "Segment `%s' of type `overwrite' requires either"
1863                               " `Start' or `Offset' attribute to be specified",
1864                               GetString (S->Name));
1865                 }
1866             } else {
1867                 if (Overwrites > 0) {
1868                     CfgError (GetSourcePos (M->LI),
1869                               "Segment `%s' is preceded by at least one segment"
1870                               " of type `overwrite'",
1871                               GetString (S->Name));
1872                 }
1873             }
1874
1875             /* Some actions depend on whether this is the load or run memory
1876             ** area.
1877             */
1878             if (S->Run == M) {
1879                 /* This is the run (and maybe load) memory area. Handle
1880                 ** alignment and explict start address and offset.
1881                 */
1882
1883                 /* Check if the alignment for the segment from the linker
1884                 ** config. is a multiple for that of the segment.
1885                 */
1886                 if ((S->RunAlignment % S->Seg->Alignment) != 0) {
1887                     /* Segment requires another alignment than configured
1888                     ** in the linker.
1889                     */
1890                     CfgWarning (GetSourcePos (S->LI),
1891                                 "Segment `%s' isn't aligned properly; the"
1892                                 " resulting executable might not be functional.",
1893                                 GetString (S->Name));
1894                 }
1895
1896                 if (S->Flags & SF_ALIGN) {
1897                     /* Align the address */
1898                     unsigned long NewAddr = AlignAddr (Addr, S->RunAlignment);
1899
1900                     /* If the first segment placed in the memory area needs
1901                     ** fill bytes for the alignment, emit a warning, since
1902                     ** that is somewhat suspicious.
1903                     */
1904                     if (M->FillLevel == 0 && NewAddr > Addr) {
1905                         CfgWarning (GetSourcePos (S->LI),
1906                                     "The first segment in memory area `%s' "
1907                                     "needs fill bytes for alignment.",
1908                                     GetString (M->Name));
1909                     }
1910
1911                     /* Use the aligned address */
1912                     Addr = NewAddr;
1913
1914                 } else if ((S->Flags & (SF_OFFSET | SF_START)) != 0 &&
1915                            (M->Flags & MF_OVERFLOW) == 0) {
1916                     /* Give the segment a fixed starting address */
1917                     unsigned long NewAddr = S->Addr;
1918
1919                     if (S->Flags & SF_OFFSET) {
1920                         /* An offset was given, no address, make an address */
1921                         NewAddr += M->Start;
1922                     }
1923
1924                     if (S->Flags & SF_OVERWRITE) {
1925                         if (NewAddr < M->Start) {
1926                             CfgError (GetSourcePos (S->LI),
1927                                       "Segment `%s' begins before memory area `%s'",
1928                                       GetString (S->Name), GetString (M->Name));
1929                         } else {
1930                             Addr = NewAddr;
1931                         }
1932                     } else {
1933                         if (NewAddr < Addr) {
1934                             /* Offset already too large */
1935                             ++Overflows;
1936                             if (S->Flags & SF_OFFSET) {
1937                                 CfgWarning (GetSourcePos (S->LI),
1938                                             "Segment `%s' offset is too small in `%s' by %lu byte%c",
1939                                             GetString (S->Name), GetString (M->Name),
1940                                             Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
1941                             } else {
1942                                 CfgWarning (GetSourcePos (S->LI),
1943                                             "Segment `%s' start address is too low in `%s' by %lu byte%c",
1944                                             GetString (S->Name), GetString (M->Name),
1945                                             Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
1946                             }
1947                         } else {
1948                             Addr = NewAddr;
1949                         }
1950                     }
1951                 }
1952
1953                 /* Set the start address of this segment, set the readonly flag
1954                 ** in the segment, and remember if the segment is in a
1955                 ** relocatable file or not.
1956                 */
1957                 S->Seg->PC = Addr;
1958                 S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
1959
1960                 /* Remember the run memory for this segment, which is also a
1961                 ** flag that the segment has been placed.
1962                 */
1963                 S->Seg->MemArea = M;
1964
1965             } else if (S->Load == M) {
1966                 /* This is the load memory area; *and*, run and load are
1967                 ** different (because of the "else" above). Handle alignment.
1968                 */
1969                 if (S->Flags & SF_ALIGN_LOAD) {
1970                     /* Align the address */
1971                     Addr = AlignAddr (Addr, S->LoadAlignment);
1972                 }
1973             }
1974
1975             /* If this is the load memory area, and the segment doesn't have a
1976             ** fill value defined, use the one from the memory area.
1977             */
1978             if (S->Load == M && (S->Flags & SF_FILLVAL) == 0) {
1979                 S->Seg->FillVal = M->FillVal;
1980             }
1981
1982             /* Increment the fill level of the memory area; and, check for an
1983             ** overflow.
1984             */
1985             M->FillLevel = Addr + S->Seg->Size - M->Start;
1986             if (M->FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) {
1987                 ++Overflows;
1988                 M->Flags |= MF_OVERFLOW;
1989                 CfgWarning (GetSourcePos (M->LI),
1990                             "Segment `%s' overflows memory area `%s' by %lu byte%c",
1991                             GetString (S->Name), GetString (M->Name),
1992                             M->FillLevel - M->Size, (M->FillLevel - M->Size == 1) ? ' ' : 's');
1993             }
1994
1995             /* If requested, define symbols for the start and size of the
1996             ** segment.
1997             */
1998             if (S->Flags & SF_DEFINE) {
1999                 if (S->Run == M && (S->Flags & SF_RUN_DEF) == 0) {
2000                     CreateRunDefines (S, Addr);
2001                 }
2002                 if (S->Load == M && (S->Flags & SF_LOAD_DEF) == 0) {
2003                     CreateLoadDefines (S, Addr);
2004                 }
2005             }
2006
2007             /* Calculate the new address */
2008             Addr += S->Seg->Size;
2009
2010             /* If this segment will go out to the file, or its place
2011             ** in the file will be filled, then increase the file size.
2012             */
2013             if (S->Load == M &&
2014                 ((S->Flags & SF_BSS) == 0 || (M->Flags & MF_FILL) != 0)) {
2015                 M->F->Size += Addr - StartAddr;
2016             }
2017         }
2018
2019         /* If requested, define symbols for start, size, and offset of the
2020         ** memory area
2021         */
2022         if (M->Flags & MF_DEFINE) {
2023             Export* E;
2024             StrBuf Buf = STATIC_STRBUF_INITIALIZER;
2025
2026             /* Define the size of the memory area */
2027             SB_Printf (&Buf, "__%s_SIZE__", GetString (M->Name));
2028             E = CreateConstExport (GetStrBufId (&Buf), M->Size);
2029             CollAppend (&E->DefLines, M->LI);
2030
2031             /* Define the fill level of the memory area */
2032             SB_Printf (&Buf, "__%s_LAST__", GetString (M->Name));
2033             E = CreateMemoryExport (GetStrBufId (&Buf), M, M->FillLevel);
2034             CollAppend (&E->DefLines, M->LI);
2035
2036             /* Define the file offset of the memory area. This isn't of much
2037             ** use for relocatable output files.
2038             */
2039             if (!M->Relocatable) {
2040                 SB_Printf (&Buf, "__%s_FILEOFFS__", GetString (M->Name));
2041                 E = CreateConstExport (GetStrBufId (&Buf), M->FileOffs);
2042                 CollAppend (&E->DefLines, M->LI);
2043             }
2044
2045             /* Throw away the string buffer */
2046             SB_Done (&Buf);
2047         }
2048
2049         /* If we didn't have an overflow, and are requested to fill the memory
2050         ** area, account for that in the file size.
2051         */
2052         if ((M->Flags & MF_OVERFLOW) == 0 && (M->Flags & MF_FILL) != 0) {
2053             M->F->Size += (M->Size - M->FillLevel);
2054         }
2055     }
2056
2057     /* Return the number of memory area overflows */
2058     return Overflows;
2059 }
2060
2061
2062
2063 void CfgWriteTarget (void)
2064 /* Write the target file(s) */
2065 {
2066     unsigned I;
2067
2068     /* Walk through the files list */
2069     for (I = 0; I < CollCount (&FileList); ++I) {
2070
2071         /* Get this entry */
2072         File* F = CollAtUnchecked (&FileList, I);
2073
2074         /* We don't need to look at files with no memory areas */
2075         if (CollCount (&F->MemoryAreas) > 0) {
2076
2077             /* Is there an output file? */
2078             if (SB_GetLen (GetStrBuf (F->Name)) > 0) {
2079
2080                 /* Assign a proper binary format */
2081                 if (F->Format == BINFMT_DEFAULT) {
2082                     F->Format = DefaultBinFmt;
2083                 }
2084
2085                 /* Call the apropriate routine for the binary format */
2086                 switch (F->Format) {
2087
2088                     case BINFMT_BINARY:
2089                         BinWriteTarget (BinFmtDesc, F);
2090                         break;
2091
2092                     case BINFMT_O65:
2093                         O65WriteTarget (O65FmtDesc, F);
2094                         break;
2095
2096                     default:
2097                         Internal ("Invalid binary format: %u", F->Format);
2098
2099                 }
2100
2101             } else {
2102
2103                 /* No output file. Walk through the list and mark all segments
2104                 ** loading into these memory areas in this file as dumped.
2105                 */
2106                 unsigned J;
2107                 for (J = 0; J < CollCount (&F->MemoryAreas); ++J) {
2108
2109                     unsigned K;
2110
2111                     /* Get this entry */
2112                     MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, J);
2113
2114                     /* Debugging */
2115                     Print (stdout, 2, "Skipping `%s'...\n", GetString (M->Name));
2116
2117                     /* Walk throught the segments */
2118                     for (K = 0; K < CollCount (&M->SegList); ++K) {
2119                         SegDesc* S = CollAtUnchecked (&M->SegList, K);
2120                         if (S->Load == M) {
2121                             /* Load area - mark the segment as dumped */
2122                             S->Seg->Dumped = 1;
2123                         }
2124                     }
2125                 }
2126             }
2127         }
2128     }
2129 }