1 /*****************************************************************************/
5 /* Target configuration file for the ld65 linker */
9 /* (C) 1998-2005 Ullrich von Bassewitz */
10 /* Römerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
63 /*****************************************************************************/
65 /*****************************************************************************/
69 /* Remember which sections we had encountered */
78 } SectionsEncountered = SE_NONE;
83 static File* FileList; /* Single linked list */
84 static unsigned FileCount; /* Number of entries in the list */
89 static Memory* MemoryList; /* Single linked list */
90 static Memory* MemoryLast; /* Last element in list */
91 static unsigned MemoryCount; /* Number of entries in the list */
93 /* Memory attributes */
94 #define MA_START 0x0001
95 #define MA_SIZE 0x0002
96 #define MA_TYPE 0x0004
97 #define MA_FILE 0x0008
98 #define MA_DEFINE 0x0010
99 #define MA_FILL 0x0020
100 #define MA_FILLVAL 0x0040
105 SegDesc* SegDescList; /* Single linked list */
106 unsigned SegDescCount; /* Number of entries in list */
108 /* Segment attributes */
109 #define SA_TYPE 0x0001
110 #define SA_LOAD 0x0002
111 #define SA_RUN 0x0004
112 #define SA_ALIGN 0x0008
113 #define SA_ALIGN_LOAD 0x0010
114 #define SA_DEFINE 0x0020
115 #define SA_OFFSET 0x0040
116 #define SA_START 0x0080
117 #define SA_OPTIONAL 0x0100
121 /* Descriptor holding information about the binary formats */
122 static BinDesc* BinFmtDesc = 0;
123 static O65Desc* O65FmtDesc = 0;
127 /*****************************************************************************/
129 /*****************************************************************************/
133 static File* NewFile (unsigned Name);
134 /* Create a new file descriptor and insert it into the list */
138 /*****************************************************************************/
139 /* List management */
140 /*****************************************************************************/
144 static File* FindFile (unsigned Name)
145 /* Find a file with a given name. */
149 if (F->Name == Name) {
159 static File* GetFile (unsigned Name)
160 /* Get a file entry with the given name. Create a new one if needed. */
162 File* F = FindFile (Name);
164 /* Create a new one */
172 static void FileInsert (File* F, Memory* M)
173 /* Insert the memory area into the files list */
176 if (F->MemList == 0) {
180 F->MemLast->FNext = M;
187 static Memory* CfgFindMemory (unsigned Name)
188 /* Find the memory are with the given name. Return NULL if not found */
190 Memory* M = MemoryList;
192 if (M->Name == Name) {
202 static Memory* CfgGetMemory (unsigned Name)
203 /* Find the memory are with the given name. Print an error on an invalid name */
205 Memory* M = CfgFindMemory (Name);
207 CfgError ("Invalid memory area `%s'", GetString (Name));
214 static SegDesc* CfgFindSegDesc (unsigned Name)
215 /* Find the segment descriptor with the given name, return NULL if not found. */
217 SegDesc* S = SegDescList;
219 if (S->Name == Name) {
232 static void SegDescInsert (SegDesc* S)
233 /* Insert a segment descriptor into the list of segment descriptors */
235 /* Insert the struct into the list */
236 S->Next = SegDescList;
243 static void MemoryInsert (Memory* M, SegDesc* S)
244 /* Insert the segment descriptor into the memory area list */
246 /* Create a new node for the entry */
247 MemListNode* N = xmalloc (sizeof (MemListNode));
251 if (M->SegLast == 0) {
255 M->SegLast->Next = N;
262 /*****************************************************************************/
263 /* Constructors/Destructors */
264 /*****************************************************************************/
268 static File* NewFile (unsigned Name)
269 /* Create a new file descriptor and insert it into the list */
271 /* Allocate memory */
272 File* F = xmalloc (sizeof (File));
274 /* Initialize the fields */
277 F->Format = BINFMT_DEFAULT;
281 /* Insert the struct into the list */
286 /* ...and return it */
292 static Memory* NewMemory (unsigned Name)
293 /* Create a new memory section and insert it into the list */
295 /* Check for duplicate names */
296 Memory* M = CfgFindMemory (Name);
298 CfgError ("Memory area `%s' defined twice", GetString (Name));
301 /* Allocate memory */
302 M = xmalloc (sizeof (Memory));
304 /* Initialize the fields */
319 /* Insert the struct into the list */
320 if (MemoryLast == 0) {
324 MemoryLast->Next = M;
329 /* ...and return it */
335 static SegDesc* NewSegDesc (unsigned Name)
336 /* Create a segment descriptor */
340 /* Check for duplicate names */
341 SegDesc* S = CfgFindSegDesc (Name);
343 CfgError ("Segment `%s' defined twice", GetString (Name));
346 /* Search for the actual segment in the input files. The function may
347 * return NULL (no such segment), this is checked later.
349 Seg = SegFind (Name);
351 /* Allocate memory */
352 S = xmalloc (sizeof (SegDesc));
354 /* Initialize the fields */
362 /* ...and return it */
368 static void FreeSegDesc (SegDesc* S)
369 /* Free a segment descriptor */
376 /*****************************************************************************/
378 /*****************************************************************************/
382 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
383 /* Check if the item is already defined. Print an error if so. If not, set
384 * the marker that we have a definition now.
388 CfgError ("%s is already defined", Name);
395 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
396 /* Check that a mandatory attribute was given */
398 if ((Attr & Mask) == 0) {
399 CfgError ("%s attribute is missing", Name);
405 static void ParseMemory (void)
406 /* Parse a MEMORY section */
408 static const IdentTok Attributes [] = {
409 { "START", CFGTOK_START },
410 { "SIZE", CFGTOK_SIZE },
411 { "TYPE", CFGTOK_TYPE },
412 { "FILE", CFGTOK_FILE },
413 { "DEFINE", CFGTOK_DEFINE },
414 { "FILL", CFGTOK_FILL },
415 { "FILLVAL", CFGTOK_FILLVAL },
417 static const IdentTok Types [] = {
422 while (CfgTok == CFGTOK_IDENT) {
424 /* Create a new entry on the heap */
425 Memory* M = NewMemory (GetStringId (CfgSVal));
427 /* Skip the name and the following colon */
431 /* Read the attributes */
432 while (CfgTok == CFGTOK_IDENT) {
434 /* Map the identifier to a token */
436 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
439 /* An optional assignment follows */
441 CfgOptionalAssign ();
443 /* Check which attribute was given */
447 FlagAttr (&M->Attr, MA_START, "START");
448 M->Start = CfgIntExpr ();
452 FlagAttr (&M->Attr, MA_SIZE, "SIZE");
453 M->Size = CfgIntExpr ();
457 FlagAttr (&M->Attr, MA_TYPE, "TYPE");
458 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
459 if (CfgTok == CFGTOK_RO) {
466 FlagAttr (&M->Attr, MA_FILE, "FILE");
468 /* Get the file entry and insert the memory area */
469 FileInsert (GetFile (GetStringId (CfgSVal)), M);
474 FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
475 /* Map the token to a boolean */
477 if (CfgTok == CFGTOK_TRUE) {
478 M->Flags |= MF_DEFINE;
484 FlagAttr (&M->Attr, MA_FILL, "FILL");
485 /* Map the token to a boolean */
487 if (CfgTok == CFGTOK_TRUE) {
494 FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
495 M->FillVal = (unsigned char) CfgCheckedIntExpr (0, 0xFF);
499 FAIL ("Unexpected attribute token");
503 /* Skip an optional comma */
507 /* Skip the semicolon */
510 /* Check for mandatory parameters */
511 AttrCheck (M->Attr, MA_START, "START");
512 AttrCheck (M->Attr, MA_SIZE, "SIZE");
514 /* If we don't have a file name for output given, use the default
517 if ((M->Attr & MA_FILE) == 0) {
518 FileInsert (GetFile (GetStringId (OutputName)), M);
522 /* Remember we had this section */
523 SectionsEncountered |= SE_MEMORY;
528 static void ParseFiles (void)
529 /* Parse a FILES section */
531 static const IdentTok Attributes [] = {
532 { "FORMAT", CFGTOK_FORMAT },
534 static const IdentTok Formats [] = {
535 { "O65", CFGTOK_O65 },
536 { "BIN", CFGTOK_BIN },
537 { "BINARY", CFGTOK_BIN },
541 /* The MEMORY section must preceed the FILES section */
542 if ((SectionsEncountered & SE_MEMORY) == 0) {
543 CfgError ("MEMORY must precede FILES");
546 /* Parse all files */
547 while (CfgTok != CFGTOK_RCURLY) {
551 /* We expect a string value here */
554 /* Search for the file, it must exist */
555 F = FindFile (GetStringId (CfgSVal));
557 CfgError ("File `%s' not found in MEMORY section", CfgSVal);
560 /* Skip the token and the following colon */
564 /* Read the attributes */
565 while (CfgTok == CFGTOK_IDENT) {
567 /* Map the identifier to a token */
569 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
572 /* An optional assignment follows */
574 CfgOptionalAssign ();
576 /* Check which attribute was given */
580 if (F->Format != BINFMT_DEFAULT) {
581 /* We've set the format already! */
582 Error ("Cannot set a file format twice");
584 /* Read the format token */
585 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
589 F->Format = BINFMT_BINARY;
593 F->Format = BINFMT_O65;
597 Error ("Unexpected format token");
602 FAIL ("Unexpected attribute token");
606 /* Skip the attribute value and an optional comma */
611 /* Skip the semicolon */
616 /* Remember we had this section */
617 SectionsEncountered |= SE_FILES;
622 static void ParseSegments (void)
623 /* Parse a SEGMENTS section */
625 static const IdentTok Attributes [] = {
626 { "ALIGN", CFGTOK_ALIGN },
627 { "ALIGN_LOAD", CFGTOK_ALIGN_LOAD },
628 { "DEFINE", CFGTOK_DEFINE },
629 { "LOAD", CFGTOK_LOAD },
630 { "OFFSET", CFGTOK_OFFSET },
631 { "OPTIONAL", CFGTOK_OPTIONAL },
632 { "RUN", CFGTOK_RUN },
633 { "START", CFGTOK_START },
634 { "TYPE", CFGTOK_TYPE },
636 static const IdentTok Types [] = {
639 { "BSS", CFGTOK_BSS },
646 /* The MEMORY section must preceed the SEGMENTS section */
647 if ((SectionsEncountered & SE_MEMORY) == 0) {
648 CfgError ("MEMORY must precede SEGMENTS");
651 while (CfgTok == CFGTOK_IDENT) {
655 /* Create a new entry on the heap */
656 S = NewSegDesc (GetStringId (CfgSVal));
658 /* Skip the name and the following colon */
662 /* Read the attributes */
663 while (CfgTok == CFGTOK_IDENT) {
665 /* Map the identifier to a token */
667 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
670 /* An optional assignment follows */
672 CfgOptionalAssign ();
674 /* Check which attribute was given */
678 FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
679 Val = CfgCheckedIntExpr (1, 0x10000);
680 S->Align = BitFind (Val);
681 if ((0x01L << S->Align) != Val) {
682 CfgError ("Alignment must be a power of 2");
684 S->Flags |= SF_ALIGN;
687 case CFGTOK_ALIGN_LOAD:
688 FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
689 Val = CfgCheckedIntExpr (1, 0x10000);
690 S->AlignLoad = BitFind (Val);
691 if ((0x01L << S->AlignLoad) != Val) {
692 CfgError ("Alignment must be a power of 2");
694 S->Flags |= SF_ALIGN_LOAD;
698 FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
699 /* Map the token to a boolean */
701 if (CfgTok == CFGTOK_TRUE) {
702 S->Flags |= SF_DEFINE;
708 FlagAttr (&S->Attr, SA_LOAD, "LOAD");
709 S->Load = CfgGetMemory (GetStringId (CfgSVal));
714 FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
715 S->Addr = CfgCheckedIntExpr (1, 0x1000000);
716 S->Flags |= SF_OFFSET;
719 case CFGTOK_OPTIONAL:
720 FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL");
722 if (CfgTok == CFGTOK_TRUE) {
723 S->Flags |= SF_OPTIONAL;
729 FlagAttr (&S->Attr, SA_RUN, "RUN");
730 S->Run = CfgGetMemory (GetStringId (CfgSVal));
735 FlagAttr (&S->Attr, SA_START, "START");
736 S->Addr = CfgCheckedIntExpr (1, 0x1000000);
737 S->Flags |= SF_START;
741 FlagAttr (&S->Attr, SA_TYPE, "TYPE");
742 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
744 case CFGTOK_RO: S->Flags |= SF_RO; break;
745 case CFGTOK_RW: /* Default */ break;
746 case CFGTOK_BSS: S->Flags |= SF_BSS; break;
747 case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break;
748 default: Internal ("Unexpected token: %d", CfgTok);
754 FAIL ("Unexpected attribute token");
758 /* Skip an optional comma */
762 /* Check for mandatory parameters */
763 AttrCheck (S->Attr, SA_LOAD, "LOAD");
765 /* Set defaults for stuff not given */
766 if ((S->Attr & SA_RUN) == 0) {
771 /* If the segment is marked as BSS style, and if the segment exists
772 * in any of the object file, check that there's no initialized data
775 if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
776 Warning ("%s(%u): Segment with type `bss' contains initialized data",
777 CfgGetName (), CfgErrorLine);
780 /* An attribute of ALIGN_LOAD doesn't make sense if there are no
781 * separate run and load memory areas.
783 if ((S->Flags & SF_ALIGN_LOAD) != 0 && (S->Load == S->Run)) {
784 Warning ("%s(%u): ALIGN_LOAD attribute specified, but no separate "
785 "LOAD and RUN memory areas assigned",
786 CfgGetName (), CfgErrorLine);
787 /* Remove the flag */
788 S->Flags &= ~SF_ALIGN_LOAD;
791 /* If the segment is marked as BSS style, it may not have separate
792 * load and run memory areas, because it's is never written to disk.
794 if ((S->Flags & SF_BSS) != 0 && (S->Load != S->Run)) {
795 Warning ("%s(%u): Segment with type `bss' has both LOAD and RUN "
796 "memory areas assigned", CfgGetName (), CfgErrorLine);
799 /* Don't allow read/write data to be put into a readonly area */
800 if ((S->Flags & SF_RO) == 0) {
801 if (S->Run->Flags & MF_RO) {
802 CfgError ("Cannot put r/w segment `%s' in r/o memory area `%s'",
803 GetString (S->Name), GetString (S->Run->Name));
807 /* Only one of ALIGN, START and OFFSET may be used */
808 Count = ((S->Flags & SF_ALIGN) != 0) +
809 ((S->Flags & SF_OFFSET) != 0) +
810 ((S->Flags & SF_START) != 0);
812 CfgError ("Only one of ALIGN, START, OFFSET may be used");
815 /* If this segment does exist in any of the object files, insert the
816 * descriptor into the list of segment descriptors. Otherwise print a
817 * warning and discard it, because the segment pointer in the
818 * descriptor is invalid.
821 /* Insert the descriptor into the list of all descriptors */
823 /* Insert the segment into the memory area list */
824 MemoryInsert (S->Run, S);
825 if (S->Load != S->Run) {
826 /* We have separate RUN and LOAD areas */
827 MemoryInsert (S->Load, S);
830 /* Print a warning if the segment is not optional */
831 if ((S->Flags & SF_OPTIONAL) == 0) {
832 CfgWarning ("Segment `%s' does not exist", GetString (S->Name));
834 /* Discard the descriptor */
838 /* Skip the semicolon */
842 /* Remember we had this section */
843 SectionsEncountered |= SE_SEGMENTS;
848 static void ParseO65 (void)
849 /* Parse the o65 format section */
851 static const IdentTok Attributes [] = {
852 { "EXPORT", CFGTOK_EXPORT },
853 { "IMPORT", CFGTOK_IMPORT },
854 { "TYPE", CFGTOK_TYPE },
857 { "VERSION", CFGTOK_VERSION },
859 static const IdentTok Types [] = {
860 { "SMALL", CFGTOK_SMALL },
861 { "LARGE", CFGTOK_LARGE },
863 static const IdentTok OperatingSystems [] = {
864 { "LUNIX", CFGTOK_LUNIX },
865 { "OSA65", CFGTOK_OSA65 },
866 { "CC65", CFGTOK_CC65 },
867 { "OPENCBM", CFGTOK_OPENCBM },
870 /* Bitmask to remember the attributes we got already */
874 atOSVersion = 0x0002,
881 unsigned AttrFlags = atNone;
883 /* Remember the attributes read */
885 unsigned OS = 0; /* Initialize to keep gcc happy */
886 unsigned Version = 0;
888 /* Read the attributes */
889 while (CfgTok == CFGTOK_IDENT) {
891 /* Map the identifier to a token */
893 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
896 /* An optional assignment follows */
898 CfgOptionalAssign ();
900 /* Check which attribute was given */
904 /* Remember we had this token (maybe more than once) */
905 AttrFlags |= atExport;
906 /* We expect an identifier */
908 /* Convert the string into a string index */
909 CfgSValId = GetStringId (CfgSVal);
910 /* Check if the export symbol is also defined as an import. */
911 if (O65GetImport (O65FmtDesc, CfgSValId) != 0) {
912 CfgError ("Exported symbol `%s' cannot be an import", CfgSVal);
914 /* Check if we have this symbol defined already. The entry
915 * routine will check this also, but we get a more verbose
916 * error message when checking it here.
918 if (O65GetExport (O65FmtDesc, CfgSValId) != 0) {
919 CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
921 /* Insert the symbol into the table */
922 O65SetExport (O65FmtDesc, CfgSValId);
923 /* Eat the identifier token */
928 /* Remember we had this token (maybe more than once) */
929 AttrFlags |= atImport;
930 /* We expect an identifier */
932 /* Convert the string into a string index */
933 CfgSValId = GetStringId (CfgSVal);
934 /* Check if the imported symbol is also defined as an export. */
935 if (O65GetExport (O65FmtDesc, CfgSValId) != 0) {
936 CfgError ("Imported symbol `%s' cannot be an export", CfgSVal);
938 /* Check if we have this symbol defined already. The entry
939 * routine will check this also, but we get a more verbose
940 * error message when checking it here.
942 if (O65GetImport (O65FmtDesc, CfgSValId) != 0) {
943 CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
945 /* Insert the symbol into the table */
946 O65SetImport (O65FmtDesc, CfgSValId);
947 /* Eat the identifier token */
952 /* Cannot have this attribute twice */
953 FlagAttr (&AttrFlags, atType, "TYPE");
954 /* Get the type of the executable */
955 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
959 O65SetSmallModel (O65FmtDesc);
963 O65SetLargeModel (O65FmtDesc);
967 CfgError ("Unexpected type token");
969 /* Eat the attribute token */
974 /* Cannot use this attribute twice */
975 FlagAttr (&AttrFlags, atOS, "OS");
976 /* Get the operating system. It may be specified as name or
977 * as a number in the range 1..255.
979 if (CfgTok == CFGTOK_INTCON) {
980 CfgRangeCheck (O65OS_MIN, O65OS_MAX);
981 OS = (unsigned) CfgIVal;
983 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
985 case CFGTOK_LUNIX: OS = O65OS_LUNIX; break;
986 case CFGTOK_OSA65: OS = O65OS_OSA65; break;
987 case CFGTOK_CC65: OS = O65OS_CC65; break;
988 case CFGTOK_OPENCBM: OS = O65OS_OPENCBM; break;
989 default: CfgError ("Unexpected OS token");
996 /* Cannot have this attribute twice */
997 FlagAttr (&AttrFlags, atID, "ID");
998 /* We're expecting a number in the 0..$FFFF range*/
999 ModuleId = (unsigned) CfgCheckedIntExpr (0, 0xFFFF);
1002 case CFGTOK_VERSION:
1003 /* Cannot have this attribute twice */
1004 FlagAttr (&AttrFlags, atVersion, "VERSION");
1005 /* We're expecting a number in byte range */
1006 Version = (unsigned) CfgCheckedIntExpr (0, 0xFF);
1010 FAIL ("Unexpected attribute token");
1014 /* Skip an optional comma */
1015 CfgOptionalComma ();
1018 /* Check if we have all mandatory attributes */
1019 AttrCheck (AttrFlags, atOS, "OS");
1021 /* Check for attributes that may not be combined */
1022 if (OS == O65OS_CC65) {
1023 if ((AttrFlags & (atImport | atExport)) != 0 && ModuleId < 0x8000) {
1024 CfgError ("OS type CC65 may not have imports or exports for ids < $8000");
1027 if (AttrFlags & atID) {
1028 CfgError ("Operating system does not support the ID attribute");
1032 /* Set the O65 operating system to use */
1033 O65SetOS (O65FmtDesc, OS, Version, ModuleId);
1038 static void ParseFormats (void)
1039 /* Parse a target format section */
1041 static const IdentTok Formats [] = {
1042 { "O65", CFGTOK_O65 },
1043 { "BIN", CFGTOK_BIN },
1044 { "BINARY", CFGTOK_BIN },
1047 while (CfgTok == CFGTOK_IDENT) {
1049 /* Map the identifier to a token */
1051 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
1054 /* Skip the name and the following colon */
1058 /* Parse the format options */
1059 switch (FormatTok) {
1066 /* No attribibutes available */
1070 Error ("Unexpected format token");
1073 /* Skip the semicolon */
1078 /* Remember we had this section */
1079 SectionsEncountered |= SE_FORMATS;
1084 static void ParseConDes (void)
1085 /* Parse the CONDES feature */
1087 static const IdentTok Attributes [] = {
1088 { "SEGMENT", CFGTOK_SEGMENT },
1089 { "LABEL", CFGTOK_LABEL },
1090 { "COUNT", CFGTOK_COUNT },
1091 { "TYPE", CFGTOK_TYPE },
1092 { "ORDER", CFGTOK_ORDER },
1095 static const IdentTok Types [] = {
1096 { "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
1097 { "DESTRUCTOR", CFGTOK_DESTRUCTOR },
1098 { "INTERRUPTOR", CFGTOK_INTERRUPTOR },
1101 static const IdentTok Orders [] = {
1102 { "DECREASING", CFGTOK_DECREASING },
1103 { "INCREASING", CFGTOK_INCREASING },
1106 /* Attribute values. */
1107 unsigned SegName = INVALID_STRING_ID;
1108 unsigned Label = INVALID_STRING_ID;
1109 unsigned Count = INVALID_STRING_ID;
1110 /* Initialize to avoid gcc warnings: */
1112 ConDesOrder Order = cdIncreasing;
1114 /* Bitmask to remember the attributes we got already */
1123 unsigned AttrFlags = atNone;
1125 /* Parse the attributes */
1128 /* Map the identifier to a token */
1130 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1133 /* An optional assignment follows */
1135 CfgOptionalAssign ();
1137 /* Check which attribute was given */
1140 case CFGTOK_SEGMENT:
1141 /* Don't allow this twice */
1142 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1143 /* We expect an identifier */
1145 /* Remember the value for later */
1146 SegName = GetStringId (CfgSVal);
1150 /* Don't allow this twice */
1151 FlagAttr (&AttrFlags, atLabel, "LABEL");
1152 /* We expect an identifier */
1154 /* Remember the value for later */
1155 Label = GetStringId (CfgSVal);
1159 /* Don't allow this twice */
1160 FlagAttr (&AttrFlags, atCount, "COUNT");
1161 /* We expect an identifier */
1163 /* Remember the value for later */
1164 Count = GetStringId (CfgSVal);
1168 /* Don't allow this twice */
1169 FlagAttr (&AttrFlags, atType, "TYPE");
1170 /* The type may be given as id or numerical */
1171 if (CfgTok == CFGTOK_INTCON) {
1172 CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1173 Type = (int) CfgIVal;
1175 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1177 case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
1178 case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
1179 case CFGTOK_INTERRUPTOR: Type = CD_TYPE_INT; break;
1180 default: FAIL ("Unexpected type token");
1186 /* Don't allow this twice */
1187 FlagAttr (&AttrFlags, atOrder, "ORDER");
1188 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1190 case CFGTOK_DECREASING: Order = cdDecreasing; break;
1191 case CFGTOK_INCREASING: Order = cdIncreasing; break;
1192 default: FAIL ("Unexpected order token");
1197 FAIL ("Unexpected attribute token");
1201 /* Skip the attribute value */
1204 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1205 if (CfgTok == CFGTOK_SEMI) {
1207 } else if (CfgTok == CFGTOK_COMMA) {
1212 /* Check if we have all mandatory attributes */
1213 AttrCheck (AttrFlags, atSegName, "SEGMENT");
1214 AttrCheck (AttrFlags, atLabel, "LABEL");
1215 AttrCheck (AttrFlags, atType, "TYPE");
1217 /* Check if the condes has already attributes defined */
1218 if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1219 CfgError ("CONDES attributes for type %d are already defined", Type);
1222 /* Define the attributes */
1223 ConDesSetSegName (Type, SegName);
1224 ConDesSetLabel (Type, Label);
1225 if (AttrFlags & atCount) {
1226 ConDesSetCountSym (Type, Count);
1228 if (AttrFlags & atOrder) {
1229 ConDesSetOrder (Type, Order);
1235 static void ParseStartAddress (void)
1236 /* Parse the STARTADDRESS feature */
1238 static const IdentTok Attributes [] = {
1239 { "DEFAULT", CFGTOK_DEFAULT },
1243 /* Attribute values. */
1244 unsigned long DefStartAddr = 0;
1246 /* Bitmask to remember the attributes we got already */
1251 unsigned AttrFlags = atNone;
1253 /* Parse the attributes */
1256 /* Map the identifier to a token */
1258 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1261 /* An optional assignment follows */
1263 CfgOptionalAssign ();
1265 /* Check which attribute was given */
1268 case CFGTOK_DEFAULT:
1269 /* Don't allow this twice */
1270 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1271 /* We expect a numeric expression */
1272 DefStartAddr = CfgCheckedIntExpr (0, 0xFFFFFF);
1276 FAIL ("Unexpected attribute token");
1280 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1281 if (CfgTok == CFGTOK_SEMI) {
1283 } else if (CfgTok == CFGTOK_COMMA) {
1288 /* Check if we have all mandatory attributes */
1289 AttrCheck (AttrFlags, atDefault, "DEFAULT");
1291 /* If no start address was given on the command line, use the one given
1294 if (!HaveStartAddr) {
1295 StartAddr = DefStartAddr;
1301 static void ParseFeatures (void)
1302 /* Parse a features section */
1304 static const IdentTok Features [] = {
1305 { "CONDES", CFGTOK_CONDES },
1306 { "STARTADDRESS", CFGTOK_STARTADDRESS },
1309 while (CfgTok == CFGTOK_IDENT) {
1311 /* Map the identifier to a token */
1312 cfgtok_t FeatureTok;
1313 CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1314 FeatureTok = CfgTok;
1316 /* Skip the name and the following colon */
1320 /* Parse the format options */
1321 switch (FeatureTok) {
1327 case CFGTOK_STARTADDRESS:
1328 ParseStartAddress ();
1333 FAIL ("Unexpected feature token");
1336 /* Skip the semicolon */
1340 /* Remember we had this section */
1341 SectionsEncountered |= SE_FEATURES;
1346 static void ParseSymbols (void)
1347 /* Parse a symbols section */
1349 static const IdentTok Attributes[] = {
1350 { "VALUE", CFGTOK_VALUE },
1351 { "WEAK", CFGTOK_WEAK },
1354 while (CfgTok == CFGTOK_IDENT) {
1359 /* Remember the name */
1360 unsigned Name = GetStringId (CfgSVal);
1363 /* Support both, old and new syntax here. New syntax is a colon
1364 * followed by an attribute list, old syntax is an optional equal
1365 * sign plus a value.
1367 if (CfgTok != CFGTOK_COLON) {
1371 /* Allow an optional assignment */
1372 CfgOptionalAssign ();
1374 /* Make sure the next token is an integer expression, read and
1377 Val = CfgIntExpr ();
1381 /* Bitmask to remember the attributes we got already */
1387 unsigned AttrFlags = atNone;
1390 /* New syntax - skip the colon */
1393 /* Parse the attributes */
1396 /* Map the identifier to a token */
1398 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1401 /* Skip the attribute name */
1404 /* An optional assignment follows */
1405 CfgOptionalAssign ();
1407 /* Check which attribute was given */
1411 /* Don't allow this twice */
1412 FlagAttr (&AttrFlags, atValue, "VALUE");
1413 /* We expect a numeric expression */
1414 Val = CfgIntExpr ();
1418 /* Don't allow this twice */
1419 FlagAttr (&AttrFlags, atWeak, "WEAK");
1421 Weak = (CfgTok == CFGTOK_TRUE);
1426 FAIL ("Unexpected attribute token");
1430 /* Semicolon ends the decl, otherwise accept an optional comma */
1431 if (CfgTok == CFGTOK_SEMI) {
1433 } else if (CfgTok == CFGTOK_COMMA) {
1438 /* Check if we have all mandatory attributes */
1439 AttrCheck (AttrFlags, atValue, "VALUE");
1441 /* Weak is optional, the default are non weak symbols */
1442 if ((AttrFlags & atWeak) == 0) {
1448 /* Check if the symbol is already defined */
1449 if (FindExport (Name) != 0) {
1450 /* If the symbol is not marked as weak, this is an error.
1451 * Otherwise ignore the symbol from the config.
1454 CfgError ("Symbol `%s' is already defined", GetString (Name));
1457 /* The symbol is undefined, generate an export */
1458 CreateConstExport (Name, Val);
1461 /* Skip the semicolon */
1465 /* Remember we had this section */
1466 SectionsEncountered |= SE_SYMBOLS;
1471 static void ParseConfig (void)
1472 /* Parse the config file */
1474 static const IdentTok BlockNames [] = {
1475 { "MEMORY", CFGTOK_MEMORY },
1476 { "FILES", CFGTOK_FILES },
1477 { "SEGMENTS", CFGTOK_SEGMENTS },
1478 { "FORMATS", CFGTOK_FORMATS },
1479 { "FEATURES", CFGTOK_FEATURES },
1480 { "SYMBOLS", CFGTOK_SYMBOLS },
1486 /* Read the block ident */
1487 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1491 /* Expected a curly brace */
1492 CfgConsume (CFGTOK_LCURLY, "`{' expected");
1494 /* Read the block */
1505 case CFGTOK_SEGMENTS:
1509 case CFGTOK_FORMATS:
1513 case CFGTOK_FEATURES:
1517 case CFGTOK_SYMBOLS:
1522 FAIL ("Unexpected block token");
1526 /* Skip closing brace */
1527 CfgConsume (CFGTOK_RCURLY, "`}' expected");
1529 } while (CfgTok != CFGTOK_EOF);
1535 /* Read the configuration */
1537 /* Create the descriptors for the binary formats */
1538 BinFmtDesc = NewBinDesc ();
1539 O65FmtDesc = NewO65Desc ();
1541 /* If we have a config name given, open the file, otherwise we will read
1546 /* Parse the file */
1549 /* Close the input file */
1555 static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
1556 /* Create the defines for a RUN segment */
1560 xsprintf (Buf, sizeof (Buf), "__%s_RUN__", GetString (S->Name));
1561 CreateMemoryExport (GetStringId (Buf), S->Run, SegAddr - S->Run->Start);
1562 xsprintf (Buf, sizeof (Buf), "__%s_SIZE__", GetString (S->Name));
1563 CreateConstExport (GetStringId (Buf), S->Seg->Size);
1564 S->Flags |= SF_RUN_DEF;
1569 static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
1570 /* Create the defines for a LOAD segment */
1574 xsprintf (Buf, sizeof (Buf), "__%s_LOAD__", GetString (S->Name));
1575 CreateMemoryExport (GetStringId (Buf), S->Load, SegAddr - S->Load->Start);
1576 S->Flags |= SF_LOAD_DEF;
1581 unsigned CfgAssignSegments (void)
1582 /* Assign segments, define linker symbols where requested. The function will
1583 * return the number of memory area overflows (so zero means anything went ok).
1584 * In case of overflows, a short mapfile can be generated later, to ease the
1585 * task of rearranging segments for the user.
1588 unsigned Overflows = 0;
1590 /* Walk through each of the memory sections. Add up the sizes and check
1591 * for an overflow of the section. Assign the start addresses of the
1592 * segments while doing this.
1594 Memory* M = MemoryList;
1599 /* Get the start address of this memory area */
1600 unsigned long Addr = M->Start;
1602 /* Remember if this is a relocatable memory area */
1603 M->Relocatable = RelocatableBinFmt (M->F->Format);
1605 /* Walk through the segments in this memory area */
1609 /* Get the segment from the node */
1610 SegDesc* S = N->Seg;
1612 /* Some actions depend on wether this is the load or run memory
1617 /* This is the run (and maybe load) memory area. Handle
1618 * alignment and explict start address and offset.
1620 if (S->Flags & SF_ALIGN) {
1621 /* Align the address */
1622 unsigned long Val = (0x01UL << S->Align) - 1;
1623 Addr = (Addr + Val) & ~Val;
1624 } else if (S->Flags & (SF_OFFSET | SF_START)) {
1625 /* Give the segment a fixed starting address */
1626 unsigned long NewAddr = S->Addr;
1627 if (S->Flags & SF_OFFSET) {
1628 /* An offset was given, no address, make an address */
1629 NewAddr += M->Start;
1631 if (Addr > NewAddr) {
1632 /* Offset already too large */
1633 if (S->Flags & SF_OFFSET) {
1634 Error ("Offset too small in `%s', segment `%s'",
1635 GetString (M->Name), GetString (S->Name));
1637 Error ("Start address too low in `%s', segment `%s'",
1638 GetString (M->Name), GetString (S->Name));
1644 /* Set the start address of this segment, set the readonly flag
1645 * in the segment and and remember if the segment is in a
1646 * relocatable file or not.
1649 S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
1650 S->Seg->Relocatable = M->Relocatable;
1652 } else if (S->Load == M) {
1654 /* This is the load memory area, *and* run and load are
1655 * different (because of the "else" above). Handle alignment.
1657 if (S->Flags & SF_ALIGN_LOAD) {
1658 /* Align the address */
1659 unsigned long Val = (0x01UL << S->AlignLoad) - 1;
1660 Addr = (Addr + Val) & ~Val;
1665 /* Increment the fill level of the memory area and check for an
1668 M->FillLevel = Addr + S->Seg->Size - M->Start;
1669 if (M->FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) {
1671 M->Flags |= MF_OVERFLOW;
1672 Warning ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
1673 GetString (M->Name), GetString (S->Name),
1674 M->FillLevel - M->Size);
1677 /* If requested, define symbols for the start and size of the
1680 if (S->Flags & SF_DEFINE) {
1681 if (S->Run == M && (S->Flags & SF_RUN_DEF) == 0) {
1682 CreateRunDefines (S, Addr);
1684 if (S->Load == M && (S->Flags & SF_LOAD_DEF) == 0) {
1685 CreateLoadDefines (S, Addr);
1689 /* Calculate the new address */
1690 Addr += S->Seg->Size;
1696 /* If requested, define symbols for start and size of the memory area */
1697 if (M->Flags & MF_DEFINE) {
1699 sprintf (Buf, "__%s_START__", GetString (M->Name));
1700 CreateMemoryExport (GetStringId (Buf), M, 0);
1701 sprintf (Buf, "__%s_SIZE__", GetString (M->Name));
1702 CreateConstExport (GetStringId (Buf), M->Size);
1703 sprintf (Buf, "__%s_LAST__", GetString (M->Name));
1704 CreateMemoryExport (GetStringId (Buf), M, M->FillLevel);
1707 /* Next memory area */
1711 /* Return the number of memory area overflows */
1717 void CfgWriteTarget (void)
1718 /* Write the target file(s) */
1722 /* Walk through the files list */
1725 /* We don't need to look at files with no memory areas */
1728 /* Is there an output file? */
1729 if (strlen (GetString (F->Name)) > 0) {
1731 /* Assign a proper binary format */
1732 if (F->Format == BINFMT_DEFAULT) {
1733 F->Format = DefaultBinFmt;
1736 /* Call the apropriate routine for the binary format */
1737 switch (F->Format) {
1740 BinWriteTarget (BinFmtDesc, F);
1744 O65WriteTarget (O65FmtDesc, F);
1748 Internal ("Invalid binary format: %u", F->Format);
1754 /* No output file. Walk through the list and mark all segments
1755 * loading into these memory areas in this file as dumped.
1763 Print (stdout, 2, "Skipping `%s'...\n", GetString (M->Name));
1765 /* Walk throught the segments */
1768 if (N->Seg->Load == M) {
1769 /* Load area - mark the segment as dumped */
1770 N->Seg->Seg->Dumped = 1;
1773 /* Next segment node */
1776 /* Next memory area */