Unused memory in a memory area may be filled. Use the "<tt/fill = yes/"
attribute to request this. The default value to fill unused space is zero. If
you don't like this, you may specify a byte value that is used to fill these
-areas with the "<tt/fillval/" attribute. This value is also used to fill unfilled
-areas generated by the assemblers <tt/.ALIGN/ and <tt/.RES/ directives.
+areas with the "<tt/fillval/" attribute. If there is no "<tt/fillval/"
+attribute for the segment, the "<tt/fillval/" attribute of the memory area (or
+its default) is used instead. This means that the value may also be used to
+fill unfilled areas generated by the assemblers <tt/.ALIGN/ and <tt/.RES/
+directives.
The symbol <tt/%S/ may be used to access the default start address (that is,
the one defined in the <ref id="FEATURES" name="FEATURES"> section, or the
been specified. There are no special attributes to set start or offset for
just the load memory area.
+A "<tt/fillval/" attribute may not only be specified for a memory area, but
+also for a segment. The value must be an integer between 0 and 255. It is used
+as fill value for space reserved by the assemblers <tt/.ALIGN/ and <tt/.RES/
+commands. It is also used as fill value for space between sections (part of a
+segment that comes from one object file) caused by alignment, but not for
+space that preceeds the first section.
+
To suppress the warning, the linker issues if it encounters a segment that is
not found in any of the input files, use "<tt/optional=yes/" as additional
segment attribute. Be careful when using this attribute, because a missing
/* */
/* */
/* */
-/* (C) 1999-2011, Ullrich von Bassewitz */
+/* (C) 1999-2012, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* Debugging: Check that the file offset is correct */
if (ftell (D->F) != (long)M->FileOffs) {
Internal ("Invalid file offset for memory area %s: %ld/%lu",
- GetString (M->Name), ftell (D->F), M->FileOffs);
+ GetString (M->Name), ftell (D->F), M->FileOffs);
}
/* Walk over all segments in this memory area */
*/
if (DoWrite) {
unsigned long P = ftell (D->F);
- S->Seg->FillVal = M->FillVal;
SegWrite (D->Filename, D->F, S->Seg, BinWriteExpr, D);
PrintNumVal ("Wrote", (unsigned long) (ftell (D->F) - P));
- } else if (M->Flags & MF_FILL) {
- WriteMult (D->F, M->FillVal, S->Seg->Size);
+ } else if (M->Flags & MF_FILL) {
+ WriteMult (D->F, S->Seg->FillVal, S->Seg->Size);
PrintNumVal ("Filled", (unsigned long) S->Seg->Size);
}
#define SA_OFFSET 0x0040
#define SA_START 0x0080
#define SA_OPTIONAL 0x0100
+#define SA_FILLVAL 0x0200
/* Symbol types used in the CfgSymbol structure */
typedef enum {
S->Seg = 0;
S->Attr = 0;
S->Flags = 0;
+ S->FillVal = 0;
S->RunAlignment = 1;
S->LoadAlignment = 1;
{ "ALIGN", CFGTOK_ALIGN },
{ "ALIGN_LOAD", CFGTOK_ALIGN_LOAD },
{ "DEFINE", CFGTOK_DEFINE },
+ { "FILLVAL", CFGTOK_FILLVAL },
{ "LOAD", CFGTOK_LOAD },
{ "OFFSET", CFGTOK_OFFSET },
{ "OPTIONAL", CFGTOK_OPTIONAL },
CfgNextTok ();
break;
+ case CFGTOK_FILLVAL:
+ FlagAttr (&S->Attr, SA_FILLVAL, "FILLVAL");
+ S->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
+ S->Flags |= SF_FILLVAL;
+ break;
+
case CFGTOK_LOAD:
FlagAttr (&S->Attr, SA_LOAD, "LOAD");
S->Load = CfgGetMemory (GetStrBufId (&CfgSVal));
while (I < CollCount (&SegDescList)) {
/* Get the next segment descriptor */
- SegDesc* S = CollAtUnchecked (&SegDescList, I);
+ SegDesc* S = CollAtUnchecked (&SegDescList, I);
/* Search for the actual segment in the input files. The function may
* return NULL (no such segment), this is checked later.
*/
S->Seg = SegFind (S->Name);
- /* If the segment is marked as BSS style, and if the segment exists
+ /* If the segment is marked as BSS style, and if the segment exists
* in any of the object file, check that there's no initialized data
* in the segment.
- */
- if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
+ */
+ if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
CfgWarning (GetSourcePos (S->LI),
"Segment `%s' with type `bss' contains initialized data",
- GetString (S->Name));
- }
+ GetString (S->Name));
+ }
/* If this segment does exist in any of the object files, insert the
* segment into the load/run memory areas. Otherwise print a warning
MemoryInsert (S->Load, S);
}
+ /* Use the fill value from the config */
+ S->Seg->FillVal = S->FillVal;
+
/* Process the next segment descriptor in the next run */
++I;
}
+ /* If this is the load memory area and the segment doesn't have a
+ * fill value defined, use the one from the memory area.
+ */
+ if (S->Load == M && (S->Flags & SF_FILLVAL) == 0) {
+ S->Seg->FillVal = M->FillVal;
+ }
+
/* Increment the fill level of the memory area and check for an
* overflow.
*/
/* */
/* */
/* */
-/* (C) 1998-2011, Ullrich von Bassewitz */
+/* (C) 1998-2012, Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
Segment* Seg; /* Pointer to segment structure */
unsigned Attr; /* Attributes for segment */
unsigned Flags; /* Set of bitmapped flags */
+ unsigned char FillVal; /* Fill value for this segment */
struct MemoryArea* Load; /* Load memory section */
struct MemoryArea* Run; /* Run memory section */
unsigned long Addr; /* Start address or offset into segment */
#define SF_OPTIONAL 0x0100 /* Segment is optional (must not exist) */
#define SF_RUN_DEF 0x0200 /* RUN symbols already defined */
#define SF_LOAD_DEF 0x0400 /* LOAD symbols already defined */
+#define SF_FILLVAL 0x0800 /* Segment has separate fill value */
/* Loop over all sections in this segment */
for (I = 0; I < CollCount (&S->Sections); ++I) {
- Section* Sec = CollAtUnchecked (&S->Sections, I);
- Fragment* Frag;
+
+ Section* Sec = CollAtUnchecked (&S->Sections, I);
+ Fragment* Frag;
+ unsigned char FillVal;
/* Output were this section is from */
Print (stdout, 2, " Section from \"%s\"\n", GetObjFileName (Sec->Obj));
- /* If we have fill bytes, write them now */
+ /* If we have fill bytes, write them now. Beware: If this is the
+ * first section, the fill value is not considered part of the segment
+ * and therefore taken from the memory area.
+ */
+ FillVal = (I == 0)? S->MemArea->FillVal : S->FillVal;
Print (stdout, 2, " Filling 0x%lx bytes with 0x%02x\n",
- Sec->Fill, S->FillVal);
- WriteMult (Tgt, S->FillVal, Sec->Fill);
+ Sec->Fill, FillVal);
+ WriteMult (Tgt, FillVal, Sec->Fill);
Offs += Sec->Fill;
/* Loop over all fragments in this section */