1 /*****************************************************************************/
5 /* Target configuration file for the ld65 linker */
9 /* (C) 1998-2002 Ullrich von Bassewitz */
11 /* D-70597 Stuttgart */
12 /* EMail: uz@musoftware.de */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
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
104 /* Descriptor holding information about the binary formats */
105 static BinDesc* BinFmtDesc = 0;
106 static O65Desc* O65FmtDesc = 0;
110 /*****************************************************************************/
112 /*****************************************************************************/
116 static File* NewFile (const char* Name);
117 /* Create a new file descriptor and insert it into the list */
121 /*****************************************************************************/
122 /* List management */
123 /*****************************************************************************/
127 static File* FindFile (const char* Name)
128 /* Find a file with a given name. */
132 if (strcmp (F->Name, Name) == 0) {
142 static File* GetFile (const char* Name)
143 /* Get a file entry with the given name. Create a new one if needed. */
145 File* F = FindFile (Name);
147 /* Create a new one */
155 static void FileInsert (File* F, Memory* M)
156 /* Insert the memory area into the files list */
159 if (F->MemList == 0) {
163 F->MemLast->FNext = M;
170 static Memory* CfgFindMemory (const char* Name)
171 /* Find the memory are with the given name. Return NULL if not found */
173 Memory* M = MemoryList;
175 if (strcmp (M->Name, Name) == 0) {
185 static Memory* CfgGetMemory (const char* Name)
186 /* Find the memory are with the given name. Print an error on an invalid name */
188 Memory* M = CfgFindMemory (Name);
190 CfgError ("Invalid memory area `%s'", Name);
197 static SegDesc* CfgFindSegDesc (const char* Name)
198 /* Find the segment descriptor with the given name, return NULL if not found. */
200 SegDesc* S = SegDescList;
202 if (strcmp (S->Name, Name) == 0) {
215 static void SegDescInsert (SegDesc* S)
216 /* Insert a segment descriptor into the list of segment descriptors */
218 /* Insert the struct into the list */
219 S->Next = SegDescList;
226 static void MemoryInsert (Memory* M, SegDesc* S)
227 /* Insert the segment descriptor into the memory area list */
229 /* Create a new node for the entry */
230 MemListNode* N = xmalloc (sizeof (MemListNode));
234 if (M->SegLast == 0) {
238 M->SegLast->Next = N;
245 /*****************************************************************************/
246 /* Constructors/Destructors */
247 /*****************************************************************************/
251 static File* NewFile (const char* Name)
252 /* Create a new file descriptor and insert it into the list */
254 /* Get the length of the name */
255 unsigned Len = strlen (Name);
257 /* Allocate memory */
258 File* F = xmalloc (sizeof (File) + Len);
260 /* Initialize the fields */
262 F->Format = BINFMT_DEFAULT;
265 memcpy (F->Name, Name, Len);
266 F->Name [Len] = '\0';
268 /* Insert the struct into the list */
273 /* ...and return it */
279 static Memory* NewMemory (const char* Name)
280 /* Create a new memory section and insert it into the list */
282 /* Get the length of the name */
283 unsigned Len = strlen (Name);
285 /* Check for duplicate names */
286 Memory* M = CfgFindMemory (Name);
288 CfgError ("Memory area `%s' defined twice", Name);
291 /* Allocate memory */
292 M = xmalloc (sizeof (Memory) + Len);
294 /* Initialize the fields */
306 memcpy (M->Name, Name, Len);
307 M->Name [Len] = '\0';
309 /* Insert the struct into the list */
310 if (MemoryLast == 0) {
314 MemoryLast->Next = M;
319 /* ...and return it */
325 static SegDesc* NewSegDesc (const char* Name)
326 /* Create a segment descriptor */
330 /* Get the length of the name */
331 unsigned Len = strlen (Name);
333 /* Check for duplicate names */
334 SegDesc* S = CfgFindSegDesc (Name);
336 CfgError ("Segment `%s' defined twice", Name);
339 /* Verify that the given segment does really exist */
340 Seg = SegFind (Name);
342 CfgWarning ("Segment `%s' does not exist", 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 { "LOAD", CFGTOK_LOAD },
612 { "RUN", CFGTOK_RUN },
613 { "TYPE", CFGTOK_TYPE },
614 { "ALIGN", CFGTOK_ALIGN },
615 { "DEFINE", CFGTOK_DEFINE },
616 { "OFFSET", CFGTOK_OFFSET },
617 { "START", CFGTOK_START },
619 static const IdentTok Types [] = {
622 { "BSS", CFGTOK_BSS },
624 { "WP", CFGTOK_WPROT },
625 { "WPROT", CFGTOK_WPROT },
630 while (CfgTok == CFGTOK_IDENT) {
634 /* Create a new entry on the heap */
635 S = NewSegDesc (CfgSVal);
637 /* Skip the name and the following colon */
641 /* Read the attributes */
642 while (CfgTok == CFGTOK_IDENT) {
644 /* Map the identifier to a token */
646 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
649 /* An optional assignment follows */
651 CfgOptionalAssign ();
653 /* Check which attribute was given */
657 FlagAttr (&S->Attr, SA_LOAD, "LOAD");
658 S->Load = CfgGetMemory (CfgSVal);
662 FlagAttr (&S->Attr, SA_RUN, "RUN");
663 S->Run = CfgGetMemory (CfgSVal);
667 FlagAttr (&S->Attr, SA_TYPE, "TYPE");
668 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
670 case CFGTOK_RO: S->Flags |= SF_RO; break;
671 case CFGTOK_RW: /* Default */ break;
672 case CFGTOK_BSS: S->Flags |= SF_BSS; break;
673 case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break;
674 case CFGTOK_WPROT: S->Flags |= (SF_RO | SF_WPROT); break;
675 default: Internal ("Unexpected token: %d", CfgTok);
681 FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
682 CfgRangeCheck (1, 0x10000);
683 S->Align = BitFind (CfgIVal);
684 if ((0x01UL << S->Align) != CfgIVal) {
685 CfgError ("Alignment must be a power of 2");
687 S->Flags |= SF_ALIGN;
691 FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
692 /* Map the token to a boolean */
694 if (CfgTok == CFGTOK_TRUE) {
695 S->Flags |= SF_DEFINE;
701 FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
702 CfgRangeCheck (1, 0x1000000);
704 S->Flags |= SF_OFFSET;
709 FlagAttr (&S->Attr, SA_START, "START");
710 CfgRangeCheck (1, 0x1000000);
712 S->Flags |= SF_START;
716 FAIL ("Unexpected attribute token");
720 /* Skip the attribute value and an optional comma */
725 /* Check for mandatory parameters */
726 AttrCheck (S->Attr, SA_LOAD, "LOAD");
728 /* Set defaults for stuff not given */
729 if ((S->Attr & SA_RUN) == 0) {
733 /* Both attributes given */
734 S->Flags |= SF_LOAD_AND_RUN;
736 if ((S->Attr & SA_ALIGN) == 0) {
741 /* If the segment is marked as BSS style, check that there's no
742 * initialized data in the segment.
744 if ((S->Flags & SF_BSS) != 0 && !IsBSSType (S->Seg)) {
745 Warning ("%s(%u): Segment with type `bss' contains initialized data",
746 CfgGetName (), CfgErrorLine);
749 /* If the segment is marked as BSS style, it may not have separate
750 * load and run memory areas, because it's is never written to disk.
752 if ((S->Flags & SF_BSS) != 0 && (S->Flags & SF_LOAD_AND_RUN) != 0) {
753 Warning ("%s(%u): Segment with type `bss' has both LOAD and RUN "
754 "memory areas assigned", CfgGetName (), CfgErrorLine);
757 /* Don't allow read/write data to be put into a readonly area */
758 if ((S->Flags & SF_RO) == 0) {
759 if (S->Run->Flags & MF_RO) {
760 CfgError ("Cannot put r/w segment `%s' in r/o memory area `%s'",
761 S->Name, S->Run->Name);
765 /* Only one of ALIGN, START and OFFSET may be used */
766 Count = ((S->Flags & SF_ALIGN) != 0) +
767 ((S->Flags & SF_OFFSET) != 0) +
768 ((S->Flags & SF_START) != 0);
770 CfgError ("Only one of ALIGN, START, OFFSET may be used");
773 /* If this segment does exist in any of the object files, insert the
774 * descriptor into the list of segment descriptors. Otherwise discard
775 * it silently, because the segment pointer in the descriptor is
779 /* Insert the descriptor into the list of all descriptors */
781 /* Insert the segment into the memory area list */
782 MemoryInsert (S->Run, S);
783 if ((S->Flags & SF_LOAD_AND_RUN) != 0) {
784 /* We have a separate RUN area given */
785 MemoryInsert (S->Load, S);
788 /* Segment does not exist, discard the descriptor */
792 /* Skip the semicolon */
799 static void ParseO65 (void)
800 /* Parse the o65 format section */
802 static const IdentTok Attributes [] = {
803 { "EXPORT", CFGTOK_EXPORT },
804 { "IMPORT", CFGTOK_IMPORT },
805 { "TYPE", CFGTOK_TYPE },
808 { "VERSION", CFGTOK_VERSION },
810 static const IdentTok Types [] = {
811 { "SMALL", CFGTOK_SMALL },
812 { "LARGE", CFGTOK_LARGE },
814 static const IdentTok OperatingSystems [] = {
815 { "LUNIX", CFGTOK_LUNIX },
816 { "OSA65", CFGTOK_OSA65 },
817 { "CC65", CFGTOK_CC65 },
820 /* Bitmask to remember the attributes we got already */
824 atOSVersion = 0x0002,
831 unsigned AttrFlags = atNone;
833 /* Remember the attributes read */
834 unsigned OS = 0; /* Initialize to keep gcc happy */
835 unsigned Version = 0;
837 /* Read the attributes */
838 while (CfgTok == CFGTOK_IDENT) {
840 /* Map the identifier to a token */
842 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
845 /* An optional assignment follows */
847 CfgOptionalAssign ();
849 /* Check which attribute was given */
853 /* Remember we had this token (maybe more than once) */
854 AttrFlags |= atExport;
855 /* We expect an identifier */
857 /* Check if the export symbol is also defined as an import. */
858 if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
859 CfgError ("Exported symbol `%s' cannot be an import", CfgSVal);
861 /* Check if we have this symbol defined already. The entry
862 * routine will check this also, but we get a more verbose
863 * error message when checking it here.
865 if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
866 CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
868 /* Insert the symbol into the table */
869 O65SetExport (O65FmtDesc, CfgSVal);
873 /* Remember we had this token (maybe more than once) */
874 AttrFlags |= atImport;
875 /* We expect an identifier */
877 /* Check if the imported symbol is also defined as an export. */
878 if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
879 CfgError ("Imported symbol `%s' cannot be an export", CfgSVal);
881 /* Check if we have this symbol defined already. The entry
882 * routine will check this also, but we get a more verbose
883 * error message when checking it here.
885 if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
886 CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
888 /* Insert the symbol into the table */
889 O65SetImport (O65FmtDesc, CfgSVal);
893 /* Cannot have this attribute twice */
894 FlagAttr (&AttrFlags, atType, "TYPE");
895 /* Get the type of the executable */
896 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
900 O65SetSmallModel (O65FmtDesc);
904 O65SetLargeModel (O65FmtDesc);
908 CfgError ("Unexpected type token");
913 /* Cannot use this attribute twice */
914 FlagAttr (&AttrFlags, atOS, "OS");
915 /* Get the operating system */
916 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
918 case CFGTOK_LUNIX: OS = O65OS_LUNIX; break;
919 case CFGTOK_OSA65: OS = O65OS_OSA65; break;
920 case CFGTOK_CC65: OS = O65OS_CC65; break;
921 default: CfgError ("Unexpected OS token");
926 /* Cannot have this attribute twice */
927 FlagAttr (&AttrFlags, atID, "ID");
928 /* We're expecting a number in the 0..$FFFF range*/
930 CfgRangeCheck (0, 0xFFFF);
931 ModuleId = (unsigned) CfgIVal;
935 /* Cannot have this attribute twice */
936 FlagAttr (&AttrFlags, atVersion, "VERSION");
937 /* We're expecting a number in byte range */
939 CfgRangeCheck (0, 0xFF);
940 Version = (unsigned) CfgIVal;
944 FAIL ("Unexpected attribute token");
948 /* Skip the attribute value and an optional comma */
953 /* Check if we have all mandatory attributes */
954 AttrCheck (AttrFlags, atOS, "OS");
956 /* Check for attributes that may not be combined */
957 if (OS == O65OS_CC65) {
958 if ((AttrFlags & (atImport | atExport)) != 0) {
959 CfgError ("OS type CC65 may not have imports or exports");
962 if (AttrFlags & atID) {
963 CfgError ("Operating system does not support the ID attribute");
967 /* Set the O65 operating system to use */
968 O65SetOS (O65FmtDesc, OS, Version, ModuleId);
973 static void ParseFormats (void)
974 /* Parse a target format section */
976 static const IdentTok Formats [] = {
977 { "O65", CFGTOK_O65 },
978 { "BIN", CFGTOK_BIN },
979 { "BINARY", CFGTOK_BIN },
982 while (CfgTok == CFGTOK_IDENT) {
984 /* Map the identifier to a token */
986 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
989 /* Skip the name and the following colon */
993 /* Parse the format options */
1001 /* No attribibutes available */
1005 Error ("Unexpected format token");
1008 /* Skip the semicolon */
1015 static void ParseConDes (void)
1016 /* Parse the CONDES feature */
1018 static const IdentTok Attributes [] = {
1019 { "SEGMENT", CFGTOK_SEGMENT },
1020 { "LABEL", CFGTOK_LABEL },
1021 { "COUNT", CFGTOK_COUNT },
1022 { "TYPE", CFGTOK_TYPE },
1023 { "ORDER", CFGTOK_ORDER },
1026 static const IdentTok Types [] = {
1027 { "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
1028 { "DESTRUCTOR", CFGTOK_DESTRUCTOR },
1031 static const IdentTok Orders [] = {
1032 { "DECREASING", CFGTOK_DECREASING },
1033 { "INCREASING", CFGTOK_INCREASING },
1036 /* Attribute values. */
1037 char SegName[sizeof (CfgSVal)];
1038 char Label[sizeof (CfgSVal)];
1039 char Count[sizeof (CfgSVal)];
1040 /* Initialize to avoid gcc warnings: */
1042 ConDesOrder Order = cdIncreasing;
1044 /* Bitmask to remember the attributes we got already */
1053 unsigned AttrFlags = atNone;
1055 /* Parse the attributes */
1058 /* Map the identifier to a token */
1060 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1063 /* An optional assignment follows */
1065 CfgOptionalAssign ();
1067 /* Check which attribute was given */
1070 case CFGTOK_SEGMENT:
1071 /* Don't allow this twice */
1072 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1073 /* We expect an identifier */
1075 /* Remember the value for later */
1076 strcpy (SegName, CfgSVal);
1080 /* Don't allow this twice */
1081 FlagAttr (&AttrFlags, atLabel, "LABEL");
1082 /* We expect an identifier */
1084 /* Remember the value for later */
1085 strcpy (Label, CfgSVal);
1089 /* Don't allow this twice */
1090 FlagAttr (&AttrFlags, atCount, "COUNT");
1091 /* We expect an identifier */
1093 /* Remember the value for later */
1094 strcpy (Count, CfgSVal);
1098 /* Don't allow this twice */
1099 FlagAttr (&AttrFlags, atType, "TYPE");
1100 /* The type may be given as id or numerical */
1101 if (CfgTok == CFGTOK_INTCON) {
1102 CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1103 Type = (int) CfgIVal;
1105 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1107 case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
1108 case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
1109 default: FAIL ("Unexpected type token");
1115 /* Don't allow this twice */
1116 FlagAttr (&AttrFlags, atOrder, "ORDER");
1117 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1119 case CFGTOK_DECREASING: Order = cdDecreasing; break;
1120 case CFGTOK_INCREASING: Order = cdIncreasing; break;
1121 default: FAIL ("Unexpected order token");
1126 FAIL ("Unexpected attribute token");
1130 /* Skip the attribute value */
1133 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1134 if (CfgTok == CFGTOK_SEMI) {
1136 } else if (CfgTok == CFGTOK_COMMA) {
1141 /* Check if we have all mandatory attributes */
1142 AttrCheck (AttrFlags, atSegName, "SEGMENT");
1143 AttrCheck (AttrFlags, atLabel, "LABEL");
1144 AttrCheck (AttrFlags, atType, "TYPE");
1146 /* Check if the condes has already attributes defined */
1147 if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1148 CfgError ("CONDES attributes for type %d are already defined", Type);
1151 /* Define the attributes */
1152 ConDesSetSegName (Type, SegName);
1153 ConDesSetLabel (Type, Label);
1154 if (AttrFlags & atCount) {
1155 ConDesSetCountSym (Type, Count);
1157 if (AttrFlags & atOrder) {
1158 ConDesSetOrder (Type, Order);
1164 static void ParseStartAddress (void)
1165 /* Parse the STARTADDRESS feature */
1167 static const IdentTok Attributes [] = {
1168 { "DEFAULT", CFGTOK_DEFAULT },
1172 /* Attribute values. */
1173 unsigned long DefStartAddr = 0;
1175 /* Bitmask to remember the attributes we got already */
1180 unsigned AttrFlags = atNone;
1182 /* Parse the attributes */
1185 /* Map the identifier to a token */
1187 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1190 /* An optional assignment follows */
1192 CfgOptionalAssign ();
1194 /* Check which attribute was given */
1197 case CFGTOK_DEFAULT:
1198 /* Don't allow this twice */
1199 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1200 /* We expect a number */
1202 CfgRangeCheck (0, 0xFFFFFF);
1203 /* Remember the value for later */
1204 DefStartAddr = CfgIVal;
1208 FAIL ("Unexpected attribute token");
1212 /* Skip the attribute value */
1215 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1216 if (CfgTok == CFGTOK_SEMI) {
1218 } else if (CfgTok == CFGTOK_COMMA) {
1223 /* Check if we have all mandatory attributes */
1224 AttrCheck (AttrFlags, atDefault, "DEFAULT");
1226 /* If no start address was given on the command line, use the one given
1229 if (!HaveStartAddr) {
1230 StartAddr = DefStartAddr;
1236 static void ParseFeatures (void)
1237 /* Parse a features section */
1239 static const IdentTok Features [] = {
1240 { "CONDES", CFGTOK_CONDES },
1241 { "STARTADDRESS", CFGTOK_STARTADDRESS },
1244 while (CfgTok == CFGTOK_IDENT) {
1246 /* Map the identifier to a token */
1247 cfgtok_t FeatureTok;
1248 CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1249 FeatureTok = CfgTok;
1251 /* Skip the name and the following colon */
1255 /* Parse the format options */
1256 switch (FeatureTok) {
1262 case CFGTOK_STARTADDRESS:
1263 ParseStartAddress ();
1268 Error ("Unexpected feature token");
1271 /* Skip the semicolon */
1278 static void ParseSymbols (void)
1279 /* Parse a symbols section */
1281 while (CfgTok == CFGTOK_IDENT) {
1285 /* Remember the name */
1286 char Name [sizeof (CfgSVal)];
1287 strcpy (Name, CfgSVal);
1290 /* Allow an optional assignment */
1291 CfgOptionalAssign ();
1293 /* Make sure the next token is an integer, read and skip it */
1298 /* Generate an export with the given value */
1299 CreateConstExport (Name, Val);
1301 /* Skip the semicolon */
1308 static void ParseConfig (void)
1309 /* Parse the config file */
1311 static const IdentTok BlockNames [] = {
1312 { "MEMORY", CFGTOK_MEMORY },
1313 { "FILES", CFGTOK_FILES },
1314 { "SEGMENTS", CFGTOK_SEGMENTS },
1315 { "FORMATS", CFGTOK_FORMATS },
1316 { "FEATURES", CFGTOK_FEATURES },
1317 { "SYMBOLS", CFGTOK_SYMBOLS },
1323 /* Read the block ident */
1324 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1328 /* Expected a curly brace */
1329 CfgConsume (CFGTOK_LCURLY, "`{' expected");
1331 /* Read the block */
1342 case CFGTOK_SEGMENTS:
1346 case CFGTOK_FORMATS:
1350 case CFGTOK_FEATURES:
1354 case CFGTOK_SYMBOLS:
1359 FAIL ("Unexpected block token");
1363 /* Skip closing brace */
1364 CfgConsume (CFGTOK_RCURLY, "`}' expected");
1366 } while (CfgTok != CFGTOK_EOF);
1372 /* Read the configuration */
1374 /* Create the descriptors for the binary formats */
1375 BinFmtDesc = NewBinDesc ();
1376 O65FmtDesc = NewO65Desc ();
1378 /* If we have a config name given, open the file, otherwise we will read
1383 /* Parse the file */
1386 /* Close the input file */
1392 static void CreateRunDefines (SegDesc* S)
1393 /* Create the defines for a RUN segment */
1397 xsprintf (Buf, sizeof (Buf), "__%s_RUN__", S->Name);
1398 CreateSegmentExport (Buf, S->Seg, 0);
1399 xsprintf (Buf, sizeof (Buf), "__%s_SIZE__", S->Name);
1400 CreateConstExport (Buf, S->Seg->Size);
1401 S->Flags |= SF_RUN_DEF;
1406 static void CreateLoadDefines (Memory* M, SegDesc* S)
1407 /* Create the defines for a LOAD segment */
1411 xsprintf (Buf, sizeof (Buf), "__%s_LOAD__", S->Name);
1412 CreateMemoryExport (Buf, M, S->Seg->PC - M->Start);
1413 S->Flags |= SF_LOAD_DEF;
1418 void CfgAssignSegments (void)
1419 /* Assign segments, define linker symbols where requested */
1421 /* Walk through each of the memory sections. Add up the sizes and check
1422 * for an overflow of the section. Assign the start addresses of the
1423 * segments while doing this.
1425 Memory* M = MemoryList;
1428 /* Get the start address of this memory area */
1429 unsigned long Addr = M->Start;
1431 /* Walk through the segments in this memory area */
1432 MemListNode* N = M->SegList;
1435 /* Get the segment from the node */
1436 SegDesc* S = N->Seg;
1438 /* Handle ALIGN and OFFSET/START */
1439 if (S->Flags & SF_ALIGN) {
1440 /* Align the address */
1441 unsigned long Val = (0x01UL << S->Align) - 1;
1442 Addr = (Addr + Val) & ~Val;
1443 } else if (S->Flags & (SF_OFFSET | SF_START)) {
1444 /* Give the segment a fixed starting address */
1445 unsigned long NewAddr = S->Addr;
1446 if (S->Flags & SF_OFFSET) {
1447 /* An offset was given, no address, make an address */
1448 NewAddr += M->Start;
1450 if (Addr > NewAddr) {
1451 /* Offset already too large */
1452 if (S->Flags & SF_OFFSET) {
1453 Error ("Offset too small in `%s', segment `%s'",
1456 Error ("Start address too low in `%s', segment `%s'",
1463 /* If this is the run area, set the start address of this segment */
1468 /* Increment the fill level of the memory area and check for an
1471 M->FillLevel = Addr + S->Seg->Size - M->Start;
1472 if (M->FillLevel > M->Size) {
1473 Error ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
1474 M->Name, S->Name, M->FillLevel - M->Size);
1477 /* If requested, define symbols for the start and size of the
1480 if (S->Flags & SF_DEFINE) {
1481 if ((S->Flags & SF_LOAD_AND_RUN) && S->Run == S->Load) {
1482 /* RUN and LOAD given and in one memory area.
1483 * Be careful: We will encounter this code twice, the
1484 * first time when walking the RUN list, second time when
1485 * walking the LOAD list. Be sure to define only the
1486 * relevant symbols on each walk.
1489 if ((S->Flags & SF_LOAD_DEF) == 0) {
1490 CreateLoadDefines (M, S);
1492 CHECK ((S->Flags & SF_RUN_DEF) == 0);
1493 CreateRunDefines (S);
1497 /* RUN and LOAD in different memory areas, or RUN not
1498 * given, so RUN defaults to LOAD. In the latter case, we
1499 * have only one copy of the segment in the area.
1502 CreateRunDefines (S);
1505 CreateLoadDefines (M, S);
1510 /* Calculate the new address */
1511 Addr += S->Seg->Size;
1517 /* If requested, define symbols for start and size of the memory area */
1518 if (M->Flags & MF_DEFINE) {
1520 sprintf (Buf, "__%s_START__", M->Name);
1521 CreateMemoryExport (Buf, M, 0);
1522 sprintf (Buf, "__%s_SIZE__", M->Name);
1523 CreateConstExport (Buf, M->Size);
1524 sprintf (Buf, "__%s_LAST__", M->Name);
1525 CreateConstExport (Buf, M->FillLevel);
1528 /* Next memory area */
1535 void CfgWriteTarget (void)
1536 /* Write the target file(s) */
1540 /* Walk through the files list */
1543 /* We don't need to look at files with no memory areas */
1546 /* Is there an output file? */
1547 if (strlen (F->Name) > 0) {
1549 /* Assign a proper binary format */
1550 if (F->Format == BINFMT_DEFAULT) {
1551 F->Format = DefaultBinFmt;
1554 /* Call the apropriate routine for the binary format */
1555 switch (F->Format) {
1558 BinWriteTarget (BinFmtDesc, F);
1562 O65WriteTarget (O65FmtDesc, F);
1566 Internal ("Invalid binary format: %u", F->Format);
1572 /* No output file. Walk through the list and mark all segments
1573 * loading into these memory areas in this file as dumped.
1581 Print (stdout, 2, "Skipping `%s'...\n", M->Name);
1583 /* Walk throught the segments */
1586 if (N->Seg->Load == M) {
1587 /* Load area - mark the segment as dumped */
1588 N->Seg->Seg->Dumped = 1;
1591 /* Next segment node */
1594 /* Next memory area */