X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fld65%2Fbin.c;h=e864112414ea301b43e0bf92a469539682bd9e49;hb=30b418c734011a358d6c8c477dfc314c26f9fb40;hp=7f4b08551b3eacedfcd3b865b42ad26b79427e0b;hpb=1eff067ff90379c14c6a9770a76d6a3e9f99cd82;p=cc65 diff --git a/src/ld65/bin.c b/src/ld65/bin.c index 7f4b08551..e86411241 100644 --- a/src/ld65/bin.c +++ b/src/ld65/bin.c @@ -1,15 +1,15 @@ /*****************************************************************************/ /* */ -/* bin.c */ +/* bin.c */ /* */ -/* Module to handle the raw binary format */ +/* Module to handle the raw binary format */ /* */ /* */ /* */ -/* (C) 1999-2000 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ +/* (C) 1999-2012, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -38,37 +38,41 @@ #include /* common */ +#include "alignment.h" #include "print.h" #include "xmalloc.h" /* ld65 */ -#include "global.h" +#include "bin.h" +#include "config.h" +#include "exports.h" +#include "expr.h" #include "error.h" +#include "global.h" #include "fileio.h" +#include "lineinfo.h" +#include "memarea.h" #include "segments.h" -#include "exports.h" -#include "config.h" -#include "expr.h" -#include "bin.h" +#include "spool.h" /*****************************************************************************/ -/* Data */ +/* Data */ /*****************************************************************************/ struct BinDesc { - unsigned Undef; /* Count of undefined externals */ - FILE* F; /* Output file */ - const char* Filename; /* Name of output file */ + unsigned Undef; /* Count of undefined externals */ + FILE* F; /* Output file */ + const char* Filename; /* Name of output file */ }; /*****************************************************************************/ -/* Code */ +/* Code */ /*****************************************************************************/ @@ -80,8 +84,8 @@ BinDesc* NewBinDesc (void) BinDesc* D = xmalloc (sizeof (BinDesc)); /* Initialize the fields */ - D->Undef = 0; - D->F = 0; + D->Undef = 0; + D->F = 0; D->Filename = 0; /* Return the created struct */ @@ -99,7 +103,8 @@ void FreeBinDesc (BinDesc* D) static unsigned BinWriteExpr (ExprNode* E, int Signed, unsigned Size, - unsigned long Offs, void* Data) + unsigned long Offs attribute ((unused)), + void* Data) /* Called from SegWrite for an expression. Evaluate the expression, check the * range and write the expression value to the file. */ @@ -113,108 +118,148 @@ static unsigned BinWriteExpr (ExprNode* E, int Signed, unsigned Size, static void PrintBoolVal (const char* Name, int B) /* Print a boolean value for debugging */ { - printf (" %s = %s\n", Name, B? "true" : "false"); + Print (stdout, 2, " %s = %s\n", Name, B? "true" : "false"); } -static void BinWriteMem (BinDesc* D, Memory* M) +static void PrintNumVal (const char* Name, unsigned long V) +/* Print a numerical value for debugging */ +{ + Print (stdout, 2, " %s = 0x%lx\n", Name, V); +} + + + +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; - /* Get a pointer to the first segment node */ - MemListNode* N = M->SegList; - while (N) { - - int DoWrite; - - /* Get the segment from the list node */ - SegDesc* S = N->Seg; - - /* Keep the user happy */ - Print (stdout, 1, " Writing `%s'\n", 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 the DoWrite flag for debugging */ - if (Verbosity > 1) { - PrintBoolVal ("bss", S->Flags & SF_BSS); - PrintBoolVal ("LoadArea", S->Load == M); - PrintBoolVal ("Dumped", S->Seg->Dumped); - PrintBoolVal ("DoWrite", DoWrite); - } - - /* Check if we would need an alignment */ - if (S->Seg->Align > S->Align) { - /* Segment itself requires larger alignment than configured - * in the linker. - */ - Warning ("Segment `%s' in module `%s' requires larger alignment", - S->Name, GetObjFileName (S->Seg->AlignObj)); - } - - /* Handle ALIGN and OFFSET/START */ - if (S->Flags & SF_ALIGN) { - /* Align the address */ - unsigned long Val, NewAddr; - Val = (0x01UL << S->Align) - 1; - NewAddr = (Addr + Val) & ~Val; - if (DoWrite) { - WriteMult (D->F, M->FillVal, NewAddr-Addr); - } - Addr = NewAddr; - /* Remember the fill value for the segment */ - S->Seg->FillVal = M->FillVal; - } 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) { - WriteMult (D->F, M->FillVal, 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) { - SegWrite (D->F, S->Seg, BinWriteExpr, D); - } else if (M->Flags & MF_FILL) { - WriteMult (D->F, M->FillVal, 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; - - /* Next segment node */ - N = N->Next; + /* 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) { - while (M->FillLevel < M->Size) { - Write8 (D->F, M->FillVal); - ++M->FillLevel; - } + 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; } } -static int BinUnresolved (const char* Name, void* D) +static int BinUnresolved (unsigned Name attribute ((unused)), void* D) /* Called if an unresolved symbol is encountered */ { /* Unresolved symbols are an error in binary format. Bump the counter @@ -230,41 +275,41 @@ static int BinUnresolved (const char* Name, void* D) void BinWriteTarget (BinDesc* D, struct File* F) /* Write a binary output file */ { - Memory* M; + unsigned I; /* Place the filename in the control structure */ - D->Filename = F->Name; + D->Filename = GetString (F->Name); /* Check for unresolved symbols. The function BinUnresolved is called * if we get an unresolved symbol. */ - D->Undef = 0; /* Reset the counter */ - CheckExports (BinUnresolved, D); + D->Undef = 0; /* Reset the counter */ + CheckUnresolvedImports (BinUnresolved, D); if (D->Undef > 0) { - /* We had unresolved symbols, cannot create output file */ - Error ("%u unresolved external(s) found - cannot create output file", D->Undef); + /* We had unresolved symbols, cannot create output file */ + Error ("%u unresolved external(s) found - cannot create output file", D->Undef); } /* Open the file */ - D->F = fopen (F->Name, "wb"); + D->F = fopen (D->Filename, "wb"); if (D->F == 0) { - Error ("Cannot open `%s': %s", F->Name, strerror (errno)); + Error ("Cannot open `%s': %s", D->Filename, strerror (errno)); } /* Keep the user happy */ - Print (stdout, 1, "Opened `%s'...\n", F->Name); + Print (stdout, 1, "Opened `%s'...\n", D->Filename); /* Dump all memory areas */ - M = F->MemList; - while (M) { - Print (stdout, 1, " Dumping `%s'\n", M->Name); - BinWriteMem (D, M); - M = M->FNext; + for (I = 0; I < CollCount (&F->MemoryAreas); ++I) { + /* Get this entry */ + MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, I); + Print (stdout, 1, " Dumping `%s'\n", GetString (M->Name)); + BinWriteMem (D, M); } /* Close the file */ if (fclose (D->F) != 0) { - Error ("Cannot write to `%s': %s", F->Name, strerror (errno)); + Error ("Cannot write to `%s': %s", D->Filename, strerror (errno)); } /* Reset the file and filename */ @@ -274,3 +319,5 @@ void BinWriteTarget (BinDesc* D, struct File* F) + +