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 */
304 /* Insert the struct into the list */
305 if (MemoryLast == 0) {
309 MemoryLast->Next = M;
314 /* ...and return it */
320 static SegDesc* NewSegDesc (unsigned Name)
321 /* Create a segment descriptor */
325 /* Check for duplicate names */
326 SegDesc* S = CfgFindSegDesc (Name);
328 CfgError ("Segment `%s' defined twice", GetString (Name));
331 /* Search for the actual segment in the input files. The function may
332 * return NULL (no such segment), this is checked later.
334 Seg = SegFind (Name);
336 /* Allocate memory */
337 S = xmalloc (sizeof (SegDesc));
339 /* Initialize the fields */
347 /* ...and return it */
353 static void FreeSegDesc (SegDesc* S)
354 /* Free a segment descriptor */
361 /*****************************************************************************/
363 /*****************************************************************************/
367 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
368 /* Check if the item is already defined. Print an error if so. If not, set
369 * the marker that we have a definition now.
373 CfgError ("%s is already defined", Name);
380 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
381 /* Check that a mandatory attribute was given */
383 if ((Attr & Mask) == 0) {
384 CfgError ("%s attribute is missing", Name);
390 static void ParseMemory (void)
391 /* Parse a MEMORY section */
393 static const IdentTok Attributes [] = {
394 { "START", CFGTOK_START },
395 { "SIZE", CFGTOK_SIZE },
396 { "TYPE", CFGTOK_TYPE },
397 { "FILE", CFGTOK_FILE },
398 { "DEFINE", CFGTOK_DEFINE },
399 { "FILL", CFGTOK_FILL },
400 { "FILLVAL", CFGTOK_FILLVAL },
402 static const IdentTok Types [] = {
407 while (CfgTok == CFGTOK_IDENT) {
409 /* Create a new entry on the heap */
410 Memory* M = NewMemory (GetStringId (CfgSVal));
412 /* Skip the name and the following colon */
416 /* Read the attributes */
417 while (CfgTok == CFGTOK_IDENT) {
419 /* Map the identifier to a token */
421 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
424 /* An optional assignment follows */
426 CfgOptionalAssign ();
428 /* Check which attribute was given */
432 FlagAttr (&M->Attr, MA_START, "START");
438 FlagAttr (&M->Attr, MA_SIZE, "SIZE");
444 FlagAttr (&M->Attr, MA_TYPE, "TYPE");
445 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
446 if (CfgTok == CFGTOK_RO) {
452 FlagAttr (&M->Attr, MA_FILE, "FILE");
454 /* Get the file entry and insert the memory area */
455 FileInsert (GetFile (GetStringId (CfgSVal)), M);
459 FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
460 /* Map the token to a boolean */
462 if (CfgTok == CFGTOK_TRUE) {
463 M->Flags |= MF_DEFINE;
468 FlagAttr (&M->Attr, MA_FILL, "FILL");
469 /* Map the token to a boolean */
471 if (CfgTok == CFGTOK_TRUE) {
477 FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
479 CfgRangeCheck (0, 0xFF);
480 M->FillVal = (unsigned char) CfgIVal;
484 FAIL ("Unexpected attribute token");
488 /* Skip the attribute value and an optional comma */
493 /* Skip the semicolon */
496 /* Check for mandatory parameters */
497 AttrCheck (M->Attr, MA_START, "START");
498 AttrCheck (M->Attr, MA_SIZE, "SIZE");
500 /* If we don't have a file name for output given, use the default
503 if ((M->Attr & MA_FILE) == 0) {
504 FileInsert (GetFile (GetStringId (OutputName)), M);
511 static void ParseFiles (void)
512 /* Parse a FILES section */
514 static const IdentTok Attributes [] = {
515 { "FORMAT", CFGTOK_FORMAT },
517 static const IdentTok Formats [] = {
518 { "O65", CFGTOK_O65 },
519 { "BIN", CFGTOK_BIN },
520 { "BINARY", CFGTOK_BIN },
524 /* Parse all files */
525 while (CfgTok != CFGTOK_RCURLY) {
529 /* We expect a string value here */
532 /* Search for the file, it must exist */
533 F = FindFile (GetStringId (CfgSVal));
535 CfgError ("No such file: `%s'", CfgSVal);
538 /* Skip the token and the following colon */
542 /* Read the attributes */
543 while (CfgTok == CFGTOK_IDENT) {
545 /* Map the identifier to a token */
547 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
550 /* An optional assignment follows */
552 CfgOptionalAssign ();
554 /* Check which attribute was given */
558 if (F->Format != BINFMT_DEFAULT) {
559 /* We've set the format already! */
560 Error ("Cannot set a file format twice");
562 /* Read the format token */
563 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
567 F->Format = BINFMT_BINARY;
571 F->Format = BINFMT_O65;
575 Error ("Unexpected format token");
580 FAIL ("Unexpected attribute token");
584 /* Skip the attribute value and an optional comma */
589 /* Skip the semicolon */
597 static void ParseSegments (void)
598 /* Parse a SEGMENTS section */
600 static const IdentTok Attributes [] = {
601 { "ALIGN", CFGTOK_ALIGN },
602 { "DEFINE", CFGTOK_DEFINE },
603 { "LOAD", CFGTOK_LOAD },
604 { "OFFSET", CFGTOK_OFFSET },
605 { "OPTIONAL", CFGTOK_OPTIONAL },
606 { "RUN", CFGTOK_RUN },
607 { "START", CFGTOK_START },
608 { "TYPE", CFGTOK_TYPE },
610 static const IdentTok Types [] = {
613 { "BSS", CFGTOK_BSS },
615 { "WPROT", CFGTOK_RO }, /* ### OBSOLETE */
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 default: Internal ("Unexpected token: %d", CfgTok);
713 FAIL ("Unexpected attribute token");
717 /* Skip the attribute value and an optional comma */
722 /* Check for mandatory parameters */
723 AttrCheck (S->Attr, SA_LOAD, "LOAD");
725 /* Set defaults for stuff not given */
726 if ((S->Attr & SA_RUN) == 0) {
730 /* Both attributes given */
731 S->Flags |= SF_LOAD_AND_RUN;
733 if ((S->Attr & SA_ALIGN) == 0) {
738 /* If the segment is marked as BSS style, and if the segment exists
739 * in any of the object file, check that there's no initialized data
742 if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
743 Warning ("%s(%u): Segment with type `bss' contains initialized data",
744 CfgGetName (), CfgErrorLine);
747 /* If the segment is marked as BSS style, it may not have separate
748 * load and run memory areas, because it's is never written to disk.
750 if ((S->Flags & SF_BSS) != 0 && (S->Flags & SF_LOAD_AND_RUN) != 0) {
751 Warning ("%s(%u): Segment with type `bss' has both LOAD and RUN "
752 "memory areas assigned", CfgGetName (), CfgErrorLine);
755 /* Don't allow read/write data to be put into a readonly area */
756 if ((S->Flags & SF_RO) == 0) {
757 if (S->Run->Flags & MF_RO) {
758 CfgError ("Cannot put r/w segment `%s' in r/o memory area `%s'",
759 GetString (S->Name), GetString (S->Run->Name));
763 /* Only one of ALIGN, START and OFFSET may be used */
764 Count = ((S->Flags & SF_ALIGN) != 0) +
765 ((S->Flags & SF_OFFSET) != 0) +
766 ((S->Flags & SF_START) != 0);
768 CfgError ("Only one of ALIGN, START, OFFSET may be used");
771 /* If this segment does exist in any of the object files, insert the
772 * descriptor into the list of segment descriptors. Otherwise print a
773 * warning and discard it, because the segment pointer in the
774 * descriptor is invalid.
777 /* Insert the descriptor into the list of all descriptors */
779 /* Insert the segment into the memory area list */
780 MemoryInsert (S->Run, S);
781 if ((S->Flags & SF_LOAD_AND_RUN) != 0) {
782 /* We have a separate RUN area given */
783 MemoryInsert (S->Load, S);
786 /* Print a warning if the segment is not optional */
787 if ((S->Flags & SF_OPTIONAL) == 0) {
788 CfgWarning ("Segment `%s' does not exist", GetString (S->Name));
790 /* Discard the descriptor */
794 /* Skip the semicolon */
801 static void ParseO65 (void)
802 /* Parse the o65 format section */
804 static const IdentTok Attributes [] = {
805 { "EXPORT", CFGTOK_EXPORT },
806 { "IMPORT", CFGTOK_IMPORT },
807 { "TYPE", CFGTOK_TYPE },
810 { "VERSION", CFGTOK_VERSION },
812 static const IdentTok Types [] = {
813 { "SMALL", CFGTOK_SMALL },
814 { "LARGE", CFGTOK_LARGE },
816 static const IdentTok OperatingSystems [] = {
817 { "LUNIX", CFGTOK_LUNIX },
818 { "OSA65", CFGTOK_OSA65 },
819 { "CC65", CFGTOK_CC65 },
822 /* Bitmask to remember the attributes we got already */
826 atOSVersion = 0x0002,
833 unsigned AttrFlags = atNone;
835 /* 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 /* Convert the string into a string index */
861 CfgSValId = GetStringId (CfgSVal);
862 /* Check if the export symbol is also defined as an import. */
863 if (O65GetImport (O65FmtDesc, CfgSValId) != 0) {
864 CfgError ("Exported symbol `%s' cannot be an import", CfgSVal);
866 /* Check if we have this symbol defined already. The entry
867 * routine will check this also, but we get a more verbose
868 * error message when checking it here.
870 if (O65GetExport (O65FmtDesc, CfgSValId) != 0) {
871 CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
873 /* Insert the symbol into the table */
874 O65SetExport (O65FmtDesc, CfgSValId);
878 /* Remember we had this token (maybe more than once) */
879 AttrFlags |= atImport;
880 /* We expect an identifier */
882 /* Convert the string into a string index */
883 CfgSValId = GetStringId (CfgSVal);
884 /* Check if the imported symbol is also defined as an export. */
885 if (O65GetExport (O65FmtDesc, CfgSValId) != 0) {
886 CfgError ("Imported symbol `%s' cannot be an export", CfgSVal);
888 /* Check if we have this symbol defined already. The entry
889 * routine will check this also, but we get a more verbose
890 * error message when checking it here.
892 if (O65GetImport (O65FmtDesc, CfgSValId) != 0) {
893 CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
895 /* Insert the symbol into the table */
896 O65SetImport (O65FmtDesc, CfgSValId);
900 /* Cannot have this attribute twice */
901 FlagAttr (&AttrFlags, atType, "TYPE");
902 /* Get the type of the executable */
903 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
907 O65SetSmallModel (O65FmtDesc);
911 O65SetLargeModel (O65FmtDesc);
915 CfgError ("Unexpected type token");
920 /* Cannot use this attribute twice */
921 FlagAttr (&AttrFlags, atOS, "OS");
922 /* Get the operating system */
923 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
925 case CFGTOK_LUNIX: OS = O65OS_LUNIX; break;
926 case CFGTOK_OSA65: OS = O65OS_OSA65; break;
927 case CFGTOK_CC65: OS = O65OS_CC65; break;
928 default: CfgError ("Unexpected OS token");
933 /* Cannot have this attribute twice */
934 FlagAttr (&AttrFlags, atID, "ID");
935 /* We're expecting a number in the 0..$FFFF range*/
937 CfgRangeCheck (0, 0xFFFF);
938 ModuleId = (unsigned) CfgIVal;
942 /* Cannot have this attribute twice */
943 FlagAttr (&AttrFlags, atVersion, "VERSION");
944 /* We're expecting a number in byte range */
946 CfgRangeCheck (0, 0xFF);
947 Version = (unsigned) CfgIVal;
951 FAIL ("Unexpected attribute token");
955 /* Skip the attribute value and an optional comma */
960 /* Check if we have all mandatory attributes */
961 AttrCheck (AttrFlags, atOS, "OS");
963 /* Check for attributes that may not be combined */
964 if (OS == O65OS_CC65) {
965 if ((AttrFlags & (atImport | atExport)) != 0) {
966 CfgError ("OS type CC65 may not have imports or exports");
969 if (AttrFlags & atID) {
970 CfgError ("Operating system does not support the ID attribute");
974 /* Set the O65 operating system to use */
975 O65SetOS (O65FmtDesc, OS, Version, ModuleId);
980 static void ParseFormats (void)
981 /* Parse a target format section */
983 static const IdentTok Formats [] = {
984 { "O65", CFGTOK_O65 },
985 { "BIN", CFGTOK_BIN },
986 { "BINARY", CFGTOK_BIN },
989 while (CfgTok == CFGTOK_IDENT) {
991 /* Map the identifier to a token */
993 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
996 /* Skip the name and the following colon */
1000 /* Parse the format options */
1001 switch (FormatTok) {
1008 /* No attribibutes available */
1012 Error ("Unexpected format token");
1015 /* Skip the semicolon */
1022 static void ParseConDes (void)
1023 /* Parse the CONDES feature */
1025 static const IdentTok Attributes [] = {
1026 { "SEGMENT", CFGTOK_SEGMENT },
1027 { "LABEL", CFGTOK_LABEL },
1028 { "COUNT", CFGTOK_COUNT },
1029 { "TYPE", CFGTOK_TYPE },
1030 { "ORDER", CFGTOK_ORDER },
1033 static const IdentTok Types [] = {
1034 { "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
1035 { "DESTRUCTOR", CFGTOK_DESTRUCTOR },
1038 static const IdentTok Orders [] = {
1039 { "DECREASING", CFGTOK_DECREASING },
1040 { "INCREASING", CFGTOK_INCREASING },
1043 /* Attribute values. */
1044 unsigned SegName = INVALID_STRING_ID;
1045 unsigned Label = INVALID_STRING_ID;
1046 unsigned Count = INVALID_STRING_ID;
1047 /* Initialize to avoid gcc warnings: */
1049 ConDesOrder Order = cdIncreasing;
1051 /* Bitmask to remember the attributes we got already */
1060 unsigned AttrFlags = atNone;
1062 /* Parse the attributes */
1065 /* Map the identifier to a token */
1067 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1070 /* An optional assignment follows */
1072 CfgOptionalAssign ();
1074 /* Check which attribute was given */
1077 case CFGTOK_SEGMENT:
1078 /* Don't allow this twice */
1079 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1080 /* We expect an identifier */
1082 /* Remember the value for later */
1083 SegName = GetStringId (CfgSVal);
1087 /* Don't allow this twice */
1088 FlagAttr (&AttrFlags, atLabel, "LABEL");
1089 /* We expect an identifier */
1091 /* Remember the value for later */
1092 Label = GetStringId (CfgSVal);
1096 /* Don't allow this twice */
1097 FlagAttr (&AttrFlags, atCount, "COUNT");
1098 /* We expect an identifier */
1100 /* Remember the value for later */
1101 Count = GetStringId (CfgSVal);
1105 /* Don't allow this twice */
1106 FlagAttr (&AttrFlags, atType, "TYPE");
1107 /* The type may be given as id or numerical */
1108 if (CfgTok == CFGTOK_INTCON) {
1109 CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1110 Type = (int) CfgIVal;
1112 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1114 case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
1115 case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
1116 default: FAIL ("Unexpected type token");
1122 /* Don't allow this twice */
1123 FlagAttr (&AttrFlags, atOrder, "ORDER");
1124 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1126 case CFGTOK_DECREASING: Order = cdDecreasing; break;
1127 case CFGTOK_INCREASING: Order = cdIncreasing; break;
1128 default: FAIL ("Unexpected order token");
1133 FAIL ("Unexpected attribute token");
1137 /* Skip the attribute value */
1140 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1141 if (CfgTok == CFGTOK_SEMI) {
1143 } else if (CfgTok == CFGTOK_COMMA) {
1148 /* Check if we have all mandatory attributes */
1149 AttrCheck (AttrFlags, atSegName, "SEGMENT");
1150 AttrCheck (AttrFlags, atLabel, "LABEL");
1151 AttrCheck (AttrFlags, atType, "TYPE");
1153 /* Check if the condes has already attributes defined */
1154 if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1155 CfgError ("CONDES attributes for type %d are already defined", Type);
1158 /* Define the attributes */
1159 ConDesSetSegName (Type, SegName);
1160 ConDesSetLabel (Type, Label);
1161 if (AttrFlags & atCount) {
1162 ConDesSetCountSym (Type, Count);
1164 if (AttrFlags & atOrder) {
1165 ConDesSetOrder (Type, Order);
1171 static void ParseStartAddress (void)
1172 /* Parse the STARTADDRESS feature */
1174 static const IdentTok Attributes [] = {
1175 { "DEFAULT", CFGTOK_DEFAULT },
1179 /* Attribute values. */
1180 unsigned long DefStartAddr = 0;
1182 /* Bitmask to remember the attributes we got already */
1187 unsigned AttrFlags = atNone;
1189 /* Parse the attributes */
1192 /* Map the identifier to a token */
1194 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1197 /* An optional assignment follows */
1199 CfgOptionalAssign ();
1201 /* Check which attribute was given */
1204 case CFGTOK_DEFAULT:
1205 /* Don't allow this twice */
1206 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1207 /* We expect a number */
1209 CfgRangeCheck (0, 0xFFFFFF);
1210 /* Remember the value for later */
1211 DefStartAddr = CfgIVal;
1215 FAIL ("Unexpected attribute token");
1219 /* Skip the attribute value */
1222 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1223 if (CfgTok == CFGTOK_SEMI) {
1225 } else if (CfgTok == CFGTOK_COMMA) {
1230 /* Check if we have all mandatory attributes */
1231 AttrCheck (AttrFlags, atDefault, "DEFAULT");
1233 /* If no start address was given on the command line, use the one given
1236 if (!HaveStartAddr) {
1237 StartAddr = DefStartAddr;
1243 static void ParseFeatures (void)
1244 /* Parse a features section */
1246 static const IdentTok Features [] = {
1247 { "CONDES", CFGTOK_CONDES },
1248 { "STARTADDRESS", CFGTOK_STARTADDRESS },
1251 while (CfgTok == CFGTOK_IDENT) {
1253 /* Map the identifier to a token */
1254 cfgtok_t FeatureTok;
1255 CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1256 FeatureTok = CfgTok;
1258 /* Skip the name and the following colon */
1262 /* Parse the format options */
1263 switch (FeatureTok) {
1269 case CFGTOK_STARTADDRESS:
1270 ParseStartAddress ();
1275 Error ("Unexpected feature token");
1278 /* Skip the semicolon */
1285 static void ParseSymbols (void)
1286 /* Parse a symbols section */
1288 while (CfgTok == CFGTOK_IDENT) {
1292 /* Remember the name */
1293 unsigned Name = GetStringId (CfgSVal);
1296 /* Allow an optional assignment */
1297 CfgOptionalAssign ();
1299 /* Make sure the next token is an integer, read and skip it */
1304 /* Generate an export with the given value */
1305 CreateConstExport (Name, Val);
1307 /* Skip the semicolon */
1314 static void ParseConfig (void)
1315 /* Parse the config file */
1317 static const IdentTok BlockNames [] = {
1318 { "MEMORY", CFGTOK_MEMORY },
1319 { "FILES", CFGTOK_FILES },
1320 { "SEGMENTS", CFGTOK_SEGMENTS },
1321 { "FORMATS", CFGTOK_FORMATS },
1322 { "FEATURES", CFGTOK_FEATURES },
1323 { "SYMBOLS", CFGTOK_SYMBOLS },
1329 /* Read the block ident */
1330 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1334 /* Expected a curly brace */
1335 CfgConsume (CFGTOK_LCURLY, "`{' expected");
1337 /* Read the block */
1348 case CFGTOK_SEGMENTS:
1352 case CFGTOK_FORMATS:
1356 case CFGTOK_FEATURES:
1360 case CFGTOK_SYMBOLS:
1365 FAIL ("Unexpected block token");
1369 /* Skip closing brace */
1370 CfgConsume (CFGTOK_RCURLY, "`}' expected");
1372 } while (CfgTok != CFGTOK_EOF);
1378 /* Read the configuration */
1380 /* Create the descriptors for the binary formats */
1381 BinFmtDesc = NewBinDesc ();
1382 O65FmtDesc = NewO65Desc ();
1384 /* If we have a config name given, open the file, otherwise we will read
1389 /* Parse the file */
1392 /* Close the input file */
1398 static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
1399 /* Create the defines for a RUN segment */
1403 xsprintf (Buf, sizeof (Buf), "__%s_RUN__", GetString (S->Name));
1404 CreateMemoryExport (GetStringId (Buf), S->Run, SegAddr - S->Run->Start);
1405 xsprintf (Buf, sizeof (Buf), "__%s_SIZE__", GetString (S->Name));
1406 CreateConstExport (GetStringId (Buf), S->Seg->Size);
1407 S->Flags |= SF_RUN_DEF;
1412 static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
1413 /* Create the defines for a LOAD segment */
1417 xsprintf (Buf, sizeof (Buf), "__%s_LOAD__", GetString (S->Name));
1418 CreateMemoryExport (GetStringId (Buf), S->Load, SegAddr - S->Load->Start);
1419 S->Flags |= SF_LOAD_DEF;
1424 void CfgAssignSegments (void)
1425 /* Assign segments, define linker symbols where requested */
1427 /* Walk through each of the memory sections. Add up the sizes and check
1428 * for an overflow of the section. Assign the start addresses of the
1429 * segments while doing this.
1431 Memory* M = MemoryList;
1436 /* Get the start address of this memory area */
1437 unsigned long Addr = M->Start;
1439 /* Remember if this is a relocatable memory area */
1440 M->Relocatable = RelocatableBinFmt (M->F->Format);
1442 /* Walk through the segments in this memory area */
1446 /* Get the segment from the node */
1447 SegDesc* S = N->Seg;
1449 /* Handle ALIGN and OFFSET/START */
1450 if (S->Flags & SF_ALIGN) {
1451 /* Align the address */
1452 unsigned long Val = (0x01UL << S->Align) - 1;
1453 Addr = (Addr + Val) & ~Val;
1454 } else if (S->Flags & (SF_OFFSET | SF_START)) {
1455 /* Give the segment a fixed starting address */
1456 unsigned long NewAddr = S->Addr;
1457 if (S->Flags & SF_OFFSET) {
1458 /* An offset was given, no address, make an address */
1459 NewAddr += M->Start;
1461 if (Addr > NewAddr) {
1462 /* Offset already too large */
1463 if (S->Flags & SF_OFFSET) {
1464 Error ("Offset too small in `%s', segment `%s'",
1465 GetString (M->Name), GetString (S->Name));
1467 Error ("Start address too low in `%s', segment `%s'",
1468 GetString (M->Name), GetString (S->Name));
1474 /* If this is the run area, set the start address of this segment,
1475 * set the readonly flag in the segment and and remember if the
1476 * segment is in a relocatable file or not.
1480 S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
1481 S->Seg->Relocatable = M->Relocatable;
1484 /* Increment the fill level of the memory area and check for an
1487 M->FillLevel = Addr + S->Seg->Size - M->Start;
1488 if (M->FillLevel > M->Size) {
1489 Error ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
1490 GetString (M->Name), GetString (S->Name),
1491 M->FillLevel - M->Size);
1494 /* If requested, define symbols for the start and size of the
1497 if (S->Flags & SF_DEFINE) {
1498 if ((S->Flags & SF_LOAD_AND_RUN) && S->Run == S->Load) {
1499 /* RUN and LOAD given and in one memory area.
1500 * Be careful: We will encounter this code twice, the
1501 * first time when walking the RUN list, second time when
1502 * walking the LOAD list. Be sure to define only the
1503 * relevant symbols on each walk.
1506 if ((S->Flags & SF_LOAD_DEF) == 0) {
1507 CreateLoadDefines (S, Addr);
1509 CHECK ((S->Flags & SF_RUN_DEF) == 0);
1510 CreateRunDefines (S, Addr);
1514 /* RUN and LOAD in different memory areas, or RUN not
1515 * given, so RUN defaults to LOAD. In the latter case, we
1516 * have only one copy of the segment in the area.
1519 CreateRunDefines (S, Addr);
1522 CreateLoadDefines (S, Addr);
1527 /* Calculate the new address */
1528 Addr += S->Seg->Size;
1534 /* If requested, define symbols for start and size of the memory area */
1535 if (M->Flags & MF_DEFINE) {
1537 sprintf (Buf, "__%s_START__", GetString (M->Name));
1538 CreateMemoryExport (GetStringId (Buf), M, 0);
1539 sprintf (Buf, "__%s_SIZE__", GetString (M->Name));
1540 CreateConstExport (GetStringId (Buf), M->Size);
1541 sprintf (Buf, "__%s_LAST__", GetString (M->Name));
1542 CreateMemoryExport (GetStringId (Buf), M, M->FillLevel);
1545 /* Next memory area */
1552 void CfgWriteTarget (void)
1553 /* Write the target file(s) */
1557 /* Walk through the files list */
1560 /* We don't need to look at files with no memory areas */
1563 /* Is there an output file? */
1564 if (strlen (GetString (F->Name)) > 0) {
1566 /* Assign a proper binary format */
1567 if (F->Format == BINFMT_DEFAULT) {
1568 F->Format = DefaultBinFmt;
1571 /* Call the apropriate routine for the binary format */
1572 switch (F->Format) {
1575 BinWriteTarget (BinFmtDesc, F);
1579 O65WriteTarget (O65FmtDesc, F);
1583 Internal ("Invalid binary format: %u", F->Format);
1589 /* No output file. Walk through the list and mark all segments
1590 * loading into these memory areas in this file as dumped.
1598 Print (stdout, 2, "Skipping `%s'...\n", GetString (M->Name));
1600 /* Walk throught the segments */
1603 if (N->Seg->Load == M) {
1604 /* Load area - mark the segment as dumped */
1605 N->Seg->Seg->Dumped = 1;
1608 /* Next segment node */
1611 /* Next memory area */