static void BinWriteMem (BinDesc* D, MemoryArea* M) /* Write the segments of one memory area to a file */ { unsigned I; /* Get the start address of this memory area */ unsigned long Addr = M->Start; /* 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); } /* Walk over all segments in this memory area */ for (I = 0; I < CollCount (&M->SegList); ++I) { int DoWrite; /* Get the segment */ SegDesc* S = CollAtUnchecked (&M->SegList, I); /* Keep the user happy */ Print (stdout, 1, " Writing `%s'\n", GetString (S->Name)); /* Writes do only occur in the load area and not for BSS segments */ DoWrite = (S->Flags & SF_BSS) == 0 && /* No BSS segment */ S->Load == M && /* LOAD segment */ S->Seg->Dumped == 0; /* Not already written */ /* Output debugging stuff */ PrintBoolVal ("bss", S->Flags & SF_BSS); PrintBoolVal ("LoadArea", S->Load == M); PrintBoolVal ("Dumped", S->Seg->Dumped); PrintBoolVal ("DoWrite", DoWrite); PrintNumVal ("Address", Addr); PrintNumVal ("FileOffs", (unsigned long) ftell (D->F)); /* Check if the alignment for the segment from the linker config is * a multiple for that of the segment. */ if ((S->RunAlignment % S->Seg->Alignment) != 0) { /* Segment requires another alignment than configured * in the linker. */ Warning ("Segment `%s' is not aligned properly. Resulting " "executable may not be functional.", GetString (S->Name)); } /* If this is the run memory area, we must apply run alignment. If * this is not the run memory area but the load memory area (which * means that both are different), we must apply load alignment. * Beware: DoWrite may be true even if this is the run memory area, * because it may be also the load memory area. */ if (S->Run == M) { /* Handle ALIGN and OFFSET/START */ if (S->Flags & SF_ALIGN) { /* Align the address */ unsigned long NewAddr = AlignAddr (Addr, S->RunAlignment); if (DoWrite || (M->Flags & MF_FILL) != 0) { WriteMult (D->F, M->FillVal, NewAddr - Addr); PrintNumVal ("SF_ALIGN", NewAddr - Addr); } Addr = NewAddr; } else if (S->Flags & (SF_OFFSET | SF_START)) { unsigned long NewAddr = S->Addr; if (S->Flags & SF_OFFSET) { /* It's an offset, not a fixed address, make an address */ NewAddr += M->Start; } if (DoWrite || (M->Flags & MF_FILL) != 0) { WriteMult (D->F, M->FillVal, NewAddr-Addr); PrintNumVal ("SF_OFFSET", NewAddr - Addr); } Addr = NewAddr; } } else if (S->Load == M) { /* Handle ALIGN_LOAD */ if (S->Flags & SF_ALIGN_LOAD) { /* Align the address */ unsigned long NewAddr = AlignAddr (Addr, S->LoadAlignment); if (DoWrite || (M->Flags & MF_FILL) != 0) { WriteMult (D->F, M->FillVal, NewAddr - Addr); PrintNumVal ("SF_ALIGN_LOAD", NewAddr - Addr); } Addr = NewAddr; } } /* Now write the segment to disk if it is not a BSS type segment and * if the memory area is the load area. */ if (DoWrite) { unsigned long P = ftell (D->F); 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, S->Seg->FillVal, S->Seg->Size); PrintNumVal ("Filled", (unsigned long) S->Seg->Size); } /* If this was the load memory area, mark the segment as dumped */ if (S->Load == M) { S->Seg->Dumped = 1; } /* Calculate the new address */ Addr += S->Seg->Size; } /* If a fill was requested, fill the remaining space */ if ((M->Flags & MF_FILL) != 0 && M->FillLevel < M->Size) { unsigned long ToFill = M->Size - M->FillLevel; Print (stdout, 2, " Filling 0x%lx bytes with 0x%02x\n", ToFill, M->FillVal); WriteMult (D->F, M->FillVal, ToFill); M->FillLevel = M->Size; } }
void SegWrite (const char* TgtName, FILE* Tgt, Segment* S, SegWriteFunc F, void* Data) /* Write the data from the given segment to a file. For expressions, F is ** called (see description of SegWriteFunc above). */ { unsigned I; int Sign; unsigned long Offs = 0; /* Remember the output file and offset for the segment */ S->OutputName = TgtName; S->OutputOffs = (unsigned long) ftell (Tgt); /* Loop over all sections in this segment */ for (I = 0; I < CollCount (&S->Sections); ++I) { 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. 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, FillVal); WriteMult (Tgt, FillVal, Sec->Fill); Offs += Sec->Fill; /* Loop over all fragments in this section */ Frag = Sec->FragRoot; while (Frag) { /* Output fragment data */ switch (Frag->Type) { case FRAG_LITERAL: WriteData (Tgt, Frag->LitBuf, Frag->Size); break; case FRAG_EXPR: case FRAG_SEXPR: Sign = (Frag->Type == FRAG_SEXPR); /* Call the users function and evaluate the result */ switch (F (Frag->Expr, Sign, Frag->Size, Offs, Data)) { case SEG_EXPR_OK: break; case SEG_EXPR_RANGE_ERROR: Error ("Range error in module '%s', line %u", GetFragmentSourceName (Frag), GetFragmentSourceLine (Frag)); break; case SEG_EXPR_TOO_COMPLEX: Error ("Expression too complex in module '%s', line %u", GetFragmentSourceName (Frag), GetFragmentSourceLine (Frag)); break; case SEG_EXPR_INVALID: Error ("Invalid expression in module '%s', line %u", GetFragmentSourceName (Frag), GetFragmentSourceLine (Frag)); break; default: Internal ("Invalid return code from SegWriteFunc"); } break; case FRAG_FILL: WriteMult (Tgt, S->FillVal, Frag->Size); break; default: Internal ("Invalid fragment type: %02X", Frag->Type); } /* Update the offset */ Print (stdout, 2, " Fragment with 0x%x bytes\n", Frag->Size); Offs += Frag->Size; /* Next fragment */ Frag = Frag->Next; } } }