1 /*****************************************************************************/
5 /* Target configuration file for the ld65 linker */
9 /* (C) 1998-2012, 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 /*****************************************************************************/
55 #include "alignment.h"
73 /*****************************************************************************/
75 /*****************************************************************************/
79 /* Remember which sections we had encountered */
88 } SectionsEncountered = SE_NONE;
93 static Collection FileList = STATIC_COLLECTION_INITIALIZER;
96 static Collection MemoryAreas = STATIC_COLLECTION_INITIALIZER;
98 /* Memory attributes */
99 #define MA_START 0x0001
100 #define MA_SIZE 0x0002
101 #define MA_TYPE 0x0004
102 #define MA_FILE 0x0008
103 #define MA_DEFINE 0x0010
104 #define MA_FILL 0x0020
105 #define MA_FILLVAL 0x0040
106 #define MA_BANK 0x0080
109 static Collection SegDescList = STATIC_COLLECTION_INITIALIZER;
111 /* Segment attributes */
112 #define SA_TYPE 0x0001
113 #define SA_LOAD 0x0002
114 #define SA_RUN 0x0004
115 #define SA_ALIGN 0x0008
116 #define SA_ALIGN_LOAD 0x0010
117 #define SA_DEFINE 0x0020
118 #define SA_OFFSET 0x0040
119 #define SA_START 0x0080
120 #define SA_OPTIONAL 0x0100
122 /* Symbol types used in the CfgSymbol structure */
124 CfgSymExport, /* Not really used in struct CfgSymbol */
125 CfgSymImport, /* Dito */
126 CfgSymWeak, /* Like export but weak */
127 CfgSymO65Export, /* An o65 export */
128 CfgSymO65Import, /* An o65 import */
131 /* Symbol structure. It is used for o65 imports and exports, but also for
132 * symbols from the SYMBOLS sections (symbols defined in the config file or
135 typedef struct CfgSymbol CfgSymbol;
137 CfgSymType Type; /* Type of symbol */
138 LineInfo* LI; /* Config file position */
139 unsigned Name; /* Symbol name */
140 ExprNode* Value; /* Symbol value if any */
141 unsigned AddrSize; /* Address size of symbol */
144 /* Collections with symbols */
145 static Collection CfgSymbols = STATIC_COLLECTION_INITIALIZER;
147 /* Descriptor holding information about the binary formats */
148 static BinDesc* BinFmtDesc = 0;
149 static O65Desc* O65FmtDesc = 0;
153 /*****************************************************************************/
155 /*****************************************************************************/
159 static File* NewFile (unsigned Name);
160 /* Create a new file descriptor and insert it into the list */
164 /*****************************************************************************/
165 /* List management */
166 /*****************************************************************************/
170 static File* FindFile (unsigned Name)
171 /* Find a file with a given name. */
174 for (I = 0; I < CollCount (&FileList); ++I) {
175 File* F = CollAtUnchecked (&FileList, I);
176 if (F->Name == Name) {
185 static File* GetFile (unsigned Name)
186 /* Get a file entry with the given name. Create a new one if needed. */
188 File* F = FindFile (Name);
190 /* Create a new one */
198 static void FileInsert (File* F, MemoryArea* M)
199 /* Insert the memory area into the files list */
202 CollAppend (&F->MemoryAreas, M);
207 static MemoryArea* CfgFindMemory (unsigned Name)
208 /* Find the memory are with the given name. Return NULL if not found */
211 for (I = 0; I < CollCount (&MemoryAreas); ++I) {
212 MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
213 if (M->Name == Name) {
222 static MemoryArea* CfgGetMemory (unsigned Name)
223 /* Find the memory are with the given name. Print an error on an invalid name */
225 MemoryArea* M = CfgFindMemory (Name);
227 CfgError (&CfgErrorPos, "Invalid memory area `%s'", GetString (Name));
234 static SegDesc* CfgFindSegDesc (unsigned Name)
235 /* Find the segment descriptor with the given name, return NULL if not found. */
238 for (I = 0; I < CollCount (&SegDescList); ++I) {
239 SegDesc* S = CollAtUnchecked (&SegDescList, I);
240 if (S->Name == Name) {
252 static void MemoryInsert (MemoryArea* M, SegDesc* S)
253 /* Insert the segment descriptor into the memory area list */
255 /* Insert the segment into the segment list of the memory area */
256 CollAppend (&M->SegList, S);
261 /*****************************************************************************/
262 /* Constructors/Destructors */
263 /*****************************************************************************/
267 static CfgSymbol* NewCfgSymbol (CfgSymType Type, unsigned Name)
268 /* Create a new CfgSymbol structure with the given type and name. The
269 * current config file position is recorded in the returned struct. The
270 * created struct is inserted into the CfgSymbols collection and returned.
273 /* Allocate memory */
274 CfgSymbol* Sym = xmalloc (sizeof (CfgSymbol));
276 /* Initialize the fields */
278 Sym->LI = GenLineInfo (&CfgErrorPos);
281 Sym->AddrSize = ADDR_SIZE_INVALID;
283 /* Insert the symbol into the collection */
284 CollAppend (&CfgSymbols, Sym);
286 /* Return the initialized struct */
292 static File* NewFile (unsigned Name)
293 /* Create a new file descriptor and insert it into the list */
295 /* Allocate memory */
296 File* F = xmalloc (sizeof (File));
298 /* Initialize the fields */
301 F->Format = BINFMT_DEFAULT;
303 InitCollection (&F->MemoryAreas);
305 /* Insert the struct into the list */
306 CollAppend (&FileList, F);
308 /* ...and return it */
314 static MemoryArea* CreateMemoryArea (const FilePos* Pos, unsigned Name)
315 /* Create a new memory area and insert it into the list */
317 /* Check for duplicate names */
318 MemoryArea* M = CfgFindMemory (Name);
320 CfgError (&CfgErrorPos,
321 "Memory area `%s' defined twice",
325 /* Create a new memory area */
326 M = NewMemoryArea (Pos, Name);
328 /* Insert the struct into the list ... */
329 CollAppend (&MemoryAreas, M);
331 /* ...and return it */
337 static SegDesc* NewSegDesc (unsigned Name)
338 /* Create a segment descriptor and insert it into the list */
341 /* Check for duplicate names */
342 SegDesc* S = CfgFindSegDesc (Name);
344 CfgError (&CfgErrorPos, "Segment `%s' defined twice", GetString (Name));
347 /* Allocate memory */
348 S = xmalloc (sizeof (SegDesc));
350 /* Initialize the fields */
352 S->LI = GenLineInfo (&CfgErrorPos);
357 S->LoadAlignment = 1;
359 /* Insert the struct into the list ... */
360 CollAppend (&SegDescList, S);
362 /* ...and return it */
368 static void FreeSegDesc (SegDesc* S)
369 /* Free a segment descriptor */
371 FreeLineInfo (S->LI);
377 /*****************************************************************************/
378 /* Config file parsing */
379 /*****************************************************************************/
383 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
384 /* Check if the item is already defined. Print an error if so. If not, set
385 * the marker that we have a definition now.
389 CfgError (&CfgErrorPos, "%s is already defined", Name);
396 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
397 /* Check that a mandatory attribute was given */
399 if ((Attr & Mask) == 0) {
400 CfgError (&CfgErrorPos, "%s attribute is missing", Name);
406 static void ParseMemory (void)
407 /* Parse a MEMORY section */
409 static const IdentTok Attributes [] = {
410 { "BANK", CFGTOK_BANK },
411 { "DEFINE", CFGTOK_DEFINE },
412 { "FILE", CFGTOK_FILE },
413 { "FILL", CFGTOK_FILL },
414 { "FILLVAL", CFGTOK_FILLVAL },
415 { "SIZE", CFGTOK_SIZE },
416 { "START", CFGTOK_START },
417 { "TYPE", CFGTOK_TYPE },
419 static const IdentTok Types [] = {
424 while (CfgTok == CFGTOK_IDENT) {
426 /* Create a new entry on the heap */
427 MemoryArea* M = CreateMemoryArea (&CfgErrorPos, GetStrBufId (&CfgSVal));
429 /* Skip the name and the following colon */
433 /* Read the attributes */
434 while (CfgTok == CFGTOK_IDENT) {
436 /* Map the identifier to a token */
438 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
441 /* An optional assignment follows */
443 CfgOptionalAssign ();
445 /* Check which attribute was given */
449 FlagAttr (&M->Attr, MA_BANK, "BANK");
450 M->BankExpr = CfgExpr ();
454 FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
455 /* Map the token to a boolean */
457 if (CfgTok == CFGTOK_TRUE) {
458 M->Flags |= MF_DEFINE;
464 FlagAttr (&M->Attr, MA_FILE, "FILE");
466 /* Get the file entry and insert the memory area */
467 FileInsert (GetFile (GetStrBufId (&CfgSVal)), M);
472 FlagAttr (&M->Attr, MA_FILL, "FILL");
473 /* Map the token to a boolean */
475 if (CfgTok == CFGTOK_TRUE) {
482 FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
483 M->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
487 FlagAttr (&M->Attr, MA_SIZE, "SIZE");
488 M->SizeExpr = CfgExpr ();
492 FlagAttr (&M->Attr, MA_START, "START");
493 M->StartExpr = CfgExpr ();
497 FlagAttr (&M->Attr, MA_TYPE, "TYPE");
498 CfgSpecialToken (Types, ENTRY_COUNT (Types), "TYPE");
499 if (CfgTok == CFGTOK_RO) {
506 FAIL ("Unexpected attribute token");
510 /* Skip an optional comma */
514 /* Skip the semicolon */
517 /* Check for mandatory parameters */
518 AttrCheck (M->Attr, MA_START, "START");
519 AttrCheck (M->Attr, MA_SIZE, "SIZE");
521 /* If we don't have a file name for output given, use the default
524 if ((M->Attr & MA_FILE) == 0) {
525 FileInsert (GetFile (GetStringId (OutputName)), M);
530 /* Remember we had this section */
531 SectionsEncountered |= SE_MEMORY;
536 static void ParseFiles (void)
537 /* Parse a FILES section */
539 static const IdentTok Attributes [] = {
540 { "FORMAT", CFGTOK_FORMAT },
542 static const IdentTok Formats [] = {
543 { "O65", CFGTOK_O65 },
544 { "BIN", CFGTOK_BIN },
545 { "BINARY", CFGTOK_BIN },
549 /* The MEMORY section must preceed the FILES section */
550 if ((SectionsEncountered & SE_MEMORY) == 0) {
551 CfgError (&CfgErrorPos, "MEMORY must precede FILES");
554 /* Parse all files */
555 while (CfgTok != CFGTOK_RCURLY) {
559 /* We expect a string value here */
562 /* Search for the file, it must exist */
563 F = FindFile (GetStrBufId (&CfgSVal));
565 CfgError (&CfgErrorPos,
566 "File `%s' not found in MEMORY section",
567 SB_GetConstBuf (&CfgSVal));
570 /* Skip the token and the following colon */
574 /* Read the attributes */
575 while (CfgTok == CFGTOK_IDENT) {
577 /* Map the identifier to a token */
579 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
582 /* An optional assignment follows */
584 CfgOptionalAssign ();
586 /* Check which attribute was given */
590 if (F->Format != BINFMT_DEFAULT) {
591 /* We've set the format already! */
592 CfgError (&CfgErrorPos,
593 "Cannot set a file format twice");
595 /* Read the format token */
596 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
600 F->Format = BINFMT_BINARY;
604 F->Format = BINFMT_O65;
608 Error ("Unexpected format token");
613 FAIL ("Unexpected attribute token");
617 /* Skip the attribute value and an optional comma */
622 /* Skip the semicolon */
627 /* Remember we had this section */
628 SectionsEncountered |= SE_FILES;
633 static void ParseSegments (void)
634 /* Parse a SEGMENTS section */
636 static const IdentTok Attributes [] = {
637 { "ALIGN", CFGTOK_ALIGN },
638 { "ALIGN_LOAD", CFGTOK_ALIGN_LOAD },
639 { "DEFINE", CFGTOK_DEFINE },
640 { "LOAD", CFGTOK_LOAD },
641 { "OFFSET", CFGTOK_OFFSET },
642 { "OPTIONAL", CFGTOK_OPTIONAL },
643 { "RUN", CFGTOK_RUN },
644 { "START", CFGTOK_START },
645 { "TYPE", CFGTOK_TYPE },
647 static const IdentTok Types [] = {
650 { "BSS", CFGTOK_BSS },
656 /* The MEMORY section must preceed the SEGMENTS section */
657 if ((SectionsEncountered & SE_MEMORY) == 0) {
658 CfgError (&CfgErrorPos, "MEMORY must precede SEGMENTS");
661 while (CfgTok == CFGTOK_IDENT) {
665 /* Create a new entry on the heap */
666 S = NewSegDesc (GetStrBufId (&CfgSVal));
668 /* Skip the name and the following colon */
672 /* Read the attributes */
673 while (CfgTok == CFGTOK_IDENT) {
675 /* Map the identifier to a token */
677 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
680 /* An optional assignment follows */
682 CfgOptionalAssign ();
684 /* Check which attribute was given */
688 FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
689 S->RunAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
690 S->Flags |= SF_ALIGN;
693 case CFGTOK_ALIGN_LOAD:
694 FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
695 S->LoadAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
696 S->Flags |= SF_ALIGN_LOAD;
700 FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
701 /* Map the token to a boolean */
703 if (CfgTok == CFGTOK_TRUE) {
704 S->Flags |= SF_DEFINE;
710 FlagAttr (&S->Attr, SA_LOAD, "LOAD");
711 S->Load = CfgGetMemory (GetStrBufId (&CfgSVal));
716 FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
717 S->Addr = CfgCheckedConstExpr (1, 0x1000000);
718 S->Flags |= SF_OFFSET;
721 case CFGTOK_OPTIONAL:
722 FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL");
724 if (CfgTok == CFGTOK_TRUE) {
725 S->Flags |= SF_OPTIONAL;
731 FlagAttr (&S->Attr, SA_RUN, "RUN");
732 S->Run = CfgGetMemory (GetStrBufId (&CfgSVal));
737 FlagAttr (&S->Attr, SA_START, "START");
738 S->Addr = CfgCheckedConstExpr (1, 0x1000000);
739 S->Flags |= SF_START;
743 FlagAttr (&S->Attr, SA_TYPE, "TYPE");
744 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
746 case CFGTOK_RO: S->Flags |= SF_RO; break;
747 case CFGTOK_RW: /* Default */ break;
748 case CFGTOK_BSS: S->Flags |= SF_BSS; break;
749 case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break;
750 default: Internal ("Unexpected token: %d", CfgTok);
756 FAIL ("Unexpected attribute token");
760 /* Skip an optional comma */
764 /* Check for mandatory parameters */
765 AttrCheck (S->Attr, SA_LOAD, "LOAD");
767 /* Set defaults for stuff not given */
768 if ((S->Attr & SA_RUN) == 0) {
773 /* An attribute of ALIGN_LOAD doesn't make sense if there are no
774 * separate run and load memory areas.
776 if ((S->Flags & SF_ALIGN_LOAD) != 0 && (S->Load == S->Run)) {
777 CfgWarning (&CfgErrorPos,
778 "ALIGN_LOAD attribute specified, but no separate "
779 "LOAD and RUN memory areas assigned");
780 /* Remove the flag */
781 S->Flags &= ~SF_ALIGN_LOAD;
784 /* If the segment is marked as BSS style, it may not have separate
785 * load and run memory areas, because it's is never written to disk.
787 if ((S->Flags & SF_BSS) != 0 && (S->Load != S->Run)) {
788 CfgWarning (&CfgErrorPos,
789 "Segment with type `bss' has both LOAD and RUN "
790 "memory areas assigned");
793 /* Don't allow read/write data to be put into a readonly area */
794 if ((S->Flags & SF_RO) == 0) {
795 if (S->Run->Flags & MF_RO) {
796 CfgError (&CfgErrorPos,
797 "Cannot put r/w segment `%s' in r/o memory area `%s'",
798 GetString (S->Name), GetString (S->Run->Name));
802 /* Only one of ALIGN, START and OFFSET may be used */
803 Count = ((S->Flags & SF_ALIGN) != 0) +
804 ((S->Flags & SF_OFFSET) != 0) +
805 ((S->Flags & SF_START) != 0);
807 CfgError (&CfgErrorPos,
808 "Only one of ALIGN, START, OFFSET may be used");
811 /* Skip the semicolon */
815 /* Remember we had this section */
816 SectionsEncountered |= SE_SEGMENTS;
821 static void ParseO65 (void)
822 /* Parse the o65 format section */
824 static const IdentTok Attributes [] = {
825 { "EXPORT", CFGTOK_EXPORT },
826 { "IMPORT", CFGTOK_IMPORT },
827 { "TYPE", CFGTOK_TYPE },
830 { "VERSION", CFGTOK_VERSION },
832 static const IdentTok Types [] = {
833 { "SMALL", CFGTOK_SMALL },
834 { "LARGE", CFGTOK_LARGE },
836 static const IdentTok OperatingSystems [] = {
837 { "LUNIX", CFGTOK_LUNIX },
838 { "OSA65", CFGTOK_OSA65 },
839 { "CC65", CFGTOK_CC65 },
840 { "OPENCBM", CFGTOK_OPENCBM },
843 /* Bitmask to remember the attributes we got already */
847 atOSVersion = 0x0002,
854 unsigned AttrFlags = atNone;
856 /* Remember the attributes read */
857 unsigned OS = 0; /* Initialize to keep gcc happy */
858 unsigned Version = 0;
860 /* Read the attributes */
861 while (CfgTok == CFGTOK_IDENT) {
863 /* Map the identifier to a token */
865 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
868 /* An optional assignment follows */
870 CfgOptionalAssign ();
872 /* Check which attribute was given */
876 /* Remember we had this token (maybe more than once) */
877 AttrFlags |= atExport;
878 /* We expect an identifier */
880 /* Remember it as an export for later */
881 NewCfgSymbol (CfgSymO65Export, GetStrBufId (&CfgSVal));
882 /* Eat the identifier token */
887 /* Remember we had this token (maybe more than once) */
888 AttrFlags |= atImport;
889 /* We expect an identifier */
891 /* Remember it as an import for later */
892 NewCfgSymbol (CfgSymO65Import, GetStrBufId (&CfgSVal));
893 /* Eat the identifier token */
898 /* Cannot have this attribute twice */
899 FlagAttr (&AttrFlags, atType, "TYPE");
900 /* Get the type of the executable */
901 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
905 O65SetSmallModel (O65FmtDesc);
909 O65SetLargeModel (O65FmtDesc);
913 CfgError (&CfgErrorPos, "Unexpected type token");
915 /* Eat the attribute token */
920 /* Cannot use this attribute twice */
921 FlagAttr (&AttrFlags, atOS, "OS");
922 /* Get the operating system. It may be specified as name or
923 * as a number in the range 1..255.
925 if (CfgTok == CFGTOK_INTCON) {
926 CfgRangeCheck (O65OS_MIN, O65OS_MAX);
927 OS = (unsigned) CfgIVal;
929 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
931 case CFGTOK_LUNIX: OS = O65OS_LUNIX; break;
932 case CFGTOK_OSA65: OS = O65OS_OSA65; break;
933 case CFGTOK_CC65: OS = O65OS_CC65; break;
934 case CFGTOK_OPENCBM: OS = O65OS_OPENCBM; break;
935 default: CfgError (&CfgErrorPos, "Unexpected OS token");
942 /* Cannot have this attribute twice */
943 FlagAttr (&AttrFlags, atID, "ID");
944 /* We're expecting a number in the 0..$FFFF range*/
945 ModuleId = (unsigned) CfgCheckedConstExpr (0, 0xFFFF);
949 /* Cannot have this attribute twice */
950 FlagAttr (&AttrFlags, atVersion, "VERSION");
951 /* We're expecting a number in byte range */
952 Version = (unsigned) CfgCheckedConstExpr (0, 0xFF);
956 FAIL ("Unexpected attribute token");
960 /* Skip an optional comma */
964 /* Check if we have all mandatory attributes */
965 AttrCheck (AttrFlags, atOS, "OS");
967 /* Check for attributes that may not be combined */
968 if (OS == O65OS_CC65) {
969 if ((AttrFlags & (atImport | atExport)) != 0 && ModuleId < 0x8000) {
970 CfgError (&CfgErrorPos,
971 "OS type CC65 may not have imports or exports for ids < $8000");
974 if (AttrFlags & atID) {
975 CfgError (&CfgErrorPos,
976 "Operating system does not support the ID attribute");
980 /* Set the O65 operating system to use */
981 O65SetOS (O65FmtDesc, OS, Version, ModuleId);
986 static void ParseFormats (void)
987 /* Parse a target format section */
989 static const IdentTok Formats [] = {
990 { "O65", CFGTOK_O65 },
991 { "BIN", CFGTOK_BIN },
992 { "BINARY", CFGTOK_BIN },
995 while (CfgTok == CFGTOK_IDENT) {
997 /* Map the identifier to a token */
999 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
1002 /* Skip the name and the following colon */
1006 /* Parse the format options */
1007 switch (FormatTok) {
1014 /* No attribibutes available */
1018 Error ("Unexpected format token");
1021 /* Skip the semicolon */
1026 /* Remember we had this section */
1027 SectionsEncountered |= SE_FORMATS;
1032 static void ParseConDes (void)
1033 /* Parse the CONDES feature */
1035 static const IdentTok Attributes [] = {
1036 { "SEGMENT", CFGTOK_SEGMENT },
1037 { "LABEL", CFGTOK_LABEL },
1038 { "COUNT", CFGTOK_COUNT },
1039 { "TYPE", CFGTOK_TYPE },
1040 { "ORDER", CFGTOK_ORDER },
1043 static const IdentTok Types [] = {
1044 { "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
1045 { "DESTRUCTOR", CFGTOK_DESTRUCTOR },
1046 { "INTERRUPTOR", CFGTOK_INTERRUPTOR },
1049 static const IdentTok Orders [] = {
1050 { "DECREASING", CFGTOK_DECREASING },
1051 { "INCREASING", CFGTOK_INCREASING },
1054 /* Attribute values. */
1055 unsigned SegName = INVALID_STRING_ID;
1056 unsigned Label = INVALID_STRING_ID;
1057 unsigned Count = INVALID_STRING_ID;
1058 /* Initialize to avoid gcc warnings: */
1060 ConDesOrder Order = cdIncreasing;
1062 /* Bitmask to remember the attributes we got already */
1071 unsigned AttrFlags = atNone;
1073 /* Parse the attributes */
1076 /* Map the identifier to a token */
1078 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1081 /* An optional assignment follows */
1083 CfgOptionalAssign ();
1085 /* Check which attribute was given */
1088 case CFGTOK_SEGMENT:
1089 /* Don't allow this twice */
1090 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1091 /* We expect an identifier */
1093 /* Remember the value for later */
1094 SegName = GetStrBufId (&CfgSVal);
1098 /* Don't allow this twice */
1099 FlagAttr (&AttrFlags, atLabel, "LABEL");
1100 /* We expect an identifier */
1102 /* Remember the value for later */
1103 Label = GetStrBufId (&CfgSVal);
1107 /* Don't allow this twice */
1108 FlagAttr (&AttrFlags, atCount, "COUNT");
1109 /* We expect an identifier */
1111 /* Remember the value for later */
1112 Count = GetStrBufId (&CfgSVal);
1116 /* Don't allow this twice */
1117 FlagAttr (&AttrFlags, atType, "TYPE");
1118 /* The type may be given as id or numerical */
1119 if (CfgTok == CFGTOK_INTCON) {
1120 CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1121 Type = (int) CfgIVal;
1123 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1125 case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
1126 case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
1127 case CFGTOK_INTERRUPTOR: Type = CD_TYPE_INT; break;
1128 default: FAIL ("Unexpected type token");
1134 /* Don't allow this twice */
1135 FlagAttr (&AttrFlags, atOrder, "ORDER");
1136 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1138 case CFGTOK_DECREASING: Order = cdDecreasing; break;
1139 case CFGTOK_INCREASING: Order = cdIncreasing; break;
1140 default: FAIL ("Unexpected order token");
1145 FAIL ("Unexpected attribute token");
1149 /* Skip the attribute value */
1152 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1153 if (CfgTok == CFGTOK_SEMI) {
1155 } else if (CfgTok == CFGTOK_COMMA) {
1160 /* Check if we have all mandatory attributes */
1161 AttrCheck (AttrFlags, atSegName, "SEGMENT");
1162 AttrCheck (AttrFlags, atLabel, "LABEL");
1163 AttrCheck (AttrFlags, atType, "TYPE");
1165 /* Check if the condes has already attributes defined */
1166 if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1167 CfgError (&CfgErrorPos,
1168 "CONDES attributes for type %d are already defined",
1172 /* Define the attributes */
1173 ConDesSetSegName (Type, SegName);
1174 ConDesSetLabel (Type, Label);
1175 if (AttrFlags & atCount) {
1176 ConDesSetCountSym (Type, Count);
1178 if (AttrFlags & atOrder) {
1179 ConDesSetOrder (Type, Order);
1185 static void ParseStartAddress (void)
1186 /* Parse the STARTADDRESS feature */
1188 static const IdentTok Attributes [] = {
1189 { "DEFAULT", CFGTOK_DEFAULT },
1193 /* Attribute values. */
1194 unsigned long DefStartAddr = 0;
1196 /* Bitmask to remember the attributes we got already */
1201 unsigned AttrFlags = atNone;
1203 /* Parse the attributes */
1206 /* Map the identifier to a token */
1208 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1211 /* An optional assignment follows */
1213 CfgOptionalAssign ();
1215 /* Check which attribute was given */
1218 case CFGTOK_DEFAULT:
1219 /* Don't allow this twice */
1220 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1221 /* We expect a numeric expression */
1222 DefStartAddr = CfgCheckedConstExpr (0, 0xFFFFFF);
1226 FAIL ("Unexpected attribute token");
1230 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1231 if (CfgTok == CFGTOK_SEMI) {
1233 } else if (CfgTok == CFGTOK_COMMA) {
1238 /* Check if we have all mandatory attributes */
1239 AttrCheck (AttrFlags, atDefault, "DEFAULT");
1241 /* If no start address was given on the command line, use the one given
1244 if (!HaveStartAddr) {
1245 StartAddr = DefStartAddr;
1251 static void ParseFeatures (void)
1252 /* Parse a features section */
1254 static const IdentTok Features [] = {
1255 { "CONDES", CFGTOK_CONDES },
1256 { "STARTADDRESS", CFGTOK_STARTADDRESS },
1259 while (CfgTok == CFGTOK_IDENT) {
1261 /* Map the identifier to a token */
1262 cfgtok_t FeatureTok;
1263 CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1264 FeatureTok = CfgTok;
1266 /* Skip the name and the following colon */
1270 /* Parse the format options */
1271 switch (FeatureTok) {
1277 case CFGTOK_STARTADDRESS:
1278 ParseStartAddress ();
1283 FAIL ("Unexpected feature token");
1286 /* Skip the semicolon */
1290 /* Remember we had this section */
1291 SectionsEncountered |= SE_FEATURES;
1296 static void ParseSymbols (void)
1297 /* Parse a symbols section */
1299 static const IdentTok Attributes[] = {
1300 { "ADDRSIZE", CFGTOK_ADDRSIZE },
1301 { "TYPE", CFGTOK_TYPE },
1302 { "VALUE", CFGTOK_VALUE },
1305 static const IdentTok AddrSizes [] = {
1306 { "ABS", CFGTOK_ABS },
1307 { "ABSOLUTE", CFGTOK_ABS },
1308 { "DIRECT", CFGTOK_ZP },
1309 { "DWORD", CFGTOK_LONG },
1310 { "FAR", CFGTOK_FAR },
1311 { "LONG", CFGTOK_LONG },
1312 { "NEAR", CFGTOK_ABS },
1313 { "ZEROPAGE", CFGTOK_ZP },
1314 { "ZP", CFGTOK_ZP },
1317 static const IdentTok Types [] = {
1318 { "EXPORT", CFGTOK_EXPORT },
1319 { "IMPORT", CFGTOK_IMPORT },
1320 { "WEAK", CFGTOK_WEAK },
1323 while (CfgTok == CFGTOK_IDENT) {
1325 /* Bitmask to remember the attributes we got already */
1328 atAddrSize = 0x0001,
1332 unsigned AttrFlags = atNone;
1334 ExprNode* Value = 0;
1335 CfgSymType Type = CfgSymExport;
1336 unsigned char AddrSize = ADDR_SIZE_ABS;
1341 /* Remember the name */
1342 unsigned Name = GetStrBufId (&CfgSVal);
1345 /* New syntax - skip the colon */
1348 /* Parse the attributes */
1351 /* Map the identifier to a token */
1353 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1356 /* Skip the attribute name */
1359 /* An optional assignment follows */
1360 CfgOptionalAssign ();
1362 /* Check which attribute was given */
1365 case CFGTOK_ADDRSIZE:
1366 /* Don't allow this twice */
1367 FlagAttr (&AttrFlags, atAddrSize, "ADDRSIZE");
1368 /* Map the type to a token */
1369 CfgSpecialToken (AddrSizes, ENTRY_COUNT (AddrSizes), "AddrSize");
1371 case CFGTOK_ABS: AddrSize = ADDR_SIZE_ABS; break;
1372 case CFGTOK_FAR: AddrSize = ADDR_SIZE_FAR; break;
1373 case CFGTOK_LONG: AddrSize = ADDR_SIZE_LONG; break;
1374 case CFGTOK_ZP: AddrSize = ADDR_SIZE_ZP; break;
1376 Internal ("Unexpected token: %d", CfgTok);
1382 /* Don't allow this twice */
1383 FlagAttr (&AttrFlags, atType, "TYPE");
1384 /* Map the type to a token */
1385 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1387 case CFGTOK_EXPORT: Type = CfgSymExport; break;
1388 case CFGTOK_IMPORT: Type = CfgSymImport; break;
1389 case CFGTOK_WEAK: Type = CfgSymWeak; break;
1391 Internal ("Unexpected token: %d", CfgTok);
1397 /* Don't allow this twice */
1398 FlagAttr (&AttrFlags, atValue, "VALUE");
1399 /* Value is an expression */
1404 FAIL ("Unexpected attribute token");
1408 /* Semicolon ends the decl, otherwise accept an optional comma */
1409 if (CfgTok == CFGTOK_SEMI) {
1411 } else if (CfgTok == CFGTOK_COMMA) {
1416 /* We must have a type */
1417 AttrCheck (AttrFlags, atType, "TYPE");
1419 /* Further actions depend on the type */
1423 /* We must have a value */
1424 AttrCheck (AttrFlags, atValue, "VALUE");
1425 /* Create the export */
1426 Exp = CreateExprExport (Name, Value, AddrSize);
1427 CollAppend (&Exp->DefLines, GenLineInfo (&CfgErrorPos));
1431 /* An import must not have a value */
1432 if (AttrFlags & atValue) {
1433 CfgError (&CfgErrorPos, "Imports must not have a value");
1435 /* Generate the import */
1436 Imp = InsertImport (GenImport (Name, AddrSize));
1437 /* Remember the file position */
1438 CollAppend (&Imp->RefLines, GenLineInfo (&CfgErrorPos));
1442 /* We must have a value */
1443 AttrCheck (AttrFlags, atValue, "VALUE");
1444 /* Remember the symbol for later */
1445 Sym = NewCfgSymbol (CfgSymWeak, Name);
1447 Sym->AddrSize = AddrSize;
1451 Internal ("Unexpected symbol type %d", Type);
1454 /* Skip the semicolon */
1458 /* Remember we had this section */
1459 SectionsEncountered |= SE_SYMBOLS;
1464 static void ParseConfig (void)
1465 /* Parse the config file */
1467 static const IdentTok BlockNames [] = {
1468 { "MEMORY", CFGTOK_MEMORY },
1469 { "FILES", CFGTOK_FILES },
1470 { "SEGMENTS", CFGTOK_SEGMENTS },
1471 { "FORMATS", CFGTOK_FORMATS },
1472 { "FEATURES", CFGTOK_FEATURES },
1473 { "SYMBOLS", CFGTOK_SYMBOLS },
1479 /* Read the block ident */
1480 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1484 /* Expected a curly brace */
1485 CfgConsume (CFGTOK_LCURLY, "`{' expected");
1487 /* Read the block */
1498 case CFGTOK_SEGMENTS:
1502 case CFGTOK_FORMATS:
1506 case CFGTOK_FEATURES:
1510 case CFGTOK_SYMBOLS:
1515 FAIL ("Unexpected block token");
1519 /* Skip closing brace */
1520 CfgConsume (CFGTOK_RCURLY, "`}' expected");
1522 } while (CfgTok != CFGTOK_EOF);
1528 /* Read the configuration */
1530 /* Create the descriptors for the binary formats */
1531 BinFmtDesc = NewBinDesc ();
1532 O65FmtDesc = NewO65Desc ();
1534 /* If we have a config name given, open the file, otherwise we will read
1539 /* Parse the file */
1542 /* Close the input file */
1548 /*****************************************************************************/
1549 /* Config file processing */
1550 /*****************************************************************************/
1554 static void ProcessSegments (void)
1555 /* Process the SEGMENTS section */
1559 /* Walk over the list of segment descriptors */
1561 while (I < CollCount (&SegDescList)) {
1563 /* Get the next segment descriptor */
1564 SegDesc* S = CollAtUnchecked (&SegDescList, I);
1566 /* Search for the actual segment in the input files. The function may
1567 * return NULL (no such segment), this is checked later.
1569 S->Seg = SegFind (S->Name);
1571 /* If the segment is marked as BSS style, and if the segment exists
1572 * in any of the object file, check that there's no initialized data
1575 if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
1576 CfgWarning (GetSourcePos (S->LI),
1577 "Segment `%s' with type `bss' contains initialized data",
1578 GetString (S->Name));
1581 /* If this segment does exist in any of the object files, insert the
1582 * segment into the load/run memory areas. Otherwise print a warning
1583 * and discard it, because the segment pointer in the descriptor is
1588 /* Insert the segment into the memory area list */
1589 MemoryInsert (S->Run, S);
1590 if (S->Load != S->Run) {
1591 /* We have separate RUN and LOAD areas */
1592 MemoryInsert (S->Load, S);
1595 /* Process the next segment descriptor in the next run */
1600 /* Print a warning if the segment is not optional */
1601 if ((S->Flags & SF_OPTIONAL) == 0) {
1602 CfgWarning (&CfgErrorPos,
1603 "Segment `%s' does not exist",
1604 GetString (S->Name));
1607 /* Discard the descriptor and remove it from the collection */
1609 CollDelete (&SegDescList, I);
1616 static void ProcessSymbols (void)
1617 /* Process the SYMBOLS section */
1621 /* Walk over all symbols */
1623 for (I = 0; I < CollCount (&CfgSymbols); ++I) {
1625 /* Get the next symbol */
1626 CfgSymbol* Sym = CollAtUnchecked (&CfgSymbols, I);
1628 /* Check what it is. */
1629 switch (Sym->Type) {
1631 case CfgSymO65Export:
1632 /* Check if the export symbol is also defined as an import. */
1633 if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1635 GetSourcePos (Sym->LI),
1636 "Exported o65 symbol `%s' cannot also be an o65 import",
1637 GetString (Sym->Name)
1641 /* Check if we have this symbol defined already. The entry
1642 * routine will check this also, but we get a more verbose
1643 * error message when checking it here.
1645 if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
1647 GetSourcePos (Sym->LI),
1648 "Duplicate exported o65 symbol: `%s'",
1649 GetString (Sym->Name)
1653 /* Insert the symbol into the table */
1654 O65SetExport (O65FmtDesc, Sym->Name);
1657 case CfgSymO65Import:
1658 /* Check if the import symbol is also defined as an export. */
1659 if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
1661 GetSourcePos (Sym->LI),
1662 "Imported o65 symbol `%s' cannot also be an o65 export",
1663 GetString (Sym->Name)
1667 /* Check if we have this symbol defined already. The entry
1668 * routine will check this also, but we get a more verbose
1669 * error message when checking it here.
1671 if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1673 GetSourcePos (Sym->LI),
1674 "Duplicate imported o65 symbol: `%s'",
1675 GetString (Sym->Name)
1679 /* Insert the symbol into the table */
1680 O65SetImport (O65FmtDesc, Sym->Name);
1684 /* If the symbol is not defined until now, define it */
1685 if ((E = FindExport (Sym->Name)) == 0 || IsUnresolvedExport (E)) {
1686 /* The symbol is undefined, generate an export */
1687 E = CreateExprExport (Sym->Name, Sym->Value, Sym->AddrSize);
1688 CollAppend (&E->DefLines, Sym->LI);
1693 Internal ("Unexpected symbol type %d", Sym->Type);
1702 static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
1703 /* Create the defines for a RUN segment */
1706 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1708 /* Define the run address of the segment */
1709 SB_Printf (&Buf, "__%s_RUN__", GetString (S->Name));
1710 E = CreateMemoryExport (GetStrBufId (&Buf), S->Run, SegAddr - S->Run->Start);
1711 CollAppend (&E->DefLines, S->LI);
1713 /* Define the size of the segment */
1714 SB_Printf (&Buf, "__%s_SIZE__", GetString (S->Name));
1715 E = CreateConstExport (GetStrBufId (&Buf), S->Seg->Size);
1716 CollAppend (&E->DefLines, S->LI);
1718 S->Flags |= SF_RUN_DEF;
1724 static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
1725 /* Create the defines for a LOAD segment */
1728 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1730 /* Define the load address of the segment */
1731 SB_Printf (&Buf, "__%s_LOAD__", GetString (S->Name));
1732 E = CreateMemoryExport (GetStrBufId (&Buf), S->Load, SegAddr - S->Load->Start);
1733 CollAppend (&E->DefLines, S->LI);
1735 S->Flags |= SF_LOAD_DEF;
1741 unsigned CfgProcess (void)
1742 /* Process the config file after reading in object files and libraries. This
1743 * includes postprocessing of the config file data but also assigning segments
1744 * and defining segment/memory area related symbols. The function will return
1745 * the number of memory area overflows (so zero means anything went ok).
1746 * In case of overflows, a short mapfile can be generated later, to ease the
1747 * task of rearranging segments for the user.
1750 unsigned Overflows = 0;
1753 /* Postprocess symbols. We must do that first, since weak symbols are
1754 * defined here, which may be needed later.
1758 /* Postprocess segments */
1761 /* Walk through each of the memory sections. Add up the sizes and check
1762 * for an overflow of the section. Assign the start addresses of the
1763 * segments while doing this.
1765 for (I = 0; I < CollCount (&MemoryAreas); ++I) {
1770 /* Get the next memory area */
1771 MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
1773 /* Remember the offset in the output file */
1774 M->FileOffs = M->F->Size;
1776 /* Remember if this is a relocatable memory area */
1777 M->Relocatable = RelocatableBinFmt (M->F->Format);
1779 /* Resolve the start address expression, remember the start address
1780 * and mark the memory area as placed.
1782 if (!IsConstExpr (M->StartExpr)) {
1783 CfgError (GetSourcePos (M->LI),
1784 "Start address of memory area `%s' is not constant",
1785 GetString (M->Name));
1787 Addr = M->Start = GetExprVal (M->StartExpr);
1788 M->Flags |= MF_PLACED;
1790 /* If requested, define the symbol for the start of the memory area.
1791 * Doing it here means that the expression for the size of the area
1792 * may reference this symbol.
1794 if (M->Flags & MF_DEFINE) {
1796 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1798 /* Define the start of the memory area */
1799 SB_Printf (&Buf, "__%s_START__", GetString (M->Name));
1800 E = CreateMemoryExport (GetStrBufId (&Buf), M, 0);
1801 CollAppend (&E->DefLines, M->LI);
1806 /* Resolve the size expression */
1807 if (!IsConstExpr (M->SizeExpr)) {
1808 CfgError (GetSourcePos (M->LI),
1809 "Size of memory area `%s' is not constant",
1810 GetString (M->Name));
1812 M->Size = GetExprVal (M->SizeExpr);
1814 /* Walk through the segments in this memory area */
1815 for (J = 0; J < CollCount (&M->SegList); ++J) {
1817 /* Get the segment */
1818 SegDesc* S = CollAtUnchecked (&M->SegList, J);
1820 /* Remember the start address before handling this segment */
1821 unsigned long StartAddr = Addr;
1823 /* Some actions depend on wether this is the load or run memory
1828 /* This is the run (and maybe load) memory area. Handle
1829 * alignment and explict start address and offset.
1831 if (S->Flags & SF_ALIGN) {
1832 /* Align the address */
1833 unsigned long NewAddr = AlignAddr (Addr, S->RunAlignment);
1835 /* If the first segment placed in the memory area needs
1836 * fill bytes for the alignment, emit a warning, since
1837 * this is somewhat suspicious.
1839 if (M->FillLevel == 0 && NewAddr > Addr) {
1840 CfgWarning (GetSourcePos (S->LI),
1841 "First segment in memory area `%s' does "
1842 "already need fill bytes for alignment",
1843 GetString (M->Name));
1846 /* Use the aligned address */
1849 } else if (S->Flags & (SF_OFFSET | SF_START)) {
1850 /* Give the segment a fixed starting address */
1851 unsigned long NewAddr = S->Addr;
1852 if (S->Flags & SF_OFFSET) {
1853 /* An offset was given, no address, make an address */
1854 NewAddr += M->Start;
1856 if (Addr > NewAddr) {
1857 /* Offset already too large */
1858 if (S->Flags & SF_OFFSET) {
1859 CfgError (GetSourcePos (M->LI),
1860 "Offset too small in `%s', segment `%s'",
1861 GetString (M->Name),
1862 GetString (S->Name));
1864 CfgError (GetSourcePos (M->LI),
1865 "Start address too low in `%s', segment `%s'",
1866 GetString (M->Name),
1867 GetString (S->Name));
1873 /* If the segment has .BANK expressions referring to it, it
1874 * must be placed into a memory area that has the bank
1877 if ((S->Seg->Flags & SEG_FLAG_BANKREF) != 0 && M->BankExpr == 0) {
1878 CfgError (GetSourcePos (S->LI),
1879 "Segment `%s' is refered to by .BANK, but the "
1880 "memory area `%s' it is placed into has no BANK "
1882 GetString (S->Name),
1883 GetString (M->Name));
1886 /* Set the start address of this segment, set the readonly flag
1887 * in the segment and and remember if the segment is in a
1888 * relocatable file or not.
1891 S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
1893 /* Remember the run memory for this segment, which is also a
1894 * flag that the segment has been placed.
1896 S->Seg->MemArea = M;
1898 } else if (S->Load == M) {
1900 /* This is the load memory area, *and* run and load are
1901 * different (because of the "else" above). Handle alignment.
1903 if (S->Flags & SF_ALIGN_LOAD) {
1904 /* Align the address */
1905 Addr = AlignAddr (Addr, S->LoadAlignment);
1910 /* Increment the fill level of the memory area and check for an
1913 M->FillLevel = Addr + S->Seg->Size - M->Start;
1914 if (M->FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) {
1916 M->Flags |= MF_OVERFLOW;
1917 CfgWarning (GetSourcePos (M->LI),
1918 "Memory area overflow in `%s', segment `%s' (%lu bytes)",
1919 GetString (M->Name), GetString (S->Name),
1920 M->FillLevel - M->Size);
1923 /* If requested, define symbols for the start and size of the
1926 if (S->Flags & SF_DEFINE) {
1927 if (S->Run == M && (S->Flags & SF_RUN_DEF) == 0) {
1928 CreateRunDefines (S, Addr);
1930 if (S->Load == M && (S->Flags & SF_LOAD_DEF) == 0) {
1931 CreateLoadDefines (S, Addr);
1935 /* Calculate the new address */
1936 Addr += S->Seg->Size;
1938 /* If this segment goes out to the file, increase the file size */
1939 if ((S->Flags & SF_BSS) == 0 && S->Load == M) {
1940 M->F->Size += Addr - StartAddr;
1945 /* If requested, define symbols for start, size and offset of the
1948 if (M->Flags & MF_DEFINE) {
1950 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1952 /* Define the size of the memory area */
1953 SB_Printf (&Buf, "__%s_SIZE__", GetString (M->Name));
1954 E = CreateConstExport (GetStrBufId (&Buf), M->Size);
1955 CollAppend (&E->DefLines, M->LI);
1957 /* Define the fill level of the memory area */
1958 SB_Printf (&Buf, "__%s_LAST__", GetString (M->Name));
1959 E = CreateMemoryExport (GetStrBufId (&Buf), M, M->FillLevel);
1960 CollAppend (&E->DefLines, M->LI);
1962 /* Define the file offset of the memory area. This isn't of much
1963 * use for relocatable output files.
1965 if (!M->Relocatable) {
1966 SB_Printf (&Buf, "__%s_FILEOFFS__", GetString (M->Name));
1967 E = CreateConstExport (GetStrBufId (&Buf), M->FileOffs);
1968 CollAppend (&E->DefLines, M->LI);
1971 /* Throw away the string buffer */
1975 /* If we didn't have an overflow and are requested to fill the memory
1976 * area, acount for that in the file size.
1978 if ((M->Flags & MF_OVERFLOW) == 0 && (M->Flags & MF_FILL) != 0) {
1979 M->F->Size += (M->Size - M->FillLevel);
1983 /* Return the number of memory area overflows */
1989 void CfgWriteTarget (void)
1990 /* Write the target file(s) */
1994 /* Walk through the files list */
1995 for (I = 0; I < CollCount (&FileList); ++I) {
1997 /* Get this entry */
1998 File* F = CollAtUnchecked (&FileList, I);
2000 /* We don't need to look at files with no memory areas */
2001 if (CollCount (&F->MemoryAreas) > 0) {
2003 /* Is there an output file? */
2004 if (SB_GetLen (GetStrBuf (F->Name)) > 0) {
2006 /* Assign a proper binary format */
2007 if (F->Format == BINFMT_DEFAULT) {
2008 F->Format = DefaultBinFmt;
2011 /* Call the apropriate routine for the binary format */
2012 switch (F->Format) {
2015 BinWriteTarget (BinFmtDesc, F);
2019 O65WriteTarget (O65FmtDesc, F);
2023 Internal ("Invalid binary format: %u", F->Format);
2029 /* No output file. Walk through the list and mark all segments
2030 * loading into these memory areas in this file as dumped.
2033 for (J = 0; J < CollCount (&F->MemoryAreas); ++J) {
2037 /* Get this entry */
2038 MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, J);
2041 Print (stdout, 2, "Skipping `%s'...\n", GetString (M->Name));
2043 /* Walk throught the segments */
2044 for (K = 0; K < CollCount (&M->SegList); ++K) {
2045 SegDesc* S = CollAtUnchecked (&M->SegList, K);
2047 /* Load area - mark the segment as dumped */