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 the export symbol is also defined as an import. */
837 if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
838 CfgError ("Exported symbol `%s' cannot be an import", CfgSVal);
840 /* Check if we have this symbol defined already. The entry
841 * routine will check this also, but we get a more verbose
842 * error message when checking it here.
844 if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
845 CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
847 /* Insert the symbol into the table */
848 O65SetExport (O65FmtDesc, CfgSVal);
852 /* We expect an identifier */
854 /* Check if the imported symbol is also defined as an export. */
855 if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
856 CfgError ("Imported symbol `%s' cannot be an export", CfgSVal);
858 /* Check if we have this symbol defined already. The entry
859 * routine will check this also, but we get a more verbose
860 * error message when checking it here.
862 if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
863 CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
865 /* Insert the symbol into the table */
866 O65SetImport (O65FmtDesc, CfgSVal);
870 /* Cannot have this attribute twice */
871 FlagAttr (&O65Attr, OA_TYPE, "TYPE");
872 /* Get the type of the executable */
873 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
877 O65SetSmallModel (O65FmtDesc);
881 O65SetLargeModel (O65FmtDesc);
885 CfgError ("Unexpected type token");
890 /* Cannot use this attribute twice */
891 FlagAttr (&O65Attr, OA_OS, "OS");
892 /* Get the operating system */
893 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
897 O65SetOS (O65FmtDesc, O65OS_LUNIX);
901 O65SetOS (O65FmtDesc, O65OS_OSA65);
905 CfgError ("Unexpected OS token");
910 FAIL ("Unexpected attribute token");
914 /* Skip the attribute value and an optional comma */
922 static void ParseFormats (void)
923 /* Parse a target format section */
925 static const IdentTok Formats [] = {
926 { "O65", CFGTOK_O65 },
927 { "BIN", CFGTOK_BIN },
928 { "BINARY", CFGTOK_BIN },
931 while (CfgTok == CFGTOK_IDENT) {
933 /* Map the identifier to a token */
935 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
938 /* Skip the name and the following colon */
942 /* Parse the format options */
950 /* No attribibutes available */
954 Error ("Unexpected format token");
957 /* Skip the semicolon */
964 static void ParseConDes (void)
965 /* Parse the CONDES feature */
967 static const IdentTok Attributes [] = {
968 { "SEGMENT", CFGTOK_SEGMENT },
969 { "LABEL", CFGTOK_LABEL },
970 { "COUNT", CFGTOK_COUNT },
971 { "TYPE", CFGTOK_TYPE },
972 { "ORDER", CFGTOK_ORDER },
975 static const IdentTok Types [] = {
976 { "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
977 { "DESTRUCTOR", CFGTOK_DESTRUCTOR },
980 static const IdentTok Orders [] = {
981 { "DECREASING", CFGTOK_DECREASING },
982 { "INCREASING", CFGTOK_INCREASING },
985 /* Attribute values. */
986 char SegName[sizeof (CfgSVal)];
987 char Label[sizeof (CfgSVal)];
988 char Count[sizeof (CfgSVal)];
989 /* Initialize to avoid gcc warnings: */
991 ConDesOrder Order = cdIncreasing;
993 /* Bitmask to remember the attributes we got already */
1002 unsigned AttrFlags = atNone;
1004 /* Parse the attributes */
1007 /* Map the identifier to a token */
1009 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1012 /* An optional assignment follows */
1014 CfgOptionalAssign ();
1016 /* Check which attribute was given */
1019 case CFGTOK_SEGMENT:
1020 /* Don't allow this twice */
1021 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1022 /* We expect an identifier */
1024 /* Remember the value for later */
1025 strcpy (SegName, CfgSVal);
1029 /* Don't allow this twice */
1030 FlagAttr (&AttrFlags, atLabel, "LABEL");
1031 /* We expect an identifier */
1033 /* Remember the value for later */
1034 strcpy (Label, CfgSVal);
1038 /* Don't allow this twice */
1039 FlagAttr (&AttrFlags, atCount, "COUNT");
1040 /* We expect an identifier */
1042 /* Remember the value for later */
1043 strcpy (Count, CfgSVal);
1047 /* Don't allow this twice */
1048 FlagAttr (&AttrFlags, atType, "TYPE");
1049 /* The type may be given as id or numerical */
1050 if (CfgTok == CFGTOK_INTCON) {
1051 CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1052 Type = (int) CfgIVal;
1054 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1056 case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
1057 case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
1058 default: FAIL ("Unexpected type token");
1064 /* Don't allow this twice */
1065 FlagAttr (&AttrFlags, atOrder, "ORDER");
1066 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1068 case CFGTOK_DECREASING: Order = cdDecreasing; break;
1069 case CFGTOK_INCREASING: Order = cdIncreasing; break;
1070 default: FAIL ("Unexpected order token");
1075 FAIL ("Unexpected attribute token");
1079 /* Skip the attribute value */
1082 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1083 if (CfgTok == CFGTOK_SEMI) {
1085 } else if (CfgTok == CFGTOK_COMMA) {
1090 /* Check if we have all mandatory attributes */
1091 AttrCheck (AttrFlags, atSegName, "SEGMENT");
1092 AttrCheck (AttrFlags, atLabel, "LABEL");
1093 AttrCheck (AttrFlags, atType, "TYPE");
1095 /* Check if the condes has already attributes defined */
1096 if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1097 CfgError ("CONDES attributes for type %d are already defined", Type);
1100 /* Define the attributes */
1101 ConDesSetSegName (Type, SegName);
1102 ConDesSetLabel (Type, Label);
1103 if (AttrFlags & atCount) {
1104 ConDesSetCountSym (Type, Count);
1106 if (AttrFlags & atOrder) {
1107 ConDesSetOrder (Type, Order);
1113 static void ParseFeatures (void)
1114 /* Parse a features section */
1116 static const IdentTok Features [] = {
1117 { "CONDES", CFGTOK_CONDES },
1120 while (CfgTok == CFGTOK_IDENT) {
1122 /* Map the identifier to a token */
1123 cfgtok_t FeatureTok;
1124 CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1125 FeatureTok = CfgTok;
1127 /* Skip the name and the following colon */
1131 /* Parse the format options */
1132 switch (FeatureTok) {
1139 Error ("Unexpected feature token");
1142 /* Skip the semicolon */
1149 static void ParseSymbols (void)
1150 /* Parse a symbols section */
1152 while (CfgTok == CFGTOK_IDENT) {
1156 /* Remember the name */
1157 char Name [sizeof (CfgSVal)];
1158 strcpy (Name, CfgSVal);
1161 /* Allow an optional assignment */
1162 CfgOptionalAssign ();
1164 /* Make sure the next token is an integer, read and skip it */
1169 /* Generate an export with the given value */
1170 CreateConstExport (Name, Val);
1172 /* Skip the semicolon */
1179 static void ParseConfig (void)
1180 /* Parse the config file */
1182 static const IdentTok BlockNames [] = {
1183 { "MEMORY", CFGTOK_MEMORY },
1184 { "FILES", CFGTOK_FILES },
1185 { "SEGMENTS", CFGTOK_SEGMENTS },
1186 { "FORMATS", CFGTOK_FORMATS },
1187 { "FEATURES", CFGTOK_FEATURES },
1188 { "SYMBOLS", CFGTOK_SYMBOLS },
1194 /* Read the block ident */
1195 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1199 /* Expected a curly brace */
1200 CfgConsume (CFGTOK_LCURLY, "`{' expected");
1202 /* Read the block */
1213 case CFGTOK_SEGMENTS:
1217 case CFGTOK_FORMATS:
1221 case CFGTOK_FEATURES:
1225 case CFGTOK_SYMBOLS:
1230 FAIL ("Unexpected block token");
1234 /* Skip closing brace */
1235 CfgConsume (CFGTOK_RCURLY, "`}' expected");
1237 } while (CfgTok != CFGTOK_EOF);
1243 /* Read the configuration */
1245 /* Create the descriptors for the binary formats */
1246 BinFmtDesc = NewBinDesc ();
1247 O65FmtDesc = NewO65Desc ();
1249 /* If we have a config name given, open the file, otherwise we will read
1254 /* Parse the file */
1257 /* Close the input file */
1263 static void CreateRunDefines (Memory* M, SegDesc* S, unsigned long Addr)
1264 /* Create the defines for a RUN segment */
1268 sprintf (Buf, "__%s_RUN__", S->Name);
1269 CreateMemExport (Buf, M, Addr - M->Start);
1270 sprintf (Buf, "__%s_SIZE__", S->Name);
1271 CreateConstExport (Buf, S->Seg->Size);
1272 S->Flags |= SF_RUN_DEF;
1277 static void CreateLoadDefines (Memory* M, SegDesc* S, unsigned long Addr)
1278 /* Create the defines for a LOAD segment */
1282 sprintf (Buf, "__%s_LOAD__", S->Name);
1283 CreateMemExport (Buf, M, Addr - M->Start);
1284 S->Flags |= SF_LOAD_DEF;
1289 void CfgAssignSegments (void)
1290 /* Assign segments, define linker symbols where requested */
1292 /* Walk through each of the memory sections. Add up the sizes and check
1293 * for an overflow of the section. Assign the start addresses of the
1294 * segments while doing this.
1296 Memory* M = MemoryList;
1299 /* Get the start address of this memory area */
1300 unsigned long Addr = M->Start;
1302 /* Walk through the segments in this memory area */
1303 MemListNode* N = M->SegList;
1306 /* Get the segment from the node */
1307 SegDesc* S = N->Seg;
1309 /* Handle ALIGN and OFFSET/START */
1310 if (S->Flags & SF_ALIGN) {
1311 /* Align the address */
1312 unsigned long Val = (0x01UL << S->Align) - 1;
1313 Addr = (Addr + Val) & ~Val;
1314 } else if (S->Flags & (SF_OFFSET | SF_START)) {
1315 /* Give the segment a fixed starting address */
1316 unsigned long NewAddr = S->Addr;
1317 if (S->Flags & SF_OFFSET) {
1318 /* An offset was given, no address, make an address */
1319 NewAddr += M->Start;
1321 if (Addr > NewAddr) {
1322 /* Offset already too large */
1323 if (S->Flags & SF_OFFSET) {
1324 Error ("Offset too small in `%s', segment `%s'",
1327 Error ("Start address too low in `%s', segment `%s'",
1334 /* If this is the run area, set the start address of this segment */
1339 /* Increment the fill level of the memory area and check for an
1342 M->FillLevel = Addr + S->Seg->Size - M->Start;
1343 if (M->FillLevel > M->Size) {
1344 Error ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
1345 M->Name, S->Name, M->FillLevel - M->Size);
1348 /* If requested, define symbols for the start and size of the
1351 if (S->Flags & SF_DEFINE) {
1352 if ((S->Flags & SF_LOAD_AND_RUN) && S->Run == S->Load) {
1353 /* RUN and LOAD given and in one memory area.
1354 * Be careful: We will encounter this code twice, the
1355 * first time when walking the RUN list, second time when
1356 * walking the LOAD list. Be sure to define only the
1357 * relevant symbols on each walk.
1360 if ((S->Flags & SF_LOAD_DEF) == 0) {
1361 CreateLoadDefines (M, S, Addr);
1363 CHECK ((S->Flags & SF_RUN_DEF) == 0);
1364 CreateRunDefines (M, S, Addr);
1368 /* RUN and LOAD in different memory areas, or RUN not
1369 * given, so RUN defaults to LOAD. In the latter case, we
1370 * have only one copy of the segment in the area.
1373 CreateRunDefines (M, S, Addr);
1376 CreateLoadDefines (M, S, Addr);
1381 /* Calculate the new address */
1382 Addr += S->Seg->Size;
1388 /* If requested, define symbols for start and size of the memory area */
1389 if (M->Flags & MF_DEFINE) {
1391 sprintf (Buf, "__%s_START__", M->Name);
1392 CreateMemExport (Buf, M, 0);
1393 sprintf (Buf, "__%s_SIZE__", M->Name);
1394 CreateConstExport (Buf, M->Size);
1395 sprintf (Buf, "__%s_LAST__", M->Name);
1396 CreateConstExport (Buf, M->FillLevel);
1399 /* Next memory area */
1406 void CfgWriteTarget (void)
1407 /* Write the target file(s) */
1411 /* Walk through the files list */
1414 /* We don't need to look at files with no memory areas */
1417 /* Is there an output file? */
1418 if (strlen (F->Name) > 0) {
1420 /* Assign a proper binary format */
1421 if (F->Format == BINFMT_DEFAULT) {
1422 F->Format = DefaultBinFmt;
1425 /* Call the apropriate routine for the binary format */
1426 switch (F->Format) {
1429 BinWriteTarget (BinFmtDesc, F);
1433 O65WriteTarget (O65FmtDesc, F);
1437 Internal ("Invalid binary format: %u", F->Format);
1443 /* No output file. Walk through the list and mark all segments
1444 * loading into these memory areas in this file as dumped.
1452 Print (stdout, 2, "Skipping `%s'...\n", M->Name);
1454 /* Walk throught the segments */
1457 if (N->Seg->Load == M) {
1458 /* Load area - mark the segment as dumped */
1459 N->Seg->Seg->Dumped = 1;
1462 /* Next segment node */
1465 /* Next memory area */