1 /*****************************************************************************/
5 /* Target configuration file for the ld65 linker */
9 /* (C) 1998-2005 Ullrich von Bassewitz */
10 /* Römerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
62 /*****************************************************************************/
64 /*****************************************************************************/
69 static File* FileList; /* Single linked list */
70 static unsigned FileCount; /* Number of entries in the list */
75 static Memory* MemoryList; /* Single linked list */
76 static Memory* MemoryLast; /* Last element in list */
77 static unsigned MemoryCount; /* Number of entries in the list */
79 /* Memory attributes */
80 #define MA_START 0x0001
81 #define MA_SIZE 0x0002
82 #define MA_TYPE 0x0004
83 #define MA_FILE 0x0008
84 #define MA_DEFINE 0x0010
85 #define MA_FILL 0x0020
86 #define MA_FILLVAL 0x0040
91 SegDesc* SegDescList; /* Single linked list */
92 unsigned SegDescCount; /* Number of entries in list */
94 /* Segment attributes */
95 #define SA_TYPE 0x0001
96 #define SA_LOAD 0x0002
98 #define SA_ALIGN 0x0008
99 #define SA_ALIGN_LOAD 0x0010
100 #define SA_DEFINE 0x0020
101 #define SA_OFFSET 0x0040
102 #define SA_START 0x0080
103 #define SA_OPTIONAL 0x0100
107 /* Descriptor holding information about the binary formats */
108 static BinDesc* BinFmtDesc = 0;
109 static O65Desc* O65FmtDesc = 0;
113 /*****************************************************************************/
115 /*****************************************************************************/
119 static File* NewFile (unsigned Name);
120 /* Create a new file descriptor and insert it into the list */
124 /*****************************************************************************/
125 /* List management */
126 /*****************************************************************************/
130 static File* FindFile (unsigned Name)
131 /* Find a file with a given name. */
135 if (F->Name == Name) {
145 static File* GetFile (unsigned Name)
146 /* Get a file entry with the given name. Create a new one if needed. */
148 File* F = FindFile (Name);
150 /* Create a new one */
158 static void FileInsert (File* F, Memory* M)
159 /* Insert the memory area into the files list */
162 if (F->MemList == 0) {
166 F->MemLast->FNext = M;
173 static Memory* CfgFindMemory (unsigned Name)
174 /* Find the memory are with the given name. Return NULL if not found */
176 Memory* M = MemoryList;
178 if (M->Name == Name) {
188 static Memory* CfgGetMemory (unsigned Name)
189 /* Find the memory are with the given name. Print an error on an invalid name */
191 Memory* M = CfgFindMemory (Name);
193 CfgError ("Invalid memory area `%s'", GetString (Name));
200 static SegDesc* CfgFindSegDesc (unsigned Name)
201 /* Find the segment descriptor with the given name, return NULL if not found. */
203 SegDesc* S = SegDescList;
205 if (S->Name == Name) {
218 static void SegDescInsert (SegDesc* S)
219 /* Insert a segment descriptor into the list of segment descriptors */
221 /* Insert the struct into the list */
222 S->Next = SegDescList;
229 static void MemoryInsert (Memory* M, SegDesc* S)
230 /* Insert the segment descriptor into the memory area list */
232 /* Create a new node for the entry */
233 MemListNode* N = xmalloc (sizeof (MemListNode));
237 if (M->SegLast == 0) {
241 M->SegLast->Next = N;
248 /*****************************************************************************/
249 /* Constructors/Destructors */
250 /*****************************************************************************/
254 static File* NewFile (unsigned Name)
255 /* Create a new file descriptor and insert it into the list */
257 /* Allocate memory */
258 File* F = xmalloc (sizeof (File));
260 /* Initialize the fields */
263 F->Format = BINFMT_DEFAULT;
267 /* Insert the struct into the list */
272 /* ...and return it */
278 static Memory* NewMemory (unsigned Name)
279 /* Create a new memory section and insert it into the list */
281 /* Check for duplicate names */
282 Memory* M = CfgFindMemory (Name);
284 CfgError ("Memory area `%s' defined twice", GetString (Name));
287 /* Allocate memory */
288 M = xmalloc (sizeof (Memory));
290 /* Initialize the fields */
305 /* Insert the struct into the list */
306 if (MemoryLast == 0) {
310 MemoryLast->Next = M;
315 /* ...and return it */
321 static SegDesc* NewSegDesc (unsigned Name)
322 /* Create a segment descriptor */
326 /* Check for duplicate names */
327 SegDesc* S = CfgFindSegDesc (Name);
329 CfgError ("Segment `%s' defined twice", GetString (Name));
332 /* Search for the actual segment in the input files. The function may
333 * return NULL (no such segment), this is checked later.
335 Seg = SegFind (Name);
337 /* Allocate memory */
338 S = xmalloc (sizeof (SegDesc));
340 /* Initialize the fields */
348 /* ...and return it */
354 static void FreeSegDesc (SegDesc* S)
355 /* Free a segment descriptor */
362 /*****************************************************************************/
364 /*****************************************************************************/
368 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
369 /* Check if the item is already defined. Print an error if so. If not, set
370 * the marker that we have a definition now.
374 CfgError ("%s is already defined", Name);
381 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
382 /* Check that a mandatory attribute was given */
384 if ((Attr & Mask) == 0) {
385 CfgError ("%s attribute is missing", Name);
391 static void ParseMemory (void)
392 /* Parse a MEMORY section */
394 static const IdentTok Attributes [] = {
395 { "START", CFGTOK_START },
396 { "SIZE", CFGTOK_SIZE },
397 { "TYPE", CFGTOK_TYPE },
398 { "FILE", CFGTOK_FILE },
399 { "DEFINE", CFGTOK_DEFINE },
400 { "FILL", CFGTOK_FILL },
401 { "FILLVAL", CFGTOK_FILLVAL },
403 static const IdentTok Types [] = {
408 while (CfgTok == CFGTOK_IDENT) {
410 /* Create a new entry on the heap */
411 Memory* M = NewMemory (GetStringId (CfgSVal));
413 /* Skip the name and the following colon */
417 /* Read the attributes */
418 while (CfgTok == CFGTOK_IDENT) {
420 /* Map the identifier to a token */
422 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
425 /* An optional assignment follows */
427 CfgOptionalAssign ();
429 /* Check which attribute was given */
433 FlagAttr (&M->Attr, MA_START, "START");
439 FlagAttr (&M->Attr, MA_SIZE, "SIZE");
445 FlagAttr (&M->Attr, MA_TYPE, "TYPE");
446 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
447 if (CfgTok == CFGTOK_RO) {
453 FlagAttr (&M->Attr, MA_FILE, "FILE");
455 /* Get the file entry and insert the memory area */
456 FileInsert (GetFile (GetStringId (CfgSVal)), M);
460 FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
461 /* Map the token to a boolean */
463 if (CfgTok == CFGTOK_TRUE) {
464 M->Flags |= MF_DEFINE;
469 FlagAttr (&M->Attr, MA_FILL, "FILL");
470 /* Map the token to a boolean */
472 if (CfgTok == CFGTOK_TRUE) {
478 FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
480 CfgRangeCheck (0, 0xFF);
481 M->FillVal = (unsigned char) CfgIVal;
485 FAIL ("Unexpected attribute token");
489 /* Skip the attribute value and an optional comma */
494 /* Skip the semicolon */
497 /* Check for mandatory parameters */
498 AttrCheck (M->Attr, MA_START, "START");
499 AttrCheck (M->Attr, MA_SIZE, "SIZE");
501 /* If we don't have a file name for output given, use the default
504 if ((M->Attr & MA_FILE) == 0) {
505 FileInsert (GetFile (GetStringId (OutputName)), M);
512 static void ParseFiles (void)
513 /* Parse a FILES section */
515 static const IdentTok Attributes [] = {
516 { "FORMAT", CFGTOK_FORMAT },
518 static const IdentTok Formats [] = {
519 { "O65", CFGTOK_O65 },
520 { "BIN", CFGTOK_BIN },
521 { "BINARY", CFGTOK_BIN },
525 /* Parse all files */
526 while (CfgTok != CFGTOK_RCURLY) {
530 /* We expect a string value here */
533 /* Search for the file, it must exist */
534 F = FindFile (GetStringId (CfgSVal));
536 CfgError ("No such file: `%s'", CfgSVal);
539 /* Skip the token and the following colon */
543 /* Read the attributes */
544 while (CfgTok == CFGTOK_IDENT) {
546 /* Map the identifier to a token */
548 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
551 /* An optional assignment follows */
553 CfgOptionalAssign ();
555 /* Check which attribute was given */
559 if (F->Format != BINFMT_DEFAULT) {
560 /* We've set the format already! */
561 Error ("Cannot set a file format twice");
563 /* Read the format token */
564 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
568 F->Format = BINFMT_BINARY;
572 F->Format = BINFMT_O65;
576 Error ("Unexpected format token");
581 FAIL ("Unexpected attribute token");
585 /* Skip the attribute value and an optional comma */
590 /* Skip the semicolon */
598 static void ParseSegments (void)
599 /* Parse a SEGMENTS section */
601 static const IdentTok Attributes [] = {
602 { "ALIGN", CFGTOK_ALIGN },
603 { "ALIGN_LOAD", CFGTOK_ALIGN_LOAD },
604 { "DEFINE", CFGTOK_DEFINE },
605 { "LOAD", CFGTOK_LOAD },
606 { "OFFSET", CFGTOK_OFFSET },
607 { "OPTIONAL", CFGTOK_OPTIONAL },
608 { "RUN", CFGTOK_RUN },
609 { "START", CFGTOK_START },
610 { "TYPE", CFGTOK_TYPE },
612 static const IdentTok Types [] = {
615 { "BSS", CFGTOK_BSS },
621 while (CfgTok == CFGTOK_IDENT) {
625 /* Create a new entry on the heap */
626 S = NewSegDesc (GetStringId (CfgSVal));
628 /* Skip the name and the following colon */
632 /* Read the attributes */
633 while (CfgTok == CFGTOK_IDENT) {
635 /* Map the identifier to a token */
637 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
640 /* An optional assignment follows */
642 CfgOptionalAssign ();
644 /* Check which attribute was given */
649 FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
650 CfgRangeCheck (1, 0x10000);
651 S->Align = BitFind (CfgIVal);
652 if ((0x01UL << S->Align) != CfgIVal) {
653 CfgError ("Alignment must be a power of 2");
655 S->Flags |= SF_ALIGN;
658 case CFGTOK_ALIGN_LOAD:
660 FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
661 CfgRangeCheck (1, 0x10000);
662 S->AlignLoad = BitFind (CfgIVal);
663 if ((0x01UL << S->AlignLoad) != CfgIVal) {
664 CfgError ("Alignment must be a power of 2");
666 S->Flags |= SF_ALIGN_LOAD;
670 FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
671 /* Map the token to a boolean */
673 if (CfgTok == CFGTOK_TRUE) {
674 S->Flags |= SF_DEFINE;
679 FlagAttr (&S->Attr, SA_LOAD, "LOAD");
680 S->Load = CfgGetMemory (GetStringId (CfgSVal));
685 FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
686 CfgRangeCheck (1, 0x1000000);
688 S->Flags |= SF_OFFSET;
691 case CFGTOK_OPTIONAL:
692 FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL");
694 if (CfgTok == CFGTOK_TRUE) {
695 S->Flags |= SF_OPTIONAL;
700 FlagAttr (&S->Attr, SA_RUN, "RUN");
701 S->Run = CfgGetMemory (GetStringId (CfgSVal));
706 FlagAttr (&S->Attr, SA_START, "START");
707 CfgRangeCheck (1, 0x1000000);
709 S->Flags |= SF_START;
713 FlagAttr (&S->Attr, SA_TYPE, "TYPE");
714 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
716 case CFGTOK_RO: S->Flags |= SF_RO; break;
717 case CFGTOK_RW: /* Default */ break;
718 case CFGTOK_BSS: S->Flags |= SF_BSS; break;
719 case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break;
720 default: Internal ("Unexpected token: %d", CfgTok);
725 FAIL ("Unexpected attribute token");
729 /* Skip the attribute value and an optional comma */
734 /* Check for mandatory parameters */
735 AttrCheck (S->Attr, SA_LOAD, "LOAD");
737 /* Set defaults for stuff not given */
738 if ((S->Attr & SA_RUN) == 0) {
743 /* If the segment is marked as BSS style, and if the segment exists
744 * in any of the object file, check that there's no initialized data
747 if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
748 Warning ("%s(%u): Segment with type `bss' contains initialized data",
749 CfgGetName (), CfgErrorLine);
752 /* An attribute of ALIGN_LOAD doesn't make sense if there are no
753 * separate run and load memory areas.
755 if ((S->Flags & SF_ALIGN_LOAD) != 0 && (S->Load == S->Run)) {
756 Warning ("%s(%u): ALIGN_LOAD attribute specified, but no separate "
757 "LOAD and RUN memory areas assigned",
758 CfgGetName (), CfgErrorLine);
759 /* Remove the flag */
760 S->Flags &= ~SF_ALIGN_LOAD;
763 /* If the segment is marked as BSS style, it may not have separate
764 * load and run memory areas, because it's is never written to disk.
766 if ((S->Flags & SF_BSS) != 0 && (S->Load != S->Run)) {
767 Warning ("%s(%u): Segment with type `bss' has both LOAD and RUN "
768 "memory areas assigned", CfgGetName (), CfgErrorLine);
771 /* Don't allow read/write data to be put into a readonly area */
772 if ((S->Flags & SF_RO) == 0) {
773 if (S->Run->Flags & MF_RO) {
774 CfgError ("Cannot put r/w segment `%s' in r/o memory area `%s'",
775 GetString (S->Name), GetString (S->Run->Name));
779 /* Only one of ALIGN, START and OFFSET may be used */
780 Count = ((S->Flags & SF_ALIGN) != 0) +
781 ((S->Flags & SF_OFFSET) != 0) +
782 ((S->Flags & SF_START) != 0);
784 CfgError ("Only one of ALIGN, START, OFFSET may be used");
787 /* If this segment does exist in any of the object files, insert the
788 * descriptor into the list of segment descriptors. Otherwise print a
789 * warning and discard it, because the segment pointer in the
790 * descriptor is invalid.
793 /* Insert the descriptor into the list of all descriptors */
795 /* Insert the segment into the memory area list */
796 MemoryInsert (S->Run, S);
797 if (S->Load != S->Run) {
798 /* We have separate RUN and LOAD areas */
799 MemoryInsert (S->Load, S);
802 /* Print a warning if the segment is not optional */
803 if ((S->Flags & SF_OPTIONAL) == 0) {
804 CfgWarning ("Segment `%s' does not exist", GetString (S->Name));
806 /* Discard the descriptor */
810 /* Skip the semicolon */
817 static void ParseO65 (void)
818 /* Parse the o65 format section */
820 static const IdentTok Attributes [] = {
821 { "EXPORT", CFGTOK_EXPORT },
822 { "IMPORT", CFGTOK_IMPORT },
823 { "TYPE", CFGTOK_TYPE },
826 { "VERSION", CFGTOK_VERSION },
828 static const IdentTok Types [] = {
829 { "SMALL", CFGTOK_SMALL },
830 { "LARGE", CFGTOK_LARGE },
832 static const IdentTok OperatingSystems [] = {
833 { "LUNIX", CFGTOK_LUNIX },
834 { "OSA65", CFGTOK_OSA65 },
835 { "CC65", CFGTOK_CC65 },
838 /* Bitmask to remember the attributes we got already */
842 atOSVersion = 0x0002,
849 unsigned AttrFlags = atNone;
851 /* Remember the attributes read */
853 unsigned OS = 0; /* Initialize to keep gcc happy */
854 unsigned Version = 0;
856 /* Read the attributes */
857 while (CfgTok == CFGTOK_IDENT) {
859 /* Map the identifier to a token */
861 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
864 /* An optional assignment follows */
866 CfgOptionalAssign ();
868 /* Check which attribute was given */
872 /* Remember we had this token (maybe more than once) */
873 AttrFlags |= atExport;
874 /* We expect an identifier */
876 /* Convert the string into a string index */
877 CfgSValId = GetStringId (CfgSVal);
878 /* Check if the export symbol is also defined as an import. */
879 if (O65GetImport (O65FmtDesc, CfgSValId) != 0) {
880 CfgError ("Exported symbol `%s' cannot be an import", CfgSVal);
882 /* Check if we have this symbol defined already. The entry
883 * routine will check this also, but we get a more verbose
884 * error message when checking it here.
886 if (O65GetExport (O65FmtDesc, CfgSValId) != 0) {
887 CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
889 /* Insert the symbol into the table */
890 O65SetExport (O65FmtDesc, CfgSValId);
894 /* Remember we had this token (maybe more than once) */
895 AttrFlags |= atImport;
896 /* We expect an identifier */
898 /* Convert the string into a string index */
899 CfgSValId = GetStringId (CfgSVal);
900 /* Check if the imported symbol is also defined as an export. */
901 if (O65GetExport (O65FmtDesc, CfgSValId) != 0) {
902 CfgError ("Imported symbol `%s' cannot be an export", CfgSVal);
904 /* Check if we have this symbol defined already. The entry
905 * routine will check this also, but we get a more verbose
906 * error message when checking it here.
908 if (O65GetImport (O65FmtDesc, CfgSValId) != 0) {
909 CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
911 /* Insert the symbol into the table */
912 O65SetImport (O65FmtDesc, CfgSValId);
916 /* Cannot have this attribute twice */
917 FlagAttr (&AttrFlags, atType, "TYPE");
918 /* Get the type of the executable */
919 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
923 O65SetSmallModel (O65FmtDesc);
927 O65SetLargeModel (O65FmtDesc);
931 CfgError ("Unexpected type token");
936 /* Cannot use this attribute twice */
937 FlagAttr (&AttrFlags, atOS, "OS");
938 /* Get the operating system */
939 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
941 case CFGTOK_LUNIX: OS = O65OS_LUNIX; break;
942 case CFGTOK_OSA65: OS = O65OS_OSA65; break;
943 case CFGTOK_CC65: OS = O65OS_CC65; break;
944 default: CfgError ("Unexpected OS token");
949 /* Cannot have this attribute twice */
950 FlagAttr (&AttrFlags, atID, "ID");
951 /* We're expecting a number in the 0..$FFFF range*/
953 CfgRangeCheck (0, 0xFFFF);
954 ModuleId = (unsigned) CfgIVal;
958 /* Cannot have this attribute twice */
959 FlagAttr (&AttrFlags, atVersion, "VERSION");
960 /* We're expecting a number in byte range */
962 CfgRangeCheck (0, 0xFF);
963 Version = (unsigned) CfgIVal;
967 FAIL ("Unexpected attribute token");
971 /* Skip the attribute value and an optional comma */
976 /* Check if we have all mandatory attributes */
977 AttrCheck (AttrFlags, atOS, "OS");
979 /* Check for attributes that may not be combined */
980 if (OS == O65OS_CC65) {
981 if ((AttrFlags & (atImport | atExport)) != 0) {
982 CfgError ("OS type CC65 may not have imports or exports");
985 if (AttrFlags & atID) {
986 CfgError ("Operating system does not support the ID attribute");
990 /* Set the O65 operating system to use */
991 O65SetOS (O65FmtDesc, OS, Version, ModuleId);
996 static void ParseFormats (void)
997 /* Parse a target format section */
999 static const IdentTok Formats [] = {
1000 { "O65", CFGTOK_O65 },
1001 { "BIN", CFGTOK_BIN },
1002 { "BINARY", CFGTOK_BIN },
1005 while (CfgTok == CFGTOK_IDENT) {
1007 /* Map the identifier to a token */
1009 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
1012 /* Skip the name and the following colon */
1016 /* Parse the format options */
1017 switch (FormatTok) {
1024 /* No attribibutes available */
1028 Error ("Unexpected format token");
1031 /* Skip the semicolon */
1038 static void ParseConDes (void)
1039 /* Parse the CONDES feature */
1041 static const IdentTok Attributes [] = {
1042 { "SEGMENT", CFGTOK_SEGMENT },
1043 { "LABEL", CFGTOK_LABEL },
1044 { "COUNT", CFGTOK_COUNT },
1045 { "TYPE", CFGTOK_TYPE },
1046 { "ORDER", CFGTOK_ORDER },
1049 static const IdentTok Types [] = {
1050 { "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
1051 { "DESTRUCTOR", CFGTOK_DESTRUCTOR },
1052 { "INTERRUPTOR", CFGTOK_INTERRUPTOR },
1055 static const IdentTok Orders [] = {
1056 { "DECREASING", CFGTOK_DECREASING },
1057 { "INCREASING", CFGTOK_INCREASING },
1060 /* Attribute values. */
1061 unsigned SegName = INVALID_STRING_ID;
1062 unsigned Label = INVALID_STRING_ID;
1063 unsigned Count = INVALID_STRING_ID;
1064 /* Initialize to avoid gcc warnings: */
1066 ConDesOrder Order = cdIncreasing;
1068 /* Bitmask to remember the attributes we got already */
1077 unsigned AttrFlags = atNone;
1079 /* Parse the attributes */
1082 /* Map the identifier to a token */
1084 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1087 /* An optional assignment follows */
1089 CfgOptionalAssign ();
1091 /* Check which attribute was given */
1094 case CFGTOK_SEGMENT:
1095 /* Don't allow this twice */
1096 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1097 /* We expect an identifier */
1099 /* Remember the value for later */
1100 SegName = GetStringId (CfgSVal);
1104 /* Don't allow this twice */
1105 FlagAttr (&AttrFlags, atLabel, "LABEL");
1106 /* We expect an identifier */
1108 /* Remember the value for later */
1109 Label = GetStringId (CfgSVal);
1113 /* Don't allow this twice */
1114 FlagAttr (&AttrFlags, atCount, "COUNT");
1115 /* We expect an identifier */
1117 /* Remember the value for later */
1118 Count = GetStringId (CfgSVal);
1122 /* Don't allow this twice */
1123 FlagAttr (&AttrFlags, atType, "TYPE");
1124 /* The type may be given as id or numerical */
1125 if (CfgTok == CFGTOK_INTCON) {
1126 CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1127 Type = (int) CfgIVal;
1129 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1131 case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
1132 case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
1133 case CFGTOK_INTERRUPTOR: Type = CD_TYPE_INT; break;
1134 default: FAIL ("Unexpected type token");
1140 /* Don't allow this twice */
1141 FlagAttr (&AttrFlags, atOrder, "ORDER");
1142 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1144 case CFGTOK_DECREASING: Order = cdDecreasing; break;
1145 case CFGTOK_INCREASING: Order = cdIncreasing; break;
1146 default: FAIL ("Unexpected order token");
1151 FAIL ("Unexpected attribute token");
1155 /* Skip the attribute value */
1158 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1159 if (CfgTok == CFGTOK_SEMI) {
1161 } else if (CfgTok == CFGTOK_COMMA) {
1166 /* Check if we have all mandatory attributes */
1167 AttrCheck (AttrFlags, atSegName, "SEGMENT");
1168 AttrCheck (AttrFlags, atLabel, "LABEL");
1169 AttrCheck (AttrFlags, atType, "TYPE");
1171 /* Check if the condes has already attributes defined */
1172 if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1173 CfgError ("CONDES attributes for type %d are already defined", Type);
1176 /* Define the attributes */
1177 ConDesSetSegName (Type, SegName);
1178 ConDesSetLabel (Type, Label);
1179 if (AttrFlags & atCount) {
1180 ConDesSetCountSym (Type, Count);
1182 if (AttrFlags & atOrder) {
1183 ConDesSetOrder (Type, Order);
1189 static void ParseStartAddress (void)
1190 /* Parse the STARTADDRESS feature */
1192 static const IdentTok Attributes [] = {
1193 { "DEFAULT", CFGTOK_DEFAULT },
1197 /* Attribute values. */
1198 unsigned long DefStartAddr = 0;
1200 /* Bitmask to remember the attributes we got already */
1205 unsigned AttrFlags = atNone;
1207 /* Parse the attributes */
1210 /* Map the identifier to a token */
1212 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1215 /* An optional assignment follows */
1217 CfgOptionalAssign ();
1219 /* Check which attribute was given */
1222 case CFGTOK_DEFAULT:
1223 /* Don't allow this twice */
1224 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1225 /* We expect a number */
1227 CfgRangeCheck (0, 0xFFFFFF);
1228 /* Remember the value for later */
1229 DefStartAddr = CfgIVal;
1233 FAIL ("Unexpected attribute token");
1237 /* Skip the attribute value */
1240 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1241 if (CfgTok == CFGTOK_SEMI) {
1243 } else if (CfgTok == CFGTOK_COMMA) {
1248 /* Check if we have all mandatory attributes */
1249 AttrCheck (AttrFlags, atDefault, "DEFAULT");
1251 /* If no start address was given on the command line, use the one given
1254 if (!HaveStartAddr) {
1255 StartAddr = DefStartAddr;
1261 static void ParseFeatures (void)
1262 /* Parse a features section */
1264 static const IdentTok Features [] = {
1265 { "CONDES", CFGTOK_CONDES },
1266 { "STARTADDRESS", CFGTOK_STARTADDRESS },
1269 while (CfgTok == CFGTOK_IDENT) {
1271 /* Map the identifier to a token */
1272 cfgtok_t FeatureTok;
1273 CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1274 FeatureTok = CfgTok;
1276 /* Skip the name and the following colon */
1280 /* Parse the format options */
1281 switch (FeatureTok) {
1287 case CFGTOK_STARTADDRESS:
1288 ParseStartAddress ();
1293 Error ("Unexpected feature token");
1296 /* Skip the semicolon */
1303 static void ParseSymbols (void)
1304 /* Parse a symbols section */
1306 while (CfgTok == CFGTOK_IDENT) {
1310 /* Remember the name */
1311 unsigned Name = GetStringId (CfgSVal);
1314 /* Allow an optional assignment */
1315 CfgOptionalAssign ();
1317 /* Make sure the next token is an integer, read and skip it */
1322 /* Generate an export with the given value */
1323 CreateConstExport (Name, Val);
1325 /* Skip the semicolon */
1332 static void ParseConfig (void)
1333 /* Parse the config file */
1335 static const IdentTok BlockNames [] = {
1336 { "MEMORY", CFGTOK_MEMORY },
1337 { "FILES", CFGTOK_FILES },
1338 { "SEGMENTS", CFGTOK_SEGMENTS },
1339 { "FORMATS", CFGTOK_FORMATS },
1340 { "FEATURES", CFGTOK_FEATURES },
1341 { "SYMBOLS", CFGTOK_SYMBOLS },
1347 /* Read the block ident */
1348 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1352 /* Expected a curly brace */
1353 CfgConsume (CFGTOK_LCURLY, "`{' expected");
1355 /* Read the block */
1366 case CFGTOK_SEGMENTS:
1370 case CFGTOK_FORMATS:
1374 case CFGTOK_FEATURES:
1378 case CFGTOK_SYMBOLS:
1383 FAIL ("Unexpected block token");
1387 /* Skip closing brace */
1388 CfgConsume (CFGTOK_RCURLY, "`}' expected");
1390 } while (CfgTok != CFGTOK_EOF);
1396 /* Read the configuration */
1398 /* Create the descriptors for the binary formats */
1399 BinFmtDesc = NewBinDesc ();
1400 O65FmtDesc = NewO65Desc ();
1402 /* If we have a config name given, open the file, otherwise we will read
1407 /* Parse the file */
1410 /* Close the input file */
1416 static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
1417 /* Create the defines for a RUN segment */
1421 xsprintf (Buf, sizeof (Buf), "__%s_RUN__", GetString (S->Name));
1422 CreateMemoryExport (GetStringId (Buf), S->Run, SegAddr - S->Run->Start);
1423 xsprintf (Buf, sizeof (Buf), "__%s_SIZE__", GetString (S->Name));
1424 CreateConstExport (GetStringId (Buf), S->Seg->Size);
1425 S->Flags |= SF_RUN_DEF;
1430 static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
1431 /* Create the defines for a LOAD segment */
1435 xsprintf (Buf, sizeof (Buf), "__%s_LOAD__", GetString (S->Name));
1436 CreateMemoryExport (GetStringId (Buf), S->Load, SegAddr - S->Load->Start);
1437 S->Flags |= SF_LOAD_DEF;
1442 void CfgAssignSegments (void)
1443 /* Assign segments, define linker symbols where requested */
1445 /* Walk through each of the memory sections. Add up the sizes and check
1446 * for an overflow of the section. Assign the start addresses of the
1447 * segments while doing this.
1449 Memory* M = MemoryList;
1454 /* Get the start address of this memory area */
1455 unsigned long Addr = M->Start;
1457 /* Remember if this is a relocatable memory area */
1458 M->Relocatable = RelocatableBinFmt (M->F->Format);
1460 /* Walk through the segments in this memory area */
1464 /* Get the segment from the node */
1465 SegDesc* S = N->Seg;
1467 /* Some actions depend on wether this is the load or run memory
1472 /* This is the run (and maybe load) memory area. Handle
1473 * alignment and explict start address and offset.
1475 if (S->Flags & SF_ALIGN) {
1476 /* Align the address */
1477 unsigned long Val = (0x01UL << S->Align) - 1;
1478 Addr = (Addr + Val) & ~Val;
1479 } else if (S->Flags & (SF_OFFSET | SF_START)) {
1480 /* Give the segment a fixed starting address */
1481 unsigned long NewAddr = S->Addr;
1482 if (S->Flags & SF_OFFSET) {
1483 /* An offset was given, no address, make an address */
1484 NewAddr += M->Start;
1486 if (Addr > NewAddr) {
1487 /* Offset already too large */
1488 if (S->Flags & SF_OFFSET) {
1489 Error ("Offset too small in `%s', segment `%s'",
1490 GetString (M->Name), GetString (S->Name));
1492 Error ("Start address too low in `%s', segment `%s'",
1493 GetString (M->Name), GetString (S->Name));
1499 /* Set the start address of this segment, set the readonly flag
1500 * in the segment and and remember if the segment is in a
1501 * relocatable file or not.
1504 S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
1505 S->Seg->Relocatable = M->Relocatable;
1507 } else if (S->Load == M) {
1509 /* This is the load memory area, *and* run and load are
1510 * different (because of the "else" above). Handle alignment.
1512 if (S->Flags & SF_ALIGN_LOAD) {
1513 /* Align the address */
1514 unsigned long Val = (0x01UL << S->AlignLoad) - 1;
1515 Addr = (Addr + Val) & ~Val;
1520 /* Increment the fill level of the memory area and check for an
1523 M->FillLevel = Addr + S->Seg->Size - M->Start;
1524 if (M->FillLevel > M->Size) {
1525 Error ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
1526 GetString (M->Name), GetString (S->Name),
1527 M->FillLevel - M->Size);
1530 /* If requested, define symbols for the start and size of the
1533 if (S->Flags & SF_DEFINE) {
1534 if (S->Run == M && (S->Flags & SF_RUN_DEF) == 0) {
1535 CreateRunDefines (S, Addr);
1537 if (S->Load == M && (S->Flags & SF_LOAD_DEF) == 0) {
1538 CreateLoadDefines (S, Addr);
1542 /* Calculate the new address */
1543 Addr += S->Seg->Size;
1549 /* If requested, define symbols for start and size of the memory area */
1550 if (M->Flags & MF_DEFINE) {
1552 sprintf (Buf, "__%s_START__", GetString (M->Name));
1553 CreateMemoryExport (GetStringId (Buf), M, 0);
1554 sprintf (Buf, "__%s_SIZE__", GetString (M->Name));
1555 CreateConstExport (GetStringId (Buf), M->Size);
1556 sprintf (Buf, "__%s_LAST__", GetString (M->Name));
1557 CreateMemoryExport (GetStringId (Buf), M, M->FillLevel);
1560 /* Next memory area */
1567 void CfgWriteTarget (void)
1568 /* Write the target file(s) */
1572 /* Walk through the files list */
1575 /* We don't need to look at files with no memory areas */
1578 /* Is there an output file? */
1579 if (strlen (GetString (F->Name)) > 0) {
1581 /* Assign a proper binary format */
1582 if (F->Format == BINFMT_DEFAULT) {
1583 F->Format = DefaultBinFmt;
1586 /* Call the apropriate routine for the binary format */
1587 switch (F->Format) {
1590 BinWriteTarget (BinFmtDesc, F);
1594 O65WriteTarget (O65FmtDesc, F);
1598 Internal ("Invalid binary format: %u", F->Format);
1604 /* No output file. Walk through the list and mark all segments
1605 * loading into these memory areas in this file as dumped.
1613 Print (stdout, 2, "Skipping `%s'...\n", GetString (M->Name));
1615 /* Walk throught the segments */
1618 if (N->Seg->Load == M) {
1619 /* Load area - mark the segment as dumped */
1620 N->Seg->Seg->Dumped = 1;
1623 /* Next segment node */
1626 /* Next memory area */