1 /*****************************************************************************/
5 /* Target configuration file for the ld65 linker */
9 /* (C) 1998-2008 Ullrich von Bassewitz */
10 /* Roemerstrasse 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 /*****************************************************************************/
64 /*****************************************************************************/
66 /*****************************************************************************/
70 /* Remember which sections we had encountered */
79 } SectionsEncountered = SE_NONE;
84 static File* FileList; /* Single linked list */
85 static unsigned FileCount; /* Number of entries in the list */
90 static Memory* MemoryList; /* Single linked list */
91 static Memory* MemoryLast; /* Last element in list */
92 static unsigned MemoryCount; /* Number of entries in the list */
94 /* Memory attributes */
95 #define MA_START 0x0001
96 #define MA_SIZE 0x0002
97 #define MA_TYPE 0x0004
98 #define MA_FILE 0x0008
99 #define MA_DEFINE 0x0010
100 #define MA_FILL 0x0020
101 #define MA_FILLVAL 0x0040
106 SegDesc* SegDescList; /* Single linked list */
107 unsigned SegDescCount; /* Number of entries in list */
109 /* Segment attributes */
110 #define SA_TYPE 0x0001
111 #define SA_LOAD 0x0002
112 #define SA_RUN 0x0004
113 #define SA_ALIGN 0x0008
114 #define SA_ALIGN_LOAD 0x0010
115 #define SA_DEFINE 0x0020
116 #define SA_OFFSET 0x0040
117 #define SA_START 0x0080
118 #define SA_OPTIONAL 0x0100
122 /* Descriptor holding information about the binary formats */
123 static BinDesc* BinFmtDesc = 0;
124 static O65Desc* O65FmtDesc = 0;
128 /*****************************************************************************/
130 /*****************************************************************************/
134 static File* NewFile (unsigned Name);
135 /* Create a new file descriptor and insert it into the list */
139 /*****************************************************************************/
140 /* List management */
141 /*****************************************************************************/
145 static File* FindFile (unsigned Name)
146 /* Find a file with a given name. */
150 if (F->Name == Name) {
160 static File* GetFile (unsigned Name)
161 /* Get a file entry with the given name. Create a new one if needed. */
163 File* F = FindFile (Name);
165 /* Create a new one */
173 static void FileInsert (File* F, Memory* M)
174 /* Insert the memory area into the files list */
177 if (F->MemList == 0) {
181 F->MemLast->FNext = M;
188 static Memory* CfgFindMemory (unsigned Name)
189 /* Find the memory are with the given name. Return NULL if not found */
191 Memory* M = MemoryList;
193 if (M->Name == Name) {
203 static Memory* CfgGetMemory (unsigned Name)
204 /* Find the memory are with the given name. Print an error on an invalid name */
206 Memory* M = CfgFindMemory (Name);
208 CfgError ("Invalid memory area `%s'", GetString (Name));
215 static SegDesc* CfgFindSegDesc (unsigned Name)
216 /* Find the segment descriptor with the given name, return NULL if not found. */
218 SegDesc* S = SegDescList;
220 if (S->Name == Name) {
233 static void SegDescInsert (SegDesc* S)
234 /* Insert a segment descriptor into the list of segment descriptors */
236 /* Insert the struct into the list */
237 S->Next = SegDescList;
244 static void MemoryInsert (Memory* M, SegDesc* S)
245 /* Insert the segment descriptor into the memory area list */
247 /* Create a new node for the entry */
248 MemListNode* N = xmalloc (sizeof (MemListNode));
252 if (M->SegLast == 0) {
256 M->SegLast->Next = N;
263 /*****************************************************************************/
264 /* Constructors/Destructors */
265 /*****************************************************************************/
269 static File* NewFile (unsigned Name)
270 /* Create a new file descriptor and insert it into the list */
272 /* Allocate memory */
273 File* F = xmalloc (sizeof (File));
275 /* Initialize the fields */
278 F->Format = BINFMT_DEFAULT;
282 /* Insert the struct into the list */
287 /* ...and return it */
293 static Memory* NewMemory (unsigned Name)
294 /* Create a new memory section and insert it into the list */
296 /* Check for duplicate names */
297 Memory* M = CfgFindMemory (Name);
299 CfgError ("Memory area `%s' defined twice", GetString (Name));
302 /* Allocate memory */
303 M = xmalloc (sizeof (Memory));
305 /* Initialize the fields */
320 /* Insert the struct into the list */
321 if (MemoryLast == 0) {
325 MemoryLast->Next = M;
330 /* ...and return it */
336 static SegDesc* NewSegDesc (unsigned Name)
337 /* Create a segment descriptor */
341 /* Check for duplicate names */
342 SegDesc* S = CfgFindSegDesc (Name);
344 CfgError ("Segment `%s' defined twice", GetString (Name));
347 /* Search for the actual segment in the input files. The function may
348 * return NULL (no such segment), this is checked later.
350 Seg = SegFind (Name);
352 /* Allocate memory */
353 S = xmalloc (sizeof (SegDesc));
355 /* Initialize the fields */
363 /* ...and return it */
369 static void FreeSegDesc (SegDesc* S)
370 /* Free a segment descriptor */
377 /*****************************************************************************/
379 /*****************************************************************************/
383 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
384 /* Check if the item is already defined. Print an error if so. If not, set
385 * the marker that we have a definition now.
389 CfgError ("%s is already defined", Name);
396 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
397 /* Check that a mandatory attribute was given */
399 if ((Attr & Mask) == 0) {
400 CfgError ("%s attribute is missing", Name);
406 static void ParseMemory (void)
407 /* Parse a MEMORY section */
409 static const IdentTok Attributes [] = {
410 { "START", CFGTOK_START },
411 { "SIZE", CFGTOK_SIZE },
412 { "TYPE", CFGTOK_TYPE },
413 { "FILE", CFGTOK_FILE },
414 { "DEFINE", CFGTOK_DEFINE },
415 { "FILL", CFGTOK_FILL },
416 { "FILLVAL", CFGTOK_FILLVAL },
418 static const IdentTok Types [] = {
423 while (CfgTok == CFGTOK_IDENT) {
425 /* Create a new entry on the heap */
426 Memory* M = NewMemory (GetStringId (CfgSVal));
428 /* Skip the name and the following colon */
432 /* Read the attributes */
433 while (CfgTok == CFGTOK_IDENT) {
435 /* Map the identifier to a token */
437 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
440 /* An optional assignment follows */
442 CfgOptionalAssign ();
444 /* Check which attribute was given */
448 FlagAttr (&M->Attr, MA_START, "START");
449 M->Start = CfgIntExpr ();
453 FlagAttr (&M->Attr, MA_SIZE, "SIZE");
454 M->Size = CfgIntExpr ();
458 FlagAttr (&M->Attr, MA_TYPE, "TYPE");
459 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
460 if (CfgTok == CFGTOK_RO) {
467 FlagAttr (&M->Attr, MA_FILE, "FILE");
469 /* Get the file entry and insert the memory area */
470 FileInsert (GetFile (GetStringId (CfgSVal)), M);
475 FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
476 /* Map the token to a boolean */
478 if (CfgTok == CFGTOK_TRUE) {
479 M->Flags |= MF_DEFINE;
485 FlagAttr (&M->Attr, MA_FILL, "FILL");
486 /* Map the token to a boolean */
488 if (CfgTok == CFGTOK_TRUE) {
495 FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
496 M->FillVal = (unsigned char) CfgCheckedIntExpr (0, 0xFF);
500 FAIL ("Unexpected attribute token");
504 /* Skip an optional comma */
508 /* Skip the semicolon */
511 /* Check for mandatory parameters */
512 AttrCheck (M->Attr, MA_START, "START");
513 AttrCheck (M->Attr, MA_SIZE, "SIZE");
515 /* If we don't have a file name for output given, use the default
518 if ((M->Attr & MA_FILE) == 0) {
519 FileInsert (GetFile (GetStringId (OutputName)), M);
523 /* Remember we had this section */
524 SectionsEncountered |= SE_MEMORY;
529 static void ParseFiles (void)
530 /* Parse a FILES section */
532 static const IdentTok Attributes [] = {
533 { "FORMAT", CFGTOK_FORMAT },
535 static const IdentTok Formats [] = {
536 { "O65", CFGTOK_O65 },
537 { "BIN", CFGTOK_BIN },
538 { "BINARY", CFGTOK_BIN },
542 /* The MEMORY section must preceed the FILES section */
543 if ((SectionsEncountered & SE_MEMORY) == 0) {
544 CfgError ("MEMORY must precede FILES");
547 /* Parse all files */
548 while (CfgTok != CFGTOK_RCURLY) {
552 /* We expect a string value here */
555 /* Search for the file, it must exist */
556 F = FindFile (GetStringId (CfgSVal));
558 CfgError ("File `%s' not found in MEMORY section", CfgSVal);
561 /* Skip the token and the following colon */
565 /* Read the attributes */
566 while (CfgTok == CFGTOK_IDENT) {
568 /* Map the identifier to a token */
570 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
573 /* An optional assignment follows */
575 CfgOptionalAssign ();
577 /* Check which attribute was given */
581 if (F->Format != BINFMT_DEFAULT) {
582 /* We've set the format already! */
583 Error ("Cannot set a file format twice");
585 /* Read the format token */
586 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
590 F->Format = BINFMT_BINARY;
594 F->Format = BINFMT_O65;
598 Error ("Unexpected format token");
603 FAIL ("Unexpected attribute token");
607 /* Skip the attribute value and an optional comma */
612 /* Skip the semicolon */
617 /* Remember we had this section */
618 SectionsEncountered |= SE_FILES;
623 static void ParseSegments (void)
624 /* Parse a SEGMENTS section */
626 static const IdentTok Attributes [] = {
627 { "ALIGN", CFGTOK_ALIGN },
628 { "ALIGN_LOAD", CFGTOK_ALIGN_LOAD },
629 { "DEFINE", CFGTOK_DEFINE },
630 { "LOAD", CFGTOK_LOAD },
631 { "OFFSET", CFGTOK_OFFSET },
632 { "OPTIONAL", CFGTOK_OPTIONAL },
633 { "RUN", CFGTOK_RUN },
634 { "START", CFGTOK_START },
635 { "TYPE", CFGTOK_TYPE },
637 static const IdentTok Types [] = {
640 { "BSS", CFGTOK_BSS },
647 /* The MEMORY section must preceed the SEGMENTS section */
648 if ((SectionsEncountered & SE_MEMORY) == 0) {
649 CfgError ("MEMORY must precede SEGMENTS");
652 while (CfgTok == CFGTOK_IDENT) {
656 /* Create a new entry on the heap */
657 S = NewSegDesc (GetStringId (CfgSVal));
659 /* Skip the name and the following colon */
663 /* Read the attributes */
664 while (CfgTok == CFGTOK_IDENT) {
666 /* Map the identifier to a token */
668 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
671 /* An optional assignment follows */
673 CfgOptionalAssign ();
675 /* Check which attribute was given */
679 FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
680 Val = CfgCheckedIntExpr (1, 0x10000);
681 S->Align = BitFind (Val);
682 if ((0x01L << S->Align) != Val) {
683 CfgError ("Alignment must be a power of 2");
685 S->Flags |= SF_ALIGN;
688 case CFGTOK_ALIGN_LOAD:
689 FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
690 Val = CfgCheckedIntExpr (1, 0x10000);
691 S->AlignLoad = BitFind (Val);
692 if ((0x01L << S->AlignLoad) != Val) {
693 CfgError ("Alignment must be a power of 2");
695 S->Flags |= SF_ALIGN_LOAD;
699 FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
700 /* Map the token to a boolean */
702 if (CfgTok == CFGTOK_TRUE) {
703 S->Flags |= SF_DEFINE;
709 FlagAttr (&S->Attr, SA_LOAD, "LOAD");
710 S->Load = CfgGetMemory (GetStringId (CfgSVal));
715 FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
716 S->Addr = CfgCheckedIntExpr (1, 0x1000000);
717 S->Flags |= SF_OFFSET;
720 case CFGTOK_OPTIONAL:
721 FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL");
723 if (CfgTok == CFGTOK_TRUE) {
724 S->Flags |= SF_OPTIONAL;
730 FlagAttr (&S->Attr, SA_RUN, "RUN");
731 S->Run = CfgGetMemory (GetStringId (CfgSVal));
736 FlagAttr (&S->Attr, SA_START, "START");
737 S->Addr = CfgCheckedIntExpr (1, 0x1000000);
738 S->Flags |= SF_START;
742 FlagAttr (&S->Attr, SA_TYPE, "TYPE");
743 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
745 case CFGTOK_RO: S->Flags |= SF_RO; break;
746 case CFGTOK_RW: /* Default */ break;
747 case CFGTOK_BSS: S->Flags |= SF_BSS; break;
748 case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break;
749 default: Internal ("Unexpected token: %d", CfgTok);
755 FAIL ("Unexpected attribute token");
759 /* Skip an optional comma */
763 /* Check for mandatory parameters */
764 AttrCheck (S->Attr, SA_LOAD, "LOAD");
766 /* Set defaults for stuff not given */
767 if ((S->Attr & SA_RUN) == 0) {
772 /* If the segment is marked as BSS style, and if the segment exists
773 * in any of the object file, check that there's no initialized data
776 if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
777 Warning ("%s(%u): Segment with type `bss' contains initialized data",
778 CfgGetName (), CfgErrorLine);
781 /* An attribute of ALIGN_LOAD doesn't make sense if there are no
782 * separate run and load memory areas.
784 if ((S->Flags & SF_ALIGN_LOAD) != 0 && (S->Load == S->Run)) {
785 Warning ("%s(%u): ALIGN_LOAD attribute specified, but no separate "
786 "LOAD and RUN memory areas assigned",
787 CfgGetName (), CfgErrorLine);
788 /* Remove the flag */
789 S->Flags &= ~SF_ALIGN_LOAD;
792 /* If the segment is marked as BSS style, it may not have separate
793 * load and run memory areas, because it's is never written to disk.
795 if ((S->Flags & SF_BSS) != 0 && (S->Load != S->Run)) {
796 Warning ("%s(%u): Segment with type `bss' has both LOAD and RUN "
797 "memory areas assigned", CfgGetName (), CfgErrorLine);
800 /* Don't allow read/write data to be put into a readonly area */
801 if ((S->Flags & SF_RO) == 0) {
802 if (S->Run->Flags & MF_RO) {
803 CfgError ("Cannot put r/w segment `%s' in r/o memory area `%s'",
804 GetString (S->Name), GetString (S->Run->Name));
808 /* Only one of ALIGN, START and OFFSET may be used */
809 Count = ((S->Flags & SF_ALIGN) != 0) +
810 ((S->Flags & SF_OFFSET) != 0) +
811 ((S->Flags & SF_START) != 0);
813 CfgError ("Only one of ALIGN, START, OFFSET may be used");
816 /* If this segment does exist in any of the object files, insert the
817 * descriptor into the list of segment descriptors. Otherwise print a
818 * warning and discard it, because the segment pointer in the
819 * descriptor is invalid.
822 /* Insert the descriptor into the list of all descriptors */
824 /* Insert the segment into the memory area list */
825 MemoryInsert (S->Run, S);
826 if (S->Load != S->Run) {
827 /* We have separate RUN and LOAD areas */
828 MemoryInsert (S->Load, S);
831 /* Print a warning if the segment is not optional */
832 if ((S->Flags & SF_OPTIONAL) == 0) {
833 CfgWarning ("Segment `%s' does not exist", GetString (S->Name));
835 /* Discard the descriptor */
839 /* Skip the semicolon */
843 /* Remember we had this section */
844 SectionsEncountered |= SE_SEGMENTS;
849 static void ParseO65 (void)
850 /* Parse the o65 format section */
852 static const IdentTok Attributes [] = {
853 { "EXPORT", CFGTOK_EXPORT },
854 { "IMPORT", CFGTOK_IMPORT },
855 { "TYPE", CFGTOK_TYPE },
858 { "VERSION", CFGTOK_VERSION },
860 static const IdentTok Types [] = {
861 { "SMALL", CFGTOK_SMALL },
862 { "LARGE", CFGTOK_LARGE },
864 static const IdentTok OperatingSystems [] = {
865 { "LUNIX", CFGTOK_LUNIX },
866 { "OSA65", CFGTOK_OSA65 },
867 { "CC65", CFGTOK_CC65 },
868 { "OPENCBM", CFGTOK_OPENCBM },
871 /* Bitmask to remember the attributes we got already */
875 atOSVersion = 0x0002,
882 unsigned AttrFlags = atNone;
884 /* Remember the attributes read */
886 unsigned OS = 0; /* Initialize to keep gcc happy */
887 unsigned Version = 0;
889 /* Read the attributes */
890 while (CfgTok == CFGTOK_IDENT) {
892 /* Map the identifier to a token */
894 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
897 /* An optional assignment follows */
899 CfgOptionalAssign ();
901 /* Check which attribute was given */
905 /* Remember we had this token (maybe more than once) */
906 AttrFlags |= atExport;
907 /* We expect an identifier */
909 /* Convert the string into a string index */
910 CfgSValId = GetStringId (CfgSVal);
911 /* Check if the export symbol is also defined as an import. */
912 if (O65GetImport (O65FmtDesc, CfgSValId) != 0) {
913 CfgError ("Exported symbol `%s' cannot be an import", CfgSVal);
915 /* Check if we have this symbol defined already. The entry
916 * routine will check this also, but we get a more verbose
917 * error message when checking it here.
919 if (O65GetExport (O65FmtDesc, CfgSValId) != 0) {
920 CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
922 /* Insert the symbol into the table */
923 O65SetExport (O65FmtDesc, CfgSValId);
924 /* Eat the identifier token */
929 /* Remember we had this token (maybe more than once) */
930 AttrFlags |= atImport;
931 /* We expect an identifier */
933 /* Convert the string into a string index */
934 CfgSValId = GetStringId (CfgSVal);
935 /* Check if the imported symbol is also defined as an export. */
936 if (O65GetExport (O65FmtDesc, CfgSValId) != 0) {
937 CfgError ("Imported symbol `%s' cannot be an export", CfgSVal);
939 /* Check if we have this symbol defined already. The entry
940 * routine will check this also, but we get a more verbose
941 * error message when checking it here.
943 if (O65GetImport (O65FmtDesc, CfgSValId) != 0) {
944 CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
946 /* Insert the symbol into the table */
947 O65SetImport (O65FmtDesc, CfgSValId);
948 /* Eat the identifier token */
953 /* Cannot have this attribute twice */
954 FlagAttr (&AttrFlags, atType, "TYPE");
955 /* Get the type of the executable */
956 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
960 O65SetSmallModel (O65FmtDesc);
964 O65SetLargeModel (O65FmtDesc);
968 CfgError ("Unexpected type token");
970 /* Eat the attribute token */
975 /* Cannot use this attribute twice */
976 FlagAttr (&AttrFlags, atOS, "OS");
977 /* Get the operating system. It may be specified as name or
978 * as a number in the range 1..255.
980 if (CfgTok == CFGTOK_INTCON) {
981 CfgRangeCheck (O65OS_MIN, O65OS_MAX);
982 OS = (unsigned) CfgIVal;
984 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
986 case CFGTOK_LUNIX: OS = O65OS_LUNIX; break;
987 case CFGTOK_OSA65: OS = O65OS_OSA65; break;
988 case CFGTOK_CC65: OS = O65OS_CC65; break;
989 case CFGTOK_OPENCBM: OS = O65OS_OPENCBM; break;
990 default: CfgError ("Unexpected OS token");
997 /* Cannot have this attribute twice */
998 FlagAttr (&AttrFlags, atID, "ID");
999 /* We're expecting a number in the 0..$FFFF range*/
1000 ModuleId = (unsigned) CfgCheckedIntExpr (0, 0xFFFF);
1003 case CFGTOK_VERSION:
1004 /* Cannot have this attribute twice */
1005 FlagAttr (&AttrFlags, atVersion, "VERSION");
1006 /* We're expecting a number in byte range */
1007 Version = (unsigned) CfgCheckedIntExpr (0, 0xFF);
1011 FAIL ("Unexpected attribute token");
1015 /* Skip an optional comma */
1016 CfgOptionalComma ();
1019 /* Check if we have all mandatory attributes */
1020 AttrCheck (AttrFlags, atOS, "OS");
1022 /* Check for attributes that may not be combined */
1023 if (OS == O65OS_CC65) {
1024 if ((AttrFlags & (atImport | atExport)) != 0 && ModuleId < 0x8000) {
1025 CfgError ("OS type CC65 may not have imports or exports for ids < $8000");
1028 if (AttrFlags & atID) {
1029 CfgError ("Operating system does not support the ID attribute");
1033 /* Set the O65 operating system to use */
1034 O65SetOS (O65FmtDesc, OS, Version, ModuleId);
1039 static void ParseFormats (void)
1040 /* Parse a target format section */
1042 static const IdentTok Formats [] = {
1043 { "O65", CFGTOK_O65 },
1044 { "BIN", CFGTOK_BIN },
1045 { "BINARY", CFGTOK_BIN },
1048 while (CfgTok == CFGTOK_IDENT) {
1050 /* Map the identifier to a token */
1052 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
1055 /* Skip the name and the following colon */
1059 /* Parse the format options */
1060 switch (FormatTok) {
1067 /* No attribibutes available */
1071 Error ("Unexpected format token");
1074 /* Skip the semicolon */
1079 /* Remember we had this section */
1080 SectionsEncountered |= SE_FORMATS;
1085 static void ParseConDes (void)
1086 /* Parse the CONDES feature */
1088 static const IdentTok Attributes [] = {
1089 { "SEGMENT", CFGTOK_SEGMENT },
1090 { "LABEL", CFGTOK_LABEL },
1091 { "COUNT", CFGTOK_COUNT },
1092 { "TYPE", CFGTOK_TYPE },
1093 { "ORDER", CFGTOK_ORDER },
1096 static const IdentTok Types [] = {
1097 { "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
1098 { "DESTRUCTOR", CFGTOK_DESTRUCTOR },
1099 { "INTERRUPTOR", CFGTOK_INTERRUPTOR },
1102 static const IdentTok Orders [] = {
1103 { "DECREASING", CFGTOK_DECREASING },
1104 { "INCREASING", CFGTOK_INCREASING },
1107 /* Attribute values. */
1108 unsigned SegName = INVALID_STRING_ID;
1109 unsigned Label = INVALID_STRING_ID;
1110 unsigned Count = INVALID_STRING_ID;
1111 /* Initialize to avoid gcc warnings: */
1113 ConDesOrder Order = cdIncreasing;
1115 /* Bitmask to remember the attributes we got already */
1124 unsigned AttrFlags = atNone;
1126 /* Parse the attributes */
1129 /* Map the identifier to a token */
1131 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1134 /* An optional assignment follows */
1136 CfgOptionalAssign ();
1138 /* Check which attribute was given */
1141 case CFGTOK_SEGMENT:
1142 /* Don't allow this twice */
1143 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1144 /* We expect an identifier */
1146 /* Remember the value for later */
1147 SegName = GetStringId (CfgSVal);
1151 /* Don't allow this twice */
1152 FlagAttr (&AttrFlags, atLabel, "LABEL");
1153 /* We expect an identifier */
1155 /* Remember the value for later */
1156 Label = GetStringId (CfgSVal);
1160 /* Don't allow this twice */
1161 FlagAttr (&AttrFlags, atCount, "COUNT");
1162 /* We expect an identifier */
1164 /* Remember the value for later */
1165 Count = GetStringId (CfgSVal);
1169 /* Don't allow this twice */
1170 FlagAttr (&AttrFlags, atType, "TYPE");
1171 /* The type may be given as id or numerical */
1172 if (CfgTok == CFGTOK_INTCON) {
1173 CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1174 Type = (int) CfgIVal;
1176 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1178 case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
1179 case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
1180 case CFGTOK_INTERRUPTOR: Type = CD_TYPE_INT; break;
1181 default: FAIL ("Unexpected type token");
1187 /* Don't allow this twice */
1188 FlagAttr (&AttrFlags, atOrder, "ORDER");
1189 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1191 case CFGTOK_DECREASING: Order = cdDecreasing; break;
1192 case CFGTOK_INCREASING: Order = cdIncreasing; break;
1193 default: FAIL ("Unexpected order token");
1198 FAIL ("Unexpected attribute token");
1202 /* Skip the attribute value */
1205 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1206 if (CfgTok == CFGTOK_SEMI) {
1208 } else if (CfgTok == CFGTOK_COMMA) {
1213 /* Check if we have all mandatory attributes */
1214 AttrCheck (AttrFlags, atSegName, "SEGMENT");
1215 AttrCheck (AttrFlags, atLabel, "LABEL");
1216 AttrCheck (AttrFlags, atType, "TYPE");
1218 /* Check if the condes has already attributes defined */
1219 if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1220 CfgError ("CONDES attributes for type %d are already defined", Type);
1223 /* Define the attributes */
1224 ConDesSetSegName (Type, SegName);
1225 ConDesSetLabel (Type, Label);
1226 if (AttrFlags & atCount) {
1227 ConDesSetCountSym (Type, Count);
1229 if (AttrFlags & atOrder) {
1230 ConDesSetOrder (Type, Order);
1236 static void ParseStartAddress (void)
1237 /* Parse the STARTADDRESS feature */
1239 static const IdentTok Attributes [] = {
1240 { "DEFAULT", CFGTOK_DEFAULT },
1244 /* Attribute values. */
1245 unsigned long DefStartAddr = 0;
1247 /* Bitmask to remember the attributes we got already */
1252 unsigned AttrFlags = atNone;
1254 /* Parse the attributes */
1257 /* Map the identifier to a token */
1259 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1262 /* An optional assignment follows */
1264 CfgOptionalAssign ();
1266 /* Check which attribute was given */
1269 case CFGTOK_DEFAULT:
1270 /* Don't allow this twice */
1271 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1272 /* We expect a numeric expression */
1273 DefStartAddr = CfgCheckedIntExpr (0, 0xFFFFFF);
1277 FAIL ("Unexpected attribute token");
1281 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1282 if (CfgTok == CFGTOK_SEMI) {
1284 } else if (CfgTok == CFGTOK_COMMA) {
1289 /* Check if we have all mandatory attributes */
1290 AttrCheck (AttrFlags, atDefault, "DEFAULT");
1292 /* If no start address was given on the command line, use the one given
1295 if (!HaveStartAddr) {
1296 StartAddr = DefStartAddr;
1302 static void ParseFeatures (void)
1303 /* Parse a features section */
1305 static const IdentTok Features [] = {
1306 { "CONDES", CFGTOK_CONDES },
1307 { "STARTADDRESS", CFGTOK_STARTADDRESS },
1310 while (CfgTok == CFGTOK_IDENT) {
1312 /* Map the identifier to a token */
1313 cfgtok_t FeatureTok;
1314 CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1315 FeatureTok = CfgTok;
1317 /* Skip the name and the following colon */
1321 /* Parse the format options */
1322 switch (FeatureTok) {
1328 case CFGTOK_STARTADDRESS:
1329 ParseStartAddress ();
1334 FAIL ("Unexpected feature token");
1337 /* Skip the semicolon */
1341 /* Remember we had this section */
1342 SectionsEncountered |= SE_FEATURES;
1347 static void ParseSymbols (void)
1348 /* Parse a symbols section */
1350 static const IdentTok Attributes[] = {
1351 { "VALUE", CFGTOK_VALUE },
1352 { "WEAK", CFGTOK_WEAK },
1355 while (CfgTok == CFGTOK_IDENT) {
1361 /* Remember the name */
1362 unsigned Name = GetStringId (CfgSVal);
1365 /* Support both, old and new syntax here. New syntax is a colon
1366 * followed by an attribute list, old syntax is an optional equal
1367 * sign plus a value.
1369 if (CfgTok != CFGTOK_COLON) {
1373 /* Allow an optional assignment */
1374 CfgOptionalAssign ();
1376 /* Make sure the next token is an integer expression, read and
1379 Val = CfgIntExpr ();
1383 /* Bitmask to remember the attributes we got already */
1389 unsigned AttrFlags = atNone;
1392 /* New syntax - skip the colon */
1395 /* Parse the attributes */
1398 /* Map the identifier to a token */
1400 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1403 /* Skip the attribute name */
1406 /* An optional assignment follows */
1407 CfgOptionalAssign ();
1409 /* Check which attribute was given */
1413 /* Don't allow this twice */
1414 FlagAttr (&AttrFlags, atValue, "VALUE");
1415 /* We expect a numeric expression */
1416 Val = CfgIntExpr ();
1420 /* Don't allow this twice */
1421 FlagAttr (&AttrFlags, atWeak, "WEAK");
1423 Weak = (CfgTok == CFGTOK_TRUE);
1428 FAIL ("Unexpected attribute token");
1432 /* Semicolon ends the decl, otherwise accept an optional comma */
1433 if (CfgTok == CFGTOK_SEMI) {
1435 } else if (CfgTok == CFGTOK_COMMA) {
1440 /* Check if we have all mandatory attributes */
1441 AttrCheck (AttrFlags, atValue, "VALUE");
1443 /* Weak is optional, the default are non weak symbols */
1444 if ((AttrFlags & atWeak) == 0) {
1450 /* Check if the symbol is already defined */
1451 if ((E = FindExport (Name)) != 0 && !IsUnresolvedExport (E)) {
1452 /* If the symbol is not marked as weak, this is an error.
1453 * Otherwise ignore the symbol from the config.
1456 CfgError ("Symbol `%s' is already defined", GetString (Name));
1459 /* The symbol is undefined, generate an export */
1460 CreateConstExport (Name, Val);
1463 /* Skip the semicolon */
1467 /* Remember we had this section */
1468 SectionsEncountered |= SE_SYMBOLS;
1473 static void ParseConfig (void)
1474 /* Parse the config file */
1476 static const IdentTok BlockNames [] = {
1477 { "MEMORY", CFGTOK_MEMORY },
1478 { "FILES", CFGTOK_FILES },
1479 { "SEGMENTS", CFGTOK_SEGMENTS },
1480 { "FORMATS", CFGTOK_FORMATS },
1481 { "FEATURES", CFGTOK_FEATURES },
1482 { "SYMBOLS", CFGTOK_SYMBOLS },
1488 /* Read the block ident */
1489 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1493 /* Expected a curly brace */
1494 CfgConsume (CFGTOK_LCURLY, "`{' expected");
1496 /* Read the block */
1507 case CFGTOK_SEGMENTS:
1511 case CFGTOK_FORMATS:
1515 case CFGTOK_FEATURES:
1519 case CFGTOK_SYMBOLS:
1524 FAIL ("Unexpected block token");
1528 /* Skip closing brace */
1529 CfgConsume (CFGTOK_RCURLY, "`}' expected");
1531 } while (CfgTok != CFGTOK_EOF);
1537 /* Read the configuration */
1539 /* Create the descriptors for the binary formats */
1540 BinFmtDesc = NewBinDesc ();
1541 O65FmtDesc = NewO65Desc ();
1543 /* If we have a config name given, open the file, otherwise we will read
1548 /* Parse the file */
1551 /* Close the input file */
1557 static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
1558 /* Create the defines for a RUN segment */
1560 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1562 SB_Printf (&Buf, "__%s_RUN__", GetString (S->Name));
1563 CreateMemoryExport (GetStrBufId (&Buf), S->Run, SegAddr - S->Run->Start);
1564 SB_Printf (&Buf, "__%s_SIZE__", GetString (S->Name));
1565 CreateConstExport (GetStrBufId (&Buf), S->Seg->Size);
1566 S->Flags |= SF_RUN_DEF;
1572 static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
1573 /* Create the defines for a LOAD segment */
1575 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1577 SB_Printf (&Buf, "__%s_LOAD__", GetString (S->Name));
1578 CreateMemoryExport (GetStrBufId (&Buf), S->Load, SegAddr - S->Load->Start);
1579 S->Flags |= SF_LOAD_DEF;
1585 unsigned CfgAssignSegments (void)
1586 /* Assign segments, define linker symbols where requested. The function will
1587 * return the number of memory area overflows (so zero means anything went ok).
1588 * In case of overflows, a short mapfile can be generated later, to ease the
1589 * task of rearranging segments for the user.
1592 unsigned Overflows = 0;
1594 /* Walk through each of the memory sections. Add up the sizes and check
1595 * for an overflow of the section. Assign the start addresses of the
1596 * segments while doing this.
1598 Memory* M = MemoryList;
1603 /* Get the start address of this memory area */
1604 unsigned long Addr = M->Start;
1606 /* Remember if this is a relocatable memory area */
1607 M->Relocatable = RelocatableBinFmt (M->F->Format);
1609 /* Walk through the segments in this memory area */
1613 /* Get the segment from the node */
1614 SegDesc* S = N->Seg;
1616 /* Some actions depend on wether this is the load or run memory
1621 /* This is the run (and maybe load) memory area. Handle
1622 * alignment and explict start address and offset.
1624 if (S->Flags & SF_ALIGN) {
1625 /* Align the address */
1626 unsigned long Val = (0x01UL << S->Align) - 1;
1627 Addr = (Addr + Val) & ~Val;
1628 } else if (S->Flags & (SF_OFFSET | SF_START)) {
1629 /* Give the segment a fixed starting address */
1630 unsigned long NewAddr = S->Addr;
1631 if (S->Flags & SF_OFFSET) {
1632 /* An offset was given, no address, make an address */
1633 NewAddr += M->Start;
1635 if (Addr > NewAddr) {
1636 /* Offset already too large */
1637 if (S->Flags & SF_OFFSET) {
1638 Error ("Offset too small in `%s', segment `%s'",
1639 GetString (M->Name), GetString (S->Name));
1641 Error ("Start address too low in `%s', segment `%s'",
1642 GetString (M->Name), GetString (S->Name));
1648 /* Set the start address of this segment, set the readonly flag
1649 * in the segment and and remember if the segment is in a
1650 * relocatable file or not.
1653 S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
1654 S->Seg->Relocatable = M->Relocatable;
1656 } else if (S->Load == M) {
1658 /* This is the load memory area, *and* run and load are
1659 * different (because of the "else" above). Handle alignment.
1661 if (S->Flags & SF_ALIGN_LOAD) {
1662 /* Align the address */
1663 unsigned long Val = (0x01UL << S->AlignLoad) - 1;
1664 Addr = (Addr + Val) & ~Val;
1669 /* Increment the fill level of the memory area and check for an
1672 M->FillLevel = Addr + S->Seg->Size - M->Start;
1673 if (M->FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) {
1675 M->Flags |= MF_OVERFLOW;
1676 Warning ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
1677 GetString (M->Name), GetString (S->Name),
1678 M->FillLevel - M->Size);
1681 /* If requested, define symbols for the start and size of the
1684 if (S->Flags & SF_DEFINE) {
1685 if (S->Run == M && (S->Flags & SF_RUN_DEF) == 0) {
1686 CreateRunDefines (S, Addr);
1688 if (S->Load == M && (S->Flags & SF_LOAD_DEF) == 0) {
1689 CreateLoadDefines (S, Addr);
1693 /* Calculate the new address */
1694 Addr += S->Seg->Size;
1700 /* If requested, define symbols for start and size of the memory area */
1701 if (M->Flags & MF_DEFINE) {
1702 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1703 SB_Printf (&Buf, "__%s_START__", GetString (M->Name));
1704 CreateMemoryExport (GetStrBufId (&Buf), M, 0);
1705 SB_Printf (&Buf, "__%s_SIZE__", GetString (M->Name));
1706 CreateConstExport (GetStrBufId (&Buf), M->Size);
1707 SB_Printf (&Buf, "__%s_LAST__", GetString (M->Name));
1708 CreateMemoryExport (GetStrBufId (&Buf), M, M->FillLevel);
1712 /* Next memory area */
1716 /* Return the number of memory area overflows */
1722 void CfgWriteTarget (void)
1723 /* Write the target file(s) */
1727 /* Walk through the files list */
1730 /* We don't need to look at files with no memory areas */
1733 /* Is there an output file? */
1734 if (SB_GetLen (GetStrBuf (F->Name)) > 0) {
1736 /* Assign a proper binary format */
1737 if (F->Format == BINFMT_DEFAULT) {
1738 F->Format = DefaultBinFmt;
1741 /* Call the apropriate routine for the binary format */
1742 switch (F->Format) {
1745 BinWriteTarget (BinFmtDesc, F);
1749 O65WriteTarget (O65FmtDesc, F);
1753 Internal ("Invalid binary format: %u", F->Format);
1759 /* No output file. Walk through the list and mark all segments
1760 * loading into these memory areas in this file as dumped.
1768 Print (stdout, 2, "Skipping `%s'...\n", GetString (M->Name));
1770 /* Walk throught the segments */
1773 if (N->Seg->Load == M) {
1774 /* Load area - mark the segment as dumped */
1775 N->Seg->Seg->Dumped = 1;
1778 /* Next segment node */
1781 /* Next memory area */