1 /*****************************************************************************/
5 /* Target configuration file for the ld65 linker */
9 /* (C) 1998-2000 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 /*****************************************************************************/
60 /*****************************************************************************/
62 /*****************************************************************************/
67 static File* FileList; /* Single linked list */
68 static unsigned FileCount; /* Number of entries in the list */
73 static Memory* MemoryList; /* Single linked list */
74 static Memory* MemoryLast; /* Last element in list */
75 static unsigned MemoryCount; /* Number of entries in the list */
77 /* Memory attributes */
78 #define MA_START 0x0001
79 #define MA_SIZE 0x0002
80 #define MA_TYPE 0x0004
81 #define MA_FILE 0x0008
82 #define MA_DEFINE 0x0010
83 #define MA_FILL 0x0020
84 #define MA_FILLVAL 0x0040
89 SegDesc* SegDescList; /* Single linked list */
90 unsigned SegDescCount; /* Number of entries in list */
92 /* Segment attributes */
93 #define SA_TYPE 0x0001
94 #define SA_LOAD 0x0002
96 #define SA_ALIGN 0x0008
97 #define SA_DEFINE 0x0010
98 #define SA_OFFSET 0x0020
99 #define SA_START 0x0040
103 /* Descriptor holding information about the binary formats */
104 static BinDesc* BinFmtDesc = 0;
105 static O65Desc* O65FmtDesc = 0;
107 /* Attributes for the o65 format */
108 static unsigned O65Attr = 0;
110 #define OA_TYPE 0x0002
111 #define OA_VERSION 0x0004
112 #define OA_OSVERSION 0x0008
113 #define OA_TEXT 0x0010
114 #define OA_DATA 0x0020
115 #define OA_BSS 0x0040
120 /*****************************************************************************/
122 /*****************************************************************************/
126 static File* NewFile (const char* Name);
127 /* Create a new file descriptor and insert it into the list */
131 /*****************************************************************************/
132 /* List management */
133 /*****************************************************************************/
137 static File* FindFile (const char* Name)
138 /* Find a file with a given name. */
142 if (strcmp (F->Name, Name) == 0) {
152 static File* GetFile (const char* Name)
153 /* Get a file entry with the given name. Create a new one if needed. */
155 File* F = FindFile (Name);
157 /* Create a new one */
165 static void FileInsert (File* F, Memory* M)
166 /* Insert the memory area into the files list */
169 if (F->MemList == 0) {
173 F->MemLast->FNext = M;
180 static Memory* CfgFindMemory (const char* Name)
181 /* Find the memory are with the given name. Return NULL if not found */
183 Memory* M = MemoryList;
185 if (strcmp (M->Name, Name) == 0) {
195 static Memory* CfgGetMemory (const char* Name)
196 /* Find the memory are with the given name. Print an error on an invalid name */
198 Memory* M = CfgFindMemory (Name);
200 CfgError ("Invalid memory area `%s'", Name);
207 static SegDesc* CfgFindSegDesc (const char* Name)
208 /* Find the segment descriptor with the given name, return NULL if not found. */
210 SegDesc* S = SegDescList;
212 if (strcmp (S->Name, Name) == 0) {
225 static void SegDescInsert (SegDesc* S)
226 /* Insert a segment descriptor into the list of segment descriptors */
228 /* Insert the struct into the list */
229 S->Next = SegDescList;
236 static void MemoryInsert (Memory* M, SegDesc* S)
237 /* Insert the segment descriptor into the memory area list */
239 /* Create a new node for the entry */
240 MemListNode* N = xmalloc (sizeof (MemListNode));
244 if (M->SegLast == 0) {
248 M->SegLast->Next = N;
255 /*****************************************************************************/
256 /* Constructors/Destructors */
257 /*****************************************************************************/
261 static File* NewFile (const char* Name)
262 /* Create a new file descriptor and insert it into the list */
264 /* Get the length of the name */
265 unsigned Len = strlen (Name);
267 /* Allocate memory */
268 File* F = xmalloc (sizeof (File) + Len);
270 /* Initialize the fields */
272 F->Format = BINFMT_DEFAULT;
275 memcpy (F->Name, Name, Len);
276 F->Name [Len] = '\0';
278 /* Insert the struct into the list */
283 /* ...and return it */
289 static Memory* NewMemory (const char* Name)
290 /* Create a new memory section and insert it into the list */
292 /* Get the length of the name */
293 unsigned Len = strlen (Name);
295 /* Check for duplicate names */
296 Memory* M = CfgFindMemory (Name);
298 CfgError ("Memory area `%s' defined twice", Name);
301 /* Allocate memory */
302 M = xmalloc (sizeof (Memory) + Len);
304 /* Initialize the fields */
316 memcpy (M->Name, Name, Len);
317 M->Name [Len] = '\0';
319 /* Insert the struct into the list */
320 if (MemoryLast == 0) {
324 MemoryLast->Next = M;
329 /* ...and return it */
335 static SegDesc* NewSegDesc (const char* Name)
336 /* Create a segment descriptor */
340 /* Get the length of the name */
341 unsigned Len = strlen (Name);
343 /* Check for duplicate names */
344 SegDesc* S = CfgFindSegDesc (Name);
346 CfgError ("Segment `%s' defined twice", Name);
349 /* Verify that the given segment does really exist */
350 Seg = SegFind (Name);
352 CfgWarning ("Segment `%s' does not exist", Name);
355 /* Allocate memory */
356 S = xmalloc (sizeof (SegDesc) + Len);
358 /* Initialize the fields */
364 memcpy (S->Name, Name, Len);
365 S->Name [Len] = '\0';
367 /* ...and return it */
373 static void FreeSegDesc (SegDesc* S)
374 /* Free a segment descriptor */
381 /*****************************************************************************/
383 /*****************************************************************************/
387 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
388 /* Check if the item is already defined. Print an error if so. If not, set
389 * the marker that we have a definition now.
393 CfgError ("%s is already defined", Name);
400 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
401 /* Check that a mandatory attribute was given */
403 if ((Attr & Mask) == 0) {
404 CfgError ("%s attribute is missing", Name);
410 static void ParseMemory (void)
411 /* Parse a MEMORY section */
413 static const IdentTok Attributes [] = {
414 { "START", CFGTOK_START },
415 { "SIZE", CFGTOK_SIZE },
416 { "TYPE", CFGTOK_TYPE },
417 { "FILE", CFGTOK_FILE },
418 { "DEFINE", CFGTOK_DEFINE },
419 { "FILL", CFGTOK_FILL },
420 { "FILLVAL", CFGTOK_FILLVAL },
422 static const IdentTok Types [] = {
427 while (CfgTok == CFGTOK_IDENT) {
429 /* Create a new entry on the heap */
430 Memory* M = NewMemory (CfgSVal);
432 /* Skip the name and the following colon */
436 /* Read the attributes */
437 while (CfgTok == CFGTOK_IDENT) {
439 /* Map the identifier to a token */
441 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
444 /* An optional assignment follows */
446 CfgOptionalAssign ();
448 /* Check which attribute was given */
452 FlagAttr (&M->Attr, MA_START, "START");
458 FlagAttr (&M->Attr, MA_SIZE, "SIZE");
464 FlagAttr (&M->Attr, MA_TYPE, "TYPE");
465 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
466 if (CfgTok == CFGTOK_RO) {
472 FlagAttr (&M->Attr, MA_FILE, "FILE");
474 /* Get the file entry and insert the memory area */
475 FileInsert (GetFile (CfgSVal), M);
479 FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
480 /* Map the token to a boolean */
482 if (CfgTok == CFGTOK_TRUE) {
483 M->Flags |= MF_DEFINE;
488 FlagAttr (&M->Attr, MA_FILL, "FILL");
489 /* Map the token to a boolean */
491 if (CfgTok == CFGTOK_TRUE) {
497 FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
499 CfgRangeCheck (0, 0xFF);
500 M->FillVal = (unsigned char) CfgIVal;
504 FAIL ("Unexpected attribute token");
508 /* Skip the attribute value and an optional comma */
513 /* Skip the semicolon */
516 /* Check for mandatory parameters */
517 AttrCheck (M->Attr, MA_START, "START");
518 AttrCheck (M->Attr, MA_SIZE, "SIZE");
520 /* If we don't have a file name for output given, use the default
523 if ((M->Attr & MA_FILE) == 0) {
524 FileInsert (GetFile (OutputName), M);
531 static void ParseFiles (void)
532 /* Parse a FILES section */
534 static const IdentTok Attributes [] = {
535 { "FORMAT", CFGTOK_FORMAT },
537 static const IdentTok Formats [] = {
538 { "O65", CFGTOK_O65 },
539 { "BIN", CFGTOK_BIN },
540 { "BINARY", CFGTOK_BIN },
544 /* Parse all files */
545 while (CfgTok != CFGTOK_RCURLY) {
549 /* We expect a string value here */
552 /* Search for the file, it must exist */
553 F = FindFile (CfgSVal);
555 CfgError ("No such file: `%s'", CfgSVal);
558 /* Skip the token and the following colon */
562 /* Read the attributes */
563 while (CfgTok == CFGTOK_IDENT) {
565 /* Map the identifier to a token */
567 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
570 /* An optional assignment follows */
572 CfgOptionalAssign ();
574 /* Check which attribute was given */
578 if (F->Format != BINFMT_DEFAULT) {
579 /* We've set the format already! */
580 Error ("Cannot set a file format twice");
582 /* Read the format token */
583 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
587 F->Format = BINFMT_BINARY;
591 F->Format = BINFMT_O65;
595 Error ("Unexpected format token");
600 FAIL ("Unexpected attribute token");
604 /* Skip the attribute value and an optional comma */
609 /* Skip the semicolon */
617 static void ParseSegments (void)
618 /* Parse a SEGMENTS section */
620 static const IdentTok Attributes [] = {
621 { "LOAD", CFGTOK_LOAD },
622 { "RUN", CFGTOK_RUN },
623 { "TYPE", CFGTOK_TYPE },
624 { "ALIGN", CFGTOK_ALIGN },
625 { "DEFINE", CFGTOK_DEFINE },
626 { "OFFSET", CFGTOK_OFFSET },
627 { "START", CFGTOK_START },
629 static const IdentTok Types [] = {
632 { "BSS", CFGTOK_BSS },
634 { "WP", CFGTOK_WPROT },
635 { "WPROT", CFGTOK_WPROT },
640 while (CfgTok == CFGTOK_IDENT) {
644 /* Create a new entry on the heap */
645 S = NewSegDesc (CfgSVal);
647 /* Skip the name and the following colon */
651 /* Read the attributes */
652 while (CfgTok == CFGTOK_IDENT) {
654 /* Map the identifier to a token */
656 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
659 /* An optional assignment follows */
661 CfgOptionalAssign ();
663 /* Check which attribute was given */
667 FlagAttr (&S->Attr, SA_LOAD, "LOAD");
668 S->Load = CfgGetMemory (CfgSVal);
672 FlagAttr (&S->Attr, SA_RUN, "RUN");
673 S->Run = CfgGetMemory (CfgSVal);
677 FlagAttr (&S->Attr, SA_TYPE, "TYPE");
678 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
680 case CFGTOK_RO: S->Flags |= SF_RO; break;
681 case CFGTOK_RW: /* Default */ break;
682 case CFGTOK_BSS: S->Flags |= SF_BSS; break;
683 case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break;
684 case CFGTOK_WPROT: S->Flags |= (SF_RO | SF_WPROT); break;
685 default: Internal ("Unexpected token: %d", CfgTok);
691 FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
692 CfgRangeCheck (1, 0x10000);
693 S->Align = BitFind (CfgIVal);
694 if ((0x01UL << S->Align) != CfgIVal) {
695 CfgError ("Alignment must be a power of 2");
697 S->Flags |= SF_ALIGN;
701 FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
702 /* Map the token to a boolean */
704 if (CfgTok == CFGTOK_TRUE) {
705 S->Flags |= SF_DEFINE;
711 FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
712 CfgRangeCheck (1, 0x1000000);
714 S->Flags |= SF_OFFSET;
719 FlagAttr (&S->Attr, SA_START, "START");
720 CfgRangeCheck (1, 0x1000000);
722 S->Flags |= SF_START;
726 FAIL ("Unexpected attribute token");
730 /* Skip the attribute value and an optional comma */
735 /* Skip the semicolon */
738 /* Check for mandatory parameters */
739 AttrCheck (S->Attr, SA_LOAD, "LOAD");
741 /* Set defaults for stuff not given */
742 if ((S->Attr & SA_RUN) == 0) {
746 /* Both attributes given */
747 S->Flags |= SF_LOAD_AND_RUN;
749 if ((S->Attr & SA_ALIGN) == 0) {
754 /* If the segment is marked as BSS style, check that there's no
755 * initialized data in the segment.
757 if ((S->Flags & SF_BSS) != 0 && !IsBSSType (S->Seg)) {
758 Warning ("%s(%u): Segment with type `bss' contains initialized data",
759 CfgGetName (), CfgErrorLine);
762 /* Don't allow read/write data to be put into a readonly area */
763 if ((S->Flags & SF_RO) == 0) {
764 if (S->Run->Flags & MF_RO) {
765 CfgError ("Cannot put r/w segment `%s' in r/o memory area `%s'",
766 S->Name, S->Run->Name);
770 /* Only one of ALIGN, START and OFFSET may be used */
771 Count = ((S->Flags & SF_ALIGN) != 0) +
772 ((S->Flags & SF_OFFSET) != 0) +
773 ((S->Flags & SF_START) != 0);
775 CfgError ("Only one of ALIGN, START, OFFSET may be used");
778 /* If this segment does exist in any of the object files, insert the
779 * descriptor into the list of segment descriptors. Otherwise discard
780 * it silently, because the segment pointer in the descriptor is
784 /* Insert the descriptor into the list of all descriptors */
786 /* Insert the segment into the memory area list */
787 MemoryInsert (S->Run, S);
788 if ((S->Flags & SF_LOAD_AND_RUN) != 0) {
789 /* We have a separate RUN area given */
790 MemoryInsert (S->Load, S);
793 /* Segment does not exist, discard the descriptor */
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 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 },
819 while (CfgTok == CFGTOK_IDENT) {
821 /* Map the identifier to a token */
823 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
826 /* An optional assignment follows */
828 CfgOptionalAssign ();
830 /* Check which attribute was given */
834 /* We expect an identifier */
836 /* Check if we have this symbol defined already. The entry
837 * routine will check this also, but we get a more verbose
838 * error message when checking it here.
840 if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
841 CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
843 /* Insert the symbol into the table */
844 O65SetExport (O65FmtDesc, CfgSVal);
848 /* We expect an identifier */
850 /* Check if we have this symbol defined already. The entry
851 * routine will check this also, but we get a more verbose
852 * error message when checking it here.
854 if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
855 CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
857 /* Insert the symbol into the table */
858 O65SetImport (O65FmtDesc, CfgSVal);
862 /* Cannot have this attribute twice */
863 FlagAttr (&O65Attr, OA_TYPE, "TYPE");
864 /* Get the type of the executable */
865 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
869 /* Default, nothing to do */
873 O65SetLargeModel (O65FmtDesc);
877 CfgError ("Unexpected type token");
882 /* Cannot use this attribute twice */
883 FlagAttr (&O65Attr, OA_OS, "OS");
884 /* Get the operating system */
885 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
889 O65SetOS (O65FmtDesc, O65OS_LUNIX);
893 O65SetOS (O65FmtDesc, O65OS_OSA65);
897 CfgError ("Unexpected OS token");
902 FAIL ("Unexpected attribute token");
906 /* Skip the attribute value and an optional comma */
914 static void ParseFormats (void)
915 /* Parse a target format section */
917 static const IdentTok Formats [] = {
918 { "O65", CFGTOK_O65 },
919 { "BIN", CFGTOK_BIN },
920 { "BINARY", CFGTOK_BIN },
923 while (CfgTok == CFGTOK_IDENT) {
925 /* Map the identifier to a token */
927 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
930 /* Skip the name and the following colon */
934 /* Parse the format options */
942 /* No attribibutes available */
946 Error ("Unexpected format token");
949 /* Skip the semicolon */
956 static void ParseConDes (void)
957 /* Parse the CONDES feature */
959 static const IdentTok Attributes [] = {
960 { "SEGMENT", CFGTOK_SEGMENT },
961 { "LABEL", CFGTOK_LABEL },
962 { "COUNT", CFGTOK_COUNT },
963 { "TYPE", CFGTOK_TYPE },
964 { "ORDER", CFGTOK_ORDER },
967 static const IdentTok Types [] = {
968 { "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
969 { "DESTRUCTOR", CFGTOK_DESTRUCTOR },
972 static const IdentTok Orders [] = {
973 { "DECREASING", CFGTOK_DECREASING },
974 { "INCREASING", CFGTOK_INCREASING },
977 /* Attribute values. */
978 char SegName[sizeof (CfgSVal)];
979 char Label[sizeof (CfgSVal)];
980 char Count[sizeof (CfgSVal)];
981 /* Initialize to avoid gcc warnings: */
983 ConDesOrder Order = cdIncreasing;
985 /* Bitmask to remember the attributes we got already */
994 unsigned AttrFlags = atNone;
996 /* Parse the attributes */
999 /* Map the identifier to a token */
1001 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1004 /* An optional assignment follows */
1006 CfgOptionalAssign ();
1008 /* Check which attribute was given */
1011 case CFGTOK_SEGMENT:
1012 /* Don't allow this twice */
1013 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1014 /* We expect an identifier */
1016 /* Remember the value for later */
1017 strcpy (SegName, CfgSVal);
1021 /* Don't allow this twice */
1022 FlagAttr (&AttrFlags, atLabel, "LABEL");
1023 /* We expect an identifier */
1025 /* Remember the value for later */
1026 strcpy (Label, CfgSVal);
1030 /* Don't allow this twice */
1031 FlagAttr (&AttrFlags, atCount, "COUNT");
1032 /* We expect an identifier */
1034 /* Remember the value for later */
1035 strcpy (Count, CfgSVal);
1039 /* Don't allow this twice */
1040 FlagAttr (&AttrFlags, atType, "TYPE");
1041 /* The type may be given as id or numerical */
1042 if (CfgTok == CFGTOK_INTCON) {
1043 CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1044 Type = (int) CfgIVal;
1046 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1048 case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
1049 case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
1050 default: FAIL ("Unexpected type token");
1056 /* Don't allow this twice */
1057 FlagAttr (&AttrFlags, atOrder, "ORDER");
1058 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1060 case CFGTOK_DECREASING: Order = cdDecreasing; break;
1061 case CFGTOK_INCREASING: Order = cdIncreasing; break;
1062 default: FAIL ("Unexpected order token");
1067 FAIL ("Unexpected attribute token");
1071 /* Skip the attribute value */
1074 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1075 if (CfgTok == CFGTOK_SEMI) {
1077 } else if (CfgTok == CFGTOK_COMMA) {
1082 /* Check if we have all mandatory attributes */
1083 AttrCheck (AttrFlags, atSegName, "SEGMENT");
1084 AttrCheck (AttrFlags, atLabel, "LABEL");
1085 AttrCheck (AttrFlags, atType, "TYPE");
1087 /* Check if the condes has already attributes defined */
1088 if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1089 CfgError ("CONDES attributes for type %d are already defined", Type);
1092 /* Define the attributes */
1093 ConDesSetSegName (Type, SegName);
1094 ConDesSetLabel (Type, Label);
1095 if (AttrFlags & atCount) {
1096 ConDesSetCountSym (Type, Count);
1098 if (AttrFlags & atOrder) {
1099 ConDesSetOrder (Type, Order);
1105 static void ParseFeatures (void)
1106 /* Parse a features section */
1108 static const IdentTok Features [] = {
1109 { "CONDES", CFGTOK_CONDES },
1112 while (CfgTok == CFGTOK_IDENT) {
1114 /* Map the identifier to a token */
1115 cfgtok_t FeatureTok;
1116 CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1117 FeatureTok = CfgTok;
1119 /* Skip the name and the following colon */
1123 /* Parse the format options */
1124 switch (FeatureTok) {
1131 Error ("Unexpected feature token");
1134 /* Skip the semicolon */
1141 static void ParseSymbols (void)
1142 /* Parse a symbols section */
1144 while (CfgTok == CFGTOK_IDENT) {
1148 /* Remember the name */
1149 char Name [sizeof (CfgSVal)];
1150 strcpy (Name, CfgSVal);
1153 /* Allow an optional assignment */
1154 CfgOptionalAssign ();
1156 /* Make sure the next token is an integer, read and skip it */
1161 /* Generate an export with the given value */
1162 CreateConstExport (Name, Val);
1164 /* Skip the semicolon */
1171 static void ParseConfig (void)
1172 /* Parse the config file */
1174 static const IdentTok BlockNames [] = {
1175 { "MEMORY", CFGTOK_MEMORY },
1176 { "FILES", CFGTOK_FILES },
1177 { "SEGMENTS", CFGTOK_SEGMENTS },
1178 { "FORMATS", CFGTOK_FORMATS },
1179 { "FEATURES", CFGTOK_FEATURES },
1180 { "SYMBOLS", CFGTOK_SYMBOLS },
1186 /* Read the block ident */
1187 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1191 /* Expected a curly brace */
1192 CfgConsume (CFGTOK_LCURLY, "`{' expected");
1194 /* Read the block */
1205 case CFGTOK_SEGMENTS:
1209 case CFGTOK_FORMATS:
1213 case CFGTOK_FEATURES:
1217 case CFGTOK_SYMBOLS:
1222 FAIL ("Unexpected block token");
1226 /* Skip closing brace */
1227 CfgConsume (CFGTOK_RCURLY, "`}' expected");
1229 } while (CfgTok != CFGTOK_EOF);
1235 /* Read the configuration */
1237 /* Create the descriptors for the binary formats */
1238 BinFmtDesc = NewBinDesc ();
1239 O65FmtDesc = NewO65Desc ();
1241 /* If we have a config name given, open the file, otherwise we will read
1246 /* Parse the file */
1249 /* Close the input file */
1255 static void CreateRunDefines (Memory* M, SegDesc* S, unsigned long Addr)
1256 /* Create the defines for a RUN segment */
1260 sprintf (Buf, "__%s_RUN__", S->Name);
1261 CreateMemExport (Buf, M, Addr - M->Start);
1262 sprintf (Buf, "__%s_SIZE__", S->Name);
1263 CreateConstExport (Buf, S->Seg->Size);
1264 S->Flags |= SF_RUN_DEF;
1269 static void CreateLoadDefines (Memory* M, SegDesc* S, unsigned long Addr)
1270 /* Create the defines for a LOAD segment */
1274 sprintf (Buf, "__%s_LOAD__", S->Name);
1275 CreateMemExport (Buf, M, Addr - M->Start);
1276 S->Flags |= SF_LOAD_DEF;
1281 void CfgAssignSegments (void)
1282 /* Assign segments, define linker symbols where requested */
1284 /* Walk through each of the memory sections. Add up the sizes and check
1285 * for an overflow of the section. Assign the start addresses of the
1286 * segments while doing this.
1288 Memory* M = MemoryList;
1291 /* Get the start address of this memory area */
1292 unsigned long Addr = M->Start;
1294 /* Walk through the segments in this memory area */
1295 MemListNode* N = M->SegList;
1298 /* Get the segment from the node */
1299 SegDesc* S = N->Seg;
1301 /* Handle ALIGN and OFFSET/START */
1302 if (S->Flags & SF_ALIGN) {
1303 /* Align the address */
1304 unsigned long Val = (0x01UL << S->Align) - 1;
1305 Addr = (Addr + Val) & ~Val;
1306 } else if (S->Flags & (SF_OFFSET | SF_START)) {
1307 /* Give the segment a fixed starting address */
1308 unsigned long NewAddr = S->Addr;
1309 if (S->Flags & SF_OFFSET) {
1310 /* An offset was given, no address, make an address */
1311 NewAddr += M->Start;
1313 if (Addr > NewAddr) {
1314 /* Offset already too large */
1315 if (S->Flags & SF_OFFSET) {
1316 Error ("Offset too small in `%s', segment `%s'",
1319 Error ("Start address too low in `%s', segment `%s'",
1326 /* If this is the run area, set the start address of this segment */
1331 /* Increment the fill level of the memory area and check for an
1334 M->FillLevel = Addr + S->Seg->Size - M->Start;
1335 if (M->FillLevel > M->Size) {
1336 Error ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
1337 M->Name, S->Name, M->FillLevel - M->Size);
1340 /* If requested, define symbols for the start and size of the
1343 if (S->Flags & SF_DEFINE) {
1344 if ((S->Flags & SF_LOAD_AND_RUN) && S->Run == S->Load) {
1345 /* RUN and LOAD given and in one memory area.
1346 * Be careful: We will encounter this code twice, the
1347 * first time when walking the RUN list, second time when
1348 * walking the LOAD list. Be sure to define only the
1349 * relevant symbols on each walk.
1352 if ((S->Flags & SF_LOAD_DEF) == 0) {
1353 CreateLoadDefines (M, S, Addr);
1355 CHECK ((S->Flags & SF_RUN_DEF) == 0);
1356 CreateRunDefines (M, S, Addr);
1360 /* RUN and LOAD in different memory areas, or RUN not
1361 * given, so RUN defaults to LOAD. In the latter case, we
1362 * have only one copy of the segment in the area.
1365 CreateRunDefines (M, S, Addr);
1368 CreateLoadDefines (M, S, Addr);
1373 /* Calculate the new address */
1374 Addr += S->Seg->Size;
1380 /* If requested, define symbols for start and size of the memory area */
1381 if (M->Flags & MF_DEFINE) {
1383 sprintf (Buf, "__%s_START__", M->Name);
1384 CreateMemExport (Buf, M, 0);
1385 sprintf (Buf, "__%s_SIZE__", M->Name);
1386 CreateConstExport (Buf, M->Size);
1387 sprintf (Buf, "__%s_LAST__", M->Name);
1388 CreateConstExport (Buf, M->FillLevel);
1391 /* Next memory area */
1398 void CfgWriteTarget (void)
1399 /* Write the target file(s) */
1403 /* Walk through the files list */
1406 /* We don't need to look at files with no memory areas */
1409 /* Is there an output file? */
1410 if (strlen (F->Name) > 0) {
1412 /* Assign a proper binary format */
1413 if (F->Format == BINFMT_DEFAULT) {
1414 F->Format = DefaultBinFmt;
1417 /* Call the apropriate routine for the binary format */
1418 switch (F->Format) {
1421 BinWriteTarget (BinFmtDesc, F);
1425 O65WriteTarget (O65FmtDesc, F);
1429 Internal ("Invalid binary format: %u", F->Format);
1435 /* No output file. Walk through the list and mark all segments
1436 * loading into these memory areas in this file as dumped.
1444 Print (stdout, 2, "Skipping `%s'...\n", M->Name);
1446 /* Walk throught the segments */
1449 if (N->Seg->Load == M) {
1450 /* Load area - mark the segment as dumped */
1451 N->Seg->Seg->Dumped = 1;
1454 /* Next segment node */
1457 /* Next memory area */