1 /*****************************************************************************/
5 /* Target configuration file for the ld65 linker */
9 /* (c) 1998-2013, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
14 /* With contributions from: */
16 /* - "David M. Lloyd" <david.lloyd@redhat.com> */
19 /* This software is provided 'as-is', without any expressed or implied */
20 /* warranty. In no event will the authors be held liable for any damages */
21 /* arising from the use of this software. */
23 /* Permission is granted to anyone to use this software for any purpose, */
24 /* including commercial applications, and to alter it and redistribute it */
25 /* freely, subject to the following restrictions: */
27 /* 1. The origin of this software must not be misrepresented; you must not */
28 /* claim that you wrote the original software. If you use this software */
29 /* in a product, an acknowledgment in the product documentation would be */
30 /* appreciated but is not required. */
31 /* 2. Altered source versions must be plainly marked as such, and must not */
32 /* be misrepresented as being the original software. */
33 /* 3. This notice may not be removed or altered from any source */
36 /*****************************************************************************/
56 #include "alignment.h"
75 /*****************************************************************************/
77 /*****************************************************************************/
81 /* Remember which sections we had encountered */
90 } SectionsEncountered = SE_NONE;
95 static Collection FileList = STATIC_COLLECTION_INITIALIZER;
98 static Collection MemoryAreas = STATIC_COLLECTION_INITIALIZER;
100 /* Memory attributes */
101 #define MA_START 0x0001
102 #define MA_SIZE 0x0002
103 #define MA_TYPE 0x0004
104 #define MA_FILE 0x0008
105 #define MA_DEFINE 0x0010
106 #define MA_FILL 0x0020
107 #define MA_FILLVAL 0x0040
108 #define MA_BANK 0x0080
111 static Collection SegDescList = STATIC_COLLECTION_INITIALIZER;
113 /* Segment attributes */
114 #define SA_TYPE 0x0001
115 #define SA_LOAD 0x0002
116 #define SA_RUN 0x0004
117 #define SA_ALIGN 0x0008
118 #define SA_ALIGN_LOAD 0x0010
119 #define SA_DEFINE 0x0020
120 #define SA_OFFSET 0x0040
121 #define SA_START 0x0080
122 #define SA_OPTIONAL 0x0100
123 #define SA_FILLVAL 0x0200
125 /* Symbol types used in the CfgSymbol structure */
127 CfgSymExport, /* Not really used in struct CfgSymbol */
128 CfgSymImport, /* Dito */
129 CfgSymWeak, /* Like export but weak */
130 CfgSymO65Export, /* An o65 export */
131 CfgSymO65Import, /* An o65 import */
134 /* Symbol structure. It is used for o65 imports and exports, but also for
135 ** symbols from the SYMBOLS sections (symbols defined in the config file or
138 typedef struct CfgSymbol CfgSymbol;
140 CfgSymType Type; /* Type of symbol */
141 LineInfo* LI; /* Config file position */
142 unsigned Name; /* Symbol name */
143 ExprNode* Value; /* Symbol value if any */
144 unsigned AddrSize; /* Address size of symbol */
147 /* Collections with symbols */
148 static Collection CfgSymbols = STATIC_COLLECTION_INITIALIZER;
150 /* Descriptor holding information about the binary formats */
151 static BinDesc* BinFmtDesc = 0;
152 static O65Desc* O65FmtDesc = 0;
153 static XexDesc* XexFmtDesc = 0;
157 /*****************************************************************************/
159 /*****************************************************************************/
163 static File* NewFile (unsigned Name);
164 /* Create a new file descriptor and insert it into the list */
168 /*****************************************************************************/
169 /* List management */
170 /*****************************************************************************/
174 static File* FindFile (unsigned Name)
175 /* Find a file with a given name. */
178 for (I = 0; I < CollCount (&FileList); ++I) {
179 File* F = CollAtUnchecked (&FileList, I);
180 if (F->Name == Name) {
189 static File* GetFile (unsigned Name)
190 /* Get a file entry with the given name. Create a new one if needed. */
192 File* F = FindFile (Name);
194 /* Create a new one */
202 static void FileInsert (File* F, MemoryArea* M)
203 /* Insert the memory area into the files list */
206 CollAppend (&F->MemoryAreas, M);
211 static MemoryArea* CfgFindMemory (unsigned Name)
212 /* Find the memory are with the given name. Return NULL if not found */
215 for (I = 0; I < CollCount (&MemoryAreas); ++I) {
216 MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
217 if (M->Name == Name) {
226 static MemoryArea* CfgGetMemory (unsigned Name)
227 /* Find the memory are with the given name. Print an error on an invalid name */
229 MemoryArea* M = CfgFindMemory (Name);
231 CfgError (&CfgErrorPos, "Invalid memory area '%s'", GetString (Name));
238 static SegDesc* CfgFindSegDesc (unsigned Name)
239 /* Find the segment descriptor with the given name, return NULL if not found. */
242 for (I = 0; I < CollCount (&SegDescList); ++I) {
243 SegDesc* S = CollAtUnchecked (&SegDescList, I);
244 if (S->Name == Name) {
256 static void MemoryInsert (MemoryArea* M, SegDesc* S)
257 /* Insert the segment descriptor into the memory area list */
259 /* Insert the segment into the segment list of the memory area */
260 CollAppend (&M->SegList, S);
265 /*****************************************************************************/
266 /* Constructors/Destructors */
267 /*****************************************************************************/
271 static CfgSymbol* NewCfgSymbol (CfgSymType Type, unsigned Name)
272 /* Create a new CfgSymbol structure with the given type and name. The
273 ** current config file position is recorded in the returned struct. The
274 ** created struct is inserted into the CfgSymbols collection and returned.
277 /* Allocate memory */
278 CfgSymbol* Sym = xmalloc (sizeof (CfgSymbol));
280 /* Initialize the fields */
282 Sym->LI = GenLineInfo (&CfgErrorPos);
285 Sym->AddrSize = ADDR_SIZE_INVALID;
287 /* Insert the symbol into the collection */
288 CollAppend (&CfgSymbols, Sym);
290 /* Return the initialized struct */
296 static File* NewFile (unsigned Name)
297 /* Create a new file descriptor and insert it into the list */
299 /* Allocate memory */
300 File* F = xmalloc (sizeof (File));
302 /* Initialize the fields */
305 F->Format = BINFMT_DEFAULT;
307 InitCollection (&F->MemoryAreas);
309 /* Insert the struct into the list */
310 CollAppend (&FileList, F);
312 /* ...and return it */
318 static MemoryArea* CreateMemoryArea (const FilePos* Pos, unsigned Name)
319 /* Create a new memory area and insert it into the list */
321 /* Check for duplicate names */
322 MemoryArea* M = CfgFindMemory (Name);
324 CfgError (&CfgErrorPos,
325 "Memory area '%s' defined twice",
329 /* Create a new memory area */
330 M = NewMemoryArea (Pos, Name);
332 /* Insert the struct into the list ... */
333 CollAppend (&MemoryAreas, M);
335 /* ...and return it */
341 static SegDesc* NewSegDesc (unsigned Name)
342 /* Create a segment descriptor and insert it into the list */
345 /* Check for duplicate names */
346 SegDesc* S = CfgFindSegDesc (Name);
348 CfgError (&CfgErrorPos, "Segment '%s' defined twice", GetString (Name));
351 /* Allocate memory */
352 S = xmalloc (sizeof (SegDesc));
354 /* Initialize the fields */
356 S->LI = GenLineInfo (&CfgErrorPos);
362 S->LoadAlignment = 1;
364 /* Insert the struct into the list ... */
365 CollAppend (&SegDescList, S);
367 /* ...and return it */
373 static void FreeSegDesc (SegDesc* S)
374 /* Free a segment descriptor */
376 FreeLineInfo (S->LI);
382 /*****************************************************************************/
383 /* Config file parsing */
384 /*****************************************************************************/
388 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
389 /* Check if the item is already defined. Print an error if so. If not, set
390 ** the marker that we have a definition now.
394 CfgError (&CfgErrorPos, "%s is already defined", Name);
401 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
402 /* Check that a mandatory attribute was given */
404 if ((Attr & Mask) == 0) {
405 CfgError (&CfgErrorPos, "%s attribute is missing", Name);
411 static void ParseMemory (void)
412 /* Parse a MEMORY section */
414 static const IdentTok Attributes [] = {
415 { "BANK", CFGTOK_BANK },
416 { "DEFINE", CFGTOK_DEFINE },
417 { "FILE", CFGTOK_FILE },
418 { "FILL", CFGTOK_FILL },
419 { "FILLVAL", CFGTOK_FILLVAL },
420 { "SIZE", CFGTOK_SIZE },
421 { "START", CFGTOK_START },
422 { "TYPE", CFGTOK_TYPE },
424 static const IdentTok Types [] = {
429 while (CfgTok == CFGTOK_IDENT) {
431 /* Create a new entry on the heap */
432 MemoryArea* M = CreateMemoryArea (&CfgErrorPos, GetStrBufId (&CfgSVal));
434 /* Skip the name and the following colon */
438 /* Read the attributes */
439 while (CfgTok == CFGTOK_IDENT) {
441 /* Map the identifier to a token */
443 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
446 /* An optional assignment follows */
448 CfgOptionalAssign ();
450 /* Check which attribute was given */
454 FlagAttr (&M->Attr, MA_BANK, "BANK");
455 M->BankExpr = CfgExpr ();
459 FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
460 /* Map the token to a boolean */
462 if (CfgTok == CFGTOK_TRUE) {
463 M->Flags |= MF_DEFINE;
469 FlagAttr (&M->Attr, MA_FILE, "FILE");
471 /* Get the file entry and insert the memory area */
472 FileInsert (GetFile (GetStrBufId (&CfgSVal)), M);
477 FlagAttr (&M->Attr, MA_FILL, "FILL");
478 /* Map the token to a boolean */
480 if (CfgTok == CFGTOK_TRUE) {
487 FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
488 M->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
492 FlagAttr (&M->Attr, MA_SIZE, "SIZE");
493 M->SizeExpr = CfgExpr ();
497 FlagAttr (&M->Attr, MA_START, "START");
498 M->StartExpr = CfgExpr ();
502 FlagAttr (&M->Attr, MA_TYPE, "TYPE");
503 CfgSpecialToken (Types, ENTRY_COUNT (Types), "TYPE");
504 if (CfgTok == CFGTOK_RO) {
511 FAIL ("Unexpected attribute token");
515 /* Skip an optional comma */
519 /* Skip the semicolon */
522 /* Check for mandatory parameters */
523 AttrCheck (M->Attr, MA_START, "START");
524 AttrCheck (M->Attr, MA_SIZE, "SIZE");
526 /* If we don't have a file name for output given, use the default
529 if ((M->Attr & MA_FILE) == 0) {
530 FileInsert (GetFile (GetStringId (OutputName)), M);
535 /* Remember we had this section */
536 SectionsEncountered |= SE_MEMORY;
541 static void ParseFiles (void)
542 /* Parse a FILES section */
544 static const IdentTok Attributes [] = {
545 { "FORMAT", CFGTOK_FORMAT },
547 static const IdentTok Formats [] = {
548 { "ATARI", CFGTOK_ATARIEXE },
549 { "O65", CFGTOK_O65 },
550 { "BIN", CFGTOK_BIN },
551 { "BINARY", CFGTOK_BIN },
555 /* The MEMORY section must preceed the FILES section */
556 if ((SectionsEncountered & SE_MEMORY) == 0) {
557 CfgError (&CfgErrorPos, "MEMORY must precede FILES");
560 /* Parse all files */
561 while (CfgTok != CFGTOK_RCURLY) {
565 /* We expect a string value here */
568 /* Search for the file, it must exist */
569 F = FindFile (GetStrBufId (&CfgSVal));
571 CfgError (&CfgErrorPos,
572 "File '%s' not found in MEMORY section",
573 SB_GetConstBuf (&CfgSVal));
576 /* Skip the token and the following colon */
580 /* Read the attributes */
581 while (CfgTok == CFGTOK_IDENT) {
583 /* Map the identifier to a token */
585 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
588 /* An optional assignment follows */
590 CfgOptionalAssign ();
592 /* Check which attribute was given */
596 if (F->Format != BINFMT_DEFAULT) {
597 /* We've set the format already! */
598 CfgError (&CfgErrorPos,
599 "Cannot set a file format twice");
601 /* Read the format token */
602 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
606 F->Format = BINFMT_BINARY;
610 F->Format = BINFMT_O65;
613 case CFGTOK_ATARIEXE:
614 F->Format = BINFMT_ATARIEXE;
618 Error ("Unexpected format token");
623 FAIL ("Unexpected attribute token");
627 /* Skip the attribute value and an optional comma */
632 /* Skip the semicolon */
637 /* Remember we had this section */
638 SectionsEncountered |= SE_FILES;
643 static void ParseSegments (void)
644 /* Parse a SEGMENTS section */
646 static const IdentTok Attributes [] = {
647 { "ALIGN", CFGTOK_ALIGN },
648 { "ALIGN_LOAD", CFGTOK_ALIGN_LOAD },
649 { "DEFINE", CFGTOK_DEFINE },
650 { "FILLVAL", CFGTOK_FILLVAL },
651 { "LOAD", CFGTOK_LOAD },
652 { "OFFSET", CFGTOK_OFFSET },
653 { "OPTIONAL", CFGTOK_OPTIONAL },
654 { "RUN", CFGTOK_RUN },
655 { "START", CFGTOK_START },
656 { "TYPE", CFGTOK_TYPE },
658 static const IdentTok Types [] = {
661 { "BSS", CFGTOK_BSS },
663 { "OVERWRITE", CFGTOK_OVERWRITE },
668 /* The MEMORY section must preceed the SEGMENTS section */
669 if ((SectionsEncountered & SE_MEMORY) == 0) {
670 CfgError (&CfgErrorPos, "MEMORY must precede SEGMENTS");
673 while (CfgTok == CFGTOK_IDENT) {
677 /* Create a new entry on the heap */
678 S = NewSegDesc (GetStrBufId (&CfgSVal));
680 /* Skip the name and the following colon */
684 /* Read the attributes */
685 while (CfgTok == CFGTOK_IDENT) {
687 /* Map the identifier to a token */
689 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
692 /* An optional assignment follows */
694 CfgOptionalAssign ();
696 /* Check which attribute was given */
700 FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
701 S->RunAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
702 S->Flags |= SF_ALIGN;
705 case CFGTOK_ALIGN_LOAD:
706 FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
707 S->LoadAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
708 S->Flags |= SF_ALIGN_LOAD;
712 FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
713 /* Map the token to a boolean */
715 if (CfgTok == CFGTOK_TRUE) {
716 S->Flags |= SF_DEFINE;
722 FlagAttr (&S->Attr, SA_FILLVAL, "FILLVAL");
723 S->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
724 S->Flags |= SF_FILLVAL;
728 FlagAttr (&S->Attr, SA_LOAD, "LOAD");
729 S->Load = CfgGetMemory (GetStrBufId (&CfgSVal));
734 FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
735 S->Addr = CfgCheckedConstExpr (1, 0x1000000);
736 S->Flags |= SF_OFFSET;
739 case CFGTOK_OPTIONAL:
740 FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL");
742 if (CfgTok == CFGTOK_TRUE) {
743 S->Flags |= SF_OPTIONAL;
749 FlagAttr (&S->Attr, SA_RUN, "RUN");
750 S->Run = CfgGetMemory (GetStrBufId (&CfgSVal));
755 FlagAttr (&S->Attr, SA_START, "START");
756 S->Addr = CfgCheckedConstExpr (1, 0x1000000);
757 S->Flags |= SF_START;
761 FlagAttr (&S->Attr, SA_TYPE, "TYPE");
762 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
764 case CFGTOK_RO: S->Flags |= SF_RO; break;
765 case CFGTOK_RW: /* Default */ break;
766 case CFGTOK_BSS: S->Flags |= SF_BSS; break;
767 case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break;
768 case CFGTOK_OVERWRITE: S->Flags |= (SF_OVERWRITE | SF_RO); break;
769 default: Internal ("Unexpected token: %d", CfgTok);
775 FAIL ("Unexpected attribute token");
779 /* Skip an optional comma */
783 /* Check for mandatory parameters */
784 AttrCheck (S->Attr, SA_LOAD, "LOAD");
786 /* Set defaults for stuff not given */
787 if ((S->Attr & SA_RUN) == 0) {
792 /* An attribute of ALIGN_LOAD doesn't make sense if there are no
793 ** separate run and load memory areas.
795 if ((S->Flags & SF_ALIGN_LOAD) != 0 && (S->Load == S->Run)) {
796 CfgWarning (&CfgErrorPos,
797 "ALIGN_LOAD attribute specified, but no separate "
798 "LOAD and RUN memory areas assigned");
799 /* Remove the flag */
800 S->Flags &= ~SF_ALIGN_LOAD;
803 /* If the segment is marked as BSS style, it may not have separate
804 ** load and run memory areas, because it's is never written to disk.
806 if ((S->Flags & SF_BSS) != 0 && (S->Load != S->Run)) {
807 CfgWarning (&CfgErrorPos,
808 "Segment with type 'bss' has both LOAD and RUN "
809 "memory areas assigned");
812 /* Don't allow read/write data to be put into a readonly area */
813 if ((S->Flags & SF_RO) == 0) {
814 if (S->Run->Flags & MF_RO) {
815 CfgError (&CfgErrorPos,
816 "Cannot put r/w segment '%s' in r/o memory area '%s'",
817 GetString (S->Name), GetString (S->Run->Name));
821 /* Only one of ALIGN, START and OFFSET may be used */
822 Count = ((S->Flags & SF_ALIGN) != 0) +
823 ((S->Flags & SF_OFFSET) != 0) +
824 ((S->Flags & SF_START) != 0);
826 CfgError (&CfgErrorPos,
827 "Only one of ALIGN, START, OFFSET may be used");
830 /* Skip the semicolon */
834 /* Remember we had this section */
835 SectionsEncountered |= SE_SEGMENTS;
840 static void ParseO65 (void)
841 /* Parse the o65 format section */
843 static const IdentTok Attributes [] = {
844 { "EXPORT", CFGTOK_EXPORT },
845 { "IMPORT", CFGTOK_IMPORT },
846 { "TYPE", CFGTOK_TYPE },
849 { "VERSION", CFGTOK_VERSION },
851 static const IdentTok Types [] = {
852 { "SMALL", CFGTOK_SMALL },
853 { "LARGE", CFGTOK_LARGE },
855 static const IdentTok OperatingSystems [] = {
856 { "LUNIX", CFGTOK_LUNIX },
857 { "OSA65", CFGTOK_OSA65 },
858 { "CC65", CFGTOK_CC65 },
859 { "OPENCBM", CFGTOK_OPENCBM },
862 /* Bitmask to remember the attributes we got already */
866 atOSVersion = 0x0002,
873 unsigned AttrFlags = atNone;
875 /* Remember the attributes read */
876 unsigned OS = 0; /* Initialize to keep gcc happy */
877 unsigned Version = 0;
879 /* Read the attributes */
880 while (CfgTok == CFGTOK_IDENT) {
882 /* Map the identifier to a token */
884 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
887 /* An optional assignment follows */
889 CfgOptionalAssign ();
891 /* Check which attribute was given */
895 /* Remember we had this token (maybe more than once) */
896 AttrFlags |= atExport;
897 /* We expect an identifier */
899 /* Remember it as an export for later */
900 NewCfgSymbol (CfgSymO65Export, GetStrBufId (&CfgSVal));
901 /* Eat the identifier token */
906 /* Remember we had this token (maybe more than once) */
907 AttrFlags |= atImport;
908 /* We expect an identifier */
910 /* Remember it as an import for later */
911 NewCfgSymbol (CfgSymO65Import, GetStrBufId (&CfgSVal));
912 /* Eat the identifier token */
917 /* Cannot have this attribute twice */
918 FlagAttr (&AttrFlags, atType, "TYPE");
919 /* Get the type of the executable */
920 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
924 O65SetSmallModel (O65FmtDesc);
928 O65SetLargeModel (O65FmtDesc);
932 CfgError (&CfgErrorPos, "Unexpected type token");
934 /* Eat the attribute token */
939 /* Cannot use this attribute twice */
940 FlagAttr (&AttrFlags, atOS, "OS");
941 /* Get the operating system. It may be specified as name or
942 ** as a number in the range 1..255.
944 if (CfgTok == CFGTOK_INTCON) {
945 CfgRangeCheck (O65OS_MIN, O65OS_MAX);
946 OS = (unsigned) CfgIVal;
948 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
950 case CFGTOK_LUNIX: OS = O65OS_LUNIX; break;
951 case CFGTOK_OSA65: OS = O65OS_OSA65; break;
952 case CFGTOK_CC65: OS = O65OS_CC65; break;
953 case CFGTOK_OPENCBM: OS = O65OS_OPENCBM; break;
954 default: CfgError (&CfgErrorPos, "Unexpected OS token");
961 /* Cannot have this attribute twice */
962 FlagAttr (&AttrFlags, atID, "ID");
963 /* We're expecting a number in the 0..$FFFF range*/
964 ModuleId = (unsigned) CfgCheckedConstExpr (0, 0xFFFF);
968 /* Cannot have this attribute twice */
969 FlagAttr (&AttrFlags, atVersion, "VERSION");
970 /* We're expecting a number in byte range */
971 Version = (unsigned) CfgCheckedConstExpr (0, 0xFF);
975 FAIL ("Unexpected attribute token");
979 /* Skip an optional comma */
983 /* Check if we have all mandatory attributes */
984 AttrCheck (AttrFlags, atOS, "OS");
986 /* Check for attributes that may not be combined */
987 if (OS == O65OS_CC65) {
988 if ((AttrFlags & (atImport | atExport)) != 0 && ModuleId < 0x8000) {
989 CfgError (&CfgErrorPos,
990 "OS type CC65 may not have imports or exports for ids < $8000");
993 if (AttrFlags & atID) {
994 CfgError (&CfgErrorPos,
995 "Operating system does not support the ID attribute");
999 /* Set the O65 operating system to use */
1000 O65SetOS (O65FmtDesc, OS, Version, ModuleId);
1005 static void ParseFormats (void)
1006 /* Parse a target format section */
1008 static const IdentTok Formats [] = {
1009 { "O65", CFGTOK_O65 },
1010 { "BIN", CFGTOK_BIN },
1011 { "BINARY", CFGTOK_BIN },
1014 while (CfgTok == CFGTOK_IDENT) {
1016 /* Map the identifier to a token */
1018 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
1021 /* Skip the name and the following colon */
1025 /* Parse the format options */
1026 switch (FormatTok) {
1033 case CFGTOK_ATARIEXE:
1034 /* No attribibutes available */
1038 Error ("Unexpected format token");
1041 /* Skip the semicolon */
1046 /* Remember we had this section */
1047 SectionsEncountered |= SE_FORMATS;
1052 static void ParseConDes (void)
1053 /* Parse the CONDES feature */
1055 static const IdentTok Attributes [] = {
1056 { "COUNT", CFGTOK_COUNT },
1057 { "IMPORT", CFGTOK_IMPORT },
1058 { "LABEL", CFGTOK_LABEL },
1059 { "ORDER", CFGTOK_ORDER },
1060 { "SEGMENT", CFGTOK_SEGMENT },
1061 { "TYPE", CFGTOK_TYPE },
1064 static const IdentTok Types [] = {
1065 { "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
1066 { "DESTRUCTOR", CFGTOK_DESTRUCTOR },
1067 { "INTERRUPTOR", CFGTOK_INTERRUPTOR },
1070 static const IdentTok Orders [] = {
1071 { "DECREASING", CFGTOK_DECREASING },
1072 { "INCREASING", CFGTOK_INCREASING },
1075 /* Attribute values. */
1076 unsigned Count = INVALID_STRING_ID;
1077 unsigned Label = INVALID_STRING_ID;
1078 unsigned SegName = INVALID_STRING_ID;
1079 ConDesImport Import;
1080 /* Initialize to avoid gcc warnings: */
1082 ConDesOrder Order = cdIncreasing;
1084 /* Bitmask to remember the attributes we got already */
1094 unsigned AttrFlags = atNone;
1096 /* Parse the attributes */
1099 /* Map the identifier to a token */
1101 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1104 /* An optional assignment follows */
1106 CfgOptionalAssign ();
1108 /* Check which attribute was given */
1112 /* Don't allow this twice */
1113 FlagAttr (&AttrFlags, atCount, "COUNT");
1114 /* We expect an identifier */
1116 /* Remember the value for later */
1117 Count = GetStrBufId (&CfgSVal);
1121 /* Don't allow this twice */
1122 FlagAttr (&AttrFlags, atImport, "IMPORT");
1123 /* We expect an identifier */
1125 /* Remember value and position for later */
1126 Import.Name = GetStrBufId (&CfgSVal);
1127 Import.Pos = CfgErrorPos;
1128 Import.AddrSize = ADDR_SIZE_ABS;
1132 /* Don't allow this twice */
1133 FlagAttr (&AttrFlags, atLabel, "LABEL");
1134 /* We expect an identifier */
1136 /* Remember the value for later */
1137 Label = GetStrBufId (&CfgSVal);
1141 /* Don't allow this twice */
1142 FlagAttr (&AttrFlags, atOrder, "ORDER");
1143 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1145 case CFGTOK_DECREASING: Order = cdDecreasing; break;
1146 case CFGTOK_INCREASING: Order = cdIncreasing; break;
1147 default: FAIL ("Unexpected order token");
1151 case CFGTOK_SEGMENT:
1152 /* Don't allow this twice */
1153 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1154 /* We expect an identifier */
1156 /* Remember the value for later */
1157 SegName = GetStrBufId (&CfgSVal);
1161 /* Don't allow this twice */
1162 FlagAttr (&AttrFlags, atType, "TYPE");
1163 /* The type may be given as id or numerical */
1164 if (CfgTok == CFGTOK_INTCON) {
1165 CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1166 Type = (int) CfgIVal;
1168 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1170 case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
1171 case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
1172 case CFGTOK_INTERRUPTOR: Type = CD_TYPE_INT; break;
1173 default: FAIL ("Unexpected type token");
1179 FAIL ("Unexpected attribute token");
1183 /* Skip the attribute value */
1186 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1187 if (CfgTok == CFGTOK_SEMI) {
1189 } else if (CfgTok == CFGTOK_COMMA) {
1194 /* Check if we have all mandatory attributes */
1195 AttrCheck (AttrFlags, atSegName, "SEGMENT");
1196 AttrCheck (AttrFlags, atLabel, "LABEL");
1197 AttrCheck (AttrFlags, atType, "TYPE");
1199 /* Check if the condes has already attributes defined */
1200 if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1201 CfgError (&CfgErrorPos,
1202 "CONDES attributes for type %d are already defined",
1206 /* Define the attributes */
1207 ConDesSetSegName (Type, SegName);
1208 ConDesSetLabel (Type, Label);
1209 if (AttrFlags & atCount) {
1210 ConDesSetCountSym (Type, Count);
1212 if (AttrFlags & atImport) {
1213 ConDesSetImport (Type, &Import);
1215 if (AttrFlags & atOrder) {
1216 ConDesSetOrder (Type, Order);
1222 static void ParseStartAddress (void)
1223 /* Parse the STARTADDRESS feature */
1225 static const IdentTok Attributes [] = {
1226 { "DEFAULT", CFGTOK_DEFAULT },
1230 /* Attribute values. */
1231 unsigned long DefStartAddr = 0;
1233 /* Bitmask to remember the attributes we got already */
1238 unsigned AttrFlags = atNone;
1240 /* Parse the attributes */
1243 /* Map the identifier to a token */
1245 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1248 /* An optional assignment follows */
1250 CfgOptionalAssign ();
1252 /* Check which attribute was given */
1255 case CFGTOK_DEFAULT:
1256 /* Don't allow this twice */
1257 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1258 /* We expect a numeric expression */
1259 DefStartAddr = CfgCheckedConstExpr (0, 0xFFFFFF);
1263 FAIL ("Unexpected attribute token");
1267 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1268 if (CfgTok == CFGTOK_SEMI) {
1270 } else if (CfgTok == CFGTOK_COMMA) {
1275 /* Check if we have all mandatory attributes */
1276 AttrCheck (AttrFlags, atDefault, "DEFAULT");
1278 /* If no start address was given on the command line, use the one given
1281 if (!HaveStartAddr) {
1282 StartAddr = DefStartAddr;
1288 static void ParseFeatures (void)
1289 /* Parse a features section */
1291 static const IdentTok Features [] = {
1292 { "CONDES", CFGTOK_CONDES },
1293 { "STARTADDRESS", CFGTOK_STARTADDRESS },
1296 while (CfgTok == CFGTOK_IDENT) {
1298 /* Map the identifier to a token */
1299 cfgtok_t FeatureTok;
1300 CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1301 FeatureTok = CfgTok;
1303 /* Skip the name and the following colon */
1307 /* Parse the format options */
1308 switch (FeatureTok) {
1314 case CFGTOK_STARTADDRESS:
1315 ParseStartAddress ();
1320 FAIL ("Unexpected feature token");
1323 /* Skip the semicolon */
1327 /* Remember we had this section */
1328 SectionsEncountered |= SE_FEATURES;
1333 static void ParseSymbols (void)
1334 /* Parse a symbols section */
1336 static const IdentTok Attributes[] = {
1337 { "ADDRSIZE", CFGTOK_ADDRSIZE },
1338 { "TYPE", CFGTOK_TYPE },
1339 { "VALUE", CFGTOK_VALUE },
1342 static const IdentTok AddrSizes [] = {
1343 { "ABS", CFGTOK_ABS },
1344 { "ABSOLUTE", CFGTOK_ABS },
1345 { "DIRECT", CFGTOK_ZP },
1346 { "DWORD", CFGTOK_LONG },
1347 { "FAR", CFGTOK_FAR },
1348 { "LONG", CFGTOK_LONG },
1349 { "NEAR", CFGTOK_ABS },
1350 { "ZEROPAGE", CFGTOK_ZP },
1351 { "ZP", CFGTOK_ZP },
1354 static const IdentTok Types [] = {
1355 { "EXPORT", CFGTOK_EXPORT },
1356 { "IMPORT", CFGTOK_IMPORT },
1357 { "WEAK", CFGTOK_WEAK },
1360 while (CfgTok == CFGTOK_IDENT) {
1362 /* Bitmask to remember the attributes we got already */
1365 atAddrSize = 0x0001,
1369 unsigned AttrFlags = atNone;
1371 ExprNode* Value = 0;
1372 CfgSymType Type = CfgSymExport;
1373 unsigned char AddrSize = ADDR_SIZE_ABS;
1378 /* Remember the name */
1379 unsigned Name = GetStrBufId (&CfgSVal);
1382 /* New syntax - skip the colon */
1385 /* Parse the attributes */
1388 /* Map the identifier to a token */
1390 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1393 /* Skip the attribute name */
1396 /* An optional assignment follows */
1397 CfgOptionalAssign ();
1399 /* Check which attribute was given */
1402 case CFGTOK_ADDRSIZE:
1403 /* Don't allow this twice */
1404 FlagAttr (&AttrFlags, atAddrSize, "ADDRSIZE");
1405 /* Map the type to a token */
1406 CfgSpecialToken (AddrSizes, ENTRY_COUNT (AddrSizes), "AddrSize");
1408 case CFGTOK_ABS: AddrSize = ADDR_SIZE_ABS; break;
1409 case CFGTOK_FAR: AddrSize = ADDR_SIZE_FAR; break;
1410 case CFGTOK_LONG: AddrSize = ADDR_SIZE_LONG; break;
1411 case CFGTOK_ZP: AddrSize = ADDR_SIZE_ZP; break;
1413 Internal ("Unexpected token: %d", CfgTok);
1419 /* Don't allow this twice */
1420 FlagAttr (&AttrFlags, atType, "TYPE");
1421 /* Map the type to a token */
1422 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1424 case CFGTOK_EXPORT: Type = CfgSymExport; break;
1425 case CFGTOK_IMPORT: Type = CfgSymImport; break;
1426 case CFGTOK_WEAK: Type = CfgSymWeak; break;
1428 Internal ("Unexpected token: %d", CfgTok);
1434 /* Don't allow this twice */
1435 FlagAttr (&AttrFlags, atValue, "VALUE");
1436 /* Value is an expression */
1441 FAIL ("Unexpected attribute token");
1445 /* Semicolon ends the decl, otherwise accept an optional comma */
1446 if (CfgTok == CFGTOK_SEMI) {
1448 } else if (CfgTok == CFGTOK_COMMA) {
1453 /* We must have a type */
1454 AttrCheck (AttrFlags, atType, "TYPE");
1456 /* Further actions depend on the type */
1460 /* We must have a value */
1461 AttrCheck (AttrFlags, atValue, "VALUE");
1462 /* Create the export */
1463 Exp = CreateExprExport (Name, Value, AddrSize);
1464 CollAppend (&Exp->DefLines, GenLineInfo (&CfgErrorPos));
1468 /* An import must not have a value */
1469 if (AttrFlags & atValue) {
1470 CfgError (&CfgErrorPos, "Imports must not have a value");
1472 /* Generate the import */
1473 Imp = InsertImport (GenImport (Name, AddrSize));
1474 /* Remember the file position */
1475 CollAppend (&Imp->RefLines, GenLineInfo (&CfgErrorPos));
1479 /* We must have a value */
1480 AttrCheck (AttrFlags, atValue, "VALUE");
1481 /* Remember the symbol for later */
1482 Sym = NewCfgSymbol (CfgSymWeak, Name);
1484 Sym->AddrSize = AddrSize;
1488 Internal ("Unexpected symbol type %d", Type);
1491 /* Skip the semicolon */
1495 /* Remember we had this section */
1496 SectionsEncountered |= SE_SYMBOLS;
1501 static void ParseConfig (void)
1502 /* Parse the config file */
1504 static const IdentTok BlockNames [] = {
1505 { "MEMORY", CFGTOK_MEMORY },
1506 { "FILES", CFGTOK_FILES },
1507 { "SEGMENTS", CFGTOK_SEGMENTS },
1508 { "FORMATS", CFGTOK_FORMATS },
1509 { "FEATURES", CFGTOK_FEATURES },
1510 { "SYMBOLS", CFGTOK_SYMBOLS },
1516 /* Read the block ident */
1517 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1521 /* Expected a curly brace */
1522 CfgConsume (CFGTOK_LCURLY, "'{' expected");
1524 /* Read the block */
1535 case CFGTOK_SEGMENTS:
1539 case CFGTOK_FORMATS:
1543 case CFGTOK_FEATURES:
1547 case CFGTOK_SYMBOLS:
1552 FAIL ("Unexpected block token");
1556 /* Skip closing brace */
1557 CfgConsume (CFGTOK_RCURLY, "'}' expected");
1559 } while (CfgTok != CFGTOK_EOF);
1565 /* Read the configuration */
1567 /* Create the descriptors for the binary formats */
1568 BinFmtDesc = NewBinDesc ();
1569 O65FmtDesc = NewO65Desc ();
1570 XexFmtDesc = NewXexDesc ();
1572 /* If we have a config name given, open the file, otherwise we will read
1577 /* Parse the file */
1580 /* Close the input file */
1586 /*****************************************************************************/
1587 /* Config file processing */
1588 /*****************************************************************************/
1592 static void ProcessSegments (void)
1593 /* Process the SEGMENTS section */
1597 /* Walk over the list of segment descriptors */
1599 while (I < CollCount (&SegDescList)) {
1601 /* Get the next segment descriptor */
1602 SegDesc* S = CollAtUnchecked (&SegDescList, I);
1604 /* Search for the actual segment in the input files. The function may
1605 ** return NULL (no such segment), this is checked later.
1607 S->Seg = SegFind (S->Name);
1609 /* If the segment is marked as BSS style, and if the segment exists
1610 ** in any of the object file, check that there's no initialized data
1613 if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
1614 CfgWarning (GetSourcePos (S->LI),
1615 "Segment '%s' with type 'bss' contains initialized data",
1616 GetString (S->Name));
1619 /* If this segment does exist in any of the object files, insert the
1620 ** segment into the load/run memory areas. Otherwise print a warning
1621 ** and discard it, because the segment pointer in the descriptor is
1626 /* Insert the segment into the memory area list */
1627 MemoryInsert (S->Run, S);
1628 if (S->Load != S->Run) {
1629 /* We have separate RUN and LOAD areas */
1630 MemoryInsert (S->Load, S);
1633 /* Use the fill value from the config */
1634 S->Seg->FillVal = S->FillVal;
1636 /* Process the next segment descriptor in the next run */
1641 /* Print a warning if the segment is not optional */
1642 if ((S->Flags & SF_OPTIONAL) == 0) {
1643 CfgWarning (&CfgErrorPos,
1644 "Segment '%s' does not exist",
1645 GetString (S->Name));
1648 /* Discard the descriptor and remove it from the collection */
1650 CollDelete (&SegDescList, I);
1657 static void ProcessSymbols (void)
1658 /* Process the SYMBOLS section */
1662 /* Walk over all symbols */
1664 for (I = 0; I < CollCount (&CfgSymbols); ++I) {
1666 /* Get the next symbol */
1667 CfgSymbol* Sym = CollAtUnchecked (&CfgSymbols, I);
1669 /* Check what it is. */
1670 switch (Sym->Type) {
1672 case CfgSymO65Export:
1673 /* Check if the export symbol is also defined as an import. */
1674 if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1676 GetSourcePos (Sym->LI),
1677 "Exported o65 symbol '%s' cannot also be an o65 import",
1678 GetString (Sym->Name)
1682 /* Check if we have this symbol defined already. The entry
1683 ** routine will check this also, but we get a more verbose
1684 ** error message when checking it here.
1686 if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
1688 GetSourcePos (Sym->LI),
1689 "Duplicate exported o65 symbol: '%s'",
1690 GetString (Sym->Name)
1694 /* Insert the symbol into the table */
1695 O65SetExport (O65FmtDesc, Sym->Name);
1698 case CfgSymO65Import:
1699 /* Check if the import symbol is also defined as an export. */
1700 if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
1702 GetSourcePos (Sym->LI),
1703 "Imported o65 symbol '%s' cannot also be an o65 export",
1704 GetString (Sym->Name)
1708 /* Check if we have this symbol defined already. The entry
1709 ** routine will check this also, but we get a more verbose
1710 ** error message when checking it here.
1712 if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1714 GetSourcePos (Sym->LI),
1715 "Duplicate imported o65 symbol: '%s'",
1716 GetString (Sym->Name)
1720 /* Insert the symbol into the table */
1721 O65SetImport (O65FmtDesc, Sym->Name);
1725 /* If the symbol is not defined until now, define it */
1726 if ((E = FindExport (Sym->Name)) == 0 || IsUnresolvedExport (E)) {
1727 /* The symbol is undefined, generate an export */
1728 E = CreateExprExport (Sym->Name, Sym->Value, Sym->AddrSize);
1729 CollAppend (&E->DefLines, Sym->LI);
1734 Internal ("Unexpected symbol type %d", Sym->Type);
1743 static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
1744 /* Create the defines for a RUN segment */
1747 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1749 /* Define the run address of the segment */
1750 SB_Printf (&Buf, "__%s_RUN__", GetString (S->Name));
1751 E = CreateMemoryExport (GetStrBufId (&Buf), S->Run, SegAddr - S->Run->Start);
1752 CollAppend (&E->DefLines, S->LI);
1754 /* Define the size of the segment */
1755 SB_Printf (&Buf, "__%s_SIZE__", GetString (S->Name));
1756 E = CreateConstExport (GetStrBufId (&Buf), S->Seg->Size);
1757 CollAppend (&E->DefLines, S->LI);
1759 S->Flags |= SF_RUN_DEF;
1765 static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
1766 /* Create the defines for a LOAD segment */
1769 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1771 /* Define the load address of the segment */
1772 SB_Printf (&Buf, "__%s_LOAD__", GetString (S->Name));
1773 E = CreateMemoryExport (GetStrBufId (&Buf), S->Load, SegAddr - S->Load->Start);
1774 CollAppend (&E->DefLines, S->LI);
1776 S->Flags |= SF_LOAD_DEF;
1782 unsigned CfgProcess (void)
1783 /* Process the config file, after reading in object files and libraries. This
1784 ** includes postprocessing of the config file data; but also assigning segments,
1785 ** and defining segment/memory-area related symbols. The function will return
1786 ** the number of memory area overflows (so, zero means everything went OK).
1787 ** In case of overflows, a short mapfile can be generated later, to ease the
1788 ** user's task of re-arranging segments.
1791 unsigned Overflows = 0;
1794 /* Postprocess symbols. We must do that first, since weak symbols are
1795 ** defined here, which may be needed later.
1799 /* Postprocess segments */
1802 /* Walk through each of the memory sections. Add up the sizes; and, check
1803 ** for an overflow of the section. Assign the start addresses of the
1804 ** segments while doing that.
1806 for (I = 0; I < CollCount (&MemoryAreas); ++I) {
1809 unsigned Overwrites = 0;
1811 /* Get the next memory area */
1812 MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
1814 /* Remember the offset in the output file */
1815 M->FileOffs = M->F->Size;
1817 /* Remember if this is a relocatable memory area */
1818 M->Relocatable = RelocatableBinFmt (M->F->Format);
1820 /* Resolve the start address expression, remember the start address,
1821 ** and mark the memory area as placed.
1823 if (!IsConstExpr (M->StartExpr)) {
1824 CfgError (GetSourcePos (M->LI),
1825 "Start address of memory area '%s' is not constant",
1826 GetString (M->Name));
1828 Addr = M->Start = GetExprVal (M->StartExpr);
1829 M->Flags |= MF_PLACED;
1831 /* If requested, define the symbol for the start of the memory area.
1832 ** Doing it here means that the expression for the size of the area
1833 ** may reference this symbol.
1835 if (M->Flags & MF_DEFINE) {
1837 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1839 /* Define the start of the memory area */
1840 SB_Printf (&Buf, "__%s_START__", GetString (M->Name));
1841 E = CreateMemoryExport (GetStrBufId (&Buf), M, 0);
1842 CollAppend (&E->DefLines, M->LI);
1847 /* Resolve the size expression */
1848 if (!IsConstExpr (M->SizeExpr)) {
1849 CfgError (GetSourcePos (M->LI),
1850 "Size of memory area '%s' is not constant",
1851 GetString (M->Name));
1853 M->Size = GetExprVal (M->SizeExpr);
1855 /* Walk through the segments in this memory area */
1856 for (J = 0; J < CollCount (&M->SegList); ++J) {
1857 /* Get the segment */
1858 SegDesc* S = CollAtUnchecked (&M->SegList, J);
1860 /* Remember the start address before handling this segment */
1861 unsigned long StartAddr = Addr;
1863 /* Take note of "overwrite" segments and make sure there are no
1864 ** other segment types following them in current memory region.
1866 if (S->Flags & SF_OVERWRITE) {
1867 if (S->Flags & (SF_OFFSET | SF_START)) {
1870 CfgError (GetSourcePos (M->LI),
1871 "Segment '%s' of type 'overwrite' requires either"
1872 " 'Start' or 'Offset' attribute to be specified",
1873 GetString (S->Name));
1876 if (Overwrites > 0) {
1877 CfgError (GetSourcePos (M->LI),
1878 "Segment '%s' is preceded by at least one segment"
1879 " of type 'overwrite'",
1880 GetString (S->Name));
1884 /* Some actions depend on whether this is the load or run memory
1888 /* This is the run (and maybe load) memory area. Handle
1889 ** alignment and explict start address and offset.
1892 /* Check if the alignment for the segment from the linker
1893 ** config is a multiple for that of the segment.
1894 ** If START or OFFSET is provided instead of ALIGN, check
1895 ** if its address fits alignment requirements.
1897 unsigned long AlignedBy = (S->Flags & SF_START) ? S->Addr
1898 : (S->Flags & SF_OFFSET) ? (S->Addr + M->Start)
1900 if ((AlignedBy % S->Seg->Alignment) != 0) {
1901 /* Segment requires another alignment than configured
1904 CfgWarning (GetSourcePos (S->LI),
1905 "Segment '%s' isn't aligned properly; the"
1906 " resulting executable might not be functional.",
1907 GetString (S->Name));
1910 if (S->Flags & SF_ALIGN) {
1911 /* Align the address */
1912 unsigned long NewAddr = AlignAddr (Addr, S->RunAlignment);
1914 /* If the first segment placed in the memory area needs
1915 ** fill bytes for the alignment, emit a warning, since
1916 ** that is somewhat suspicious.
1918 if (M->FillLevel == 0 && NewAddr > Addr) {
1919 CfgWarning (GetSourcePos (S->LI),
1920 "The first segment in memory area '%s' "
1921 "needs fill bytes for alignment.",
1922 GetString (M->Name));
1925 /* Use the aligned address */
1928 } else if ((S->Flags & (SF_OFFSET | SF_START)) != 0 &&
1929 (M->Flags & MF_OVERFLOW) == 0) {
1930 /* Give the segment a fixed starting address */
1931 unsigned long NewAddr = S->Addr;
1933 if (S->Flags & SF_OFFSET) {
1934 /* An offset was given, no address, make an address */
1935 NewAddr += M->Start;
1938 if (S->Flags & SF_OVERWRITE) {
1939 if (NewAddr < M->Start) {
1940 CfgError (GetSourcePos (S->LI),
1941 "Segment '%s' begins before memory area '%s'",
1942 GetString (S->Name), GetString (M->Name));
1947 if (NewAddr < Addr) {
1948 /* Offset already too large */
1950 if (S->Flags & SF_OFFSET) {
1951 CfgWarning (GetSourcePos (S->LI),
1952 "Segment '%s' offset is too small in '%s' by %lu byte%c",
1953 GetString (S->Name), GetString (M->Name),
1954 Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
1956 CfgWarning (GetSourcePos (S->LI),
1957 "Segment '%s' start address is too low in '%s' by %lu byte%c",
1958 GetString (S->Name), GetString (M->Name),
1959 Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
1967 /* Set the start address of this segment, set the readonly flag
1968 ** in the segment, and remember if the segment is in a
1969 ** relocatable file or not.
1972 S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
1974 /* Remember the run memory for this segment, which is also a
1975 ** flag that the segment has been placed.
1977 S->Seg->MemArea = M;
1979 } else if (S->Load == M) {
1980 /* This is the load memory area; *and*, run and load are
1981 ** different (because of the "else" above). Handle alignment.
1983 if (S->Flags & SF_ALIGN_LOAD) {
1984 /* Align the address */
1985 Addr = AlignAddr (Addr, S->LoadAlignment);
1989 /* If this is the load memory area, and the segment doesn't have a
1990 ** fill value defined, use the one from the memory area.
1992 if (S->Load == M && (S->Flags & SF_FILLVAL) == 0) {
1993 S->Seg->FillVal = M->FillVal;
1996 /* Increment the fill level of the memory area; and, check for an
1999 M->FillLevel = Addr + S->Seg->Size - M->Start;
2000 if (M->FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) {
2002 M->Flags |= MF_OVERFLOW;
2003 CfgWarning (GetSourcePos (M->LI),
2004 "Segment '%s' overflows memory area '%s' by %lu byte%c",
2005 GetString (S->Name), GetString (M->Name),
2006 M->FillLevel - M->Size, (M->FillLevel - M->Size == 1) ? ' ' : 's');
2009 /* If requested, define symbols for the start and size of the
2012 if (S->Flags & SF_DEFINE) {
2013 if (S->Run == M && (S->Flags & SF_RUN_DEF) == 0) {
2014 CreateRunDefines (S, Addr);
2016 if (S->Load == M && (S->Flags & SF_LOAD_DEF) == 0) {
2017 CreateLoadDefines (S, Addr);
2021 /* Calculate the new address */
2022 Addr += S->Seg->Size;
2024 /* If this segment will go out to the file, or its place
2025 ** in the file will be filled, then increase the file size.
2028 ((S->Flags & SF_BSS) == 0 || (M->Flags & MF_FILL) != 0)) {
2029 M->F->Size += Addr - StartAddr;
2033 /* If requested, define symbols for start, size, and offset of the
2036 if (M->Flags & MF_DEFINE) {
2038 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
2040 /* Define the size of the memory area */
2041 SB_Printf (&Buf, "__%s_SIZE__", GetString (M->Name));
2042 E = CreateConstExport (GetStrBufId (&Buf), M->Size);
2043 CollAppend (&E->DefLines, M->LI);
2045 /* Define the fill level of the memory area */
2046 SB_Printf (&Buf, "__%s_LAST__", GetString (M->Name));
2047 E = CreateMemoryExport (GetStrBufId (&Buf), M, M->FillLevel);
2048 CollAppend (&E->DefLines, M->LI);
2050 /* Define the file offset of the memory area. This isn't of much
2051 ** use for relocatable output files.
2053 if (!M->Relocatable) {
2054 SB_Printf (&Buf, "__%s_FILEOFFS__", GetString (M->Name));
2055 E = CreateConstExport (GetStrBufId (&Buf), M->FileOffs);
2056 CollAppend (&E->DefLines, M->LI);
2059 /* Throw away the string buffer */
2063 /* If we didn't have an overflow, and are requested to fill the memory
2064 ** area, account for that in the file size.
2066 if ((M->Flags & MF_OVERFLOW) == 0 && (M->Flags & MF_FILL) != 0) {
2067 M->F->Size += (M->Size - M->FillLevel);
2071 /* Return the number of memory area overflows */
2077 void CfgWriteTarget (void)
2078 /* Write the target file(s) */
2082 /* Walk through the files list */
2083 for (I = 0; I < CollCount (&FileList); ++I) {
2085 /* Get this entry */
2086 File* F = CollAtUnchecked (&FileList, I);
2088 /* We don't need to look at files with no memory areas */
2089 if (CollCount (&F->MemoryAreas) > 0) {
2091 /* Is there an output file? */
2092 if (SB_GetLen (GetStrBuf (F->Name)) > 0) {
2094 /* Assign a proper binary format */
2095 if (F->Format == BINFMT_DEFAULT) {
2096 F->Format = DefaultBinFmt;
2099 /* Call the apropriate routine for the binary format */
2100 switch (F->Format) {
2103 BinWriteTarget (BinFmtDesc, F);
2107 O65WriteTarget (O65FmtDesc, F);
2110 case BINFMT_ATARIEXE:
2111 XexWriteTarget (XexFmtDesc, F);
2115 Internal ("Invalid binary format: %u", F->Format);
2121 /* No output file. Walk through the list and mark all segments
2122 ** loading into these memory areas in this file as dumped.
2125 for (J = 0; J < CollCount (&F->MemoryAreas); ++J) {
2129 /* Get this entry */
2130 MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, J);
2133 Print (stdout, 2, "Skipping '%s'...\n", GetString (M->Name));
2135 /* Walk throught the segments */
2136 for (K = 0; K < CollCount (&M->SegList); ++K) {
2137 SegDesc* S = CollAtUnchecked (&M->SegList, K);
2139 /* Load area - mark the segment as dumped */