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"
74 /*****************************************************************************/
76 /*****************************************************************************/
80 /* Remember which sections we had encountered */
89 } SectionsEncountered = SE_NONE;
94 static Collection FileList = STATIC_COLLECTION_INITIALIZER;
97 static Collection MemoryAreas = STATIC_COLLECTION_INITIALIZER;
99 /* Memory attributes */
100 #define MA_START 0x0001
101 #define MA_SIZE 0x0002
102 #define MA_TYPE 0x0004
103 #define MA_FILE 0x0008
104 #define MA_DEFINE 0x0010
105 #define MA_FILL 0x0020
106 #define MA_FILLVAL 0x0040
107 #define MA_BANK 0x0080
110 static Collection SegDescList = STATIC_COLLECTION_INITIALIZER;
112 /* Segment attributes */
113 #define SA_TYPE 0x0001
114 #define SA_LOAD 0x0002
115 #define SA_RUN 0x0004
116 #define SA_ALIGN 0x0008
117 #define SA_ALIGN_LOAD 0x0010
118 #define SA_DEFINE 0x0020
119 #define SA_OFFSET 0x0040
120 #define SA_START 0x0080
121 #define SA_OPTIONAL 0x0100
122 #define SA_FILLVAL 0x0200
124 /* Symbol types used in the CfgSymbol structure */
126 CfgSymExport, /* Not really used in struct CfgSymbol */
127 CfgSymImport, /* Dito */
128 CfgSymWeak, /* Like export but weak */
129 CfgSymO65Export, /* An o65 export */
130 CfgSymO65Import, /* An o65 import */
133 /* Symbol structure. It is used for o65 imports and exports, but also for
134 ** symbols from the SYMBOLS sections (symbols defined in the config file or
137 typedef struct CfgSymbol CfgSymbol;
139 CfgSymType Type; /* Type of symbol */
140 LineInfo* LI; /* Config file position */
141 unsigned Name; /* Symbol name */
142 ExprNode* Value; /* Symbol value if any */
143 unsigned AddrSize; /* Address size of symbol */
146 /* Collections with symbols */
147 static Collection CfgSymbols = STATIC_COLLECTION_INITIALIZER;
149 /* Descriptor holding information about the binary formats */
150 static BinDesc* BinFmtDesc = 0;
151 static O65Desc* O65FmtDesc = 0;
155 /*****************************************************************************/
157 /*****************************************************************************/
161 static File* NewFile (unsigned Name);
162 /* Create a new file descriptor and insert it into the list */
166 /*****************************************************************************/
167 /* List management */
168 /*****************************************************************************/
172 static File* FindFile (unsigned Name)
173 /* Find a file with a given name. */
176 for (I = 0; I < CollCount (&FileList); ++I) {
177 File* F = CollAtUnchecked (&FileList, I);
178 if (F->Name == Name) {
187 static File* GetFile (unsigned Name)
188 /* Get a file entry with the given name. Create a new one if needed. */
190 File* F = FindFile (Name);
192 /* Create a new one */
200 static void FileInsert (File* F, MemoryArea* M)
201 /* Insert the memory area into the files list */
204 CollAppend (&F->MemoryAreas, M);
209 static MemoryArea* CfgFindMemory (unsigned Name)
210 /* Find the memory are with the given name. Return NULL if not found */
213 for (I = 0; I < CollCount (&MemoryAreas); ++I) {
214 MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
215 if (M->Name == Name) {
224 static MemoryArea* CfgGetMemory (unsigned Name)
225 /* Find the memory are with the given name. Print an error on an invalid name */
227 MemoryArea* M = CfgFindMemory (Name);
229 CfgError (&CfgErrorPos, "Invalid memory area `%s'", GetString (Name));
236 static SegDesc* CfgFindSegDesc (unsigned Name)
237 /* Find the segment descriptor with the given name, return NULL if not found. */
240 for (I = 0; I < CollCount (&SegDescList); ++I) {
241 SegDesc* S = CollAtUnchecked (&SegDescList, I);
242 if (S->Name == Name) {
254 static void MemoryInsert (MemoryArea* M, SegDesc* S)
255 /* Insert the segment descriptor into the memory area list */
257 /* Insert the segment into the segment list of the memory area */
258 CollAppend (&M->SegList, S);
263 /*****************************************************************************/
264 /* Constructors/Destructors */
265 /*****************************************************************************/
269 static CfgSymbol* NewCfgSymbol (CfgSymType Type, unsigned Name)
270 /* Create a new CfgSymbol structure with the given type and name. The
271 ** current config file position is recorded in the returned struct. The
272 ** created struct is inserted into the CfgSymbols collection and returned.
275 /* Allocate memory */
276 CfgSymbol* Sym = xmalloc (sizeof (CfgSymbol));
278 /* Initialize the fields */
280 Sym->LI = GenLineInfo (&CfgErrorPos);
283 Sym->AddrSize = ADDR_SIZE_INVALID;
285 /* Insert the symbol into the collection */
286 CollAppend (&CfgSymbols, Sym);
288 /* Return the initialized struct */
294 static File* NewFile (unsigned Name)
295 /* Create a new file descriptor and insert it into the list */
297 /* Allocate memory */
298 File* F = xmalloc (sizeof (File));
300 /* Initialize the fields */
303 F->Format = BINFMT_DEFAULT;
305 InitCollection (&F->MemoryAreas);
307 /* Insert the struct into the list */
308 CollAppend (&FileList, F);
310 /* ...and return it */
316 static MemoryArea* CreateMemoryArea (const FilePos* Pos, unsigned Name)
317 /* Create a new memory area and insert it into the list */
319 /* Check for duplicate names */
320 MemoryArea* M = CfgFindMemory (Name);
322 CfgError (&CfgErrorPos,
323 "Memory area `%s' defined twice",
327 /* Create a new memory area */
328 M = NewMemoryArea (Pos, Name);
330 /* Insert the struct into the list ... */
331 CollAppend (&MemoryAreas, M);
333 /* ...and return it */
339 static SegDesc* NewSegDesc (unsigned Name)
340 /* Create a segment descriptor and insert it into the list */
343 /* Check for duplicate names */
344 SegDesc* S = CfgFindSegDesc (Name);
346 CfgError (&CfgErrorPos, "Segment `%s' defined twice", GetString (Name));
349 /* Allocate memory */
350 S = xmalloc (sizeof (SegDesc));
352 /* Initialize the fields */
354 S->LI = GenLineInfo (&CfgErrorPos);
360 S->LoadAlignment = 1;
362 /* Insert the struct into the list ... */
363 CollAppend (&SegDescList, S);
365 /* ...and return it */
371 static void FreeSegDesc (SegDesc* S)
372 /* Free a segment descriptor */
374 FreeLineInfo (S->LI);
380 /*****************************************************************************/
381 /* Config file parsing */
382 /*****************************************************************************/
386 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
387 /* Check if the item is already defined. Print an error if so. If not, set
388 ** the marker that we have a definition now.
392 CfgError (&CfgErrorPos, "%s is already defined", Name);
399 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
400 /* Check that a mandatory attribute was given */
402 if ((Attr & Mask) == 0) {
403 CfgError (&CfgErrorPos, "%s attribute is missing", Name);
409 static void ParseMemory (void)
410 /* Parse a MEMORY section */
412 static const IdentTok Attributes [] = {
413 { "BANK", CFGTOK_BANK },
414 { "DEFINE", CFGTOK_DEFINE },
415 { "FILE", CFGTOK_FILE },
416 { "FILL", CFGTOK_FILL },
417 { "FILLVAL", CFGTOK_FILLVAL },
418 { "SIZE", CFGTOK_SIZE },
419 { "START", CFGTOK_START },
420 { "TYPE", CFGTOK_TYPE },
422 static const IdentTok Types [] = {
427 while (CfgTok == CFGTOK_IDENT) {
429 /* Create a new entry on the heap */
430 MemoryArea* M = CreateMemoryArea (&CfgErrorPos, GetStrBufId (&CfgSVal));
432 /* Skip the name and the following colon */
436 /* Read the attributes */
437 while (CfgTok == CFGTOK_IDENT) {
439 /* Map the identifier to a token */
441 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
444 /* An optional assignment follows */
446 CfgOptionalAssign ();
448 /* Check which attribute was given */
452 FlagAttr (&M->Attr, MA_BANK, "BANK");
453 M->BankExpr = CfgExpr ();
457 FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
458 /* Map the token to a boolean */
460 if (CfgTok == CFGTOK_TRUE) {
461 M->Flags |= MF_DEFINE;
467 FlagAttr (&M->Attr, MA_FILE, "FILE");
469 /* Get the file entry and insert the memory area */
470 FileInsert (GetFile (GetStrBufId (&CfgSVal)), M);
475 FlagAttr (&M->Attr, MA_FILL, "FILL");
476 /* Map the token to a boolean */
478 if (CfgTok == CFGTOK_TRUE) {
485 FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
486 M->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
490 FlagAttr (&M->Attr, MA_SIZE, "SIZE");
491 M->SizeExpr = CfgExpr ();
495 FlagAttr (&M->Attr, MA_START, "START");
496 M->StartExpr = CfgExpr ();
500 FlagAttr (&M->Attr, MA_TYPE, "TYPE");
501 CfgSpecialToken (Types, ENTRY_COUNT (Types), "TYPE");
502 if (CfgTok == CFGTOK_RO) {
509 FAIL ("Unexpected attribute token");
513 /* Skip an optional comma */
517 /* Skip the semicolon */
520 /* Check for mandatory parameters */
521 AttrCheck (M->Attr, MA_START, "START");
522 AttrCheck (M->Attr, MA_SIZE, "SIZE");
524 /* If we don't have a file name for output given, use the default
527 if ((M->Attr & MA_FILE) == 0) {
528 FileInsert (GetFile (GetStringId (OutputName)), M);
533 /* Remember we had this section */
534 SectionsEncountered |= SE_MEMORY;
539 static void ParseFiles (void)
540 /* Parse a FILES section */
542 static const IdentTok Attributes [] = {
543 { "FORMAT", CFGTOK_FORMAT },
545 static const IdentTok Formats [] = {
546 { "O65", CFGTOK_O65 },
547 { "BIN", CFGTOK_BIN },
548 { "BINARY", CFGTOK_BIN },
552 /* The MEMORY section must preceed the FILES section */
553 if ((SectionsEncountered & SE_MEMORY) == 0) {
554 CfgError (&CfgErrorPos, "MEMORY must precede FILES");
557 /* Parse all files */
558 while (CfgTok != CFGTOK_RCURLY) {
562 /* We expect a string value here */
565 /* Search for the file, it must exist */
566 F = FindFile (GetStrBufId (&CfgSVal));
568 CfgError (&CfgErrorPos,
569 "File `%s' not found in MEMORY section",
570 SB_GetConstBuf (&CfgSVal));
573 /* Skip the token and the following colon */
577 /* Read the attributes */
578 while (CfgTok == CFGTOK_IDENT) {
580 /* Map the identifier to a token */
582 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
585 /* An optional assignment follows */
587 CfgOptionalAssign ();
589 /* Check which attribute was given */
593 if (F->Format != BINFMT_DEFAULT) {
594 /* We've set the format already! */
595 CfgError (&CfgErrorPos,
596 "Cannot set a file format twice");
598 /* Read the format token */
599 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
603 F->Format = BINFMT_BINARY;
607 F->Format = BINFMT_O65;
611 Error ("Unexpected format token");
616 FAIL ("Unexpected attribute token");
620 /* Skip the attribute value and an optional comma */
625 /* Skip the semicolon */
630 /* Remember we had this section */
631 SectionsEncountered |= SE_FILES;
636 static void ParseSegments (void)
637 /* Parse a SEGMENTS section */
639 static const IdentTok Attributes [] = {
640 { "ALIGN", CFGTOK_ALIGN },
641 { "ALIGN_LOAD", CFGTOK_ALIGN_LOAD },
642 { "DEFINE", CFGTOK_DEFINE },
643 { "FILLVAL", CFGTOK_FILLVAL },
644 { "LOAD", CFGTOK_LOAD },
645 { "OFFSET", CFGTOK_OFFSET },
646 { "OPTIONAL", CFGTOK_OPTIONAL },
647 { "RUN", CFGTOK_RUN },
648 { "START", CFGTOK_START },
649 { "TYPE", CFGTOK_TYPE },
651 static const IdentTok Types [] = {
654 { "BSS", CFGTOK_BSS },
656 { "OVERWRITE", CFGTOK_OVERWRITE },
661 /* The MEMORY section must preceed the SEGMENTS section */
662 if ((SectionsEncountered & SE_MEMORY) == 0) {
663 CfgError (&CfgErrorPos, "MEMORY must precede SEGMENTS");
666 while (CfgTok == CFGTOK_IDENT) {
670 /* Create a new entry on the heap */
671 S = NewSegDesc (GetStrBufId (&CfgSVal));
673 /* Skip the name and the following colon */
677 /* Read the attributes */
678 while (CfgTok == CFGTOK_IDENT) {
680 /* Map the identifier to a token */
682 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
685 /* An optional assignment follows */
687 CfgOptionalAssign ();
689 /* Check which attribute was given */
693 FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
694 S->RunAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
695 S->Flags |= SF_ALIGN;
698 case CFGTOK_ALIGN_LOAD:
699 FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
700 S->LoadAlignment = (unsigned) CfgCheckedConstExpr (1, MAX_ALIGNMENT);
701 S->Flags |= SF_ALIGN_LOAD;
705 FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
706 /* Map the token to a boolean */
708 if (CfgTok == CFGTOK_TRUE) {
709 S->Flags |= SF_DEFINE;
715 FlagAttr (&S->Attr, SA_FILLVAL, "FILLVAL");
716 S->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
717 S->Flags |= SF_FILLVAL;
721 FlagAttr (&S->Attr, SA_LOAD, "LOAD");
722 S->Load = CfgGetMemory (GetStrBufId (&CfgSVal));
727 FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
728 S->Addr = CfgCheckedConstExpr (1, 0x1000000);
729 S->Flags |= SF_OFFSET;
732 case CFGTOK_OPTIONAL:
733 FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL");
735 if (CfgTok == CFGTOK_TRUE) {
736 S->Flags |= SF_OPTIONAL;
742 FlagAttr (&S->Attr, SA_RUN, "RUN");
743 S->Run = CfgGetMemory (GetStrBufId (&CfgSVal));
748 FlagAttr (&S->Attr, SA_START, "START");
749 S->Addr = CfgCheckedConstExpr (1, 0x1000000);
750 S->Flags |= SF_START;
754 FlagAttr (&S->Attr, SA_TYPE, "TYPE");
755 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
757 case CFGTOK_RO: S->Flags |= SF_RO; break;
758 case CFGTOK_RW: /* Default */ break;
759 case CFGTOK_BSS: S->Flags |= SF_BSS; break;
760 case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break;
761 case CFGTOK_OVERWRITE: S->Flags |= (SF_OVERWRITE | SF_RO); break;
762 default: Internal ("Unexpected token: %d", CfgTok);
768 FAIL ("Unexpected attribute token");
772 /* Skip an optional comma */
776 /* Check for mandatory parameters */
777 AttrCheck (S->Attr, SA_LOAD, "LOAD");
779 /* Set defaults for stuff not given */
780 if ((S->Attr & SA_RUN) == 0) {
785 /* An attribute of ALIGN_LOAD doesn't make sense if there are no
786 ** separate run and load memory areas.
788 if ((S->Flags & SF_ALIGN_LOAD) != 0 && (S->Load == S->Run)) {
789 CfgWarning (&CfgErrorPos,
790 "ALIGN_LOAD attribute specified, but no separate "
791 "LOAD and RUN memory areas assigned");
792 /* Remove the flag */
793 S->Flags &= ~SF_ALIGN_LOAD;
796 /* If the segment is marked as BSS style, it may not have separate
797 ** load and run memory areas, because it's is never written to disk.
799 if ((S->Flags & SF_BSS) != 0 && (S->Load != S->Run)) {
800 CfgWarning (&CfgErrorPos,
801 "Segment with type `bss' has both LOAD and RUN "
802 "memory areas assigned");
805 /* Don't allow read/write data to be put into a readonly area */
806 if ((S->Flags & SF_RO) == 0) {
807 if (S->Run->Flags & MF_RO) {
808 CfgError (&CfgErrorPos,
809 "Cannot put r/w segment `%s' in r/o memory area `%s'",
810 GetString (S->Name), GetString (S->Run->Name));
814 /* Only one of ALIGN, START and OFFSET may be used */
815 Count = ((S->Flags & SF_ALIGN) != 0) +
816 ((S->Flags & SF_OFFSET) != 0) +
817 ((S->Flags & SF_START) != 0);
819 CfgError (&CfgErrorPos,
820 "Only one of ALIGN, START, OFFSET may be used");
823 /* Skip the semicolon */
827 /* Remember we had this section */
828 SectionsEncountered |= SE_SEGMENTS;
833 static void ParseO65 (void)
834 /* Parse the o65 format section */
836 static const IdentTok Attributes [] = {
837 { "EXPORT", CFGTOK_EXPORT },
838 { "IMPORT", CFGTOK_IMPORT },
839 { "TYPE", CFGTOK_TYPE },
842 { "VERSION", CFGTOK_VERSION },
844 static const IdentTok Types [] = {
845 { "SMALL", CFGTOK_SMALL },
846 { "LARGE", CFGTOK_LARGE },
848 static const IdentTok OperatingSystems [] = {
849 { "LUNIX", CFGTOK_LUNIX },
850 { "OSA65", CFGTOK_OSA65 },
851 { "CC65", CFGTOK_CC65 },
852 { "OPENCBM", CFGTOK_OPENCBM },
855 /* Bitmask to remember the attributes we got already */
859 atOSVersion = 0x0002,
866 unsigned AttrFlags = atNone;
868 /* Remember the attributes read */
869 unsigned OS = 0; /* Initialize to keep gcc happy */
870 unsigned Version = 0;
872 /* Read the attributes */
873 while (CfgTok == CFGTOK_IDENT) {
875 /* Map the identifier to a token */
877 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
880 /* An optional assignment follows */
882 CfgOptionalAssign ();
884 /* Check which attribute was given */
888 /* Remember we had this token (maybe more than once) */
889 AttrFlags |= atExport;
890 /* We expect an identifier */
892 /* Remember it as an export for later */
893 NewCfgSymbol (CfgSymO65Export, GetStrBufId (&CfgSVal));
894 /* Eat the identifier token */
899 /* Remember we had this token (maybe more than once) */
900 AttrFlags |= atImport;
901 /* We expect an identifier */
903 /* Remember it as an import for later */
904 NewCfgSymbol (CfgSymO65Import, GetStrBufId (&CfgSVal));
905 /* Eat the identifier token */
910 /* Cannot have this attribute twice */
911 FlagAttr (&AttrFlags, atType, "TYPE");
912 /* Get the type of the executable */
913 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
917 O65SetSmallModel (O65FmtDesc);
921 O65SetLargeModel (O65FmtDesc);
925 CfgError (&CfgErrorPos, "Unexpected type token");
927 /* Eat the attribute token */
932 /* Cannot use this attribute twice */
933 FlagAttr (&AttrFlags, atOS, "OS");
934 /* Get the operating system. It may be specified as name or
935 ** as a number in the range 1..255.
937 if (CfgTok == CFGTOK_INTCON) {
938 CfgRangeCheck (O65OS_MIN, O65OS_MAX);
939 OS = (unsigned) CfgIVal;
941 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
943 case CFGTOK_LUNIX: OS = O65OS_LUNIX; break;
944 case CFGTOK_OSA65: OS = O65OS_OSA65; break;
945 case CFGTOK_CC65: OS = O65OS_CC65; break;
946 case CFGTOK_OPENCBM: OS = O65OS_OPENCBM; break;
947 default: CfgError (&CfgErrorPos, "Unexpected OS token");
954 /* Cannot have this attribute twice */
955 FlagAttr (&AttrFlags, atID, "ID");
956 /* We're expecting a number in the 0..$FFFF range*/
957 ModuleId = (unsigned) CfgCheckedConstExpr (0, 0xFFFF);
961 /* Cannot have this attribute twice */
962 FlagAttr (&AttrFlags, atVersion, "VERSION");
963 /* We're expecting a number in byte range */
964 Version = (unsigned) CfgCheckedConstExpr (0, 0xFF);
968 FAIL ("Unexpected attribute token");
972 /* Skip an optional comma */
976 /* Check if we have all mandatory attributes */
977 AttrCheck (AttrFlags, atOS, "OS");
979 /* Check for attributes that may not be combined */
980 if (OS == O65OS_CC65) {
981 if ((AttrFlags & (atImport | atExport)) != 0 && ModuleId < 0x8000) {
982 CfgError (&CfgErrorPos,
983 "OS type CC65 may not have imports or exports for ids < $8000");
986 if (AttrFlags & atID) {
987 CfgError (&CfgErrorPos,
988 "Operating system does not support the ID attribute");
992 /* Set the O65 operating system to use */
993 O65SetOS (O65FmtDesc, OS, Version, ModuleId);
998 static void ParseFormats (void)
999 /* Parse a target format section */
1001 static const IdentTok Formats [] = {
1002 { "O65", CFGTOK_O65 },
1003 { "BIN", CFGTOK_BIN },
1004 { "BINARY", CFGTOK_BIN },
1007 while (CfgTok == CFGTOK_IDENT) {
1009 /* Map the identifier to a token */
1011 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
1014 /* Skip the name and the following colon */
1018 /* Parse the format options */
1019 switch (FormatTok) {
1026 /* No attribibutes available */
1030 Error ("Unexpected format token");
1033 /* Skip the semicolon */
1038 /* Remember we had this section */
1039 SectionsEncountered |= SE_FORMATS;
1044 static void ParseConDes (void)
1045 /* Parse the CONDES feature */
1047 static const IdentTok Attributes [] = {
1048 { "COUNT", CFGTOK_COUNT },
1049 { "IMPORT", CFGTOK_IMPORT },
1050 { "LABEL", CFGTOK_LABEL },
1051 { "ORDER", CFGTOK_ORDER },
1052 { "SEGMENT", CFGTOK_SEGMENT },
1053 { "TYPE", CFGTOK_TYPE },
1056 static const IdentTok Types [] = {
1057 { "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
1058 { "DESTRUCTOR", CFGTOK_DESTRUCTOR },
1059 { "INTERRUPTOR", CFGTOK_INTERRUPTOR },
1062 static const IdentTok Orders [] = {
1063 { "DECREASING", CFGTOK_DECREASING },
1064 { "INCREASING", CFGTOK_INCREASING },
1067 /* Attribute values. */
1068 unsigned Count = INVALID_STRING_ID;
1069 unsigned Label = INVALID_STRING_ID;
1070 unsigned SegName = INVALID_STRING_ID;
1071 ConDesImport Import;
1072 /* Initialize to avoid gcc warnings: */
1074 ConDesOrder Order = cdIncreasing;
1076 /* Bitmask to remember the attributes we got already */
1086 unsigned AttrFlags = atNone;
1088 /* Parse the attributes */
1091 /* Map the identifier to a token */
1093 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1096 /* An optional assignment follows */
1098 CfgOptionalAssign ();
1100 /* Check which attribute was given */
1104 /* Don't allow this twice */
1105 FlagAttr (&AttrFlags, atCount, "COUNT");
1106 /* We expect an identifier */
1108 /* Remember the value for later */
1109 Count = GetStrBufId (&CfgSVal);
1113 /* Don't allow this twice */
1114 FlagAttr (&AttrFlags, atImport, "IMPORT");
1115 /* We expect an identifier */
1117 /* Remember value and position for later */
1118 Import.Name = GetStrBufId (&CfgSVal);
1119 Import.Pos = CfgErrorPos;
1120 Import.AddrSize = ADDR_SIZE_ABS;
1124 /* Don't allow this twice */
1125 FlagAttr (&AttrFlags, atLabel, "LABEL");
1126 /* We expect an identifier */
1128 /* Remember the value for later */
1129 Label = GetStrBufId (&CfgSVal);
1133 /* Don't allow this twice */
1134 FlagAttr (&AttrFlags, atOrder, "ORDER");
1135 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1137 case CFGTOK_DECREASING: Order = cdDecreasing; break;
1138 case CFGTOK_INCREASING: Order = cdIncreasing; break;
1139 default: FAIL ("Unexpected order token");
1143 case CFGTOK_SEGMENT:
1144 /* Don't allow this twice */
1145 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1146 /* We expect an identifier */
1148 /* Remember the value for later */
1149 SegName = GetStrBufId (&CfgSVal);
1153 /* Don't allow this twice */
1154 FlagAttr (&AttrFlags, atType, "TYPE");
1155 /* The type may be given as id or numerical */
1156 if (CfgTok == CFGTOK_INTCON) {
1157 CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1158 Type = (int) CfgIVal;
1160 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1162 case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
1163 case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
1164 case CFGTOK_INTERRUPTOR: Type = CD_TYPE_INT; break;
1165 default: FAIL ("Unexpected type token");
1171 FAIL ("Unexpected attribute token");
1175 /* Skip the attribute value */
1178 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1179 if (CfgTok == CFGTOK_SEMI) {
1181 } else if (CfgTok == CFGTOK_COMMA) {
1186 /* Check if we have all mandatory attributes */
1187 AttrCheck (AttrFlags, atSegName, "SEGMENT");
1188 AttrCheck (AttrFlags, atLabel, "LABEL");
1189 AttrCheck (AttrFlags, atType, "TYPE");
1191 /* Check if the condes has already attributes defined */
1192 if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1193 CfgError (&CfgErrorPos,
1194 "CONDES attributes for type %d are already defined",
1198 /* Define the attributes */
1199 ConDesSetSegName (Type, SegName);
1200 ConDesSetLabel (Type, Label);
1201 if (AttrFlags & atCount) {
1202 ConDesSetCountSym (Type, Count);
1204 if (AttrFlags & atImport) {
1205 ConDesSetImport (Type, &Import);
1207 if (AttrFlags & atOrder) {
1208 ConDesSetOrder (Type, Order);
1214 static void ParseStartAddress (void)
1215 /* Parse the STARTADDRESS feature */
1217 static const IdentTok Attributes [] = {
1218 { "DEFAULT", CFGTOK_DEFAULT },
1222 /* Attribute values. */
1223 unsigned long DefStartAddr = 0;
1225 /* Bitmask to remember the attributes we got already */
1230 unsigned AttrFlags = atNone;
1232 /* Parse the attributes */
1235 /* Map the identifier to a token */
1237 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1240 /* An optional assignment follows */
1242 CfgOptionalAssign ();
1244 /* Check which attribute was given */
1247 case CFGTOK_DEFAULT:
1248 /* Don't allow this twice */
1249 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1250 /* We expect a numeric expression */
1251 DefStartAddr = CfgCheckedConstExpr (0, 0xFFFFFF);
1255 FAIL ("Unexpected attribute token");
1259 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1260 if (CfgTok == CFGTOK_SEMI) {
1262 } else if (CfgTok == CFGTOK_COMMA) {
1267 /* Check if we have all mandatory attributes */
1268 AttrCheck (AttrFlags, atDefault, "DEFAULT");
1270 /* If no start address was given on the command line, use the one given
1273 if (!HaveStartAddr) {
1274 StartAddr = DefStartAddr;
1280 static void ParseFeatures (void)
1281 /* Parse a features section */
1283 static const IdentTok Features [] = {
1284 { "CONDES", CFGTOK_CONDES },
1285 { "STARTADDRESS", CFGTOK_STARTADDRESS },
1288 while (CfgTok == CFGTOK_IDENT) {
1290 /* Map the identifier to a token */
1291 cfgtok_t FeatureTok;
1292 CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1293 FeatureTok = CfgTok;
1295 /* Skip the name and the following colon */
1299 /* Parse the format options */
1300 switch (FeatureTok) {
1306 case CFGTOK_STARTADDRESS:
1307 ParseStartAddress ();
1312 FAIL ("Unexpected feature token");
1315 /* Skip the semicolon */
1319 /* Remember we had this section */
1320 SectionsEncountered |= SE_FEATURES;
1325 static void ParseSymbols (void)
1326 /* Parse a symbols section */
1328 static const IdentTok Attributes[] = {
1329 { "ADDRSIZE", CFGTOK_ADDRSIZE },
1330 { "TYPE", CFGTOK_TYPE },
1331 { "VALUE", CFGTOK_VALUE },
1334 static const IdentTok AddrSizes [] = {
1335 { "ABS", CFGTOK_ABS },
1336 { "ABSOLUTE", CFGTOK_ABS },
1337 { "DIRECT", CFGTOK_ZP },
1338 { "DWORD", CFGTOK_LONG },
1339 { "FAR", CFGTOK_FAR },
1340 { "LONG", CFGTOK_LONG },
1341 { "NEAR", CFGTOK_ABS },
1342 { "ZEROPAGE", CFGTOK_ZP },
1343 { "ZP", CFGTOK_ZP },
1346 static const IdentTok Types [] = {
1347 { "EXPORT", CFGTOK_EXPORT },
1348 { "IMPORT", CFGTOK_IMPORT },
1349 { "WEAK", CFGTOK_WEAK },
1352 while (CfgTok == CFGTOK_IDENT) {
1354 /* Bitmask to remember the attributes we got already */
1357 atAddrSize = 0x0001,
1361 unsigned AttrFlags = atNone;
1363 ExprNode* Value = 0;
1364 CfgSymType Type = CfgSymExport;
1365 unsigned char AddrSize = ADDR_SIZE_ABS;
1370 /* Remember the name */
1371 unsigned Name = GetStrBufId (&CfgSVal);
1374 /* New syntax - skip the colon */
1377 /* Parse the attributes */
1380 /* Map the identifier to a token */
1382 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1385 /* Skip the attribute name */
1388 /* An optional assignment follows */
1389 CfgOptionalAssign ();
1391 /* Check which attribute was given */
1394 case CFGTOK_ADDRSIZE:
1395 /* Don't allow this twice */
1396 FlagAttr (&AttrFlags, atAddrSize, "ADDRSIZE");
1397 /* Map the type to a token */
1398 CfgSpecialToken (AddrSizes, ENTRY_COUNT (AddrSizes), "AddrSize");
1400 case CFGTOK_ABS: AddrSize = ADDR_SIZE_ABS; break;
1401 case CFGTOK_FAR: AddrSize = ADDR_SIZE_FAR; break;
1402 case CFGTOK_LONG: AddrSize = ADDR_SIZE_LONG; break;
1403 case CFGTOK_ZP: AddrSize = ADDR_SIZE_ZP; break;
1405 Internal ("Unexpected token: %d", CfgTok);
1411 /* Don't allow this twice */
1412 FlagAttr (&AttrFlags, atType, "TYPE");
1413 /* Map the type to a token */
1414 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1416 case CFGTOK_EXPORT: Type = CfgSymExport; break;
1417 case CFGTOK_IMPORT: Type = CfgSymImport; break;
1418 case CFGTOK_WEAK: Type = CfgSymWeak; break;
1420 Internal ("Unexpected token: %d", CfgTok);
1426 /* Don't allow this twice */
1427 FlagAttr (&AttrFlags, atValue, "VALUE");
1428 /* Value is an expression */
1433 FAIL ("Unexpected attribute token");
1437 /* Semicolon ends the decl, otherwise accept an optional comma */
1438 if (CfgTok == CFGTOK_SEMI) {
1440 } else if (CfgTok == CFGTOK_COMMA) {
1445 /* We must have a type */
1446 AttrCheck (AttrFlags, atType, "TYPE");
1448 /* Further actions depend on the type */
1452 /* We must have a value */
1453 AttrCheck (AttrFlags, atValue, "VALUE");
1454 /* Create the export */
1455 Exp = CreateExprExport (Name, Value, AddrSize);
1456 CollAppend (&Exp->DefLines, GenLineInfo (&CfgErrorPos));
1460 /* An import must not have a value */
1461 if (AttrFlags & atValue) {
1462 CfgError (&CfgErrorPos, "Imports must not have a value");
1464 /* Generate the import */
1465 Imp = InsertImport (GenImport (Name, AddrSize));
1466 /* Remember the file position */
1467 CollAppend (&Imp->RefLines, GenLineInfo (&CfgErrorPos));
1471 /* We must have a value */
1472 AttrCheck (AttrFlags, atValue, "VALUE");
1473 /* Remember the symbol for later */
1474 Sym = NewCfgSymbol (CfgSymWeak, Name);
1476 Sym->AddrSize = AddrSize;
1480 Internal ("Unexpected symbol type %d", Type);
1483 /* Skip the semicolon */
1487 /* Remember we had this section */
1488 SectionsEncountered |= SE_SYMBOLS;
1493 static void ParseConfig (void)
1494 /* Parse the config file */
1496 static const IdentTok BlockNames [] = {
1497 { "MEMORY", CFGTOK_MEMORY },
1498 { "FILES", CFGTOK_FILES },
1499 { "SEGMENTS", CFGTOK_SEGMENTS },
1500 { "FORMATS", CFGTOK_FORMATS },
1501 { "FEATURES", CFGTOK_FEATURES },
1502 { "SYMBOLS", CFGTOK_SYMBOLS },
1508 /* Read the block ident */
1509 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1513 /* Expected a curly brace */
1514 CfgConsume (CFGTOK_LCURLY, "`{' expected");
1516 /* Read the block */
1527 case CFGTOK_SEGMENTS:
1531 case CFGTOK_FORMATS:
1535 case CFGTOK_FEATURES:
1539 case CFGTOK_SYMBOLS:
1544 FAIL ("Unexpected block token");
1548 /* Skip closing brace */
1549 CfgConsume (CFGTOK_RCURLY, "`}' expected");
1551 } while (CfgTok != CFGTOK_EOF);
1557 /* Read the configuration */
1559 /* Create the descriptors for the binary formats */
1560 BinFmtDesc = NewBinDesc ();
1561 O65FmtDesc = NewO65Desc ();
1563 /* If we have a config name given, open the file, otherwise we will read
1568 /* Parse the file */
1571 /* Close the input file */
1577 /*****************************************************************************/
1578 /* Config file processing */
1579 /*****************************************************************************/
1583 static void ProcessSegments (void)
1584 /* Process the SEGMENTS section */
1588 /* Walk over the list of segment descriptors */
1590 while (I < CollCount (&SegDescList)) {
1592 /* Get the next segment descriptor */
1593 SegDesc* S = CollAtUnchecked (&SegDescList, I);
1595 /* Search for the actual segment in the input files. The function may
1596 ** return NULL (no such segment), this is checked later.
1598 S->Seg = SegFind (S->Name);
1600 /* If the segment is marked as BSS style, and if the segment exists
1601 ** in any of the object file, check that there's no initialized data
1604 if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
1605 CfgWarning (GetSourcePos (S->LI),
1606 "Segment `%s' with type `bss' contains initialized data",
1607 GetString (S->Name));
1610 /* If this segment does exist in any of the object files, insert the
1611 ** segment into the load/run memory areas. Otherwise print a warning
1612 ** and discard it, because the segment pointer in the descriptor is
1617 /* Insert the segment into the memory area list */
1618 MemoryInsert (S->Run, S);
1619 if (S->Load != S->Run) {
1620 /* We have separate RUN and LOAD areas */
1621 MemoryInsert (S->Load, S);
1624 /* Use the fill value from the config */
1625 S->Seg->FillVal = S->FillVal;
1627 /* Process the next segment descriptor in the next run */
1632 /* Print a warning if the segment is not optional */
1633 if ((S->Flags & SF_OPTIONAL) == 0) {
1634 CfgWarning (&CfgErrorPos,
1635 "Segment `%s' does not exist",
1636 GetString (S->Name));
1639 /* Discard the descriptor and remove it from the collection */
1641 CollDelete (&SegDescList, I);
1648 static void ProcessSymbols (void)
1649 /* Process the SYMBOLS section */
1653 /* Walk over all symbols */
1655 for (I = 0; I < CollCount (&CfgSymbols); ++I) {
1657 /* Get the next symbol */
1658 CfgSymbol* Sym = CollAtUnchecked (&CfgSymbols, I);
1660 /* Check what it is. */
1661 switch (Sym->Type) {
1663 case CfgSymO65Export:
1664 /* Check if the export symbol is also defined as an import. */
1665 if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1667 GetSourcePos (Sym->LI),
1668 "Exported o65 symbol `%s' cannot also be an o65 import",
1669 GetString (Sym->Name)
1673 /* Check if we have this symbol defined already. The entry
1674 ** routine will check this also, but we get a more verbose
1675 ** error message when checking it here.
1677 if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
1679 GetSourcePos (Sym->LI),
1680 "Duplicate exported o65 symbol: `%s'",
1681 GetString (Sym->Name)
1685 /* Insert the symbol into the table */
1686 O65SetExport (O65FmtDesc, Sym->Name);
1689 case CfgSymO65Import:
1690 /* Check if the import symbol is also defined as an export. */
1691 if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
1693 GetSourcePos (Sym->LI),
1694 "Imported o65 symbol `%s' cannot also be an o65 export",
1695 GetString (Sym->Name)
1699 /* Check if we have this symbol defined already. The entry
1700 ** routine will check this also, but we get a more verbose
1701 ** error message when checking it here.
1703 if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
1705 GetSourcePos (Sym->LI),
1706 "Duplicate imported o65 symbol: `%s'",
1707 GetString (Sym->Name)
1711 /* Insert the symbol into the table */
1712 O65SetImport (O65FmtDesc, Sym->Name);
1716 /* If the symbol is not defined until now, define it */
1717 if ((E = FindExport (Sym->Name)) == 0 || IsUnresolvedExport (E)) {
1718 /* The symbol is undefined, generate an export */
1719 E = CreateExprExport (Sym->Name, Sym->Value, Sym->AddrSize);
1720 CollAppend (&E->DefLines, Sym->LI);
1725 Internal ("Unexpected symbol type %d", Sym->Type);
1734 static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
1735 /* Create the defines for a RUN segment */
1738 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1740 /* Define the run address of the segment */
1741 SB_Printf (&Buf, "__%s_RUN__", GetString (S->Name));
1742 E = CreateMemoryExport (GetStrBufId (&Buf), S->Run, SegAddr - S->Run->Start);
1743 CollAppend (&E->DefLines, S->LI);
1745 /* Define the size of the segment */
1746 SB_Printf (&Buf, "__%s_SIZE__", GetString (S->Name));
1747 E = CreateConstExport (GetStrBufId (&Buf), S->Seg->Size);
1748 CollAppend (&E->DefLines, S->LI);
1750 S->Flags |= SF_RUN_DEF;
1756 static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
1757 /* Create the defines for a LOAD segment */
1760 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1762 /* Define the load address of the segment */
1763 SB_Printf (&Buf, "__%s_LOAD__", GetString (S->Name));
1764 E = CreateMemoryExport (GetStrBufId (&Buf), S->Load, SegAddr - S->Load->Start);
1765 CollAppend (&E->DefLines, S->LI);
1767 S->Flags |= SF_LOAD_DEF;
1773 unsigned CfgProcess (void)
1774 /* Process the config file, after reading in object files and libraries. This
1775 ** includes postprocessing of the config file data; but also assigning segments,
1776 ** and defining segment/memory-area related symbols. The function will return
1777 ** the number of memory area overflows (so, zero means everything went OK).
1778 ** In case of overflows, a short mapfile can be generated later, to ease the
1779 ** user's task of re-arranging segments.
1782 unsigned Overflows = 0;
1785 /* Postprocess symbols. We must do that first, since weak symbols are
1786 ** defined here, which may be needed later.
1790 /* Postprocess segments */
1793 /* Walk through each of the memory sections. Add up the sizes; and, check
1794 ** for an overflow of the section. Assign the start addresses of the
1795 ** segments while doing that.
1797 for (I = 0; I < CollCount (&MemoryAreas); ++I) {
1800 unsigned Overwrites = 0;
1802 /* Get the next memory area */
1803 MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
1805 /* Remember the offset in the output file */
1806 M->FileOffs = M->F->Size;
1808 /* Remember if this is a relocatable memory area */
1809 M->Relocatable = RelocatableBinFmt (M->F->Format);
1811 /* Resolve the start address expression, remember the start address,
1812 ** and mark the memory area as placed.
1814 if (!IsConstExpr (M->StartExpr)) {
1815 CfgError (GetSourcePos (M->LI),
1816 "Start address of memory area `%s' is not constant",
1817 GetString (M->Name));
1819 Addr = M->Start = GetExprVal (M->StartExpr);
1820 M->Flags |= MF_PLACED;
1822 /* If requested, define the symbol for the start of the memory area.
1823 ** Doing it here means that the expression for the size of the area
1824 ** may reference this symbol.
1826 if (M->Flags & MF_DEFINE) {
1828 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1830 /* Define the start of the memory area */
1831 SB_Printf (&Buf, "__%s_START__", GetString (M->Name));
1832 E = CreateMemoryExport (GetStrBufId (&Buf), M, 0);
1833 CollAppend (&E->DefLines, M->LI);
1838 /* Resolve the size expression */
1839 if (!IsConstExpr (M->SizeExpr)) {
1840 CfgError (GetSourcePos (M->LI),
1841 "Size of memory area `%s' is not constant",
1842 GetString (M->Name));
1844 M->Size = GetExprVal (M->SizeExpr);
1846 /* Walk through the segments in this memory area */
1847 for (J = 0; J < CollCount (&M->SegList); ++J) {
1848 /* Get the segment */
1849 SegDesc* S = CollAtUnchecked (&M->SegList, J);
1851 /* Remember the start address before handling this segment */
1852 unsigned long StartAddr = Addr;
1854 /* Take note of "overwrite" segments and make sure there are no
1855 ** other segment types following them in current memory region.
1857 if (S->Flags & SF_OVERWRITE) {
1858 if (S->Flags & (SF_OFFSET | SF_START)) {
1861 CfgError (GetSourcePos (M->LI),
1862 "Segment `%s' of type `overwrite' requires either"
1863 " `Start' or `Offset' attribute to be specified",
1864 GetString (S->Name));
1867 if (Overwrites > 0) {
1868 CfgError (GetSourcePos (M->LI),
1869 "Segment `%s' is preceded by at least one segment"
1870 " of type `overwrite'",
1871 GetString (S->Name));
1875 /* Some actions depend on whether this is the load or run memory
1879 /* This is the run (and maybe load) memory area. Handle
1880 ** alignment and explict start address and offset.
1883 /* Check if the alignment for the segment from the linker
1884 ** config. is a multiple for that of the segment.
1886 if ((S->RunAlignment % S->Seg->Alignment) != 0) {
1887 /* Segment requires another alignment than configured
1890 CfgWarning (GetSourcePos (S->LI),
1891 "Segment `%s' isn't aligned properly; the"
1892 " resulting executable might not be functional.",
1893 GetString (S->Name));
1896 if (S->Flags & SF_ALIGN) {
1897 /* Align the address */
1898 unsigned long NewAddr = AlignAddr (Addr, S->RunAlignment);
1900 /* If the first segment placed in the memory area needs
1901 ** fill bytes for the alignment, emit a warning, since
1902 ** that is somewhat suspicious.
1904 if (M->FillLevel == 0 && NewAddr > Addr) {
1905 CfgWarning (GetSourcePos (S->LI),
1906 "The first segment in memory area `%s' "
1907 "needs fill bytes for alignment.",
1908 GetString (M->Name));
1911 /* Use the aligned address */
1914 } else if ((S->Flags & (SF_OFFSET | SF_START)) != 0 &&
1915 (M->Flags & MF_OVERFLOW) == 0) {
1916 /* Give the segment a fixed starting address */
1917 unsigned long NewAddr = S->Addr;
1919 if (S->Flags & SF_OFFSET) {
1920 /* An offset was given, no address, make an address */
1921 NewAddr += M->Start;
1924 if (S->Flags & SF_OVERWRITE) {
1925 if (NewAddr < M->Start) {
1926 CfgError (GetSourcePos (S->LI),
1927 "Segment `%s' begins before memory area `%s'",
1928 GetString (S->Name), GetString (M->Name));
1933 if (NewAddr < Addr) {
1934 /* Offset already too large */
1936 if (S->Flags & SF_OFFSET) {
1937 CfgWarning (GetSourcePos (S->LI),
1938 "Segment `%s' offset is too small in `%s' by %lu byte%c",
1939 GetString (S->Name), GetString (M->Name),
1940 Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
1942 CfgWarning (GetSourcePos (S->LI),
1943 "Segment `%s' start address is too low in `%s' by %lu byte%c",
1944 GetString (S->Name), GetString (M->Name),
1945 Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
1953 /* Set the start address of this segment, set the readonly flag
1954 ** in the segment, and remember if the segment is in a
1955 ** relocatable file or not.
1958 S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
1960 /* Remember the run memory for this segment, which is also a
1961 ** flag that the segment has been placed.
1963 S->Seg->MemArea = M;
1965 } else if (S->Load == M) {
1966 /* This is the load memory area; *and*, run and load are
1967 ** different (because of the "else" above). Handle alignment.
1969 if (S->Flags & SF_ALIGN_LOAD) {
1970 /* Align the address */
1971 Addr = AlignAddr (Addr, S->LoadAlignment);
1975 /* If this is the load memory area, and the segment doesn't have a
1976 ** fill value defined, use the one from the memory area.
1978 if (S->Load == M && (S->Flags & SF_FILLVAL) == 0) {
1979 S->Seg->FillVal = M->FillVal;
1982 /* Increment the fill level of the memory area; and, check for an
1985 M->FillLevel = Addr + S->Seg->Size - M->Start;
1986 if (M->FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) {
1988 M->Flags |= MF_OVERFLOW;
1989 CfgWarning (GetSourcePos (M->LI),
1990 "Segment `%s' overflows memory area `%s' by %lu byte%c",
1991 GetString (S->Name), GetString (M->Name),
1992 M->FillLevel - M->Size, (M->FillLevel - M->Size == 1) ? ' ' : 's');
1995 /* If requested, define symbols for the start and size of the
1998 if (S->Flags & SF_DEFINE) {
1999 if (S->Run == M && (S->Flags & SF_RUN_DEF) == 0) {
2000 CreateRunDefines (S, Addr);
2002 if (S->Load == M && (S->Flags & SF_LOAD_DEF) == 0) {
2003 CreateLoadDefines (S, Addr);
2007 /* Calculate the new address */
2008 Addr += S->Seg->Size;
2010 /* If this segment will go out to the file, or its place
2011 ** in the file will be filled, then increase the file size.
2014 ((S->Flags & SF_BSS) == 0 || (M->Flags & MF_FILL) != 0)) {
2015 M->F->Size += Addr - StartAddr;
2019 /* If requested, define symbols for start, size, and offset of the
2022 if (M->Flags & MF_DEFINE) {
2024 StrBuf Buf = STATIC_STRBUF_INITIALIZER;
2026 /* Define the size of the memory area */
2027 SB_Printf (&Buf, "__%s_SIZE__", GetString (M->Name));
2028 E = CreateConstExport (GetStrBufId (&Buf), M->Size);
2029 CollAppend (&E->DefLines, M->LI);
2031 /* Define the fill level of the memory area */
2032 SB_Printf (&Buf, "__%s_LAST__", GetString (M->Name));
2033 E = CreateMemoryExport (GetStrBufId (&Buf), M, M->FillLevel);
2034 CollAppend (&E->DefLines, M->LI);
2036 /* Define the file offset of the memory area. This isn't of much
2037 ** use for relocatable output files.
2039 if (!M->Relocatable) {
2040 SB_Printf (&Buf, "__%s_FILEOFFS__", GetString (M->Name));
2041 E = CreateConstExport (GetStrBufId (&Buf), M->FileOffs);
2042 CollAppend (&E->DefLines, M->LI);
2045 /* Throw away the string buffer */
2049 /* If we didn't have an overflow, and are requested to fill the memory
2050 ** area, account for that in the file size.
2052 if ((M->Flags & MF_OVERFLOW) == 0 && (M->Flags & MF_FILL) != 0) {
2053 M->F->Size += (M->Size - M->FillLevel);
2057 /* Return the number of memory area overflows */
2063 void CfgWriteTarget (void)
2064 /* Write the target file(s) */
2068 /* Walk through the files list */
2069 for (I = 0; I < CollCount (&FileList); ++I) {
2071 /* Get this entry */
2072 File* F = CollAtUnchecked (&FileList, I);
2074 /* We don't need to look at files with no memory areas */
2075 if (CollCount (&F->MemoryAreas) > 0) {
2077 /* Is there an output file? */
2078 if (SB_GetLen (GetStrBuf (F->Name)) > 0) {
2080 /* Assign a proper binary format */
2081 if (F->Format == BINFMT_DEFAULT) {
2082 F->Format = DefaultBinFmt;
2085 /* Call the apropriate routine for the binary format */
2086 switch (F->Format) {
2089 BinWriteTarget (BinFmtDesc, F);
2093 O65WriteTarget (O65FmtDesc, F);
2097 Internal ("Invalid binary format: %u", F->Format);
2103 /* No output file. Walk through the list and mark all segments
2104 ** loading into these memory areas in this file as dumped.
2107 for (J = 0; J < CollCount (&F->MemoryAreas); ++J) {
2111 /* Get this entry */
2112 MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, J);
2115 Print (stdout, 2, "Skipping `%s'...\n", GetString (M->Name));
2117 /* Walk throught the segments */
2118 for (K = 0; K < CollCount (&M->SegList); ++K) {
2119 SegDesc* S = CollAtUnchecked (&M->SegList, K);
2121 /* Load area - mark the segment as dumped */