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 /*****************************************************************************/
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_DEFINE 0x0010
100 #define SA_OFFSET 0x0020
101 #define SA_START 0x0040
102 #define SA_OPTIONAL 0x0080
106 /* Descriptor holding information about the binary formats */
107 static BinDesc* BinFmtDesc = 0;
108 static O65Desc* O65FmtDesc = 0;
112 /*****************************************************************************/
114 /*****************************************************************************/
118 static File* NewFile (unsigned Name);
119 /* Create a new file descriptor and insert it into the list */
123 /*****************************************************************************/
124 /* List management */
125 /*****************************************************************************/
129 static File* FindFile (unsigned Name)
130 /* Find a file with a given name. */
134 if (F->Name == Name) {
144 static File* GetFile (unsigned Name)
145 /* Get a file entry with the given name. Create a new one if needed. */
147 File* F = FindFile (Name);
149 /* Create a new one */
157 static void FileInsert (File* F, Memory* M)
158 /* Insert the memory area into the files list */
161 if (F->MemList == 0) {
165 F->MemLast->FNext = M;
172 static Memory* CfgFindMemory (unsigned Name)
173 /* Find the memory are with the given name. Return NULL if not found */
175 Memory* M = MemoryList;
177 if (M->Name == Name) {
187 static Memory* CfgGetMemory (unsigned Name)
188 /* Find the memory are with the given name. Print an error on an invalid name */
190 Memory* M = CfgFindMemory (Name);
192 CfgError ("Invalid memory area `%s'", GetString (Name));
199 static SegDesc* CfgFindSegDesc (unsigned Name)
200 /* Find the segment descriptor with the given name, return NULL if not found. */
202 SegDesc* S = SegDescList;
204 if (S->Name == Name) {
217 static void SegDescInsert (SegDesc* S)
218 /* Insert a segment descriptor into the list of segment descriptors */
220 /* Insert the struct into the list */
221 S->Next = SegDescList;
228 static void MemoryInsert (Memory* M, SegDesc* S)
229 /* Insert the segment descriptor into the memory area list */
231 /* Create a new node for the entry */
232 MemListNode* N = xmalloc (sizeof (MemListNode));
236 if (M->SegLast == 0) {
240 M->SegLast->Next = N;
247 /*****************************************************************************/
248 /* Constructors/Destructors */
249 /*****************************************************************************/
253 static File* NewFile (unsigned Name)
254 /* Create a new file descriptor and insert it into the list */
256 /* Allocate memory */
257 File* F = xmalloc (sizeof (File));
259 /* Initialize the fields */
262 F->Format = BINFMT_DEFAULT;
266 /* Insert the struct into the list */
271 /* ...and return it */
277 static Memory* NewMemory (unsigned Name)
278 /* Create a new memory section and insert it into the list */
280 /* Check for duplicate names */
281 Memory* M = CfgFindMemory (Name);
283 CfgError ("Memory area `%s' defined twice", GetString (Name));
286 /* Allocate memory */
287 M = xmalloc (sizeof (Memory));
289 /* Initialize the fields */
303 /* Insert the struct into the list */
304 if (MemoryLast == 0) {
308 MemoryLast->Next = M;
313 /* ...and return it */
319 static SegDesc* NewSegDesc (unsigned Name)
320 /* Create a segment descriptor */
324 /* Check for duplicate names */
325 SegDesc* S = CfgFindSegDesc (Name);
327 CfgError ("Segment `%s' defined twice", GetString (Name));
330 /* Search for the actual segment in the input files. The function may
331 * return NULL (no such segment), this is checked later.
333 Seg = SegFind (Name);
335 /* Allocate memory */
336 S = xmalloc (sizeof (SegDesc));
338 /* Initialize the fields */
346 /* ...and return it */
352 static void FreeSegDesc (SegDesc* S)
353 /* Free a segment descriptor */
360 /*****************************************************************************/
362 /*****************************************************************************/
366 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
367 /* Check if the item is already defined. Print an error if so. If not, set
368 * the marker that we have a definition now.
372 CfgError ("%s is already defined", Name);
379 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
380 /* Check that a mandatory attribute was given */
382 if ((Attr & Mask) == 0) {
383 CfgError ("%s attribute is missing", Name);
389 static void ParseMemory (void)
390 /* Parse a MEMORY section */
392 static const IdentTok Attributes [] = {
393 { "START", CFGTOK_START },
394 { "SIZE", CFGTOK_SIZE },
395 { "TYPE", CFGTOK_TYPE },
396 { "FILE", CFGTOK_FILE },
397 { "DEFINE", CFGTOK_DEFINE },
398 { "FILL", CFGTOK_FILL },
399 { "FILLVAL", CFGTOK_FILLVAL },
401 static const IdentTok Types [] = {
406 while (CfgTok == CFGTOK_IDENT) {
408 /* Create a new entry on the heap */
409 Memory* M = NewMemory (GetStringId (CfgSVal));
411 /* Skip the name and the following colon */
415 /* Read the attributes */
416 while (CfgTok == CFGTOK_IDENT) {
418 /* Map the identifier to a token */
420 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
423 /* An optional assignment follows */
425 CfgOptionalAssign ();
427 /* Check which attribute was given */
431 FlagAttr (&M->Attr, MA_START, "START");
437 FlagAttr (&M->Attr, MA_SIZE, "SIZE");
443 FlagAttr (&M->Attr, MA_TYPE, "TYPE");
444 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
445 if (CfgTok == CFGTOK_RO) {
451 FlagAttr (&M->Attr, MA_FILE, "FILE");
453 /* Get the file entry and insert the memory area */
454 FileInsert (GetFile (GetStringId (CfgSVal)), M);
458 FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
459 /* Map the token to a boolean */
461 if (CfgTok == CFGTOK_TRUE) {
462 M->Flags |= MF_DEFINE;
467 FlagAttr (&M->Attr, MA_FILL, "FILL");
468 /* Map the token to a boolean */
470 if (CfgTok == CFGTOK_TRUE) {
476 FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
478 CfgRangeCheck (0, 0xFF);
479 M->FillVal = (unsigned char) CfgIVal;
483 FAIL ("Unexpected attribute token");
487 /* Skip the attribute value and an optional comma */
492 /* Skip the semicolon */
495 /* Check for mandatory parameters */
496 AttrCheck (M->Attr, MA_START, "START");
497 AttrCheck (M->Attr, MA_SIZE, "SIZE");
499 /* If we don't have a file name for output given, use the default
502 if ((M->Attr & MA_FILE) == 0) {
503 FileInsert (GetFile (GetStringId (OutputName)), M);
510 static void ParseFiles (void)
511 /* Parse a FILES section */
513 static const IdentTok Attributes [] = {
514 { "FORMAT", CFGTOK_FORMAT },
516 static const IdentTok Formats [] = {
517 { "O65", CFGTOK_O65 },
518 { "BIN", CFGTOK_BIN },
519 { "BINARY", CFGTOK_BIN },
523 /* Parse all files */
524 while (CfgTok != CFGTOK_RCURLY) {
528 /* We expect a string value here */
531 /* Search for the file, it must exist */
532 F = FindFile (GetStringId (CfgSVal));
534 CfgError ("No such file: `%s'", CfgSVal);
537 /* Skip the token and the following colon */
541 /* Read the attributes */
542 while (CfgTok == CFGTOK_IDENT) {
544 /* Map the identifier to a token */
546 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
549 /* An optional assignment follows */
551 CfgOptionalAssign ();
553 /* Check which attribute was given */
557 if (F->Format != BINFMT_DEFAULT) {
558 /* We've set the format already! */
559 Error ("Cannot set a file format twice");
561 /* Read the format token */
562 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
566 F->Format = BINFMT_BINARY;
570 F->Format = BINFMT_O65;
574 Error ("Unexpected format token");
579 FAIL ("Unexpected attribute token");
583 /* Skip the attribute value and an optional comma */
588 /* Skip the semicolon */
596 static void ParseSegments (void)
597 /* Parse a SEGMENTS section */
599 static const IdentTok Attributes [] = {
600 { "ALIGN", CFGTOK_ALIGN },
601 { "DEFINE", CFGTOK_DEFINE },
602 { "LOAD", CFGTOK_LOAD },
603 { "OFFSET", CFGTOK_OFFSET },
604 { "OPTIONAL", CFGTOK_OPTIONAL },
605 { "RUN", CFGTOK_RUN },
606 { "START", CFGTOK_START },
607 { "TYPE", CFGTOK_TYPE },
609 static const IdentTok Types [] = {
612 { "BSS", CFGTOK_BSS },
614 { "WP", CFGTOK_WPROT },
615 { "WPROT", CFGTOK_WPROT },
620 while (CfgTok == CFGTOK_IDENT) {
624 /* Create a new entry on the heap */
625 S = NewSegDesc (GetStringId (CfgSVal));
627 /* Skip the name and the following colon */
631 /* Read the attributes */
632 while (CfgTok == CFGTOK_IDENT) {
634 /* Map the identifier to a token */
636 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
639 /* An optional assignment follows */
641 CfgOptionalAssign ();
643 /* Check which attribute was given */
648 FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
649 CfgRangeCheck (1, 0x10000);
650 S->Align = BitFind (CfgIVal);
651 if ((0x01UL << S->Align) != CfgIVal) {
652 CfgError ("Alignment must be a power of 2");
654 S->Flags |= SF_ALIGN;
658 FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
659 /* Map the token to a boolean */
661 if (CfgTok == CFGTOK_TRUE) {
662 S->Flags |= SF_DEFINE;
667 FlagAttr (&S->Attr, SA_LOAD, "LOAD");
668 S->Load = CfgGetMemory (GetStringId (CfgSVal));
673 FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
674 CfgRangeCheck (1, 0x1000000);
676 S->Flags |= SF_OFFSET;
679 case CFGTOK_OPTIONAL:
680 FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL");
682 if (CfgTok == CFGTOK_TRUE) {
683 S->Flags |= SF_OPTIONAL;
688 FlagAttr (&S->Attr, SA_RUN, "RUN");
689 S->Run = CfgGetMemory (GetStringId (CfgSVal));
694 FlagAttr (&S->Attr, SA_START, "START");
695 CfgRangeCheck (1, 0x1000000);
697 S->Flags |= SF_START;
701 FlagAttr (&S->Attr, SA_TYPE, "TYPE");
702 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
704 case CFGTOK_RO: S->Flags |= SF_RO; break;
705 case CFGTOK_RW: /* Default */ break;
706 case CFGTOK_BSS: S->Flags |= SF_BSS; break;
707 case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break;
708 case CFGTOK_WPROT: S->Flags |= (SF_RO | SF_WPROT); break;
709 default: Internal ("Unexpected token: %d", CfgTok);
714 FAIL ("Unexpected attribute token");
718 /* Skip the attribute value and an optional comma */
723 /* Check for mandatory parameters */
724 AttrCheck (S->Attr, SA_LOAD, "LOAD");
726 /* Set defaults for stuff not given */
727 if ((S->Attr & SA_RUN) == 0) {
731 /* Both attributes given */
732 S->Flags |= SF_LOAD_AND_RUN;
734 if ((S->Attr & SA_ALIGN) == 0) {
739 /* If the segment is marked as BSS style, and if the segment exists
740 * in any of the object file, check that there's no initialized data
743 if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
744 Warning ("%s(%u): Segment with type `bss' contains initialized data",
745 CfgGetName (), CfgErrorLine);
748 /* If the segment is marked as BSS style, it may not have separate
749 * load and run memory areas, because it's is never written to disk.
751 if ((S->Flags & SF_BSS) != 0 && (S->Flags & SF_LOAD_AND_RUN) != 0) {
752 Warning ("%s(%u): Segment with type `bss' has both LOAD and RUN "
753 "memory areas assigned", CfgGetName (), CfgErrorLine);
756 /* Don't allow read/write data to be put into a readonly area */
757 if ((S->Flags & SF_RO) == 0) {
758 if (S->Run->Flags & MF_RO) {
759 CfgError ("Cannot put r/w segment `%s' in r/o memory area `%s'",
760 GetString (S->Name), GetString (S->Run->Name));
764 /* Only one of ALIGN, START and OFFSET may be used */
765 Count = ((S->Flags & SF_ALIGN) != 0) +
766 ((S->Flags & SF_OFFSET) != 0) +
767 ((S->Flags & SF_START) != 0);
769 CfgError ("Only one of ALIGN, START, OFFSET may be used");
772 /* If this segment does exist in any of the object files, insert the
773 * descriptor into the list of segment descriptors. Otherwise print a
774 * warning and discard it, because the segment pointer in the
775 * descriptor is invalid.
778 /* Insert the descriptor into the list of all descriptors */
780 /* Insert the segment into the memory area list */
781 MemoryInsert (S->Run, S);
782 if ((S->Flags & SF_LOAD_AND_RUN) != 0) {
783 /* We have a separate RUN area given */
784 MemoryInsert (S->Load, S);
787 /* Print a warning if the segment is not optional */
788 if ((S->Flags & SF_OPTIONAL) == 0) {
789 CfgWarning ("Segment `%s' does not exist", GetString (S->Name));
791 /* Discard the descriptor */
795 /* Skip the semicolon */
802 static void ParseO65 (void)
803 /* Parse the o65 format section */
805 static const IdentTok Attributes [] = {
806 { "EXPORT", CFGTOK_EXPORT },
807 { "IMPORT", CFGTOK_IMPORT },
808 { "TYPE", CFGTOK_TYPE },
811 { "VERSION", CFGTOK_VERSION },
813 static const IdentTok Types [] = {
814 { "SMALL", CFGTOK_SMALL },
815 { "LARGE", CFGTOK_LARGE },
817 static const IdentTok OperatingSystems [] = {
818 { "LUNIX", CFGTOK_LUNIX },
819 { "OSA65", CFGTOK_OSA65 },
820 { "CC65", CFGTOK_CC65 },
823 /* Bitmask to remember the attributes we got already */
827 atOSVersion = 0x0002,
834 unsigned AttrFlags = atNone;
836 /* Remember the attributes read */
837 unsigned OS = 0; /* Initialize to keep gcc happy */
838 unsigned Version = 0;
840 /* Read the attributes */
841 while (CfgTok == CFGTOK_IDENT) {
843 /* Map the identifier to a token */
845 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
848 /* An optional assignment follows */
850 CfgOptionalAssign ();
852 /* Check which attribute was given */
856 /* Remember we had this token (maybe more than once) */
857 AttrFlags |= atExport;
858 /* We expect an identifier */
860 /* Check if the export symbol is also defined as an import. */
861 if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
862 CfgError ("Exported symbol `%s' cannot be an import", CfgSVal);
864 /* Check if we have this symbol defined already. The entry
865 * routine will check this also, but we get a more verbose
866 * error message when checking it here.
868 if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
869 CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
871 /* Insert the symbol into the table */
872 O65SetExport (O65FmtDesc, CfgSVal);
876 /* Remember we had this token (maybe more than once) */
877 AttrFlags |= atImport;
878 /* We expect an identifier */
880 /* Check if the imported symbol is also defined as an export. */
881 if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
882 CfgError ("Imported symbol `%s' cannot be an export", CfgSVal);
884 /* Check if we have this symbol defined already. The entry
885 * routine will check this also, but we get a more verbose
886 * error message when checking it here.
888 if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
889 CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
891 /* Insert the symbol into the table */
892 O65SetImport (O65FmtDesc, CfgSVal);
896 /* Cannot have this attribute twice */
897 FlagAttr (&AttrFlags, atType, "TYPE");
898 /* Get the type of the executable */
899 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
903 O65SetSmallModel (O65FmtDesc);
907 O65SetLargeModel (O65FmtDesc);
911 CfgError ("Unexpected type token");
916 /* Cannot use this attribute twice */
917 FlagAttr (&AttrFlags, atOS, "OS");
918 /* Get the operating system */
919 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
921 case CFGTOK_LUNIX: OS = O65OS_LUNIX; break;
922 case CFGTOK_OSA65: OS = O65OS_OSA65; break;
923 case CFGTOK_CC65: OS = O65OS_CC65; break;
924 default: CfgError ("Unexpected OS token");
929 /* Cannot have this attribute twice */
930 FlagAttr (&AttrFlags, atID, "ID");
931 /* We're expecting a number in the 0..$FFFF range*/
933 CfgRangeCheck (0, 0xFFFF);
934 ModuleId = (unsigned) CfgIVal;
938 /* Cannot have this attribute twice */
939 FlagAttr (&AttrFlags, atVersion, "VERSION");
940 /* We're expecting a number in byte range */
942 CfgRangeCheck (0, 0xFF);
943 Version = (unsigned) CfgIVal;
947 FAIL ("Unexpected attribute token");
951 /* Skip the attribute value and an optional comma */
956 /* Check if we have all mandatory attributes */
957 AttrCheck (AttrFlags, atOS, "OS");
959 /* Check for attributes that may not be combined */
960 if (OS == O65OS_CC65) {
961 if ((AttrFlags & (atImport | atExport)) != 0) {
962 CfgError ("OS type CC65 may not have imports or exports");
965 if (AttrFlags & atID) {
966 CfgError ("Operating system does not support the ID attribute");
970 /* Set the O65 operating system to use */
971 O65SetOS (O65FmtDesc, OS, Version, ModuleId);
976 static void ParseFormats (void)
977 /* Parse a target format section */
979 static const IdentTok Formats [] = {
980 { "O65", CFGTOK_O65 },
981 { "BIN", CFGTOK_BIN },
982 { "BINARY", CFGTOK_BIN },
985 while (CfgTok == CFGTOK_IDENT) {
987 /* Map the identifier to a token */
989 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
992 /* Skip the name and the following colon */
996 /* Parse the format options */
1004 /* No attribibutes available */
1008 Error ("Unexpected format token");
1011 /* Skip the semicolon */
1018 static void ParseConDes (void)
1019 /* Parse the CONDES feature */
1021 static const IdentTok Attributes [] = {
1022 { "SEGMENT", CFGTOK_SEGMENT },
1023 { "LABEL", CFGTOK_LABEL },
1024 { "COUNT", CFGTOK_COUNT },
1025 { "TYPE", CFGTOK_TYPE },
1026 { "ORDER", CFGTOK_ORDER },
1029 static const IdentTok Types [] = {
1030 { "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
1031 { "DESTRUCTOR", CFGTOK_DESTRUCTOR },
1034 static const IdentTok Orders [] = {
1035 { "DECREASING", CFGTOK_DECREASING },
1036 { "INCREASING", CFGTOK_INCREASING },
1039 /* Attribute values. */
1040 unsigned SegName = INVALID_STRING_ID;
1041 unsigned Label = INVALID_STRING_ID;
1042 unsigned Count = INVALID_STRING_ID;
1043 /* Initialize to avoid gcc warnings: */
1045 ConDesOrder Order = cdIncreasing;
1047 /* Bitmask to remember the attributes we got already */
1056 unsigned AttrFlags = atNone;
1058 /* Parse the attributes */
1061 /* Map the identifier to a token */
1063 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1066 /* An optional assignment follows */
1068 CfgOptionalAssign ();
1070 /* Check which attribute was given */
1073 case CFGTOK_SEGMENT:
1074 /* Don't allow this twice */
1075 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1076 /* We expect an identifier */
1078 /* Remember the value for later */
1079 SegName = GetStringId (CfgSVal);
1083 /* Don't allow this twice */
1084 FlagAttr (&AttrFlags, atLabel, "LABEL");
1085 /* We expect an identifier */
1087 /* Remember the value for later */
1088 Label = GetStringId (CfgSVal);
1092 /* Don't allow this twice */
1093 FlagAttr (&AttrFlags, atCount, "COUNT");
1094 /* We expect an identifier */
1096 /* Remember the value for later */
1097 Count = GetStringId (CfgSVal);
1101 /* Don't allow this twice */
1102 FlagAttr (&AttrFlags, atType, "TYPE");
1103 /* The type may be given as id or numerical */
1104 if (CfgTok == CFGTOK_INTCON) {
1105 CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1106 Type = (int) CfgIVal;
1108 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1110 case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
1111 case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
1112 default: FAIL ("Unexpected type token");
1118 /* Don't allow this twice */
1119 FlagAttr (&AttrFlags, atOrder, "ORDER");
1120 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1122 case CFGTOK_DECREASING: Order = cdDecreasing; break;
1123 case CFGTOK_INCREASING: Order = cdIncreasing; break;
1124 default: FAIL ("Unexpected order token");
1129 FAIL ("Unexpected attribute token");
1133 /* Skip the attribute value */
1136 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1137 if (CfgTok == CFGTOK_SEMI) {
1139 } else if (CfgTok == CFGTOK_COMMA) {
1144 /* Check if we have all mandatory attributes */
1145 AttrCheck (AttrFlags, atSegName, "SEGMENT");
1146 AttrCheck (AttrFlags, atLabel, "LABEL");
1147 AttrCheck (AttrFlags, atType, "TYPE");
1149 /* Check if the condes has already attributes defined */
1150 if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1151 CfgError ("CONDES attributes for type %d are already defined", Type);
1154 /* Define the attributes */
1155 ConDesSetSegName (Type, SegName);
1156 ConDesSetLabel (Type, Label);
1157 if (AttrFlags & atCount) {
1158 ConDesSetCountSym (Type, Count);
1160 if (AttrFlags & atOrder) {
1161 ConDesSetOrder (Type, Order);
1167 static void ParseStartAddress (void)
1168 /* Parse the STARTADDRESS feature */
1170 static const IdentTok Attributes [] = {
1171 { "DEFAULT", CFGTOK_DEFAULT },
1175 /* Attribute values. */
1176 unsigned long DefStartAddr = 0;
1178 /* Bitmask to remember the attributes we got already */
1183 unsigned AttrFlags = atNone;
1185 /* Parse the attributes */
1188 /* Map the identifier to a token */
1190 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1193 /* An optional assignment follows */
1195 CfgOptionalAssign ();
1197 /* Check which attribute was given */
1200 case CFGTOK_DEFAULT:
1201 /* Don't allow this twice */
1202 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1203 /* We expect a number */
1205 CfgRangeCheck (0, 0xFFFFFF);
1206 /* Remember the value for later */
1207 DefStartAddr = CfgIVal;
1211 FAIL ("Unexpected attribute token");
1215 /* Skip the attribute value */
1218 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1219 if (CfgTok == CFGTOK_SEMI) {
1221 } else if (CfgTok == CFGTOK_COMMA) {
1226 /* Check if we have all mandatory attributes */
1227 AttrCheck (AttrFlags, atDefault, "DEFAULT");
1229 /* If no start address was given on the command line, use the one given
1232 if (!HaveStartAddr) {
1233 StartAddr = DefStartAddr;
1239 static void ParseFeatures (void)
1240 /* Parse a features section */
1242 static const IdentTok Features [] = {
1243 { "CONDES", CFGTOK_CONDES },
1244 { "STARTADDRESS", CFGTOK_STARTADDRESS },
1247 while (CfgTok == CFGTOK_IDENT) {
1249 /* Map the identifier to a token */
1250 cfgtok_t FeatureTok;
1251 CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1252 FeatureTok = CfgTok;
1254 /* Skip the name and the following colon */
1258 /* Parse the format options */
1259 switch (FeatureTok) {
1265 case CFGTOK_STARTADDRESS:
1266 ParseStartAddress ();
1271 Error ("Unexpected feature token");
1274 /* Skip the semicolon */
1281 static void ParseSymbols (void)
1282 /* Parse a symbols section */
1284 while (CfgTok == CFGTOK_IDENT) {
1288 /* Remember the name */
1289 unsigned Name = GetStringId (CfgSVal);
1292 /* Allow an optional assignment */
1293 CfgOptionalAssign ();
1295 /* Make sure the next token is an integer, read and skip it */
1300 /* Generate an export with the given value */
1301 CreateConstExport (Name, Val);
1303 /* Skip the semicolon */
1310 static void ParseConfig (void)
1311 /* Parse the config file */
1313 static const IdentTok BlockNames [] = {
1314 { "MEMORY", CFGTOK_MEMORY },
1315 { "FILES", CFGTOK_FILES },
1316 { "SEGMENTS", CFGTOK_SEGMENTS },
1317 { "FORMATS", CFGTOK_FORMATS },
1318 { "FEATURES", CFGTOK_FEATURES },
1319 { "SYMBOLS", CFGTOK_SYMBOLS },
1325 /* Read the block ident */
1326 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1330 /* Expected a curly brace */
1331 CfgConsume (CFGTOK_LCURLY, "`{' expected");
1333 /* Read the block */
1344 case CFGTOK_SEGMENTS:
1348 case CFGTOK_FORMATS:
1352 case CFGTOK_FEATURES:
1356 case CFGTOK_SYMBOLS:
1361 FAIL ("Unexpected block token");
1365 /* Skip closing brace */
1366 CfgConsume (CFGTOK_RCURLY, "`}' expected");
1368 } while (CfgTok != CFGTOK_EOF);
1374 /* Read the configuration */
1376 /* Create the descriptors for the binary formats */
1377 BinFmtDesc = NewBinDesc ();
1378 O65FmtDesc = NewO65Desc ();
1380 /* If we have a config name given, open the file, otherwise we will read
1385 /* Parse the file */
1388 /* Close the input file */
1394 static void CreateRunDefines (SegDesc* S)
1395 /* Create the defines for a RUN segment */
1399 xsprintf (Buf, sizeof (Buf), "__%s_RUN__", GetString (S->Name));
1400 CreateSegmentExport (GetStringId (Buf), S->Seg, 0);
1401 xsprintf (Buf, sizeof (Buf), "__%s_SIZE__", GetString (S->Name));
1402 CreateConstExport (GetStringId (Buf), S->Seg->Size);
1403 S->Flags |= SF_RUN_DEF;
1408 static void CreateLoadDefines (Memory* M, SegDesc* S)
1409 /* Create the defines for a LOAD segment */
1413 xsprintf (Buf, sizeof (Buf), "__%s_LOAD__", GetString (S->Name));
1414 CreateMemoryExport (GetStringId (Buf), M, S->Seg->PC - M->Start);
1415 S->Flags |= SF_LOAD_DEF;
1420 void CfgAssignSegments (void)
1421 /* Assign segments, define linker symbols where requested */
1423 /* Walk through each of the memory sections. Add up the sizes and check
1424 * for an overflow of the section. Assign the start addresses of the
1425 * segments while doing this.
1427 Memory* M = MemoryList;
1430 /* Get the start address of this memory area */
1431 unsigned long Addr = M->Start;
1433 /* Walk through the segments in this memory area */
1434 MemListNode* N = M->SegList;
1437 /* Get the segment from the node */
1438 SegDesc* S = N->Seg;
1440 /* Handle ALIGN and OFFSET/START */
1441 if (S->Flags & SF_ALIGN) {
1442 /* Align the address */
1443 unsigned long Val = (0x01UL << S->Align) - 1;
1444 Addr = (Addr + Val) & ~Val;
1445 } else if (S->Flags & (SF_OFFSET | SF_START)) {
1446 /* Give the segment a fixed starting address */
1447 unsigned long NewAddr = S->Addr;
1448 if (S->Flags & SF_OFFSET) {
1449 /* An offset was given, no address, make an address */
1450 NewAddr += M->Start;
1452 if (Addr > NewAddr) {
1453 /* Offset already too large */
1454 if (S->Flags & SF_OFFSET) {
1455 Error ("Offset too small in `%s', segment `%s'",
1456 GetString (M->Name), GetString (S->Name));
1458 Error ("Start address too low in `%s', segment `%s'",
1459 GetString (M->Name), GetString (S->Name));
1465 /* If this is the run area, set the start address of this segment */
1470 /* Increment the fill level of the memory area and check for an
1473 M->FillLevel = Addr + S->Seg->Size - M->Start;
1474 if (M->FillLevel > M->Size) {
1475 Error ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
1476 GetString (M->Name), GetString (S->Name),
1477 M->FillLevel - M->Size);
1480 /* If requested, define symbols for the start and size of the
1483 if (S->Flags & SF_DEFINE) {
1484 if ((S->Flags & SF_LOAD_AND_RUN) && S->Run == S->Load) {
1485 /* RUN and LOAD given and in one memory area.
1486 * Be careful: We will encounter this code twice, the
1487 * first time when walking the RUN list, second time when
1488 * walking the LOAD list. Be sure to define only the
1489 * relevant symbols on each walk.
1492 if ((S->Flags & SF_LOAD_DEF) == 0) {
1493 CreateLoadDefines (M, S);
1495 CHECK ((S->Flags & SF_RUN_DEF) == 0);
1496 CreateRunDefines (S);
1500 /* RUN and LOAD in different memory areas, or RUN not
1501 * given, so RUN defaults to LOAD. In the latter case, we
1502 * have only one copy of the segment in the area.
1505 CreateRunDefines (S);
1508 CreateLoadDefines (M, S);
1513 /* Calculate the new address */
1514 Addr += S->Seg->Size;
1520 /* If requested, define symbols for start and size of the memory area */
1521 if (M->Flags & MF_DEFINE) {
1523 sprintf (Buf, "__%s_START__", GetString (M->Name));
1524 CreateMemoryExport (GetStringId (Buf), M, 0);
1525 sprintf (Buf, "__%s_SIZE__", GetString (M->Name));
1526 CreateConstExport (GetStringId (Buf), M->Size);
1527 sprintf (Buf, "__%s_LAST__", GetString (M->Name));
1528 CreateConstExport (GetStringId (Buf), M->FillLevel);
1531 /* Next memory area */
1538 void CfgWriteTarget (void)
1539 /* Write the target file(s) */
1543 /* Walk through the files list */
1546 /* We don't need to look at files with no memory areas */
1549 /* Is there an output file? */
1550 if (strlen (GetString (F->Name)) > 0) {
1552 /* Assign a proper binary format */
1553 if (F->Format == BINFMT_DEFAULT) {
1554 F->Format = DefaultBinFmt;
1557 /* Call the apropriate routine for the binary format */
1558 switch (F->Format) {
1561 BinWriteTarget (BinFmtDesc, F);
1565 O65WriteTarget (O65FmtDesc, F);
1569 Internal ("Invalid binary format: %u", F->Format);
1575 /* No output file. Walk through the list and mark all segments
1576 * loading into these memory areas in this file as dumped.
1584 Print (stdout, 2, "Skipping `%s'...\n", GetString (M->Name));
1586 /* Walk throught the segments */
1589 if (N->Seg->Load == M) {
1590 /* Load area - mark the segment as dumped */
1591 N->Seg->Seg->Dumped = 1;
1594 /* Next segment node */
1597 /* Next memory area */