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