1 /*****************************************************************************/
5 /* Target configuration file for the ld65 linker */
9 /* (C) 1998-2003 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 /*****************************************************************************/
61 /*****************************************************************************/
63 /*****************************************************************************/
68 static File* FileList; /* Single linked list */
69 static unsigned FileCount; /* Number of entries in the list */
74 static Memory* MemoryList; /* Single linked list */
75 static Memory* MemoryLast; /* Last element in list */
76 static unsigned MemoryCount; /* Number of entries in the list */
78 /* Memory attributes */
79 #define MA_START 0x0001
80 #define MA_SIZE 0x0002
81 #define MA_TYPE 0x0004
82 #define MA_FILE 0x0008
83 #define MA_DEFINE 0x0010
84 #define MA_FILL 0x0020
85 #define MA_FILLVAL 0x0040
90 SegDesc* SegDescList; /* Single linked list */
91 unsigned SegDescCount; /* Number of entries in list */
93 /* Segment attributes */
94 #define SA_TYPE 0x0001
95 #define SA_LOAD 0x0002
97 #define SA_ALIGN 0x0008
98 #define SA_DEFINE 0x0010
99 #define SA_OFFSET 0x0020
100 #define SA_START 0x0040
101 #define SA_OPTIONAL 0x0080
105 /* Descriptor holding information about the binary formats */
106 static BinDesc* BinFmtDesc = 0;
107 static O65Desc* O65FmtDesc = 0;
111 /*****************************************************************************/
113 /*****************************************************************************/
117 static File* NewFile (const char* Name);
118 /* Create a new file descriptor and insert it into the list */
122 /*****************************************************************************/
123 /* List management */
124 /*****************************************************************************/
128 static File* FindFile (const char* Name)
129 /* Find a file with a given name. */
133 if (strcmp (F->Name, Name) == 0) {
143 static File* GetFile (const char* Name)
144 /* Get a file entry with the given name. Create a new one if needed. */
146 File* F = FindFile (Name);
148 /* Create a new one */
156 static void FileInsert (File* F, Memory* M)
157 /* Insert the memory area into the files list */
160 if (F->MemList == 0) {
164 F->MemLast->FNext = M;
171 static Memory* CfgFindMemory (const char* Name)
172 /* Find the memory are with the given name. Return NULL if not found */
174 Memory* M = MemoryList;
176 if (strcmp (M->Name, Name) == 0) {
186 static Memory* CfgGetMemory (const char* Name)
187 /* Find the memory are with the given name. Print an error on an invalid name */
189 Memory* M = CfgFindMemory (Name);
191 CfgError ("Invalid memory area `%s'", Name);
198 static SegDesc* CfgFindSegDesc (const char* Name)
199 /* Find the segment descriptor with the given name, return NULL if not found. */
201 SegDesc* S = SegDescList;
203 if (strcmp (S->Name, Name) == 0) {
216 static void SegDescInsert (SegDesc* S)
217 /* Insert a segment descriptor into the list of segment descriptors */
219 /* Insert the struct into the list */
220 S->Next = SegDescList;
227 static void MemoryInsert (Memory* M, SegDesc* S)
228 /* Insert the segment descriptor into the memory area list */
230 /* Create a new node for the entry */
231 MemListNode* N = xmalloc (sizeof (MemListNode));
235 if (M->SegLast == 0) {
239 M->SegLast->Next = N;
246 /*****************************************************************************/
247 /* Constructors/Destructors */
248 /*****************************************************************************/
252 static File* NewFile (const char* Name)
253 /* Create a new file descriptor and insert it into the list */
255 /* Get the length of the name */
256 unsigned Len = strlen (Name);
258 /* Allocate memory */
259 File* F = xmalloc (sizeof (File) + Len);
261 /* Initialize the fields */
263 F->Format = BINFMT_DEFAULT;
266 memcpy (F->Name, Name, Len);
267 F->Name [Len] = '\0';
269 /* Insert the struct into the list */
274 /* ...and return it */
280 static Memory* NewMemory (const char* Name)
281 /* Create a new memory section and insert it into the list */
283 /* Get the length of the name */
284 unsigned Len = strlen (Name);
286 /* Check for duplicate names */
287 Memory* M = CfgFindMemory (Name);
289 CfgError ("Memory area `%s' defined twice", Name);
292 /* Allocate memory */
293 M = xmalloc (sizeof (Memory) + Len);
295 /* Initialize the fields */
307 memcpy (M->Name, Name, Len);
308 M->Name [Len] = '\0';
310 /* Insert the struct into the list */
311 if (MemoryLast == 0) {
315 MemoryLast->Next = M;
320 /* ...and return it */
326 static SegDesc* NewSegDesc (const char* Name)
327 /* Create a segment descriptor */
331 /* Get the length of the name */
332 unsigned Len = strlen (Name);
334 /* Check for duplicate names */
335 SegDesc* S = CfgFindSegDesc (Name);
337 CfgError ("Segment `%s' defined twice", Name);
340 /* Search for the actual segment in the input files. The function may
341 * return NULL (no such segment), this is checked later.
343 Seg = SegFind (Name);
345 /* Allocate memory */
346 S = xmalloc (sizeof (SegDesc) + Len);
348 /* Initialize the fields */
354 memcpy (S->Name, Name, Len);
355 S->Name [Len] = '\0';
357 /* ...and return it */
363 static void FreeSegDesc (SegDesc* S)
364 /* Free a segment descriptor */
371 /*****************************************************************************/
373 /*****************************************************************************/
377 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
378 /* Check if the item is already defined. Print an error if so. If not, set
379 * the marker that we have a definition now.
383 CfgError ("%s is already defined", Name);
390 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
391 /* Check that a mandatory attribute was given */
393 if ((Attr & Mask) == 0) {
394 CfgError ("%s attribute is missing", Name);
400 static void ParseMemory (void)
401 /* Parse a MEMORY section */
403 static const IdentTok Attributes [] = {
404 { "START", CFGTOK_START },
405 { "SIZE", CFGTOK_SIZE },
406 { "TYPE", CFGTOK_TYPE },
407 { "FILE", CFGTOK_FILE },
408 { "DEFINE", CFGTOK_DEFINE },
409 { "FILL", CFGTOK_FILL },
410 { "FILLVAL", CFGTOK_FILLVAL },
412 static const IdentTok Types [] = {
417 while (CfgTok == CFGTOK_IDENT) {
419 /* Create a new entry on the heap */
420 Memory* M = NewMemory (CfgSVal);
422 /* Skip the name and the following colon */
426 /* Read the attributes */
427 while (CfgTok == CFGTOK_IDENT) {
429 /* Map the identifier to a token */
431 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
434 /* An optional assignment follows */
436 CfgOptionalAssign ();
438 /* Check which attribute was given */
442 FlagAttr (&M->Attr, MA_START, "START");
448 FlagAttr (&M->Attr, MA_SIZE, "SIZE");
454 FlagAttr (&M->Attr, MA_TYPE, "TYPE");
455 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
456 if (CfgTok == CFGTOK_RO) {
462 FlagAttr (&M->Attr, MA_FILE, "FILE");
464 /* Get the file entry and insert the memory area */
465 FileInsert (GetFile (CfgSVal), M);
469 FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
470 /* Map the token to a boolean */
472 if (CfgTok == CFGTOK_TRUE) {
473 M->Flags |= MF_DEFINE;
478 FlagAttr (&M->Attr, MA_FILL, "FILL");
479 /* Map the token to a boolean */
481 if (CfgTok == CFGTOK_TRUE) {
487 FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
489 CfgRangeCheck (0, 0xFF);
490 M->FillVal = (unsigned char) CfgIVal;
494 FAIL ("Unexpected attribute token");
498 /* Skip the attribute value and an optional comma */
503 /* Skip the semicolon */
506 /* Check for mandatory parameters */
507 AttrCheck (M->Attr, MA_START, "START");
508 AttrCheck (M->Attr, MA_SIZE, "SIZE");
510 /* If we don't have a file name for output given, use the default
513 if ((M->Attr & MA_FILE) == 0) {
514 FileInsert (GetFile (OutputName), M);
521 static void ParseFiles (void)
522 /* Parse a FILES section */
524 static const IdentTok Attributes [] = {
525 { "FORMAT", CFGTOK_FORMAT },
527 static const IdentTok Formats [] = {
528 { "O65", CFGTOK_O65 },
529 { "BIN", CFGTOK_BIN },
530 { "BINARY", CFGTOK_BIN },
534 /* Parse all files */
535 while (CfgTok != CFGTOK_RCURLY) {
539 /* We expect a string value here */
542 /* Search for the file, it must exist */
543 F = FindFile (CfgSVal);
545 CfgError ("No such file: `%s'", CfgSVal);
548 /* Skip the token and the following colon */
552 /* Read the attributes */
553 while (CfgTok == CFGTOK_IDENT) {
555 /* Map the identifier to a token */
557 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
560 /* An optional assignment follows */
562 CfgOptionalAssign ();
564 /* Check which attribute was given */
568 if (F->Format != BINFMT_DEFAULT) {
569 /* We've set the format already! */
570 Error ("Cannot set a file format twice");
572 /* Read the format token */
573 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
577 F->Format = BINFMT_BINARY;
581 F->Format = BINFMT_O65;
585 Error ("Unexpected format token");
590 FAIL ("Unexpected attribute token");
594 /* Skip the attribute value and an optional comma */
599 /* Skip the semicolon */
607 static void ParseSegments (void)
608 /* Parse a SEGMENTS section */
610 static const IdentTok Attributes [] = {
611 { "ALIGN", CFGTOK_ALIGN },
612 { "DEFINE", CFGTOK_DEFINE },
613 { "LOAD", CFGTOK_LOAD },
614 { "OFFSET", CFGTOK_OFFSET },
615 { "OPTIONAL", CFGTOK_OPTIONAL },
616 { "RUN", CFGTOK_RUN },
617 { "START", CFGTOK_START },
618 { "TYPE", CFGTOK_TYPE },
620 static const IdentTok Types [] = {
623 { "BSS", CFGTOK_BSS },
625 { "WP", CFGTOK_WPROT },
626 { "WPROT", CFGTOK_WPROT },
631 while (CfgTok == CFGTOK_IDENT) {
635 /* Create a new entry on the heap */
636 S = NewSegDesc (CfgSVal);
638 /* Skip the name and the following colon */
642 /* Read the attributes */
643 while (CfgTok == CFGTOK_IDENT) {
645 /* Map the identifier to a token */
647 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
650 /* An optional assignment follows */
652 CfgOptionalAssign ();
654 /* Check which attribute was given */
659 FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
660 CfgRangeCheck (1, 0x10000);
661 S->Align = BitFind (CfgIVal);
662 if ((0x01UL << S->Align) != CfgIVal) {
663 CfgError ("Alignment must be a power of 2");
665 S->Flags |= SF_ALIGN;
669 FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
670 /* Map the token to a boolean */
672 if (CfgTok == CFGTOK_TRUE) {
673 S->Flags |= SF_DEFINE;
678 FlagAttr (&S->Attr, SA_LOAD, "LOAD");
679 S->Load = CfgGetMemory (CfgSVal);
684 FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
685 CfgRangeCheck (1, 0x1000000);
687 S->Flags |= SF_OFFSET;
690 case CFGTOK_OPTIONAL:
691 FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL");
693 if (CfgTok == CFGTOK_TRUE) {
694 S->Flags |= SF_OPTIONAL;
699 FlagAttr (&S->Attr, SA_RUN, "RUN");
700 S->Run = CfgGetMemory (CfgSVal);
705 FlagAttr (&S->Attr, SA_START, "START");
706 CfgRangeCheck (1, 0x1000000);
708 S->Flags |= SF_START;
712 FlagAttr (&S->Attr, SA_TYPE, "TYPE");
713 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
715 case CFGTOK_RO: S->Flags |= SF_RO; break;
716 case CFGTOK_RW: /* Default */ break;
717 case CFGTOK_BSS: S->Flags |= SF_BSS; break;
718 case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break;
719 case CFGTOK_WPROT: S->Flags |= (SF_RO | SF_WPROT); 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) {
742 /* Both attributes given */
743 S->Flags |= SF_LOAD_AND_RUN;
745 if ((S->Attr & SA_ALIGN) == 0) {
750 /* If the segment is marked as BSS style, and if the segment exists
751 * in any of the object file, check that there's no initialized data
754 if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
755 Warning ("%s(%u): Segment with type `bss' contains initialized data",
756 CfgGetName (), CfgErrorLine);
759 /* If the segment is marked as BSS style, it may not have separate
760 * load and run memory areas, because it's is never written to disk.
762 if ((S->Flags & SF_BSS) != 0 && (S->Flags & SF_LOAD_AND_RUN) != 0) {
763 Warning ("%s(%u): Segment with type `bss' has both LOAD and RUN "
764 "memory areas assigned", CfgGetName (), CfgErrorLine);
767 /* Don't allow read/write data to be put into a readonly area */
768 if ((S->Flags & SF_RO) == 0) {
769 if (S->Run->Flags & MF_RO) {
770 CfgError ("Cannot put r/w segment `%s' in r/o memory area `%s'",
771 S->Name, S->Run->Name);
775 /* Only one of ALIGN, START and OFFSET may be used */
776 Count = ((S->Flags & SF_ALIGN) != 0) +
777 ((S->Flags & SF_OFFSET) != 0) +
778 ((S->Flags & SF_START) != 0);
780 CfgError ("Only one of ALIGN, START, OFFSET may be used");
783 /* If this segment does exist in any of the object files, insert the
784 * descriptor into the list of segment descriptors. Otherwise print a
785 * warning and discard it, because the segment pointer in the
786 * descriptor is invalid.
789 /* Insert the descriptor into the list of all descriptors */
791 /* Insert the segment into the memory area list */
792 MemoryInsert (S->Run, S);
793 if ((S->Flags & SF_LOAD_AND_RUN) != 0) {
794 /* We have a separate RUN area given */
795 MemoryInsert (S->Load, S);
798 /* Print a warning if the segment is not optional */
799 if ((S->Flags & SF_OPTIONAL) == 0) {
800 CfgWarning ("Segment `%s' does not exist", S->Name);
802 /* Discard the descriptor */
806 /* Skip the semicolon */
813 static void ParseO65 (void)
814 /* Parse the o65 format section */
816 static const IdentTok Attributes [] = {
817 { "EXPORT", CFGTOK_EXPORT },
818 { "IMPORT", CFGTOK_IMPORT },
819 { "TYPE", CFGTOK_TYPE },
822 { "VERSION", CFGTOK_VERSION },
824 static const IdentTok Types [] = {
825 { "SMALL", CFGTOK_SMALL },
826 { "LARGE", CFGTOK_LARGE },
828 static const IdentTok OperatingSystems [] = {
829 { "LUNIX", CFGTOK_LUNIX },
830 { "OSA65", CFGTOK_OSA65 },
831 { "CC65", CFGTOK_CC65 },
834 /* Bitmask to remember the attributes we got already */
838 atOSVersion = 0x0002,
845 unsigned AttrFlags = atNone;
847 /* Remember the attributes read */
848 unsigned OS = 0; /* Initialize to keep gcc happy */
849 unsigned Version = 0;
851 /* Read the attributes */
852 while (CfgTok == CFGTOK_IDENT) {
854 /* Map the identifier to a token */
856 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
859 /* An optional assignment follows */
861 CfgOptionalAssign ();
863 /* Check which attribute was given */
867 /* Remember we had this token (maybe more than once) */
868 AttrFlags |= atExport;
869 /* We expect an identifier */
871 /* Check if the export symbol is also defined as an import. */
872 if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
873 CfgError ("Exported symbol `%s' cannot be an import", CfgSVal);
875 /* Check if we have this symbol defined already. The entry
876 * routine will check this also, but we get a more verbose
877 * error message when checking it here.
879 if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
880 CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
882 /* Insert the symbol into the table */
883 O65SetExport (O65FmtDesc, CfgSVal);
887 /* Remember we had this token (maybe more than once) */
888 AttrFlags |= atImport;
889 /* We expect an identifier */
891 /* Check if the imported symbol is also defined as an export. */
892 if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
893 CfgError ("Imported symbol `%s' cannot be an export", CfgSVal);
895 /* Check if we have this symbol defined already. The entry
896 * routine will check this also, but we get a more verbose
897 * error message when checking it here.
899 if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
900 CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
902 /* Insert the symbol into the table */
903 O65SetImport (O65FmtDesc, CfgSVal);
907 /* Cannot have this attribute twice */
908 FlagAttr (&AttrFlags, atType, "TYPE");
909 /* Get the type of the executable */
910 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
914 O65SetSmallModel (O65FmtDesc);
918 O65SetLargeModel (O65FmtDesc);
922 CfgError ("Unexpected type token");
927 /* Cannot use this attribute twice */
928 FlagAttr (&AttrFlags, atOS, "OS");
929 /* Get the operating system */
930 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
932 case CFGTOK_LUNIX: OS = O65OS_LUNIX; break;
933 case CFGTOK_OSA65: OS = O65OS_OSA65; break;
934 case CFGTOK_CC65: OS = O65OS_CC65; break;
935 default: CfgError ("Unexpected OS token");
940 /* Cannot have this attribute twice */
941 FlagAttr (&AttrFlags, atID, "ID");
942 /* We're expecting a number in the 0..$FFFF range*/
944 CfgRangeCheck (0, 0xFFFF);
945 ModuleId = (unsigned) CfgIVal;
949 /* Cannot have this attribute twice */
950 FlagAttr (&AttrFlags, atVersion, "VERSION");
951 /* We're expecting a number in byte range */
953 CfgRangeCheck (0, 0xFF);
954 Version = (unsigned) CfgIVal;
958 FAIL ("Unexpected attribute token");
962 /* Skip the attribute value and an optional comma */
967 /* Check if we have all mandatory attributes */
968 AttrCheck (AttrFlags, atOS, "OS");
970 /* Check for attributes that may not be combined */
971 if (OS == O65OS_CC65) {
972 if ((AttrFlags & (atImport | atExport)) != 0) {
973 CfgError ("OS type CC65 may not have imports or exports");
976 if (AttrFlags & atID) {
977 CfgError ("Operating system does not support the ID attribute");
981 /* Set the O65 operating system to use */
982 O65SetOS (O65FmtDesc, OS, Version, ModuleId);
987 static void ParseFormats (void)
988 /* Parse a target format section */
990 static const IdentTok Formats [] = {
991 { "O65", CFGTOK_O65 },
992 { "BIN", CFGTOK_BIN },
993 { "BINARY", CFGTOK_BIN },
996 while (CfgTok == CFGTOK_IDENT) {
998 /* Map the identifier to a token */
1000 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
1003 /* Skip the name and the following colon */
1007 /* Parse the format options */
1008 switch (FormatTok) {
1015 /* No attribibutes available */
1019 Error ("Unexpected format token");
1022 /* Skip the semicolon */
1029 static void ParseConDes (void)
1030 /* Parse the CONDES feature */
1032 static const IdentTok Attributes [] = {
1033 { "SEGMENT", CFGTOK_SEGMENT },
1034 { "LABEL", CFGTOK_LABEL },
1035 { "COUNT", CFGTOK_COUNT },
1036 { "TYPE", CFGTOK_TYPE },
1037 { "ORDER", CFGTOK_ORDER },
1040 static const IdentTok Types [] = {
1041 { "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
1042 { "DESTRUCTOR", CFGTOK_DESTRUCTOR },
1045 static const IdentTok Orders [] = {
1046 { "DECREASING", CFGTOK_DECREASING },
1047 { "INCREASING", CFGTOK_INCREASING },
1050 /* Attribute values. */
1051 char SegName[sizeof (CfgSVal)];
1052 char Label[sizeof (CfgSVal)];
1053 char Count[sizeof (CfgSVal)];
1054 /* Initialize to avoid gcc warnings: */
1056 ConDesOrder Order = cdIncreasing;
1058 /* Bitmask to remember the attributes we got already */
1067 unsigned AttrFlags = atNone;
1069 /* Parse the attributes */
1072 /* Map the identifier to a token */
1074 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1077 /* An optional assignment follows */
1079 CfgOptionalAssign ();
1081 /* Check which attribute was given */
1084 case CFGTOK_SEGMENT:
1085 /* Don't allow this twice */
1086 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1087 /* We expect an identifier */
1089 /* Remember the value for later */
1090 strcpy (SegName, CfgSVal);
1094 /* Don't allow this twice */
1095 FlagAttr (&AttrFlags, atLabel, "LABEL");
1096 /* We expect an identifier */
1098 /* Remember the value for later */
1099 strcpy (Label, CfgSVal);
1103 /* Don't allow this twice */
1104 FlagAttr (&AttrFlags, atCount, "COUNT");
1105 /* We expect an identifier */
1107 /* Remember the value for later */
1108 strcpy (Count, CfgSVal);
1112 /* Don't allow this twice */
1113 FlagAttr (&AttrFlags, atType, "TYPE");
1114 /* The type may be given as id or numerical */
1115 if (CfgTok == CFGTOK_INTCON) {
1116 CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1117 Type = (int) CfgIVal;
1119 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1121 case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
1122 case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
1123 default: FAIL ("Unexpected type token");
1129 /* Don't allow this twice */
1130 FlagAttr (&AttrFlags, atOrder, "ORDER");
1131 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1133 case CFGTOK_DECREASING: Order = cdDecreasing; break;
1134 case CFGTOK_INCREASING: Order = cdIncreasing; break;
1135 default: FAIL ("Unexpected order token");
1140 FAIL ("Unexpected attribute token");
1144 /* Skip the attribute value */
1147 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1148 if (CfgTok == CFGTOK_SEMI) {
1150 } else if (CfgTok == CFGTOK_COMMA) {
1155 /* Check if we have all mandatory attributes */
1156 AttrCheck (AttrFlags, atSegName, "SEGMENT");
1157 AttrCheck (AttrFlags, atLabel, "LABEL");
1158 AttrCheck (AttrFlags, atType, "TYPE");
1160 /* Check if the condes has already attributes defined */
1161 if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1162 CfgError ("CONDES attributes for type %d are already defined", Type);
1165 /* Define the attributes */
1166 ConDesSetSegName (Type, SegName);
1167 ConDesSetLabel (Type, Label);
1168 if (AttrFlags & atCount) {
1169 ConDesSetCountSym (Type, Count);
1171 if (AttrFlags & atOrder) {
1172 ConDesSetOrder (Type, Order);
1178 static void ParseStartAddress (void)
1179 /* Parse the STARTADDRESS feature */
1181 static const IdentTok Attributes [] = {
1182 { "DEFAULT", CFGTOK_DEFAULT },
1186 /* Attribute values. */
1187 unsigned long DefStartAddr = 0;
1189 /* Bitmask to remember the attributes we got already */
1194 unsigned AttrFlags = atNone;
1196 /* Parse the attributes */
1199 /* Map the identifier to a token */
1201 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1204 /* An optional assignment follows */
1206 CfgOptionalAssign ();
1208 /* Check which attribute was given */
1211 case CFGTOK_DEFAULT:
1212 /* Don't allow this twice */
1213 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1214 /* We expect a number */
1216 CfgRangeCheck (0, 0xFFFFFF);
1217 /* Remember the value for later */
1218 DefStartAddr = CfgIVal;
1222 FAIL ("Unexpected attribute token");
1226 /* Skip the attribute value */
1229 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1230 if (CfgTok == CFGTOK_SEMI) {
1232 } else if (CfgTok == CFGTOK_COMMA) {
1237 /* Check if we have all mandatory attributes */
1238 AttrCheck (AttrFlags, atDefault, "DEFAULT");
1240 /* If no start address was given on the command line, use the one given
1243 if (!HaveStartAddr) {
1244 StartAddr = DefStartAddr;
1250 static void ParseFeatures (void)
1251 /* Parse a features section */
1253 static const IdentTok Features [] = {
1254 { "CONDES", CFGTOK_CONDES },
1255 { "STARTADDRESS", CFGTOK_STARTADDRESS },
1258 while (CfgTok == CFGTOK_IDENT) {
1260 /* Map the identifier to a token */
1261 cfgtok_t FeatureTok;
1262 CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1263 FeatureTok = CfgTok;
1265 /* Skip the name and the following colon */
1269 /* Parse the format options */
1270 switch (FeatureTok) {
1276 case CFGTOK_STARTADDRESS:
1277 ParseStartAddress ();
1282 Error ("Unexpected feature token");
1285 /* Skip the semicolon */
1292 static void ParseSymbols (void)
1293 /* Parse a symbols section */
1295 while (CfgTok == CFGTOK_IDENT) {
1299 /* Remember the name */
1300 char Name [sizeof (CfgSVal)];
1301 strcpy (Name, CfgSVal);
1304 /* Allow an optional assignment */
1305 CfgOptionalAssign ();
1307 /* Make sure the next token is an integer, read and skip it */
1312 /* Generate an export with the given value */
1313 CreateConstExport (Name, Val);
1315 /* Skip the semicolon */
1322 static void ParseConfig (void)
1323 /* Parse the config file */
1325 static const IdentTok BlockNames [] = {
1326 { "MEMORY", CFGTOK_MEMORY },
1327 { "FILES", CFGTOK_FILES },
1328 { "SEGMENTS", CFGTOK_SEGMENTS },
1329 { "FORMATS", CFGTOK_FORMATS },
1330 { "FEATURES", CFGTOK_FEATURES },
1331 { "SYMBOLS", CFGTOK_SYMBOLS },
1337 /* Read the block ident */
1338 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1342 /* Expected a curly brace */
1343 CfgConsume (CFGTOK_LCURLY, "`{' expected");
1345 /* Read the block */
1356 case CFGTOK_SEGMENTS:
1360 case CFGTOK_FORMATS:
1364 case CFGTOK_FEATURES:
1368 case CFGTOK_SYMBOLS:
1373 FAIL ("Unexpected block token");
1377 /* Skip closing brace */
1378 CfgConsume (CFGTOK_RCURLY, "`}' expected");
1380 } while (CfgTok != CFGTOK_EOF);
1386 /* Read the configuration */
1388 /* Create the descriptors for the binary formats */
1389 BinFmtDesc = NewBinDesc ();
1390 O65FmtDesc = NewO65Desc ();
1392 /* If we have a config name given, open the file, otherwise we will read
1397 /* Parse the file */
1400 /* Close the input file */
1406 static void CreateRunDefines (SegDesc* S)
1407 /* Create the defines for a RUN segment */
1411 xsprintf (Buf, sizeof (Buf), "__%s_RUN__", S->Name);
1412 CreateSegmentExport (Buf, S->Seg, 0);
1413 xsprintf (Buf, sizeof (Buf), "__%s_SIZE__", S->Name);
1414 CreateConstExport (Buf, S->Seg->Size);
1415 S->Flags |= SF_RUN_DEF;
1420 static void CreateLoadDefines (Memory* M, SegDesc* S)
1421 /* Create the defines for a LOAD segment */
1425 xsprintf (Buf, sizeof (Buf), "__%s_LOAD__", S->Name);
1426 CreateMemoryExport (Buf, M, S->Seg->PC - M->Start);
1427 S->Flags |= SF_LOAD_DEF;
1432 void CfgAssignSegments (void)
1433 /* Assign segments, define linker symbols where requested */
1435 /* Walk through each of the memory sections. Add up the sizes and check
1436 * for an overflow of the section. Assign the start addresses of the
1437 * segments while doing this.
1439 Memory* M = MemoryList;
1442 /* Get the start address of this memory area */
1443 unsigned long Addr = M->Start;
1445 /* Walk through the segments in this memory area */
1446 MemListNode* N = M->SegList;
1449 /* Get the segment from the node */
1450 SegDesc* S = N->Seg;
1452 /* Handle ALIGN and OFFSET/START */
1453 if (S->Flags & SF_ALIGN) {
1454 /* Align the address */
1455 unsigned long Val = (0x01UL << S->Align) - 1;
1456 Addr = (Addr + Val) & ~Val;
1457 } else if (S->Flags & (SF_OFFSET | SF_START)) {
1458 /* Give the segment a fixed starting address */
1459 unsigned long NewAddr = S->Addr;
1460 if (S->Flags & SF_OFFSET) {
1461 /* An offset was given, no address, make an address */
1462 NewAddr += M->Start;
1464 if (Addr > NewAddr) {
1465 /* Offset already too large */
1466 if (S->Flags & SF_OFFSET) {
1467 Error ("Offset too small in `%s', segment `%s'",
1470 Error ("Start address too low in `%s', segment `%s'",
1477 /* If this is the run area, set the start address of this segment */
1482 /* Increment the fill level of the memory area and check for an
1485 M->FillLevel = Addr + S->Seg->Size - M->Start;
1486 if (M->FillLevel > M->Size) {
1487 Error ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
1488 M->Name, S->Name, M->FillLevel - M->Size);
1491 /* If requested, define symbols for the start and size of the
1494 if (S->Flags & SF_DEFINE) {
1495 if ((S->Flags & SF_LOAD_AND_RUN) && S->Run == S->Load) {
1496 /* RUN and LOAD given and in one memory area.
1497 * Be careful: We will encounter this code twice, the
1498 * first time when walking the RUN list, second time when
1499 * walking the LOAD list. Be sure to define only the
1500 * relevant symbols on each walk.
1503 if ((S->Flags & SF_LOAD_DEF) == 0) {
1504 CreateLoadDefines (M, S);
1506 CHECK ((S->Flags & SF_RUN_DEF) == 0);
1507 CreateRunDefines (S);
1511 /* RUN and LOAD in different memory areas, or RUN not
1512 * given, so RUN defaults to LOAD. In the latter case, we
1513 * have only one copy of the segment in the area.
1516 CreateRunDefines (S);
1519 CreateLoadDefines (M, S);
1524 /* Calculate the new address */
1525 Addr += S->Seg->Size;
1531 /* If requested, define symbols for start and size of the memory area */
1532 if (M->Flags & MF_DEFINE) {
1534 sprintf (Buf, "__%s_START__", M->Name);
1535 CreateMemoryExport (Buf, M, 0);
1536 sprintf (Buf, "__%s_SIZE__", M->Name);
1537 CreateConstExport (Buf, M->Size);
1538 sprintf (Buf, "__%s_LAST__", M->Name);
1539 CreateConstExport (Buf, M->FillLevel);
1542 /* Next memory area */
1549 void CfgWriteTarget (void)
1550 /* Write the target file(s) */
1554 /* Walk through the files list */
1557 /* We don't need to look at files with no memory areas */
1560 /* Is there an output file? */
1561 if (strlen (F->Name) > 0) {
1563 /* Assign a proper binary format */
1564 if (F->Format == BINFMT_DEFAULT) {
1565 F->Format = DefaultBinFmt;
1568 /* Call the apropriate routine for the binary format */
1569 switch (F->Format) {
1572 BinWriteTarget (BinFmtDesc, F);
1576 O65WriteTarget (O65FmtDesc, F);
1580 Internal ("Invalid binary format: %u", F->Format);
1586 /* No output file. Walk through the list and mark all segments
1587 * loading into these memory areas in this file as dumped.
1595 Print (stdout, 2, "Skipping `%s'...\n", M->Name);
1597 /* Walk throught the segments */
1600 if (N->Seg->Load == M) {
1601 /* Load area - mark the segment as dumped */
1602 N->Seg->Seg->Dumped = 1;
1605 /* Next segment node */
1608 /* Next memory area */