1 /*****************************************************************************/
5 /* Target configuration file for the ld65 linker */
9 /* (C) 1998-2010, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
67 /*****************************************************************************/
69 /*****************************************************************************/
73 /* Remember which sections we had encountered */
82 } SectionsEncountered = SE_NONE;
87 static Collection FileList = STATIC_COLLECTION_INITIALIZER;
90 static Collection MemoryAreas = STATIC_COLLECTION_INITIALIZER;
92 /* Memory attributes */
93 #define MA_START 0x0001
94 #define MA_SIZE 0x0002
95 #define MA_TYPE 0x0004
96 #define MA_FILE 0x0008
97 #define MA_DEFINE 0x0010
98 #define MA_FILL 0x0020
99 #define MA_FILLVAL 0x0040
102 static Collection SegDescList = STATIC_COLLECTION_INITIALIZER;
104 /* Segment attributes */
105 #define SA_TYPE 0x0001
106 #define SA_LOAD 0x0002
107 #define SA_RUN 0x0004
108 #define SA_ALIGN 0x0008
109 #define SA_ALIGN_LOAD 0x0010
110 #define SA_DEFINE 0x0020
111 #define SA_OFFSET 0x0040
112 #define SA_START 0x0080
113 #define SA_OPTIONAL 0x0100
115 /* Symbol types used in the CfgSymbol structure */
117 CfgSymExport, /* Not really used in struct CfgSymbol */
118 CfgSymImport, /* Dito */
119 CfgSymWeak, /* Like export but weak */
120 CfgSymO65Export, /* An o65 export */
121 CfgSymO65Import, /* An o65 import */
124 /* Symbol structure. It is used for o65 imports and exports, but also for
125 * symbols from the SYMBOLS sections (symbols defined in the config file or
128 typedef struct CfgSymbol CfgSymbol;
130 CfgSymType Type; /* Type of symbol */
131 LineInfo* LI; /* Config file position */
132 unsigned Name; /* Symbol name */
133 ExprNode* Value; /* Symbol value if any */
134 unsigned AddrSize; /* Address size of symbol */
137 /* Collections with symbols */
138 static Collection CfgSymbols = STATIC_COLLECTION_INITIALIZER;
140 /* Descriptor holding information about the binary formats */
141 static BinDesc* BinFmtDesc = 0;
142 static O65Desc* O65FmtDesc = 0;
146 /*****************************************************************************/
148 /*****************************************************************************/
152 static File* NewFile (unsigned Name);
153 /* Create a new file descriptor and insert it into the list */
157 /*****************************************************************************/
158 /* List management */
159 /*****************************************************************************/
163 static File* FindFile (unsigned Name)
164 /* Find a file with a given name. */
167 for (I = 0; I < CollCount (&FileList); ++I) {
168 File* F = CollAtUnchecked (&FileList, I);
169 if (F->Name == Name) {
178 static File* GetFile (unsigned Name)
179 /* Get a file entry with the given name. Create a new one if needed. */
181 File* F = FindFile (Name);
183 /* Create a new one */
191 static void FileInsert (File* F, MemoryArea* M)
192 /* Insert the memory area into the files list */
195 CollAppend (&F->MemoryAreas, M);
200 static MemoryArea* CfgFindMemory (unsigned Name)
201 /* Find the memory are with the given name. Return NULL if not found */
204 for (I = 0; I < CollCount (&MemoryAreas); ++I) {
205 MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
206 if (M->Name == Name) {
215 static MemoryArea* CfgGetMemory (unsigned Name)
216 /* Find the memory are with the given name. Print an error on an invalid name */
218 MemoryArea* M = CfgFindMemory (Name);
220 CfgError (&CfgErrorPos, "Invalid memory area `%s'", GetString (Name));
227 static SegDesc* CfgFindSegDesc (unsigned Name)
228 /* Find the segment descriptor with the given name, return NULL if not found. */
231 for (I = 0; I < CollCount (&SegDescList); ++I) {
232 SegDesc* S = CollAtUnchecked (&SegDescList, I);
233 if (S->Name == Name) {
245 static void MemoryInsert (MemoryArea* M, SegDesc* S)
246 /* Insert the segment descriptor into the memory area list */
248 /* Insert the segment into the segment list of the memory area */
249 CollAppend (&M->SegList, S);
254 /*****************************************************************************/
255 /* Constructors/Destructors */
256 /*****************************************************************************/
260 static CfgSymbol* NewCfgSymbol (CfgSymType Type, unsigned Name)
261 /* Create a new CfgSymbol structure with the given type and name. The
262 * current config file position is recorded in the returned struct. The
263 * created struct is inserted into the CfgSymbols collection and returned.
266 /* Allocate memory */
267 CfgSymbol* Sym = xmalloc (sizeof (CfgSymbol));
269 /* Initialize the fields */
271 Sym->LI = GenLineInfo (&CfgErrorPos);
274 Sym->AddrSize = ADDR_SIZE_INVALID;
276 /* Insert the symbol into the collection */
277 CollAppend (&CfgSymbols, Sym);
279 /* Return the initialized struct */
285 static File* NewFile (unsigned Name)
286 /* Create a new file descriptor and insert it into the list */
288 /* Allocate memory */
289 File* F = xmalloc (sizeof (File));
291 /* Initialize the fields */
294 F->Format = BINFMT_DEFAULT;
295 InitCollection (&F->MemoryAreas);
297 /* Insert the struct into the list */
298 CollAppend (&FileList, F);
300 /* ...and return it */
306 static MemoryArea* CreateMemoryArea (const FilePos* Pos, unsigned Name)
307 /* Create a new memory area and insert it into the list */
309 /* Check for duplicate names */
310 MemoryArea* M = CfgFindMemory (Name);
312 CfgError (&CfgErrorPos,
313 "Memory area `%s' defined twice",
317 /* Create a new memory area */
318 M = NewMemoryArea (Pos, Name);
320 /* Insert the struct into the list ... */
321 CollAppend (&MemoryAreas, M);
323 /* ...and return it */
329 static SegDesc* NewSegDesc (unsigned Name)
330 /* Create a segment descriptor and insert it into the list */
333 /* Check for duplicate names */
334 SegDesc* S = CfgFindSegDesc (Name);
336 CfgError (&CfgErrorPos, "Segment `%s' defined twice", GetString (Name));
339 /* Allocate memory */
340 S = xmalloc (sizeof (SegDesc));
342 /* Initialize the fields */
344 S->LI = GenLineInfo (&CfgErrorPos);
350 /* Insert the struct into the list ... */
351 CollAppend (&SegDescList, S);
353 /* ...and return it */
359 static void FreeSegDesc (SegDesc* S)
360 /* Free a segment descriptor */
367 /*****************************************************************************/
368 /* Config file parsing */
369 /*****************************************************************************/
373 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
374 /* Check if the item is already defined. Print an error if so. If not, set
375 * the marker that we have a definition now.
379 CfgError (&CfgErrorPos, "%s is already defined", Name);
386 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
387 /* Check that a mandatory attribute was given */
389 if ((Attr & Mask) == 0) {
390 CfgError (&CfgErrorPos, "%s attribute is missing", Name);
396 static void ParseMemory (void)
397 /* Parse a MEMORY section */
399 static const IdentTok Attributes [] = {
400 { "START", CFGTOK_START },
401 { "SIZE", CFGTOK_SIZE },
402 { "TYPE", CFGTOK_TYPE },
403 { "FILE", CFGTOK_FILE },
404 { "DEFINE", CFGTOK_DEFINE },
405 { "FILL", CFGTOK_FILL },
406 { "FILLVAL", CFGTOK_FILLVAL },
408 static const IdentTok Types [] = {
413 while (CfgTok == CFGTOK_IDENT) {
415 /* Create a new entry on the heap */
416 MemoryArea* M = CreateMemoryArea (&CfgErrorPos, GetStrBufId (&CfgSVal));
418 /* Skip the name and the following colon */
422 /* Read the attributes */
423 while (CfgTok == CFGTOK_IDENT) {
425 /* Map the identifier to a token */
427 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
430 /* An optional assignment follows */
432 CfgOptionalAssign ();
434 /* Check which attribute was given */
438 FlagAttr (&M->Attr, MA_START, "START");
439 M->StartExpr = CfgExpr ();
443 FlagAttr (&M->Attr, MA_SIZE, "SIZE");
444 M->SizeExpr = CfgExpr ();
448 FlagAttr (&M->Attr, MA_TYPE, "TYPE");
449 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
450 if (CfgTok == CFGTOK_RO) {
457 FlagAttr (&M->Attr, MA_FILE, "FILE");
459 /* Get the file entry and insert the memory area */
460 FileInsert (GetFile (GetStrBufId (&CfgSVal)), M);
465 FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
466 /* Map the token to a boolean */
468 if (CfgTok == CFGTOK_TRUE) {
469 M->Flags |= MF_DEFINE;
475 FlagAttr (&M->Attr, MA_FILL, "FILL");
476 /* Map the token to a boolean */
478 if (CfgTok == CFGTOK_TRUE) {
485 FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
486 M->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
490 FAIL ("Unexpected attribute token");
494 /* Skip an optional comma */
498 /* Skip the semicolon */
501 /* Check for mandatory parameters */
502 AttrCheck (M->Attr, MA_START, "START");
503 AttrCheck (M->Attr, MA_SIZE, "SIZE");
505 /* If we don't have a file name for output given, use the default
508 if ((M->Attr & MA_FILE) == 0) {
509 FileInsert (GetFile (GetStringId (OutputName)), M);
514 /* Remember we had this section */
515 SectionsEncountered |= SE_MEMORY;
520 static void ParseFiles (void)
521 /* Parse a FILES section */
523 static const IdentTok Attributes [] = {
524 { "FORMAT", CFGTOK_FORMAT },
526 static const IdentTok Formats [] = {
527 { "O65", CFGTOK_O65 },
528 { "BIN", CFGTOK_BIN },
529 { "BINARY", CFGTOK_BIN },
533 /* The MEMORY section must preceed the FILES section */
534 if ((SectionsEncountered & SE_MEMORY) == 0) {
535 CfgError (&CfgErrorPos, "MEMORY must precede FILES");
538 /* Parse all files */
539 while (CfgTok != CFGTOK_RCURLY) {
543 /* We expect a string value here */
546 /* Search for the file, it must exist */
547 F = FindFile (GetStrBufId (&CfgSVal));
549 CfgError (&CfgErrorPos,
550 "File `%s' not found in MEMORY section",
551 SB_GetConstBuf (&CfgSVal));
554 /* Skip the token and the following colon */
558 /* Read the attributes */
559 while (CfgTok == CFGTOK_IDENT) {
561 /* Map the identifier to a token */
563 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
566 /* An optional assignment follows */
568 CfgOptionalAssign ();
570 /* Check which attribute was given */
574 if (F->Format != BINFMT_DEFAULT) {
575 /* We've set the format already! */
576 CfgError (&CfgErrorPos,
577 "Cannot set a file format twice");
579 /* Read the format token */
580 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
584 F->Format = BINFMT_BINARY;
588 F->Format = BINFMT_O65;
592 Error ("Unexpected format token");
597 FAIL ("Unexpected attribute token");
601 /* Skip the attribute value and an optional comma */
606 /* Skip the semicolon */
611 /* Remember we had this section */
612 SectionsEncountered |= SE_FILES;
617 static void ParseSegments (void)
618 /* Parse a SEGMENTS section */
620 static const IdentTok Attributes [] = {
621 { "ALIGN", CFGTOK_ALIGN },
622 { "ALIGN_LOAD", CFGTOK_ALIGN_LOAD },
623 { "DEFINE", CFGTOK_DEFINE },
624 { "LOAD", CFGTOK_LOAD },
625 { "OFFSET", CFGTOK_OFFSET },
626 { "OPTIONAL", CFGTOK_OPTIONAL },
627 { "RUN", CFGTOK_RUN },
628 { "START", CFGTOK_START },
629 { "TYPE", CFGTOK_TYPE },
631 static const IdentTok Types [] = {
634 { "BSS", CFGTOK_BSS },
641 /* The MEMORY section must preceed the SEGMENTS section */
642 if ((SectionsEncountered & SE_MEMORY) == 0) {
643 CfgError (&CfgErrorPos, "MEMORY must precede SEGMENTS");
646 while (CfgTok == CFGTOK_IDENT) {
650 /* Create a new entry on the heap */
651 S = NewSegDesc (GetStrBufId (&CfgSVal));
653 /* Skip the name and the following colon */
657 /* Read the attributes */
658 while (CfgTok == CFGTOK_IDENT) {
660 /* Map the identifier to a token */
662 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
665 /* An optional assignment follows */
667 CfgOptionalAssign ();
669 /* Check which attribute was given */
673 FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
674 Val = CfgCheckedConstExpr (1, 0x10000);
675 S->Align = BitFind (Val);
676 if ((0x01L << S->Align) != Val) {
677 CfgError (&CfgErrorPos, "Alignment must be a power of 2");
679 S->Flags |= SF_ALIGN;
682 case CFGTOK_ALIGN_LOAD:
683 FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
684 Val = CfgCheckedConstExpr (1, 0x10000);
685 S->AlignLoad = BitFind (Val);
686 if ((0x01L << S->AlignLoad) != Val) {
687 CfgError (&CfgErrorPos, "Alignment must be a power of 2");
689 S->Flags |= SF_ALIGN_LOAD;
693 FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
694 /* Map the token to a boolean */
696 if (CfgTok == CFGTOK_TRUE) {
697 S->Flags |= SF_DEFINE;
703 FlagAttr (&S->Attr, SA_LOAD, "LOAD");
704 S->Load = CfgGetMemory (GetStrBufId (&CfgSVal));
709 FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
710 S->Addr = CfgCheckedConstExpr (1, 0x1000000);
711 S->Flags |= SF_OFFSET;
714 case CFGTOK_OPTIONAL:
715 FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL");
717 if (CfgTok == CFGTOK_TRUE) {
718 S->Flags |= SF_OPTIONAL;
724 FlagAttr (&S->Attr, SA_RUN, "RUN");
725 S->Run = CfgGetMemory (GetStrBufId (&CfgSVal));
730 FlagAttr (&S->Attr, SA_START, "START");
731 S->Addr = CfgCheckedConstExpr (1, 0x1000000);
732 S->Flags |= SF_START;
736 FlagAttr (&S->Attr, SA_TYPE, "TYPE");
737 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
739 case CFGTOK_RO: S->Flags |= SF_RO; break;
740 case CFGTOK_RW: /* Default */ break;
741 case CFGTOK_BSS: S->Flags |= SF_BSS; break;
742 case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break;
743 default: Internal ("Unexpected token: %d", CfgTok);
749 FAIL ("Unexpected attribute token");
753 /* Skip an optional comma */
757 /* Check for mandatory parameters */
758 AttrCheck (S->Attr, SA_LOAD, "LOAD");
760 /* Set defaults for stuff not given */
761 if ((S->Attr & SA_RUN) == 0) {
766 /* An attribute of ALIGN_LOAD doesn't make sense if there are no
767 * separate run and load memory areas.
769 if ((S->Flags & SF_ALIGN_LOAD) != 0 && (S->Load == S->Run)) {
770 CfgWarning (&CfgErrorPos,
771 "ALIGN_LOAD attribute specified, but no separate "
772 "LOAD and RUN memory areas assigned");
773 /* Remove the flag */
774 S->Flags &= ~SF_ALIGN_LOAD;
777 /* If the segment is marked as BSS style, it may not have separate
778 * load and run memory areas, because it's is never written to disk.
780 if ((S->Flags & SF_BSS) != 0 && (S->Load != S->Run)) {
781 CfgWarning (&CfgErrorPos,
782 "Segment with type `bss' has both LOAD and RUN "
783 "memory areas assigned");
786 /* Don't allow read/write data to be put into a readonly area */
787 if ((S->Flags & SF_RO) == 0) {
788 if (S->Run->Flags & MF_RO) {
789 CfgError (&CfgErrorPos,
790 "Cannot put r/w segment `%s' in r/o memory area `%s'",
791 GetString (S->Name), GetString (S->Run->Name));
795 /* Only one of ALIGN, START and OFFSET may be used */
796 Count = ((S->Flags & SF_ALIGN) != 0) +
797 ((S->Flags & SF_OFFSET) != 0) +
798 ((S->Flags & SF_START) != 0);
800 CfgError (&CfgErrorPos,
801 "Only one of ALIGN, START, OFFSET may be used");
804 /* Skip the semicolon */
808 /* Remember we had this section */
809 SectionsEncountered |= SE_SEGMENTS;
814 static void ParseO65 (void)
815 /* Parse the o65 format section */
817 static const IdentTok Attributes [] = {
818 { "EXPORT", CFGTOK_EXPORT },
819 { "IMPORT", CFGTOK_IMPORT },
820 { "TYPE", CFGTOK_TYPE },
823 { "VERSION", CFGTOK_VERSION },
825 static const IdentTok Types [] = {
826 { "SMALL", CFGTOK_SMALL },
827 { "LARGE", CFGTOK_LARGE },
829 static const IdentTok OperatingSystems [] = {
830 { "LUNIX", CFGTOK_LUNIX },
831 { "OSA65", CFGTOK_OSA65 },
832 { "CC65", CFGTOK_CC65 },
833 { "OPENCBM", CFGTOK_OPENCBM },
836 /* Bitmask to remember the attributes we got already */
840 atOSVersion = 0x0002,
847 unsigned AttrFlags = atNone;
849 /* Remember the attributes read */
850 unsigned OS = 0; /* Initialize to keep gcc happy */
851 unsigned Version = 0;
853 /* Read the attributes */
854 while (CfgTok == CFGTOK_IDENT) {
856 /* Map the identifier to a token */
858 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
861 /* An optional assignment follows */
863 CfgOptionalAssign ();
865 /* Check which attribute was given */
869 /* Remember we had this token (maybe more than once) */
870 AttrFlags |= atExport;
871 /* We expect an identifier */
873 /* Remember it as an export for later */
874 NewCfgSymbol (CfgSymO65Export, GetStrBufId (&CfgSVal));
875 /* Eat the identifier token */
880 /* Remember we had this token (maybe more than once) */
881 AttrFlags |= atImport;
882 /* We expect an identifier */
884 /* Remember it as an import for later */
885 NewCfgSymbol (CfgSymO65Import, GetStrBufId (&CfgSVal));
886 /* Eat the identifier token */
891 /* Cannot have this attribute twice */
892 FlagAttr (&AttrFlags, atType, "TYPE");
893 /* Get the type of the executable */
894 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
898 O65SetSmallModel (O65FmtDesc);
902 O65SetLargeModel (O65FmtDesc);
906 CfgError (&CfgErrorPos, "Unexpected type token");
908 /* Eat the attribute token */
913 /* Cannot use this attribute twice */
914 FlagAttr (&AttrFlags, atOS, "OS");
915 /* Get the operating system. It may be specified as name or
916 * as a number in the range 1..255.
918 if (CfgTok == CFGTOK_INTCON) {
919 CfgRangeCheck (O65OS_MIN, O65OS_MAX);
920 OS = (unsigned) CfgIVal;
922 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
924 case CFGTOK_LUNIX: OS = O65OS_LUNIX; break;
925 case CFGTOK_OSA65: OS = O65OS_OSA65; break;
926 case CFGTOK_CC65: OS = O65OS_CC65; break;
927 case CFGTOK_OPENCBM: OS = O65OS_OPENCBM; break;
928 default: CfgError (&CfgErrorPos, "Unexpected OS token");
935 /* Cannot have this attribute twice */
936 FlagAttr (&AttrFlags, atID, "ID");
937 /* We're expecting a number in the 0..$FFFF range*/
938 ModuleId = (unsigned) CfgCheckedConstExpr (0, 0xFFFF);
942 /* Cannot have this attribute twice */
943 FlagAttr (&AttrFlags, atVersion, "VERSION");
944 /* We're expecting a number in byte range */
945 Version = (unsigned) CfgCheckedConstExpr (0, 0xFF);
949 FAIL ("Unexpected attribute token");
953 /* Skip an optional comma */
957 /* Check if we have all mandatory attributes */
958 AttrCheck (AttrFlags, atOS, "OS");
960 /* Check for attributes that may not be combined */
961 if (OS == O65OS_CC65) {
962 if ((AttrFlags & (atImport | atExport)) != 0 && ModuleId < 0x8000) {
963 CfgError (&CfgErrorPos,
964 "OS type CC65 may not have imports or exports for ids < $8000");
967 if (AttrFlags & atID) {
968 CfgError (&CfgErrorPos,
969 "Operating system does not support the ID attribute");
973 /* Set the O65 operating system to use */
974 O65SetOS (O65FmtDesc, OS, Version, ModuleId);
979 static void ParseFormats (void)
980 /* Parse a target format section */
982 static const IdentTok Formats [] = {
983 { "O65", CFGTOK_O65 },
984 { "BIN", CFGTOK_BIN },
985 { "BINARY", CFGTOK_BIN },
988 while (CfgTok == CFGTOK_IDENT) {
990 /* Map the identifier to a token */
992 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
995 /* Skip the name and the following colon */
999 /* Parse the format options */
1000 switch (FormatTok) {
1007 /* No attribibutes available */
1011 Error ("Unexpected format token");
1014 /* Skip the semicolon */
1019 /* Remember we had this section */
1020 SectionsEncountered |= SE_FORMATS;
1025 static void ParseConDes (void)
1026 /* Parse the CONDES feature */
1028 static const IdentTok Attributes [] = {
1029 { "SEGMENT", CFGTOK_SEGMENT },
1030 { "LABEL", CFGTOK_LABEL },
1031 { "COUNT", CFGTOK_COUNT },
1032 { "TYPE", CFGTOK_TYPE },
1033 { "ORDER", CFGTOK_ORDER },
1036 static const IdentTok Types [] = {
1037 { "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
1038 { "DESTRUCTOR", CFGTOK_DESTRUCTOR },
1039 { "INTERRUPTOR", CFGTOK_INTERRUPTOR },
1042 static const IdentTok Orders [] = {
1043 { "DECREASING", CFGTOK_DECREASING },
1044 { "INCREASING", CFGTOK_INCREASING },
1047 /* Attribute values. */
1048 unsigned SegName = INVALID_STRING_ID;
1049 unsigned Label = INVALID_STRING_ID;
1050 unsigned Count = INVALID_STRING_ID;
1051 /* Initialize to avoid gcc warnings: */
1053 ConDesOrder Order = cdIncreasing;
1055 /* Bitmask to remember the attributes we got already */
1064 unsigned AttrFlags = atNone;
1066 /* Parse the attributes */
1069 /* Map the identifier to a token */
1071 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1074 /* An optional assignment follows */
1076 CfgOptionalAssign ();
1078 /* Check which attribute was given */
1081 case CFGTOK_SEGMENT:
1082 /* Don't allow this twice */
1083 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1084 /* We expect an identifier */
1086 /* Remember the value for later */
1087 SegName = GetStrBufId (&CfgSVal);
1091 /* Don't allow this twice */
1092 FlagAttr (&AttrFlags, atLabel, "LABEL");
1093 /* We expect an identifier */
1095 /* Remember the value for later */
1096 Label = GetStrBufId (&CfgSVal);
1100 /* Don't allow this twice */
1101 FlagAttr (&AttrFlags, atCount, "COUNT");
1102 /* We expect an identifier */
1104 /* Remember the value for later */
1105 Count = GetStrBufId (&CfgSVal);
1109 /* Don't allow this twice */
1110 FlagAttr (&AttrFlags, atType, "TYPE");
1111 /* The type may be given as id or numerical */
1112 if (CfgTok == CFGTOK_INTCON) {
1113 CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1114 Type = (int) CfgIVal;
1116 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1118 case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
1119 case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
1120 case CFGTOK_INTERRUPTOR: Type = CD_TYPE_INT; break;
1121 default: FAIL ("Unexpected type token");
1127 /* Don't allow this twice */
1128 FlagAttr (&AttrFlags, atOrder, "ORDER");
1129 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1131 case CFGTOK_DECREASING: Order = cdDecreasing; break;
1132 case CFGTOK_INCREASING: Order = cdIncreasing; break;
1133 default: FAIL ("Unexpected order token");
1138 FAIL ("Unexpected attribute token");
1142 /* Skip the attribute value */
1145 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1146 if (CfgTok == CFGTOK_SEMI) {
1148 } else if (CfgTok == CFGTOK_COMMA) {
1153 /* Check if we have all mandatory attributes */
1154 AttrCheck (AttrFlags, atSegName, "SEGMENT");
1155 AttrCheck (AttrFlags, atLabel, "LABEL");
1156 AttrCheck (AttrFlags, atType, "TYPE");
1158 /* Check if the condes has already attributes defined */
1159 if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1160 CfgError (&CfgErrorPos,
1161 "CONDES attributes for type %d are already defined",
1165 /* Define the attributes */
1166 ConDesSetSegName (Type, SegName);
1167 ConDesSetLabel (Type, Label);
1168 if (AttrFlags & atCount) {
1169 ConDesSetCountSym (Type, Count);
1171 if (AttrFlags & atOrder) {
1172 ConDesSetOrder (Type, Order);
1178 static void ParseStartAddress (void)
1179 /* Parse the STARTADDRESS feature */
1181 static const IdentTok Attributes [] = {
1182 { "DEFAULT", CFGTOK_DEFAULT },
1186 /* Attribute values. */
1187 unsigned long DefStartAddr = 0;
1189 /* Bitmask to remember the attributes we got already */
1194 unsigned AttrFlags = atNone;
1196 /* Parse the attributes */
1199 /* Map the identifier to a token */
1201 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1204 /* An optional assignment follows */
1206 CfgOptionalAssign ();
1208 /* Check which attribute was given */
1211 case CFGTOK_DEFAULT:
1212 /* Don't allow this twice */
1213 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1214 /* We expect a numeric expression */
1215 DefStartAddr = CfgCheckedConstExpr (0, 0xFFFFFF);
1219 FAIL ("Unexpected attribute token");
1223 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1224 if (CfgTok == CFGTOK_SEMI) {
1226 } else if (CfgTok == CFGTOK_COMMA) {
1231 /* Check if we have all mandatory attributes */
1232 AttrCheck (AttrFlags, atDefault, "DEFAULT");
1234 /* If no start address was given on the command line, use the one given
1237 if (!HaveStartAddr) {
1238 StartAddr = DefStartAddr;
1244 static void ParseFeatures (void)
1245 /* Parse a features section */
1247 static const IdentTok Features [] = {
1248 { "CONDES", CFGTOK_CONDES },
1249 { "STARTADDRESS", CFGTOK_STARTADDRESS },
1252 while (CfgTok == CFGTOK_IDENT) {
1254 /* Map the identifier to a token */
1255 cfgtok_t FeatureTok;
1256 CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1257 FeatureTok = CfgTok;
1259 /* Skip the name and the following colon */
1263 /* Parse the format options */
1264 switch (FeatureTok) {
1270 case CFGTOK_STARTADDRESS:
1271 ParseStartAddress ();
1276 FAIL ("Unexpected feature token");
1279 /* Skip the semicolon */
1283 /* Remember we had this section */
1284 SectionsEncountered |= SE_FEATURES;
1289 static void ParseSymbols (void)
1290 /* Parse a symbols section */
1292 static const IdentTok Attributes[] = {
1293 { "ADDRSIZE", CFGTOK_ADDRSIZE },
1294 { "TYPE", CFGTOK_TYPE },
1295 { "VALUE", CFGTOK_VALUE },
1298 static const IdentTok AddrSizes [] = {
1299 { "ABS", CFGTOK_ABS },
1300 { "ABSOLUTE", CFGTOK_ABS },
1301 { "DIRECT", CFGTOK_ZP },
1302 { "DWORD", CFGTOK_LONG },
1303 { "FAR", CFGTOK_FAR },
1304 { "LONG", CFGTOK_LONG },
1305 { "NEAR", CFGTOK_ABS },
1306 { "ZEROPAGE", CFGTOK_ZP },
1307 { "ZP", CFGTOK_ZP },
1310 static const IdentTok Types [] = {
1311 { "EXPORT", CFGTOK_EXPORT },
1312 { "IMPORT", CFGTOK_IMPORT },
1313 { "WEAK", CFGTOK_WEAK },
1316 while (CfgTok == CFGTOK_IDENT) {
1318 /* Bitmask to remember the attributes we got already */
1321 atAddrSize = 0x0001,
1325 unsigned AttrFlags = atNone;
1327 ExprNode* Value = 0;
1328 CfgSymType Type = CfgSymExport;
1329 unsigned char AddrSize = ADDR_SIZE_ABS;
1334 /* Remember the name */
1335 unsigned Name = GetStrBufId (&CfgSVal);
1338 /* New syntax - skip the colon */
1341 /* Parse the attributes */
1344 /* Map the identifier to a token */
1346 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1349 /* Skip the attribute name */
1352 /* An optional assignment follows */
1353 CfgOptionalAssign ();
1355 /* Check which attribute was given */
1358 case CFGTOK_ADDRSIZE:
1359 /* Don't allow this twice */
1360 FlagAttr (&AttrFlags, atAddrSize, "ADDRSIZE");
1361 /* Map the type to a token */
1362 CfgSpecialToken (AddrSizes, ENTRY_COUNT (AddrSizes), "AddrSize");
1364 case CFGTOK_ABS: AddrSize = ADDR_SIZE_ABS; break;
1365 case CFGTOK_FAR: AddrSize = ADDR_SIZE_FAR; break;
1366 case CFGTOK_LONG: AddrSize = ADDR_SIZE_LONG; break;
1367 case CFGTOK_ZP: AddrSize = ADDR_SIZE_ZP; break;
1369 Internal ("Unexpected token: %d", CfgTok);
1375 /* Don't allow this twice */
1376 FlagAttr (&AttrFlags, atType, "TYPE");
1377 /* Map the type to a token */
1378 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1380 case CFGTOK_EXPORT: Type = CfgSymExport; break;
1381 case CFGTOK_IMPORT: Type = CfgSymImport; break;
1382 case CFGTOK_WEAK: Type = CfgSymWeak; break;
1384 Internal ("Unexpected token: %d", CfgTok);
1390 /* Don't allow this twice */
1391 FlagAttr (&AttrFlags, atValue, "VALUE");
1392 /* Value is an expression */
1397 FAIL ("Unexpected attribute token");
1401 /* Semicolon ends the decl, otherwise accept an optional comma */
1402 if (CfgTok == CFGTOK_SEMI) {
1404 } else if (CfgTok == CFGTOK_COMMA) {
1409 /* We must have a type */
1410 AttrCheck (AttrFlags, atType, "TYPE");
1412 /* Further actions depend on the type */
1416 /* We must have a value */
1417 AttrCheck (AttrFlags, atType, "TYPE");
1418 /* Create the export */
1419 Exp = CreateExprExport (Name, Value, AddrSize);
1420 CollAppend (&Exp->LineInfos, GenLineInfo (&CfgErrorPos));
1424 /* An import must not have a value */
1425 if (AttrFlags & atValue) {
1426 CfgError (&CfgErrorPos, "Imports must not have a value");
1428 /* Generate the import */
1429 Imp = InsertImport (GenImport (Name, AddrSize));
1430 /* Remember the file position */
1431 CollAppend (&Imp->LineInfos, GenLineInfo (&CfgErrorPos));
1435 /* We must have a value */
1436 AttrCheck (AttrFlags, atType, "TYPE");
1437 /* Remember the symbol for later */
1438 Sym = NewCfgSymbol (CfgSymWeak, Name);
1440 Sym->AddrSize = AddrSize;
1444 Internal ("Unexpected symbol type %d", Type);
1447 /* Skip the semicolon */
1451 /* Remember we had this section */
1452 SectionsEncountered |= SE_SYMBOLS;
1457 static void ParseConfig (void)
1458 /* Parse the config file */
1460 static const IdentTok BlockNames [] = {
1461 { "MEMORY", CFGTOK_MEMORY },
1462 { "FILES", CFGTOK_FILES },
1463 { "SEGMENTS", CFGTOK_SEGMENTS },
1464 { "FORMATS", CFGTOK_FORMATS },
1465 { "FEATURES", CFGTOK_FEATURES },
1466 { "SYMBOLS", CFGTOK_SYMBOLS },
1472 /* Read the block ident */
1473 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1477 /* Expected a curly brace */
1478 CfgConsume (CFGTOK_LCURLY, "`{' expected");
1480 /* Read the block */
1491 case CFGTOK_SEGMENTS:
1495 case CFGTOK_FORMATS:
1499 case CFGTOK_FEATURES:
1503 case CFGTOK_SYMBOLS:
1508 FAIL ("Unexpected block token");
1512 /* Skip closing brace */
1513 CfgConsume (CFGTOK_RCURLY, "`}' expected");
1515 } while (CfgTok != CFGTOK_EOF);
1521 /* Read the configuration */
1523 /* Create the descriptors for the binary formats */
1524 BinFmtDesc = NewBinDesc ();
1525 O65FmtDesc = NewO65Desc ();
1527 /* If we have a config name given, open the file, otherwise we will read
1532 /* Parse the file */
1535 /* Close the input file */
1541 /*****************************************************************************/
1542 /* Config file processing */
1543 /*****************************************************************************/
1547 static void ProcessSegments (void)
1548 /* Process the SEGMENTS section */
1552 /* Walk over the list of segment descriptors */
1554 while (I < CollCount (&SegDescList)) {
1556 /* Get the next segment descriptor */
1557 SegDesc* S = CollAtUnchecked (&SegDescList, I);
1559 /* Search for the actual segment in the input files. The function may
1560 * return NULL (no such segment), this is checked later.
1562 S->Seg = SegFind (S->Name);
1564 /* If the segment is marked as BSS style, and if the segment exists
1565 * in any of the object file, check that there's no initialized data
1568 if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
1569 CfgWarning (GetSourcePos (S->LI),
1570 "Segment `%s' with type `bss' contains initialized data",
1571 GetString (S->Name));
1574 /* If this segment does exist in any of the object files, insert the
1575 * segment into the load/run memory areas. Otherwise print a warning
1576 * and discard it, because the segment pointer in the descriptor is
1581 /* Insert the segment into the memory area list */
1582 MemoryInsert (S->Run, S);
1583 if (S->Load != S->Run) {
1584 /* We have separate RUN and LOAD areas */
1585 MemoryInsert (S->Load, S);
1588 /* Process the next segment descriptor in the next run */
1593 /* Print a warning if the segment is not optional */
1594 if ((S->Flags & SF_OPTIONAL) == 0) {
1595 CfgWarning (&CfgErrorPos,
1596 "Segment `%s' does not exist",
1597 GetString (S->Name));
1600 /* Discard the descriptor and remove it from the collection */
1602 CollDelete (&SegDescList, I);
1609 static void ProcessSymbols (void)
1610 /* Process the SYMBOLS section */
1614 /* Walk over all symbols */
1616 for (I = 0; I < CollCount (&CfgSymbols); ++I) {
1618 /* Get the next symbol */
1619 CfgSymbol* Sym = CollAtUnchecked (&CfgSymbols, I);
1621 /* Check what it is. */
1622 switch (Sym->Type) {
1624 case CfgSymO65Export:
1625 /* Check if the export symbol is also defined as an import. */
1626 if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1628 GetSourcePos (Sym->LI),
1629 "Exported o65 symbol `%s' cannot also be an o65 import",
1630 GetString (Sym->Name)
1634 /* Check if we have this symbol defined already. The entry
1635 * routine will check this also, but we get a more verbose
1636 * error message when checking it here.
1638 if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
1640 GetSourcePos (Sym->LI),
1641 "Duplicate exported o65 symbol: `%s'",
1642 GetString (Sym->Name)
1646 /* Insert the symbol into the table */
1647 O65SetExport (O65FmtDesc, Sym->Name);
1650 case CfgSymO65Import:
1651 /* Check if the import symbol is also defined as an export. */
1652 if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
1654 GetSourcePos (Sym->LI),
1655 "Imported o65 symbol `%s' cannot also be an o65 export",
1656 GetString (Sym->Name)
1660 /* Check if we have this symbol defined already. The entry
1661 * routine will check this also, but we get a more verbose
1662 * error message when checking it here.
1664 if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1666 GetSourcePos (Sym->LI),
1667 "Duplicate imported o65 symbol: `%s'",
1668 GetString (Sym->Name)
1672 /* Insert the symbol into the table */
1673 O65SetImport (O65FmtDesc, Sym->Name);
1677 /* If the symbol is not defined until now, define it */
1678 if ((E = FindExport (Sym->Name)) == 0 || IsUnresolvedExport (E)) {
1679 /* The symbol is undefined, generate an export */
1680 E = CreateExprExport (Sym->Name, Sym->Value, Sym->AddrSize);
1681 CollAppend (&E->LineInfos, Sym->LI);
1686 Internal ("Unexpected symbol type %d", Sym->Type);
1695 static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
1696 /* Create the defines for a RUN segment */
1699 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1701 /* Define the run address of the segment */
1702 SB_Printf (&Buf, "__%s_RUN__", GetString (S->Name));
1703 E = CreateMemoryExport (GetStrBufId (&Buf), S->Run, SegAddr - S->Run->Start);
1704 CollAppend (&E->LineInfos, S->LI);
1706 /* Define the size of the segment */
1707 SB_Printf (&Buf, "__%s_SIZE__", GetString (S->Name));
1708 E = CreateConstExport (GetStrBufId (&Buf), S->Seg->Size);
1709 CollAppend (&E->LineInfos, S->LI);
1711 S->Flags |= SF_RUN_DEF;
1717 static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
1718 /* Create the defines for a LOAD segment */
1721 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1723 /* Define the load address of the segment */
1724 SB_Printf (&Buf, "__%s_LOAD__", GetString (S->Name));
1725 E = CreateMemoryExport (GetStrBufId (&Buf), S->Load, SegAddr - S->Load->Start);
1726 CollAppend (&E->LineInfos, S->LI);
1728 S->Flags |= SF_LOAD_DEF;
1734 unsigned CfgProcess (void)
1735 /* Process the config file after reading in object files and libraries. This
1736 * includes postprocessing of the config file data but also assigning segments
1737 * and defining segment/memory area related symbols. The function will return
1738 * the number of memory area overflows (so zero means anything went ok).
1739 * In case of overflows, a short mapfile can be generated later, to ease the
1740 * task of rearranging segments for the user.
1743 unsigned Overflows = 0;
1746 /* Postprocess symbols. We must do that first, since weak symbols are
1747 * defined here, which may be needed later.
1751 /* Postprocess segments */
1754 /* Walk through each of the memory sections. Add up the sizes and check
1755 * for an overflow of the section. Assign the start addresses of the
1756 * segments while doing this.
1758 for (I = 0; I < CollCount (&MemoryAreas); ++I) {
1763 /* Get the next memory area */
1764 MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
1766 /* Remember if this is a relocatable memory area */
1767 M->Relocatable = RelocatableBinFmt (M->F->Format);
1769 /* Resolve the start address expression, remember the start address
1770 * and mark the memory area as placed.
1772 if (!IsConstExpr (M->StartExpr)) {
1773 CfgError (GetSourcePos (M->LI),
1774 "Start address of memory area `%s' is not constant",
1775 GetString (M->Name));
1777 Addr = M->Start = GetExprVal (M->StartExpr);
1778 M->Flags |= MF_PLACED;
1780 /* If requested, define the symbol for the start of the memory area.
1781 * Doing it here means that the expression for the size of the area
1782 * may reference this symbol.
1784 if (M->Flags & MF_DEFINE) {
1786 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1788 /* Define the start of the memory area */
1789 SB_Printf (&Buf, "__%s_START__", GetString (M->Name));
1790 E = CreateMemoryExport (GetStrBufId (&Buf), M, 0);
1791 CollAppend (&E->LineInfos, M->LI);
1796 /* Resolve the size expression */
1797 if (!IsConstExpr (M->SizeExpr)) {
1798 CfgError (GetSourcePos (M->LI),
1799 "Size of memory area `%s' is not constant",
1800 GetString (M->Name));
1802 M->Size = GetExprVal (M->SizeExpr);
1804 /* Walk through the segments in this memory area */
1805 for (J = 0; J < CollCount (&M->SegList); ++J) {
1807 /* Get the segment */
1808 SegDesc* S = CollAtUnchecked (&M->SegList, J);
1810 /* Some actions depend on wether this is the load or run memory
1815 /* This is the run (and maybe load) memory area. Handle
1816 * alignment and explict start address and offset.
1818 if (S->Flags & SF_ALIGN) {
1819 /* Align the address */
1820 unsigned long Val = (0x01UL << S->Align) - 1;
1821 Addr = (Addr + Val) & ~Val;
1822 } else if (S->Flags & (SF_OFFSET | SF_START)) {
1823 /* Give the segment a fixed starting address */
1824 unsigned long NewAddr = S->Addr;
1825 if (S->Flags & SF_OFFSET) {
1826 /* An offset was given, no address, make an address */
1827 NewAddr += M->Start;
1829 if (Addr > NewAddr) {
1830 /* Offset already too large */
1831 if (S->Flags & SF_OFFSET) {
1832 CfgError (GetSourcePos (M->LI),
1833 "Offset too small in `%s', segment `%s'",
1834 GetString (M->Name),
1835 GetString (S->Name));
1837 CfgError (GetSourcePos (M->LI),
1838 "Start address too low in `%s', segment `%s'",
1839 GetString (M->Name),
1840 GetString (S->Name));
1846 /* Set the start address of this segment, set the readonly flag
1847 * in the segment and and remember if the segment is in a
1848 * relocatable file or not.
1851 S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
1852 S->Seg->Relocatable = M->Relocatable;
1854 /* Remember that this segment is placed */
1857 } else if (S->Load == M) {
1859 /* This is the load memory area, *and* run and load are
1860 * different (because of the "else" above). Handle alignment.
1862 if (S->Flags & SF_ALIGN_LOAD) {
1863 /* Align the address */
1864 unsigned long Val = (0x01UL << S->AlignLoad) - 1;
1865 Addr = (Addr + Val) & ~Val;
1870 /* Increment the fill level of the memory area and check for an
1873 M->FillLevel = Addr + S->Seg->Size - M->Start;
1874 if (M->FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) {
1876 M->Flags |= MF_OVERFLOW;
1877 CfgWarning (GetSourcePos (M->LI),
1878 "Memory area overflow in `%s', segment `%s' (%lu bytes)",
1879 GetString (M->Name), GetString (S->Name),
1880 M->FillLevel - M->Size);
1883 /* If requested, define symbols for the start and size of the
1886 if (S->Flags & SF_DEFINE) {
1887 if (S->Run == M && (S->Flags & SF_RUN_DEF) == 0) {
1888 CreateRunDefines (S, Addr);
1890 if (S->Load == M && (S->Flags & SF_LOAD_DEF) == 0) {
1891 CreateLoadDefines (S, Addr);
1895 /* Calculate the new address */
1896 Addr += S->Seg->Size;
1900 /* If requested, define symbols for start and size of the memory area */
1901 if (M->Flags & MF_DEFINE) {
1903 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1905 /* Define the size of the memory area */
1906 SB_Printf (&Buf, "__%s_SIZE__", GetString (M->Name));
1907 E = CreateConstExport (GetStrBufId (&Buf), M->Size);
1908 CollAppend (&E->LineInfos, M->LI);
1910 /* Define the fill level of the memory area */
1911 SB_Printf (&Buf, "__%s_LAST__", GetString (M->Name));
1912 E = CreateMemoryExport (GetStrBufId (&Buf), M, M->FillLevel);
1913 CollAppend (&E->LineInfos, M->LI);
1920 /* Return the number of memory area overflows */
1926 void CfgWriteTarget (void)
1927 /* Write the target file(s) */
1931 /* Walk through the files list */
1932 for (I = 0; I < CollCount (&FileList); ++I) {
1934 /* Get this entry */
1935 File* F = CollAtUnchecked (&FileList, I);
1937 /* We don't need to look at files with no memory areas */
1938 if (CollCount (&F->MemoryAreas) > 0) {
1940 /* Is there an output file? */
1941 if (SB_GetLen (GetStrBuf (F->Name)) > 0) {
1943 /* Assign a proper binary format */
1944 if (F->Format == BINFMT_DEFAULT) {
1945 F->Format = DefaultBinFmt;
1948 /* Call the apropriate routine for the binary format */
1949 switch (F->Format) {
1952 BinWriteTarget (BinFmtDesc, F);
1956 O65WriteTarget (O65FmtDesc, F);
1960 Internal ("Invalid binary format: %u", F->Format);
1966 /* No output file. Walk through the list and mark all segments
1967 * loading into these memory areas in this file as dumped.
1970 for (J = 0; J < CollCount (&F->MemoryAreas); ++J) {
1974 /* Get this entry */
1975 MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, J);
1978 Print (stdout, 2, "Skipping `%s'...\n", GetString (M->Name));
1980 /* Walk throught the segments */
1981 for (K = 0; K < CollCount (&M->SegList); ++K) {
1982 SegDesc* S = CollAtUnchecked (&M->SegList, K);
1984 /* Load area - mark the segment as dumped */