1 /*****************************************************************************/
5 /* Target configuration file for the ld65 linker */
9 /* (C) 1998-2002 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@musoftware.de */
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 /*****************************************************************************/
60 /*****************************************************************************/
62 /*****************************************************************************/
67 static File* FileList; /* Single linked list */
68 static unsigned FileCount; /* Number of entries in the list */
73 static Memory* MemoryList; /* Single linked list */
74 static Memory* MemoryLast; /* Last element in list */
75 static unsigned MemoryCount; /* Number of entries in the list */
77 /* Memory attributes */
78 #define MA_START 0x0001
79 #define MA_SIZE 0x0002
80 #define MA_TYPE 0x0004
81 #define MA_FILE 0x0008
82 #define MA_DEFINE 0x0010
83 #define MA_FILL 0x0020
84 #define MA_FILLVAL 0x0040
89 SegDesc* SegDescList; /* Single linked list */
90 unsigned SegDescCount; /* Number of entries in list */
92 /* Segment attributes */
93 #define SA_TYPE 0x0001
94 #define SA_LOAD 0x0002
96 #define SA_ALIGN 0x0008
97 #define SA_DEFINE 0x0010
98 #define SA_OFFSET 0x0020
99 #define SA_START 0x0040
103 /* Descriptor holding information about the binary formats */
104 static BinDesc* BinFmtDesc = 0;
105 static O65Desc* O65FmtDesc = 0;
109 /*****************************************************************************/
111 /*****************************************************************************/
115 static File* NewFile (const char* Name);
116 /* Create a new file descriptor and insert it into the list */
120 /*****************************************************************************/
121 /* List management */
122 /*****************************************************************************/
126 static File* FindFile (const char* Name)
127 /* Find a file with a given name. */
131 if (strcmp (F->Name, Name) == 0) {
141 static File* GetFile (const char* Name)
142 /* Get a file entry with the given name. Create a new one if needed. */
144 File* F = FindFile (Name);
146 /* Create a new one */
154 static void FileInsert (File* F, Memory* M)
155 /* Insert the memory area into the files list */
158 if (F->MemList == 0) {
162 F->MemLast->FNext = M;
169 static Memory* CfgFindMemory (const char* Name)
170 /* Find the memory are with the given name. Return NULL if not found */
172 Memory* M = MemoryList;
174 if (strcmp (M->Name, Name) == 0) {
184 static Memory* CfgGetMemory (const char* Name)
185 /* Find the memory are with the given name. Print an error on an invalid name */
187 Memory* M = CfgFindMemory (Name);
189 CfgError ("Invalid memory area `%s'", Name);
196 static SegDesc* CfgFindSegDesc (const char* Name)
197 /* Find the segment descriptor with the given name, return NULL if not found. */
199 SegDesc* S = SegDescList;
201 if (strcmp (S->Name, Name) == 0) {
214 static void SegDescInsert (SegDesc* S)
215 /* Insert a segment descriptor into the list of segment descriptors */
217 /* Insert the struct into the list */
218 S->Next = SegDescList;
225 static void MemoryInsert (Memory* M, SegDesc* S)
226 /* Insert the segment descriptor into the memory area list */
228 /* Create a new node for the entry */
229 MemListNode* N = xmalloc (sizeof (MemListNode));
233 if (M->SegLast == 0) {
237 M->SegLast->Next = N;
244 /*****************************************************************************/
245 /* Constructors/Destructors */
246 /*****************************************************************************/
250 static File* NewFile (const char* Name)
251 /* Create a new file descriptor and insert it into the list */
253 /* Get the length of the name */
254 unsigned Len = strlen (Name);
256 /* Allocate memory */
257 File* F = xmalloc (sizeof (File) + Len);
259 /* Initialize the fields */
261 F->Format = BINFMT_DEFAULT;
264 memcpy (F->Name, Name, Len);
265 F->Name [Len] = '\0';
267 /* Insert the struct into the list */
272 /* ...and return it */
278 static Memory* NewMemory (const char* Name)
279 /* Create a new memory section and insert it into the list */
281 /* Get the length of the name */
282 unsigned Len = strlen (Name);
284 /* Check for duplicate names */
285 Memory* M = CfgFindMemory (Name);
287 CfgError ("Memory area `%s' defined twice", Name);
290 /* Allocate memory */
291 M = xmalloc (sizeof (Memory) + Len);
293 /* Initialize the fields */
305 memcpy (M->Name, Name, Len);
306 M->Name [Len] = '\0';
308 /* Insert the struct into the list */
309 if (MemoryLast == 0) {
313 MemoryLast->Next = M;
318 /* ...and return it */
324 static SegDesc* NewSegDesc (const char* Name)
325 /* Create a segment descriptor */
329 /* Get the length of the name */
330 unsigned Len = strlen (Name);
332 /* Check for duplicate names */
333 SegDesc* S = CfgFindSegDesc (Name);
335 CfgError ("Segment `%s' defined twice", Name);
338 /* Verify that the given segment does really exist */
339 Seg = SegFind (Name);
341 CfgWarning ("Segment `%s' does not exist", Name);
344 /* Allocate memory */
345 S = xmalloc (sizeof (SegDesc) + Len);
347 /* Initialize the fields */
353 memcpy (S->Name, Name, Len);
354 S->Name [Len] = '\0';
356 /* ...and return it */
362 static void FreeSegDesc (SegDesc* S)
363 /* Free a segment descriptor */
370 /*****************************************************************************/
372 /*****************************************************************************/
376 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
377 /* Check if the item is already defined. Print an error if so. If not, set
378 * the marker that we have a definition now.
382 CfgError ("%s is already defined", Name);
389 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
390 /* Check that a mandatory attribute was given */
392 if ((Attr & Mask) == 0) {
393 CfgError ("%s attribute is missing", Name);
399 static void ParseMemory (void)
400 /* Parse a MEMORY section */
402 static const IdentTok Attributes [] = {
403 { "START", CFGTOK_START },
404 { "SIZE", CFGTOK_SIZE },
405 { "TYPE", CFGTOK_TYPE },
406 { "FILE", CFGTOK_FILE },
407 { "DEFINE", CFGTOK_DEFINE },
408 { "FILL", CFGTOK_FILL },
409 { "FILLVAL", CFGTOK_FILLVAL },
411 static const IdentTok Types [] = {
416 while (CfgTok == CFGTOK_IDENT) {
418 /* Create a new entry on the heap */
419 Memory* M = NewMemory (CfgSVal);
421 /* Skip the name and the following colon */
425 /* Read the attributes */
426 while (CfgTok == CFGTOK_IDENT) {
428 /* Map the identifier to a token */
430 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
433 /* An optional assignment follows */
435 CfgOptionalAssign ();
437 /* Check which attribute was given */
441 FlagAttr (&M->Attr, MA_START, "START");
447 FlagAttr (&M->Attr, MA_SIZE, "SIZE");
453 FlagAttr (&M->Attr, MA_TYPE, "TYPE");
454 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
455 if (CfgTok == CFGTOK_RO) {
461 FlagAttr (&M->Attr, MA_FILE, "FILE");
463 /* Get the file entry and insert the memory area */
464 FileInsert (GetFile (CfgSVal), M);
468 FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
469 /* Map the token to a boolean */
471 if (CfgTok == CFGTOK_TRUE) {
472 M->Flags |= MF_DEFINE;
477 FlagAttr (&M->Attr, MA_FILL, "FILL");
478 /* Map the token to a boolean */
480 if (CfgTok == CFGTOK_TRUE) {
486 FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
488 CfgRangeCheck (0, 0xFF);
489 M->FillVal = (unsigned char) CfgIVal;
493 FAIL ("Unexpected attribute token");
497 /* Skip the attribute value and an optional comma */
502 /* Skip the semicolon */
505 /* Check for mandatory parameters */
506 AttrCheck (M->Attr, MA_START, "START");
507 AttrCheck (M->Attr, MA_SIZE, "SIZE");
509 /* If we don't have a file name for output given, use the default
512 if ((M->Attr & MA_FILE) == 0) {
513 FileInsert (GetFile (OutputName), M);
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 /* Parse all files */
534 while (CfgTok != CFGTOK_RCURLY) {
538 /* We expect a string value here */
541 /* Search for the file, it must exist */
542 F = FindFile (CfgSVal);
544 CfgError ("No such file: `%s'", CfgSVal);
547 /* Skip the token and the following colon */
551 /* Read the attributes */
552 while (CfgTok == CFGTOK_IDENT) {
554 /* Map the identifier to a token */
556 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
559 /* An optional assignment follows */
561 CfgOptionalAssign ();
563 /* Check which attribute was given */
567 if (F->Format != BINFMT_DEFAULT) {
568 /* We've set the format already! */
569 Error ("Cannot set a file format twice");
571 /* Read the format token */
572 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
576 F->Format = BINFMT_BINARY;
580 F->Format = BINFMT_O65;
584 Error ("Unexpected format token");
589 FAIL ("Unexpected attribute token");
593 /* Skip the attribute value and an optional comma */
598 /* Skip the semicolon */
606 static void ParseSegments (void)
607 /* Parse a SEGMENTS section */
609 static const IdentTok Attributes [] = {
610 { "LOAD", CFGTOK_LOAD },
611 { "RUN", CFGTOK_RUN },
612 { "TYPE", CFGTOK_TYPE },
613 { "ALIGN", CFGTOK_ALIGN },
614 { "DEFINE", CFGTOK_DEFINE },
615 { "OFFSET", CFGTOK_OFFSET },
616 { "START", CFGTOK_START },
618 static const IdentTok Types [] = {
621 { "BSS", CFGTOK_BSS },
623 { "WP", CFGTOK_WPROT },
624 { "WPROT", CFGTOK_WPROT },
629 while (CfgTok == CFGTOK_IDENT) {
633 /* Create a new entry on the heap */
634 S = NewSegDesc (CfgSVal);
636 /* Skip the name and the following colon */
640 /* Read the attributes */
641 while (CfgTok == CFGTOK_IDENT) {
643 /* Map the identifier to a token */
645 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
648 /* An optional assignment follows */
650 CfgOptionalAssign ();
652 /* Check which attribute was given */
656 FlagAttr (&S->Attr, SA_LOAD, "LOAD");
657 S->Load = CfgGetMemory (CfgSVal);
661 FlagAttr (&S->Attr, SA_RUN, "RUN");
662 S->Run = CfgGetMemory (CfgSVal);
666 FlagAttr (&S->Attr, SA_TYPE, "TYPE");
667 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
669 case CFGTOK_RO: S->Flags |= SF_RO; break;
670 case CFGTOK_RW: /* Default */ break;
671 case CFGTOK_BSS: S->Flags |= SF_BSS; break;
672 case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break;
673 case CFGTOK_WPROT: S->Flags |= (SF_RO | SF_WPROT); break;
674 default: Internal ("Unexpected token: %d", CfgTok);
680 FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
681 CfgRangeCheck (1, 0x10000);
682 S->Align = BitFind (CfgIVal);
683 if ((0x01UL << S->Align) != CfgIVal) {
684 CfgError ("Alignment must be a power of 2");
686 S->Flags |= SF_ALIGN;
690 FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
691 /* Map the token to a boolean */
693 if (CfgTok == CFGTOK_TRUE) {
694 S->Flags |= SF_DEFINE;
700 FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
701 CfgRangeCheck (1, 0x1000000);
703 S->Flags |= SF_OFFSET;
708 FlagAttr (&S->Attr, SA_START, "START");
709 CfgRangeCheck (1, 0x1000000);
711 S->Flags |= SF_START;
715 FAIL ("Unexpected attribute token");
719 /* Skip the attribute value and an optional comma */
724 /* Skip the semicolon */
727 /* Check for mandatory parameters */
728 AttrCheck (S->Attr, SA_LOAD, "LOAD");
730 /* Set defaults for stuff not given */
731 if ((S->Attr & SA_RUN) == 0) {
735 /* Both attributes given */
736 S->Flags |= SF_LOAD_AND_RUN;
738 if ((S->Attr & SA_ALIGN) == 0) {
743 /* If the segment is marked as BSS style, check that there's no
744 * initialized data in the segment.
746 if ((S->Flags & SF_BSS) != 0 && !IsBSSType (S->Seg)) {
747 Warning ("%s(%u): Segment with type `bss' contains initialized data",
748 CfgGetName (), CfgErrorLine);
751 /* Don't allow read/write data to be put into a readonly area */
752 if ((S->Flags & SF_RO) == 0) {
753 if (S->Run->Flags & MF_RO) {
754 CfgError ("Cannot put r/w segment `%s' in r/o memory area `%s'",
755 S->Name, S->Run->Name);
759 /* Only one of ALIGN, START and OFFSET may be used */
760 Count = ((S->Flags & SF_ALIGN) != 0) +
761 ((S->Flags & SF_OFFSET) != 0) +
762 ((S->Flags & SF_START) != 0);
764 CfgError ("Only one of ALIGN, START, OFFSET may be used");
767 /* If this segment does exist in any of the object files, insert the
768 * descriptor into the list of segment descriptors. Otherwise discard
769 * it silently, because the segment pointer in the descriptor is
773 /* Insert the descriptor into the list of all descriptors */
775 /* Insert the segment into the memory area list */
776 MemoryInsert (S->Run, S);
777 if ((S->Flags & SF_LOAD_AND_RUN) != 0) {
778 /* We have a separate RUN area given */
779 MemoryInsert (S->Load, S);
782 /* Segment does not exist, discard the descriptor */
790 static void ParseO65 (void)
791 /* Parse the o65 format section */
793 static const IdentTok Attributes [] = {
794 { "EXPORT", CFGTOK_EXPORT },
795 { "IMPORT", CFGTOK_IMPORT },
796 { "TYPE", CFGTOK_TYPE },
799 { "VERSION", CFGTOK_VERSION },
801 static const IdentTok Types [] = {
802 { "SMALL", CFGTOK_SMALL },
803 { "LARGE", CFGTOK_LARGE },
805 static const IdentTok OperatingSystems [] = {
806 { "LUNIX", CFGTOK_LUNIX },
807 { "OSA65", CFGTOK_OSA65 },
808 { "CC65", CFGTOK_CC65 },
811 /* Bitmask to remember the attributes we got already */
815 atOSVersion = 0x0002,
822 unsigned AttrFlags = atNone;
824 /* Remember the attributes read */
825 unsigned OS = 0; /* Initialize to keep gcc happy */
826 unsigned Version = 0;
828 /* Read the attributes */
829 while (CfgTok == CFGTOK_IDENT) {
831 /* Map the identifier to a token */
833 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
836 /* An optional assignment follows */
838 CfgOptionalAssign ();
840 /* Check which attribute was given */
844 /* Remember we had this token (maybe more than once) */
845 AttrFlags |= atExport;
846 /* We expect an identifier */
848 /* Check if the export symbol is also defined as an import. */
849 if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
850 CfgError ("Exported symbol `%s' cannot be an import", CfgSVal);
852 /* Check if we have this symbol defined already. The entry
853 * routine will check this also, but we get a more verbose
854 * error message when checking it here.
856 if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
857 CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
859 /* Insert the symbol into the table */
860 O65SetExport (O65FmtDesc, CfgSVal);
864 /* Remember we had this token (maybe more than once) */
865 AttrFlags |= atImport;
866 /* We expect an identifier */
868 /* Check if the imported symbol is also defined as an export. */
869 if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
870 CfgError ("Imported symbol `%s' cannot be an export", CfgSVal);
872 /* Check if we have this symbol defined already. The entry
873 * routine will check this also, but we get a more verbose
874 * error message when checking it here.
876 if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
877 CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
879 /* Insert the symbol into the table */
880 O65SetImport (O65FmtDesc, CfgSVal);
884 /* Cannot have this attribute twice */
885 FlagAttr (&AttrFlags, atType, "TYPE");
886 /* Get the type of the executable */
887 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
891 O65SetSmallModel (O65FmtDesc);
895 O65SetLargeModel (O65FmtDesc);
899 CfgError ("Unexpected type token");
904 /* Cannot use this attribute twice */
905 FlagAttr (&AttrFlags, atOS, "OS");
906 /* Get the operating system */
907 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
909 case CFGTOK_LUNIX: OS = O65OS_LUNIX; break;
910 case CFGTOK_OSA65: OS = O65OS_OSA65; break;
911 case CFGTOK_CC65: OS = O65OS_CC65; break;
912 default: CfgError ("Unexpected OS token");
917 /* Cannot have this attribute twice */
918 FlagAttr (&AttrFlags, atID, "ID");
919 /* We're expecting a number in the 0..$FFFF range*/
921 CfgRangeCheck (0, 0xFFFF);
922 ModuleId = (unsigned) CfgIVal;
926 /* Cannot have this attribute twice */
927 FlagAttr (&AttrFlags, atVersion, "VERSION");
928 /* We're expecting a number in byte range */
930 CfgRangeCheck (0, 0xFF);
931 Version = (unsigned) CfgIVal;
935 FAIL ("Unexpected attribute token");
939 /* Skip the attribute value and an optional comma */
944 /* Check if we have all mandatory attributes */
945 AttrCheck (AttrFlags, atOS, "OS");
947 /* Check for attributes that may not be combined */
948 if (OS == O65OS_CC65) {
949 if ((AttrFlags & (atImport | atExport)) != 0) {
950 CfgError ("OS type CC65 may not have imports or exports");
953 if (AttrFlags & atID) {
954 CfgError ("Operating system does not support the ID attribute");
958 /* Set the O65 operating system to use */
959 O65SetOS (O65FmtDesc, OS, Version, ModuleId);
964 static void ParseFormats (void)
965 /* Parse a target format section */
967 static const IdentTok Formats [] = {
968 { "O65", CFGTOK_O65 },
969 { "BIN", CFGTOK_BIN },
970 { "BINARY", CFGTOK_BIN },
973 while (CfgTok == CFGTOK_IDENT) {
975 /* Map the identifier to a token */
977 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
980 /* Skip the name and the following colon */
984 /* Parse the format options */
992 /* No attribibutes available */
996 Error ("Unexpected format token");
999 /* Skip the semicolon */
1006 static void ParseConDes (void)
1007 /* Parse the CONDES feature */
1009 static const IdentTok Attributes [] = {
1010 { "SEGMENT", CFGTOK_SEGMENT },
1011 { "LABEL", CFGTOK_LABEL },
1012 { "COUNT", CFGTOK_COUNT },
1013 { "TYPE", CFGTOK_TYPE },
1014 { "ORDER", CFGTOK_ORDER },
1017 static const IdentTok Types [] = {
1018 { "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
1019 { "DESTRUCTOR", CFGTOK_DESTRUCTOR },
1022 static const IdentTok Orders [] = {
1023 { "DECREASING", CFGTOK_DECREASING },
1024 { "INCREASING", CFGTOK_INCREASING },
1027 /* Attribute values. */
1028 char SegName[sizeof (CfgSVal)];
1029 char Label[sizeof (CfgSVal)];
1030 char Count[sizeof (CfgSVal)];
1031 /* Initialize to avoid gcc warnings: */
1033 ConDesOrder Order = cdIncreasing;
1035 /* Bitmask to remember the attributes we got already */
1044 unsigned AttrFlags = atNone;
1046 /* Parse the attributes */
1049 /* Map the identifier to a token */
1051 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1054 /* An optional assignment follows */
1056 CfgOptionalAssign ();
1058 /* Check which attribute was given */
1061 case CFGTOK_SEGMENT:
1062 /* Don't allow this twice */
1063 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1064 /* We expect an identifier */
1066 /* Remember the value for later */
1067 strcpy (SegName, CfgSVal);
1071 /* Don't allow this twice */
1072 FlagAttr (&AttrFlags, atLabel, "LABEL");
1073 /* We expect an identifier */
1075 /* Remember the value for later */
1076 strcpy (Label, CfgSVal);
1080 /* Don't allow this twice */
1081 FlagAttr (&AttrFlags, atCount, "COUNT");
1082 /* We expect an identifier */
1084 /* Remember the value for later */
1085 strcpy (Count, CfgSVal);
1089 /* Don't allow this twice */
1090 FlagAttr (&AttrFlags, atType, "TYPE");
1091 /* The type may be given as id or numerical */
1092 if (CfgTok == CFGTOK_INTCON) {
1093 CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1094 Type = (int) CfgIVal;
1096 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1098 case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
1099 case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
1100 default: FAIL ("Unexpected type token");
1106 /* Don't allow this twice */
1107 FlagAttr (&AttrFlags, atOrder, "ORDER");
1108 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1110 case CFGTOK_DECREASING: Order = cdDecreasing; break;
1111 case CFGTOK_INCREASING: Order = cdIncreasing; break;
1112 default: FAIL ("Unexpected order token");
1117 FAIL ("Unexpected attribute token");
1121 /* Skip the attribute value */
1124 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1125 if (CfgTok == CFGTOK_SEMI) {
1127 } else if (CfgTok == CFGTOK_COMMA) {
1132 /* Check if we have all mandatory attributes */
1133 AttrCheck (AttrFlags, atSegName, "SEGMENT");
1134 AttrCheck (AttrFlags, atLabel, "LABEL");
1135 AttrCheck (AttrFlags, atType, "TYPE");
1137 /* Check if the condes has already attributes defined */
1138 if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1139 CfgError ("CONDES attributes for type %d are already defined", Type);
1142 /* Define the attributes */
1143 ConDesSetSegName (Type, SegName);
1144 ConDesSetLabel (Type, Label);
1145 if (AttrFlags & atCount) {
1146 ConDesSetCountSym (Type, Count);
1148 if (AttrFlags & atOrder) {
1149 ConDesSetOrder (Type, Order);
1155 static void ParseFeatures (void)
1156 /* Parse a features section */
1158 static const IdentTok Features [] = {
1159 { "CONDES", CFGTOK_CONDES },
1162 while (CfgTok == CFGTOK_IDENT) {
1164 /* Map the identifier to a token */
1165 cfgtok_t FeatureTok;
1166 CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1167 FeatureTok = CfgTok;
1169 /* Skip the name and the following colon */
1173 /* Parse the format options */
1174 switch (FeatureTok) {
1181 Error ("Unexpected feature token");
1184 /* Skip the semicolon */
1191 static void ParseSymbols (void)
1192 /* Parse a symbols section */
1194 while (CfgTok == CFGTOK_IDENT) {
1198 /* Remember the name */
1199 char Name [sizeof (CfgSVal)];
1200 strcpy (Name, CfgSVal);
1203 /* Allow an optional assignment */
1204 CfgOptionalAssign ();
1206 /* Make sure the next token is an integer, read and skip it */
1211 /* Generate an export with the given value */
1212 CreateConstExport (Name, Val);
1214 /* Skip the semicolon */
1221 static void ParseConfig (void)
1222 /* Parse the config file */
1224 static const IdentTok BlockNames [] = {
1225 { "MEMORY", CFGTOK_MEMORY },
1226 { "FILES", CFGTOK_FILES },
1227 { "SEGMENTS", CFGTOK_SEGMENTS },
1228 { "FORMATS", CFGTOK_FORMATS },
1229 { "FEATURES", CFGTOK_FEATURES },
1230 { "SYMBOLS", CFGTOK_SYMBOLS },
1236 /* Read the block ident */
1237 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1241 /* Expected a curly brace */
1242 CfgConsume (CFGTOK_LCURLY, "`{' expected");
1244 /* Read the block */
1255 case CFGTOK_SEGMENTS:
1259 case CFGTOK_FORMATS:
1263 case CFGTOK_FEATURES:
1267 case CFGTOK_SYMBOLS:
1272 FAIL ("Unexpected block token");
1276 /* Skip closing brace */
1277 CfgConsume (CFGTOK_RCURLY, "`}' expected");
1279 } while (CfgTok != CFGTOK_EOF);
1285 /* Read the configuration */
1287 /* Create the descriptors for the binary formats */
1288 BinFmtDesc = NewBinDesc ();
1289 O65FmtDesc = NewO65Desc ();
1291 /* If we have a config name given, open the file, otherwise we will read
1296 /* Parse the file */
1299 /* Close the input file */
1305 static void CreateRunDefines (Memory* M, SegDesc* S, unsigned long Addr)
1306 /* Create the defines for a RUN segment */
1310 sprintf (Buf, "__%s_RUN__", S->Name);
1311 CreateMemExport (Buf, M, Addr - M->Start);
1312 sprintf (Buf, "__%s_SIZE__", S->Name);
1313 CreateConstExport (Buf, S->Seg->Size);
1314 S->Flags |= SF_RUN_DEF;
1319 static void CreateLoadDefines (Memory* M, SegDesc* S, unsigned long Addr)
1320 /* Create the defines for a LOAD segment */
1324 sprintf (Buf, "__%s_LOAD__", S->Name);
1325 CreateMemExport (Buf, M, Addr - M->Start);
1326 S->Flags |= SF_LOAD_DEF;
1331 void CfgAssignSegments (void)
1332 /* Assign segments, define linker symbols where requested */
1334 /* Walk through each of the memory sections. Add up the sizes and check
1335 * for an overflow of the section. Assign the start addresses of the
1336 * segments while doing this.
1338 Memory* M = MemoryList;
1341 /* Get the start address of this memory area */
1342 unsigned long Addr = M->Start;
1344 /* Walk through the segments in this memory area */
1345 MemListNode* N = M->SegList;
1348 /* Get the segment from the node */
1349 SegDesc* S = N->Seg;
1351 /* Handle ALIGN and OFFSET/START */
1352 if (S->Flags & SF_ALIGN) {
1353 /* Align the address */
1354 unsigned long Val = (0x01UL << S->Align) - 1;
1355 Addr = (Addr + Val) & ~Val;
1356 } else if (S->Flags & (SF_OFFSET | SF_START)) {
1357 /* Give the segment a fixed starting address */
1358 unsigned long NewAddr = S->Addr;
1359 if (S->Flags & SF_OFFSET) {
1360 /* An offset was given, no address, make an address */
1361 NewAddr += M->Start;
1363 if (Addr > NewAddr) {
1364 /* Offset already too large */
1365 if (S->Flags & SF_OFFSET) {
1366 Error ("Offset too small in `%s', segment `%s'",
1369 Error ("Start address too low in `%s', segment `%s'",
1376 /* If this is the run area, set the start address of this segment */
1381 /* Increment the fill level of the memory area and check for an
1384 M->FillLevel = Addr + S->Seg->Size - M->Start;
1385 if (M->FillLevel > M->Size) {
1386 Error ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
1387 M->Name, S->Name, M->FillLevel - M->Size);
1390 /* If requested, define symbols for the start and size of the
1393 if (S->Flags & SF_DEFINE) {
1394 if ((S->Flags & SF_LOAD_AND_RUN) && S->Run == S->Load) {
1395 /* RUN and LOAD given and in one memory area.
1396 * Be careful: We will encounter this code twice, the
1397 * first time when walking the RUN list, second time when
1398 * walking the LOAD list. Be sure to define only the
1399 * relevant symbols on each walk.
1402 if ((S->Flags & SF_LOAD_DEF) == 0) {
1403 CreateLoadDefines (M, S, Addr);
1405 CHECK ((S->Flags & SF_RUN_DEF) == 0);
1406 CreateRunDefines (M, S, Addr);
1410 /* RUN and LOAD in different memory areas, or RUN not
1411 * given, so RUN defaults to LOAD. In the latter case, we
1412 * have only one copy of the segment in the area.
1415 CreateRunDefines (M, S, Addr);
1418 CreateLoadDefines (M, S, Addr);
1423 /* Calculate the new address */
1424 Addr += S->Seg->Size;
1430 /* If requested, define symbols for start and size of the memory area */
1431 if (M->Flags & MF_DEFINE) {
1433 sprintf (Buf, "__%s_START__", M->Name);
1434 CreateMemExport (Buf, M, 0);
1435 sprintf (Buf, "__%s_SIZE__", M->Name);
1436 CreateConstExport (Buf, M->Size);
1437 sprintf (Buf, "__%s_LAST__", M->Name);
1438 CreateConstExport (Buf, M->FillLevel);
1441 /* Next memory area */
1448 void CfgWriteTarget (void)
1449 /* Write the target file(s) */
1453 /* Walk through the files list */
1456 /* We don't need to look at files with no memory areas */
1459 /* Is there an output file? */
1460 if (strlen (F->Name) > 0) {
1462 /* Assign a proper binary format */
1463 if (F->Format == BINFMT_DEFAULT) {
1464 F->Format = DefaultBinFmt;
1467 /* Call the apropriate routine for the binary format */
1468 switch (F->Format) {
1471 BinWriteTarget (BinFmtDesc, F);
1475 O65WriteTarget (O65FmtDesc, F);
1479 Internal ("Invalid binary format: %u", F->Format);
1485 /* No output file. Walk through the list and mark all segments
1486 * loading into these memory areas in this file as dumped.
1494 Print (stdout, 2, "Skipping `%s'...\n", M->Name);
1496 /* Walk throught the segments */
1499 if (N->Seg->Load == M) {
1500 /* Load area - mark the segment as dumped */
1501 N->Seg->Seg->Dumped = 1;
1504 /* Next segment node */
1507 /* Next memory area */