1 /*****************************************************************************/
5 /* Target configuration file for the ld65 linker */
9 /* (C) 1998-2011, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
14 /* With contributions from: */
16 /* - "David M. Lloyd" <david.lloyd@redhat.com> */
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. */
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: */
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 */
36 /*****************************************************************************/
54 #include "alignment.h"
72 /*****************************************************************************/
74 /*****************************************************************************/
78 /* Remember which sections we had encountered */
87 } SectionsEncountered = SE_NONE;
92 static Collection FileList = STATIC_COLLECTION_INITIALIZER;
95 static Collection MemoryAreas = STATIC_COLLECTION_INITIALIZER;
97 /* Memory attributes */
98 #define MA_START 0x0001
99 #define MA_SIZE 0x0002
100 #define MA_TYPE 0x0004
101 #define MA_FILE 0x0008
102 #define MA_DEFINE 0x0010
103 #define MA_FILL 0x0020
104 #define MA_FILLVAL 0x0040
107 static Collection SegDescList = STATIC_COLLECTION_INITIALIZER;
109 /* Segment attributes */
110 #define SA_TYPE 0x0001
111 #define SA_LOAD 0x0002
112 #define SA_RUN 0x0004
113 #define SA_ALIGN 0x0008
114 #define SA_ALIGN_LOAD 0x0010
115 #define SA_DEFINE 0x0020
116 #define SA_OFFSET 0x0040
117 #define SA_START 0x0080
118 #define SA_OPTIONAL 0x0100
120 /* Symbol types used in the CfgSymbol structure */
122 CfgSymExport, /* Not really used in struct CfgSymbol */
123 CfgSymImport, /* Dito */
124 CfgSymWeak, /* Like export but weak */
125 CfgSymO65Export, /* An o65 export */
126 CfgSymO65Import, /* An o65 import */
129 /* Symbol structure. It is used for o65 imports and exports, but also for
130 * symbols from the SYMBOLS sections (symbols defined in the config file or
133 typedef struct CfgSymbol CfgSymbol;
135 CfgSymType Type; /* Type of symbol */
136 LineInfo* LI; /* Config file position */
137 unsigned Name; /* Symbol name */
138 ExprNode* Value; /* Symbol value if any */
139 unsigned AddrSize; /* Address size of symbol */
142 /* Collections with symbols */
143 static Collection CfgSymbols = STATIC_COLLECTION_INITIALIZER;
145 /* Descriptor holding information about the binary formats */
146 static BinDesc* BinFmtDesc = 0;
147 static O65Desc* O65FmtDesc = 0;
151 /*****************************************************************************/
153 /*****************************************************************************/
157 static File* NewFile (unsigned Name);
158 /* Create a new file descriptor and insert it into the list */
162 /*****************************************************************************/
163 /* List management */
164 /*****************************************************************************/
168 static File* FindFile (unsigned Name)
169 /* Find a file with a given name. */
172 for (I = 0; I < CollCount (&FileList); ++I) {
173 File* F = CollAtUnchecked (&FileList, I);
174 if (F->Name == Name) {
183 static File* GetFile (unsigned Name)
184 /* Get a file entry with the given name. Create a new one if needed. */
186 File* F = FindFile (Name);
188 /* Create a new one */
196 static void FileInsert (File* F, MemoryArea* M)
197 /* Insert the memory area into the files list */
200 CollAppend (&F->MemoryAreas, M);
205 static MemoryArea* CfgFindMemory (unsigned Name)
206 /* Find the memory are with the given name. Return NULL if not found */
209 for (I = 0; I < CollCount (&MemoryAreas); ++I) {
210 MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
211 if (M->Name == Name) {
220 static MemoryArea* CfgGetMemory (unsigned Name)
221 /* Find the memory are with the given name. Print an error on an invalid name */
223 MemoryArea* M = CfgFindMemory (Name);
225 CfgError (&CfgErrorPos, "Invalid memory area `%s'", GetString (Name));
232 static SegDesc* CfgFindSegDesc (unsigned Name)
233 /* Find the segment descriptor with the given name, return NULL if not found. */
236 for (I = 0; I < CollCount (&SegDescList); ++I) {
237 SegDesc* S = CollAtUnchecked (&SegDescList, I);
238 if (S->Name == Name) {
250 static void MemoryInsert (MemoryArea* M, SegDesc* S)
251 /* Insert the segment descriptor into the memory area list */
253 /* Insert the segment into the segment list of the memory area */
254 CollAppend (&M->SegList, S);
259 /*****************************************************************************/
260 /* Constructors/Destructors */
261 /*****************************************************************************/
265 static CfgSymbol* NewCfgSymbol (CfgSymType Type, unsigned Name)
266 /* Create a new CfgSymbol structure with the given type and name. The
267 * current config file position is recorded in the returned struct. The
268 * created struct is inserted into the CfgSymbols collection and returned.
271 /* Allocate memory */
272 CfgSymbol* Sym = xmalloc (sizeof (CfgSymbol));
274 /* Initialize the fields */
276 Sym->LI = GenLineInfo (&CfgErrorPos);
279 Sym->AddrSize = ADDR_SIZE_INVALID;
281 /* Insert the symbol into the collection */
282 CollAppend (&CfgSymbols, Sym);
284 /* Return the initialized struct */
290 static File* NewFile (unsigned Name)
291 /* Create a new file descriptor and insert it into the list */
293 /* Allocate memory */
294 File* F = xmalloc (sizeof (File));
296 /* Initialize the fields */
299 F->Format = BINFMT_DEFAULT;
301 InitCollection (&F->MemoryAreas);
303 /* Insert the struct into the list */
304 CollAppend (&FileList, F);
306 /* ...and return it */
312 static MemoryArea* CreateMemoryArea (const FilePos* Pos, unsigned Name)
313 /* Create a new memory area and insert it into the list */
315 /* Check for duplicate names */
316 MemoryArea* M = CfgFindMemory (Name);
318 CfgError (&CfgErrorPos,
319 "Memory area `%s' defined twice",
323 /* Create a new memory area */
324 M = NewMemoryArea (Pos, Name);
326 /* Insert the struct into the list ... */
327 CollAppend (&MemoryAreas, M);
329 /* ...and return it */
335 static SegDesc* NewSegDesc (unsigned Name)
336 /* Create a segment descriptor and insert it into the list */
339 /* Check for duplicate names */
340 SegDesc* S = CfgFindSegDesc (Name);
342 CfgError (&CfgErrorPos, "Segment `%s' defined twice", GetString (Name));
345 /* Allocate memory */
346 S = xmalloc (sizeof (SegDesc));
348 /* Initialize the fields */
350 S->LI = GenLineInfo (&CfgErrorPos);
355 S->LoadAlignment = 1;
357 /* Insert the struct into the list ... */
358 CollAppend (&SegDescList, S);
360 /* ...and return it */
366 static void FreeSegDesc (SegDesc* S)
367 /* Free a segment descriptor */
369 FreeLineInfo (S->LI);
375 /*****************************************************************************/
376 /* Config file parsing */
377 /*****************************************************************************/
381 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
382 /* Check if the item is already defined. Print an error if so. If not, set
383 * the marker that we have a definition now.
387 CfgError (&CfgErrorPos, "%s is already defined", Name);
394 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
395 /* Check that a mandatory attribute was given */
397 if ((Attr & Mask) == 0) {
398 CfgError (&CfgErrorPos, "%s attribute is missing", Name);
404 static void ParseMemory (void)
405 /* Parse a MEMORY section */
407 static const IdentTok Attributes [] = {
408 { "START", CFGTOK_START },
409 { "SIZE", CFGTOK_SIZE },
410 { "TYPE", CFGTOK_TYPE },
411 { "FILE", CFGTOK_FILE },
412 { "DEFINE", CFGTOK_DEFINE },
413 { "FILL", CFGTOK_FILL },
414 { "FILLVAL", CFGTOK_FILLVAL },
416 static const IdentTok Types [] = {
421 while (CfgTok == CFGTOK_IDENT) {
423 /* Create a new entry on the heap */
424 MemoryArea* M = CreateMemoryArea (&CfgErrorPos, GetStrBufId (&CfgSVal));
426 /* Skip the name and the following colon */
430 /* Read the attributes */
431 while (CfgTok == CFGTOK_IDENT) {
433 /* Map the identifier to a token */
435 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
438 /* An optional assignment follows */
440 CfgOptionalAssign ();
442 /* Check which attribute was given */
446 FlagAttr (&M->Attr, MA_START, "START");
447 M->StartExpr = CfgExpr ();
451 FlagAttr (&M->Attr, MA_SIZE, "SIZE");
452 M->SizeExpr = CfgExpr ();
456 FlagAttr (&M->Attr, MA_TYPE, "TYPE");
457 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
458 if (CfgTok == CFGTOK_RO) {
465 FlagAttr (&M->Attr, MA_FILE, "FILE");
467 /* Get the file entry and insert the memory area */
468 FileInsert (GetFile (GetStrBufId (&CfgSVal)), M);
473 FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
474 /* Map the token to a boolean */
476 if (CfgTok == CFGTOK_TRUE) {
477 M->Flags |= MF_DEFINE;
483 FlagAttr (&M->Attr, MA_FILL, "FILL");
484 /* Map the token to a boolean */
486 if (CfgTok == CFGTOK_TRUE) {
493 FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
494 M->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
498 FAIL ("Unexpected attribute token");
502 /* Skip an optional comma */
506 /* Skip the semicolon */
509 /* Check for mandatory parameters */
510 AttrCheck (M->Attr, MA_START, "START");
511 AttrCheck (M->Attr, MA_SIZE, "SIZE");
513 /* If we don't have a file name for output given, use the default
516 if ((M->Attr & MA_FILE) == 0) {
517 FileInsert (GetFile (GetStringId (OutputName)), M);
522 /* Remember we had this section */
523 SectionsEncountered |= SE_MEMORY;
528 static void ParseFiles (void)
529 /* Parse a FILES section */
531 static const IdentTok Attributes [] = {
532 { "FORMAT", CFGTOK_FORMAT },
534 static const IdentTok Formats [] = {
535 { "O65", CFGTOK_O65 },
536 { "BIN", CFGTOK_BIN },
537 { "BINARY", CFGTOK_BIN },
541 /* The MEMORY section must preceed the FILES section */
542 if ((SectionsEncountered & SE_MEMORY) == 0) {
543 CfgError (&CfgErrorPos, "MEMORY must precede FILES");
546 /* Parse all files */
547 while (CfgTok != CFGTOK_RCURLY) {
551 /* We expect a string value here */
554 /* Search for the file, it must exist */
555 F = FindFile (GetStrBufId (&CfgSVal));
557 CfgError (&CfgErrorPos,
558 "File `%s' not found in MEMORY section",
559 SB_GetConstBuf (&CfgSVal));
562 /* Skip the token and the following colon */
566 /* Read the attributes */
567 while (CfgTok == CFGTOK_IDENT) {
569 /* Map the identifier to a token */
571 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
574 /* An optional assignment follows */
576 CfgOptionalAssign ();
578 /* Check which attribute was given */
582 if (F->Format != BINFMT_DEFAULT) {
583 /* We've set the format already! */
584 CfgError (&CfgErrorPos,
585 "Cannot set a file format twice");
587 /* Read the format token */
588 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
592 F->Format = BINFMT_BINARY;
596 F->Format = BINFMT_O65;
600 Error ("Unexpected format token");
605 FAIL ("Unexpected attribute token");
609 /* Skip the attribute value and an optional comma */
614 /* Skip the semicolon */
619 /* Remember we had this section */
620 SectionsEncountered |= SE_FILES;
625 static void ParseSegments (void)
626 /* Parse a SEGMENTS section */
628 static const IdentTok Attributes [] = {
629 { "ALIGN", CFGTOK_ALIGN },
630 { "ALIGN_LOAD", CFGTOK_ALIGN_LOAD },
631 { "DEFINE", CFGTOK_DEFINE },
632 { "LOAD", CFGTOK_LOAD },
633 { "OFFSET", CFGTOK_OFFSET },
634 { "OPTIONAL", CFGTOK_OPTIONAL },
635 { "RUN", CFGTOK_RUN },
636 { "START", CFGTOK_START },
637 { "TYPE", CFGTOK_TYPE },
639 static const IdentTok Types [] = {
642 { "BSS", CFGTOK_BSS },
648 /* The MEMORY section must preceed the SEGMENTS section */
649 if ((SectionsEncountered & SE_MEMORY) == 0) {
650 CfgError (&CfgErrorPos, "MEMORY must precede SEGMENTS");
653 while (CfgTok == CFGTOK_IDENT) {
657 /* Create a new entry on the heap */
658 S = NewSegDesc (GetStrBufId (&CfgSVal));
660 /* Skip the name and the following colon */
664 /* Read the attributes */
665 while (CfgTok == CFGTOK_IDENT) {
667 /* Map the identifier to a token */
669 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
672 /* An optional assignment follows */
674 CfgOptionalAssign ();
676 /* Check which attribute was given */
680 FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
681 S->RunAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
682 S->Flags |= SF_ALIGN;
685 case CFGTOK_ALIGN_LOAD:
686 FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
687 S->LoadAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
688 S->Flags |= SF_ALIGN_LOAD;
692 FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
693 /* Map the token to a boolean */
695 if (CfgTok == CFGTOK_TRUE) {
696 S->Flags |= SF_DEFINE;
702 FlagAttr (&S->Attr, SA_LOAD, "LOAD");
703 S->Load = CfgGetMemory (GetStrBufId (&CfgSVal));
708 FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
709 S->Addr = CfgCheckedConstExpr (1, 0x1000000);
710 S->Flags |= SF_OFFSET;
713 case CFGTOK_OPTIONAL:
714 FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL");
716 if (CfgTok == CFGTOK_TRUE) {
717 S->Flags |= SF_OPTIONAL;
723 FlagAttr (&S->Attr, SA_RUN, "RUN");
724 S->Run = CfgGetMemory (GetStrBufId (&CfgSVal));
729 FlagAttr (&S->Attr, SA_START, "START");
730 S->Addr = CfgCheckedConstExpr (1, 0x1000000);
731 S->Flags |= SF_START;
735 FlagAttr (&S->Attr, SA_TYPE, "TYPE");
736 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
738 case CFGTOK_RO: S->Flags |= SF_RO; break;
739 case CFGTOK_RW: /* Default */ break;
740 case CFGTOK_BSS: S->Flags |= SF_BSS; break;
741 case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break;
742 default: Internal ("Unexpected token: %d", CfgTok);
748 FAIL ("Unexpected attribute token");
752 /* Skip an optional comma */
756 /* Check for mandatory parameters */
757 AttrCheck (S->Attr, SA_LOAD, "LOAD");
759 /* Set defaults for stuff not given */
760 if ((S->Attr & SA_RUN) == 0) {
765 /* An attribute of ALIGN_LOAD doesn't make sense if there are no
766 * separate run and load memory areas.
768 if ((S->Flags & SF_ALIGN_LOAD) != 0 && (S->Load == S->Run)) {
769 CfgWarning (&CfgErrorPos,
770 "ALIGN_LOAD attribute specified, but no separate "
771 "LOAD and RUN memory areas assigned");
772 /* Remove the flag */
773 S->Flags &= ~SF_ALIGN_LOAD;
776 /* If the segment is marked as BSS style, it may not have separate
777 * load and run memory areas, because it's is never written to disk.
779 if ((S->Flags & SF_BSS) != 0 && (S->Load != S->Run)) {
780 CfgWarning (&CfgErrorPos,
781 "Segment with type `bss' has both LOAD and RUN "
782 "memory areas assigned");
785 /* Don't allow read/write data to be put into a readonly area */
786 if ((S->Flags & SF_RO) == 0) {
787 if (S->Run->Flags & MF_RO) {
788 CfgError (&CfgErrorPos,
789 "Cannot put r/w segment `%s' in r/o memory area `%s'",
790 GetString (S->Name), GetString (S->Run->Name));
794 /* Only one of ALIGN, START and OFFSET may be used */
795 Count = ((S->Flags & SF_ALIGN) != 0) +
796 ((S->Flags & SF_OFFSET) != 0) +
797 ((S->Flags & SF_START) != 0);
799 CfgError (&CfgErrorPos,
800 "Only one of ALIGN, START, OFFSET may be used");
803 /* Skip the semicolon */
807 /* Remember we had this section */
808 SectionsEncountered |= SE_SEGMENTS;
813 static void ParseO65 (void)
814 /* Parse the o65 format section */
816 static const IdentTok Attributes [] = {
817 { "EXPORT", CFGTOK_EXPORT },
818 { "IMPORT", CFGTOK_IMPORT },
819 { "TYPE", CFGTOK_TYPE },
822 { "VERSION", CFGTOK_VERSION },
824 static const IdentTok Types [] = {
825 { "SMALL", CFGTOK_SMALL },
826 { "LARGE", CFGTOK_LARGE },
828 static const IdentTok OperatingSystems [] = {
829 { "LUNIX", CFGTOK_LUNIX },
830 { "OSA65", CFGTOK_OSA65 },
831 { "CC65", CFGTOK_CC65 },
832 { "OPENCBM", CFGTOK_OPENCBM },
835 /* Bitmask to remember the attributes we got already */
839 atOSVersion = 0x0002,
846 unsigned AttrFlags = atNone;
848 /* Remember the attributes read */
849 unsigned OS = 0; /* Initialize to keep gcc happy */
850 unsigned Version = 0;
852 /* Read the attributes */
853 while (CfgTok == CFGTOK_IDENT) {
855 /* Map the identifier to a token */
857 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
860 /* An optional assignment follows */
862 CfgOptionalAssign ();
864 /* Check which attribute was given */
868 /* Remember we had this token (maybe more than once) */
869 AttrFlags |= atExport;
870 /* We expect an identifier */
872 /* Remember it as an export for later */
873 NewCfgSymbol (CfgSymO65Export, GetStrBufId (&CfgSVal));
874 /* Eat the identifier token */
879 /* Remember we had this token (maybe more than once) */
880 AttrFlags |= atImport;
881 /* We expect an identifier */
883 /* Remember it as an import for later */
884 NewCfgSymbol (CfgSymO65Import, GetStrBufId (&CfgSVal));
885 /* Eat the identifier token */
890 /* Cannot have this attribute twice */
891 FlagAttr (&AttrFlags, atType, "TYPE");
892 /* Get the type of the executable */
893 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
897 O65SetSmallModel (O65FmtDesc);
901 O65SetLargeModel (O65FmtDesc);
905 CfgError (&CfgErrorPos, "Unexpected type token");
907 /* Eat the attribute token */
912 /* Cannot use this attribute twice */
913 FlagAttr (&AttrFlags, atOS, "OS");
914 /* Get the operating system. It may be specified as name or
915 * as a number in the range 1..255.
917 if (CfgTok == CFGTOK_INTCON) {
918 CfgRangeCheck (O65OS_MIN, O65OS_MAX);
919 OS = (unsigned) CfgIVal;
921 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
923 case CFGTOK_LUNIX: OS = O65OS_LUNIX; break;
924 case CFGTOK_OSA65: OS = O65OS_OSA65; break;
925 case CFGTOK_CC65: OS = O65OS_CC65; break;
926 case CFGTOK_OPENCBM: OS = O65OS_OPENCBM; break;
927 default: CfgError (&CfgErrorPos, "Unexpected OS token");
934 /* Cannot have this attribute twice */
935 FlagAttr (&AttrFlags, atID, "ID");
936 /* We're expecting a number in the 0..$FFFF range*/
937 ModuleId = (unsigned) CfgCheckedConstExpr (0, 0xFFFF);
941 /* Cannot have this attribute twice */
942 FlagAttr (&AttrFlags, atVersion, "VERSION");
943 /* We're expecting a number in byte range */
944 Version = (unsigned) CfgCheckedConstExpr (0, 0xFF);
948 FAIL ("Unexpected attribute token");
952 /* Skip an optional comma */
956 /* Check if we have all mandatory attributes */
957 AttrCheck (AttrFlags, atOS, "OS");
959 /* Check for attributes that may not be combined */
960 if (OS == O65OS_CC65) {
961 if ((AttrFlags & (atImport | atExport)) != 0 && ModuleId < 0x8000) {
962 CfgError (&CfgErrorPos,
963 "OS type CC65 may not have imports or exports for ids < $8000");
966 if (AttrFlags & atID) {
967 CfgError (&CfgErrorPos,
968 "Operating system does not support the ID attribute");
972 /* Set the O65 operating system to use */
973 O65SetOS (O65FmtDesc, OS, Version, ModuleId);
978 static void ParseFormats (void)
979 /* Parse a target format section */
981 static const IdentTok Formats [] = {
982 { "O65", CFGTOK_O65 },
983 { "BIN", CFGTOK_BIN },
984 { "BINARY", CFGTOK_BIN },
987 while (CfgTok == CFGTOK_IDENT) {
989 /* Map the identifier to a token */
991 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
994 /* Skip the name and the following colon */
998 /* Parse the format options */
1006 /* No attribibutes available */
1010 Error ("Unexpected format token");
1013 /* Skip the semicolon */
1018 /* Remember we had this section */
1019 SectionsEncountered |= SE_FORMATS;
1024 static void ParseConDes (void)
1025 /* Parse the CONDES feature */
1027 static const IdentTok Attributes [] = {
1028 { "SEGMENT", CFGTOK_SEGMENT },
1029 { "LABEL", CFGTOK_LABEL },
1030 { "COUNT", CFGTOK_COUNT },
1031 { "TYPE", CFGTOK_TYPE },
1032 { "ORDER", CFGTOK_ORDER },
1035 static const IdentTok Types [] = {
1036 { "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
1037 { "DESTRUCTOR", CFGTOK_DESTRUCTOR },
1038 { "INTERRUPTOR", CFGTOK_INTERRUPTOR },
1041 static const IdentTok Orders [] = {
1042 { "DECREASING", CFGTOK_DECREASING },
1043 { "INCREASING", CFGTOK_INCREASING },
1046 /* Attribute values. */
1047 unsigned SegName = INVALID_STRING_ID;
1048 unsigned Label = INVALID_STRING_ID;
1049 unsigned Count = INVALID_STRING_ID;
1050 /* Initialize to avoid gcc warnings: */
1052 ConDesOrder Order = cdIncreasing;
1054 /* Bitmask to remember the attributes we got already */
1063 unsigned AttrFlags = atNone;
1065 /* Parse the attributes */
1068 /* Map the identifier to a token */
1070 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1073 /* An optional assignment follows */
1075 CfgOptionalAssign ();
1077 /* Check which attribute was given */
1080 case CFGTOK_SEGMENT:
1081 /* Don't allow this twice */
1082 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1083 /* We expect an identifier */
1085 /* Remember the value for later */
1086 SegName = GetStrBufId (&CfgSVal);
1090 /* Don't allow this twice */
1091 FlagAttr (&AttrFlags, atLabel, "LABEL");
1092 /* We expect an identifier */
1094 /* Remember the value for later */
1095 Label = GetStrBufId (&CfgSVal);
1099 /* Don't allow this twice */
1100 FlagAttr (&AttrFlags, atCount, "COUNT");
1101 /* We expect an identifier */
1103 /* Remember the value for later */
1104 Count = GetStrBufId (&CfgSVal);
1108 /* Don't allow this twice */
1109 FlagAttr (&AttrFlags, atType, "TYPE");
1110 /* The type may be given as id or numerical */
1111 if (CfgTok == CFGTOK_INTCON) {
1112 CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1113 Type = (int) CfgIVal;
1115 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1117 case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
1118 case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
1119 case CFGTOK_INTERRUPTOR: Type = CD_TYPE_INT; break;
1120 default: FAIL ("Unexpected type token");
1126 /* Don't allow this twice */
1127 FlagAttr (&AttrFlags, atOrder, "ORDER");
1128 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1130 case CFGTOK_DECREASING: Order = cdDecreasing; break;
1131 case CFGTOK_INCREASING: Order = cdIncreasing; break;
1132 default: FAIL ("Unexpected order token");
1137 FAIL ("Unexpected attribute token");
1141 /* Skip the attribute value */
1144 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1145 if (CfgTok == CFGTOK_SEMI) {
1147 } else if (CfgTok == CFGTOK_COMMA) {
1152 /* Check if we have all mandatory attributes */
1153 AttrCheck (AttrFlags, atSegName, "SEGMENT");
1154 AttrCheck (AttrFlags, atLabel, "LABEL");
1155 AttrCheck (AttrFlags, atType, "TYPE");
1157 /* Check if the condes has already attributes defined */
1158 if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1159 CfgError (&CfgErrorPos,
1160 "CONDES attributes for type %d are already defined",
1164 /* Define the attributes */
1165 ConDesSetSegName (Type, SegName);
1166 ConDesSetLabel (Type, Label);
1167 if (AttrFlags & atCount) {
1168 ConDesSetCountSym (Type, Count);
1170 if (AttrFlags & atOrder) {
1171 ConDesSetOrder (Type, Order);
1177 static void ParseStartAddress (void)
1178 /* Parse the STARTADDRESS feature */
1180 static const IdentTok Attributes [] = {
1181 { "DEFAULT", CFGTOK_DEFAULT },
1185 /* Attribute values. */
1186 unsigned long DefStartAddr = 0;
1188 /* Bitmask to remember the attributes we got already */
1193 unsigned AttrFlags = atNone;
1195 /* Parse the attributes */
1198 /* Map the identifier to a token */
1200 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1203 /* An optional assignment follows */
1205 CfgOptionalAssign ();
1207 /* Check which attribute was given */
1210 case CFGTOK_DEFAULT:
1211 /* Don't allow this twice */
1212 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1213 /* We expect a numeric expression */
1214 DefStartAddr = CfgCheckedConstExpr (0, 0xFFFFFF);
1218 FAIL ("Unexpected attribute token");
1222 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1223 if (CfgTok == CFGTOK_SEMI) {
1225 } else if (CfgTok == CFGTOK_COMMA) {
1230 /* Check if we have all mandatory attributes */
1231 AttrCheck (AttrFlags, atDefault, "DEFAULT");
1233 /* If no start address was given on the command line, use the one given
1236 if (!HaveStartAddr) {
1237 StartAddr = DefStartAddr;
1243 static void ParseFeatures (void)
1244 /* Parse a features section */
1246 static const IdentTok Features [] = {
1247 { "CONDES", CFGTOK_CONDES },
1248 { "STARTADDRESS", CFGTOK_STARTADDRESS },
1251 while (CfgTok == CFGTOK_IDENT) {
1253 /* Map the identifier to a token */
1254 cfgtok_t FeatureTok;
1255 CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1256 FeatureTok = CfgTok;
1258 /* Skip the name and the following colon */
1262 /* Parse the format options */
1263 switch (FeatureTok) {
1269 case CFGTOK_STARTADDRESS:
1270 ParseStartAddress ();
1275 FAIL ("Unexpected feature token");
1278 /* Skip the semicolon */
1282 /* Remember we had this section */
1283 SectionsEncountered |= SE_FEATURES;
1288 static void ParseSymbols (void)
1289 /* Parse a symbols section */
1291 static const IdentTok Attributes[] = {
1292 { "ADDRSIZE", CFGTOK_ADDRSIZE },
1293 { "TYPE", CFGTOK_TYPE },
1294 { "VALUE", CFGTOK_VALUE },
1297 static const IdentTok AddrSizes [] = {
1298 { "ABS", CFGTOK_ABS },
1299 { "ABSOLUTE", CFGTOK_ABS },
1300 { "DIRECT", CFGTOK_ZP },
1301 { "DWORD", CFGTOK_LONG },
1302 { "FAR", CFGTOK_FAR },
1303 { "LONG", CFGTOK_LONG },
1304 { "NEAR", CFGTOK_ABS },
1305 { "ZEROPAGE", CFGTOK_ZP },
1306 { "ZP", CFGTOK_ZP },
1309 static const IdentTok Types [] = {
1310 { "EXPORT", CFGTOK_EXPORT },
1311 { "IMPORT", CFGTOK_IMPORT },
1312 { "WEAK", CFGTOK_WEAK },
1315 while (CfgTok == CFGTOK_IDENT) {
1317 /* Bitmask to remember the attributes we got already */
1320 atAddrSize = 0x0001,
1324 unsigned AttrFlags = atNone;
1326 ExprNode* Value = 0;
1327 CfgSymType Type = CfgSymExport;
1328 unsigned char AddrSize = ADDR_SIZE_ABS;
1333 /* Remember the name */
1334 unsigned Name = GetStrBufId (&CfgSVal);
1337 /* New syntax - skip the colon */
1340 /* Parse the attributes */
1343 /* Map the identifier to a token */
1345 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1348 /* Skip the attribute name */
1351 /* An optional assignment follows */
1352 CfgOptionalAssign ();
1354 /* Check which attribute was given */
1357 case CFGTOK_ADDRSIZE:
1358 /* Don't allow this twice */
1359 FlagAttr (&AttrFlags, atAddrSize, "ADDRSIZE");
1360 /* Map the type to a token */
1361 CfgSpecialToken (AddrSizes, ENTRY_COUNT (AddrSizes), "AddrSize");
1363 case CFGTOK_ABS: AddrSize = ADDR_SIZE_ABS; break;
1364 case CFGTOK_FAR: AddrSize = ADDR_SIZE_FAR; break;
1365 case CFGTOK_LONG: AddrSize = ADDR_SIZE_LONG; break;
1366 case CFGTOK_ZP: AddrSize = ADDR_SIZE_ZP; break;
1368 Internal ("Unexpected token: %d", CfgTok);
1374 /* Don't allow this twice */
1375 FlagAttr (&AttrFlags, atType, "TYPE");
1376 /* Map the type to a token */
1377 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1379 case CFGTOK_EXPORT: Type = CfgSymExport; break;
1380 case CFGTOK_IMPORT: Type = CfgSymImport; break;
1381 case CFGTOK_WEAK: Type = CfgSymWeak; break;
1383 Internal ("Unexpected token: %d", CfgTok);
1389 /* Don't allow this twice */
1390 FlagAttr (&AttrFlags, atValue, "VALUE");
1391 /* Value is an expression */
1396 FAIL ("Unexpected attribute token");
1400 /* Semicolon ends the decl, otherwise accept an optional comma */
1401 if (CfgTok == CFGTOK_SEMI) {
1403 } else if (CfgTok == CFGTOK_COMMA) {
1408 /* We must have a type */
1409 AttrCheck (AttrFlags, atType, "TYPE");
1411 /* Further actions depend on the type */
1415 /* We must have a value */
1416 AttrCheck (AttrFlags, atValue, "VALUE");
1417 /* Create the export */
1418 Exp = CreateExprExport (Name, Value, AddrSize);
1419 CollAppend (&Exp->DefLines, GenLineInfo (&CfgErrorPos));
1423 /* An import must not have a value */
1424 if (AttrFlags & atValue) {
1425 CfgError (&CfgErrorPos, "Imports must not have a value");
1427 /* Generate the import */
1428 Imp = InsertImport (GenImport (Name, AddrSize));
1429 /* Remember the file position */
1430 CollAppend (&Imp->RefLines, GenLineInfo (&CfgErrorPos));
1434 /* We must have a value */
1435 AttrCheck (AttrFlags, atValue, "VALUE");
1436 /* Remember the symbol for later */
1437 Sym = NewCfgSymbol (CfgSymWeak, Name);
1439 Sym->AddrSize = AddrSize;
1443 Internal ("Unexpected symbol type %d", Type);
1446 /* Skip the semicolon */
1450 /* Remember we had this section */
1451 SectionsEncountered |= SE_SYMBOLS;
1456 static void ParseConfig (void)
1457 /* Parse the config file */
1459 static const IdentTok BlockNames [] = {
1460 { "MEMORY", CFGTOK_MEMORY },
1461 { "FILES", CFGTOK_FILES },
1462 { "SEGMENTS", CFGTOK_SEGMENTS },
1463 { "FORMATS", CFGTOK_FORMATS },
1464 { "FEATURES", CFGTOK_FEATURES },
1465 { "SYMBOLS", CFGTOK_SYMBOLS },
1471 /* Read the block ident */
1472 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1476 /* Expected a curly brace */
1477 CfgConsume (CFGTOK_LCURLY, "`{' expected");
1479 /* Read the block */
1490 case CFGTOK_SEGMENTS:
1494 case CFGTOK_FORMATS:
1498 case CFGTOK_FEATURES:
1502 case CFGTOK_SYMBOLS:
1507 FAIL ("Unexpected block token");
1511 /* Skip closing brace */
1512 CfgConsume (CFGTOK_RCURLY, "`}' expected");
1514 } while (CfgTok != CFGTOK_EOF);
1520 /* Read the configuration */
1522 /* Create the descriptors for the binary formats */
1523 BinFmtDesc = NewBinDesc ();
1524 O65FmtDesc = NewO65Desc ();
1526 /* If we have a config name given, open the file, otherwise we will read
1531 /* Parse the file */
1534 /* Close the input file */
1540 /*****************************************************************************/
1541 /* Config file processing */
1542 /*****************************************************************************/
1546 static void ProcessSegments (void)
1547 /* Process the SEGMENTS section */
1551 /* Walk over the list of segment descriptors */
1553 while (I < CollCount (&SegDescList)) {
1555 /* Get the next segment descriptor */
1556 SegDesc* S = CollAtUnchecked (&SegDescList, I);
1558 /* Search for the actual segment in the input files. The function may
1559 * return NULL (no such segment), this is checked later.
1561 S->Seg = SegFind (S->Name);
1563 /* If the segment is marked as BSS style, and if the segment exists
1564 * in any of the object file, check that there's no initialized data
1567 if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
1568 CfgWarning (GetSourcePos (S->LI),
1569 "Segment `%s' with type `bss' contains initialized data",
1570 GetString (S->Name));
1573 /* If this segment does exist in any of the object files, insert the
1574 * segment into the load/run memory areas. Otherwise print a warning
1575 * and discard it, because the segment pointer in the descriptor is
1580 /* Insert the segment into the memory area list */
1581 MemoryInsert (S->Run, S);
1582 if (S->Load != S->Run) {
1583 /* We have separate RUN and LOAD areas */
1584 MemoryInsert (S->Load, S);
1587 /* Process the next segment descriptor in the next run */
1592 /* Print a warning if the segment is not optional */
1593 if ((S->Flags & SF_OPTIONAL) == 0) {
1594 CfgWarning (&CfgErrorPos,
1595 "Segment `%s' does not exist",
1596 GetString (S->Name));
1599 /* Discard the descriptor and remove it from the collection */
1601 CollDelete (&SegDescList, I);
1608 static void ProcessSymbols (void)
1609 /* Process the SYMBOLS section */
1613 /* Walk over all symbols */
1615 for (I = 0; I < CollCount (&CfgSymbols); ++I) {
1617 /* Get the next symbol */
1618 CfgSymbol* Sym = CollAtUnchecked (&CfgSymbols, I);
1620 /* Check what it is. */
1621 switch (Sym->Type) {
1623 case CfgSymO65Export:
1624 /* Check if the export symbol is also defined as an import. */
1625 if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1627 GetSourcePos (Sym->LI),
1628 "Exported o65 symbol `%s' cannot also be an o65 import",
1629 GetString (Sym->Name)
1633 /* Check if we have this symbol defined already. The entry
1634 * routine will check this also, but we get a more verbose
1635 * error message when checking it here.
1637 if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
1639 GetSourcePos (Sym->LI),
1640 "Duplicate exported o65 symbol: `%s'",
1641 GetString (Sym->Name)
1645 /* Insert the symbol into the table */
1646 O65SetExport (O65FmtDesc, Sym->Name);
1649 case CfgSymO65Import:
1650 /* Check if the import symbol is also defined as an export. */
1651 if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
1653 GetSourcePos (Sym->LI),
1654 "Imported o65 symbol `%s' cannot also be an o65 export",
1655 GetString (Sym->Name)
1659 /* Check if we have this symbol defined already. The entry
1660 * routine will check this also, but we get a more verbose
1661 * error message when checking it here.
1663 if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1665 GetSourcePos (Sym->LI),
1666 "Duplicate imported o65 symbol: `%s'",
1667 GetString (Sym->Name)
1671 /* Insert the symbol into the table */
1672 O65SetImport (O65FmtDesc, Sym->Name);
1676 /* If the symbol is not defined until now, define it */
1677 if ((E = FindExport (Sym->Name)) == 0 || IsUnresolvedExport (E)) {
1678 /* The symbol is undefined, generate an export */
1679 E = CreateExprExport (Sym->Name, Sym->Value, Sym->AddrSize);
1680 CollAppend (&E->DefLines, Sym->LI);
1685 Internal ("Unexpected symbol type %d", Sym->Type);
1694 static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
1695 /* Create the defines for a RUN segment */
1698 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1700 /* Define the run address of the segment */
1701 SB_Printf (&Buf, "__%s_RUN__", GetString (S->Name));
1702 E = CreateMemoryExport (GetStrBufId (&Buf), S->Run, SegAddr - S->Run->Start);
1703 CollAppend (&E->DefLines, S->LI);
1705 /* Define the size of the segment */
1706 SB_Printf (&Buf, "__%s_SIZE__", GetString (S->Name));
1707 E = CreateConstExport (GetStrBufId (&Buf), S->Seg->Size);
1708 CollAppend (&E->DefLines, S->LI);
1710 S->Flags |= SF_RUN_DEF;
1716 static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
1717 /* Create the defines for a LOAD segment */
1720 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1722 /* Define the load address of the segment */
1723 SB_Printf (&Buf, "__%s_LOAD__", GetString (S->Name));
1724 E = CreateMemoryExport (GetStrBufId (&Buf), S->Load, SegAddr - S->Load->Start);
1725 CollAppend (&E->DefLines, S->LI);
1727 S->Flags |= SF_LOAD_DEF;
1733 unsigned CfgProcess (void)
1734 /* Process the config file after reading in object files and libraries. This
1735 * includes postprocessing of the config file data but also assigning segments
1736 * and defining segment/memory area related symbols. The function will return
1737 * the number of memory area overflows (so zero means anything went ok).
1738 * In case of overflows, a short mapfile can be generated later, to ease the
1739 * task of rearranging segments for the user.
1742 unsigned Overflows = 0;
1745 /* Postprocess symbols. We must do that first, since weak symbols are
1746 * defined here, which may be needed later.
1750 /* Postprocess segments */
1753 /* Walk through each of the memory sections. Add up the sizes and check
1754 * for an overflow of the section. Assign the start addresses of the
1755 * segments while doing this.
1757 for (I = 0; I < CollCount (&MemoryAreas); ++I) {
1762 /* Get the next memory area */
1763 MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
1765 /* Remember the offset in the output file */
1766 M->FileOffs = M->F->Size;
1768 /* Remember if this is a relocatable memory area */
1769 M->Relocatable = RelocatableBinFmt (M->F->Format);
1771 /* Resolve the start address expression, remember the start address
1772 * and mark the memory area as placed.
1774 if (!IsConstExpr (M->StartExpr)) {
1775 CfgError (GetSourcePos (M->LI),
1776 "Start address of memory area `%s' is not constant",
1777 GetString (M->Name));
1779 Addr = M->Start = GetExprVal (M->StartExpr);
1780 M->Flags |= MF_PLACED;
1782 /* If requested, define the symbol for the start of the memory area.
1783 * Doing it here means that the expression for the size of the area
1784 * may reference this symbol.
1786 if (M->Flags & MF_DEFINE) {
1788 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1790 /* Define the start of the memory area */
1791 SB_Printf (&Buf, "__%s_START__", GetString (M->Name));
1792 E = CreateMemoryExport (GetStrBufId (&Buf), M, 0);
1793 CollAppend (&E->DefLines, M->LI);
1798 /* Resolve the size expression */
1799 if (!IsConstExpr (M->SizeExpr)) {
1800 CfgError (GetSourcePos (M->LI),
1801 "Size of memory area `%s' is not constant",
1802 GetString (M->Name));
1804 M->Size = GetExprVal (M->SizeExpr);
1806 /* Walk through the segments in this memory area */
1807 for (J = 0; J < CollCount (&M->SegList); ++J) {
1809 /* Get the segment */
1810 SegDesc* S = CollAtUnchecked (&M->SegList, J);
1812 /* Some actions depend on wether this is the load or run memory
1817 /* This is the run (and maybe load) memory area. Handle
1818 * alignment and explict start address and offset.
1820 if (S->Flags & SF_ALIGN) {
1821 /* Align the address */
1822 unsigned long NewAddr = AlignAddr (Addr, S->RunAlignment);
1824 /* If the first segment placed in the memory area needs
1825 * fill bytes for the alignment, emit a warning, since
1826 * this is somewhat suspicious.
1828 if (M->FillLevel == 0 && NewAddr > Addr) {
1829 CfgWarning (GetSourcePos (S->LI),
1830 "First segment in memory area `%s' does "
1831 "already need fill bytes for alignment",
1832 GetString (M->Name));
1835 /* Use the aligned address */
1838 } else if (S->Flags & (SF_OFFSET | SF_START)) {
1839 /* Give the segment a fixed starting address */
1840 unsigned long NewAddr = S->Addr;
1841 if (S->Flags & SF_OFFSET) {
1842 /* An offset was given, no address, make an address */
1843 NewAddr += M->Start;
1845 if (Addr > NewAddr) {
1846 /* Offset already too large */
1847 if (S->Flags & SF_OFFSET) {
1848 CfgError (GetSourcePos (M->LI),
1849 "Offset too small in `%s', segment `%s'",
1850 GetString (M->Name),
1851 GetString (S->Name));
1853 CfgError (GetSourcePos (M->LI),
1854 "Start address too low in `%s', segment `%s'",
1855 GetString (M->Name),
1856 GetString (S->Name));
1862 /* Set the start address of this segment, set the readonly flag
1863 * in the segment and and remember if the segment is in a
1864 * relocatable file or not.
1867 S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
1868 S->Seg->Relocatable = M->Relocatable;
1870 /* Remember that this segment is placed */
1873 } else if (S->Load == M) {
1875 /* This is the load memory area, *and* run and load are
1876 * different (because of the "else" above). Handle alignment.
1878 if (S->Flags & SF_ALIGN_LOAD) {
1879 /* Align the address */
1880 Addr = AlignAddr (Addr, S->LoadAlignment);
1885 /* Increment the fill level of the memory area and check for an
1888 M->FillLevel = Addr + S->Seg->Size - M->Start;
1889 if (M->FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) {
1891 M->Flags |= MF_OVERFLOW;
1892 CfgWarning (GetSourcePos (M->LI),
1893 "Memory area overflow in `%s', segment `%s' (%lu bytes)",
1894 GetString (M->Name), GetString (S->Name),
1895 M->FillLevel - M->Size);
1898 /* If requested, define symbols for the start and size of the
1901 if (S->Flags & SF_DEFINE) {
1902 if (S->Run == M && (S->Flags & SF_RUN_DEF) == 0) {
1903 CreateRunDefines (S, Addr);
1905 if (S->Load == M && (S->Flags & SF_LOAD_DEF) == 0) {
1906 CreateLoadDefines (S, Addr);
1910 /* Calculate the new address */
1911 Addr += S->Seg->Size;
1915 /* If requested, define symbols for start, size and offset of the
1918 if (M->Flags & MF_DEFINE) {
1920 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1922 /* Define the size of the memory area */
1923 SB_Printf (&Buf, "__%s_SIZE__", GetString (M->Name));
1924 E = CreateConstExport (GetStrBufId (&Buf), M->Size);
1925 CollAppend (&E->DefLines, M->LI);
1927 /* Define the fill level of the memory area */
1928 SB_Printf (&Buf, "__%s_LAST__", GetString (M->Name));
1929 E = CreateMemoryExport (GetStrBufId (&Buf), M, M->FillLevel);
1930 CollAppend (&E->DefLines, M->LI);
1932 /* Define the file offset of the memory area. This isn't of much
1933 * use for relocatable output files.
1935 if (!M->Relocatable) {
1936 SB_Printf (&Buf, "__%s_FILEOFFS__", GetString (M->Name));
1937 E = CreateConstExport (GetStrBufId (&Buf), M->FileOffs);
1938 CollAppend (&E->DefLines, M->LI);
1941 /* Throw away the string buffer */
1945 /* Grow the file by the size of the memory area */
1946 if (M->Flags & MF_FILL) {
1947 M->F->Size += M->Size;
1949 M->F->Size += M->FillLevel;
1953 /* Return the number of memory area overflows */
1959 void CfgWriteTarget (void)
1960 /* Write the target file(s) */
1964 /* Walk through the files list */
1965 for (I = 0; I < CollCount (&FileList); ++I) {
1967 /* Get this entry */
1968 File* F = CollAtUnchecked (&FileList, I);
1970 /* We don't need to look at files with no memory areas */
1971 if (CollCount (&F->MemoryAreas) > 0) {
1973 /* Is there an output file? */
1974 if (SB_GetLen (GetStrBuf (F->Name)) > 0) {
1976 /* Assign a proper binary format */
1977 if (F->Format == BINFMT_DEFAULT) {
1978 F->Format = DefaultBinFmt;
1981 /* Call the apropriate routine for the binary format */
1982 switch (F->Format) {
1985 BinWriteTarget (BinFmtDesc, F);
1989 O65WriteTarget (O65FmtDesc, F);
1993 Internal ("Invalid binary format: %u", F->Format);
1999 /* No output file. Walk through the list and mark all segments
2000 * loading into these memory areas in this file as dumped.
2003 for (J = 0; J < CollCount (&F->MemoryAreas); ++J) {
2007 /* Get this entry */
2008 MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, J);
2011 Print (stdout, 2, "Skipping `%s'...\n", GetString (M->Name));
2013 /* Walk throught the segments */
2014 for (K = 0; K < CollCount (&M->SegList); ++K) {
2015 SegDesc* S = CollAtUnchecked (&M->SegList, K);
2017 /* Load area - mark the segment as dumped */