/* */
/* */
/* */
-/* (C) 1999-2001 Ullrich von Bassewitz */
-/* Wacholderweg 14 */
-/* D-70597 Stuttgart */
-/* EMail: uz@cc65.org */
+/* (C) 1999-2011, Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
#include <stdio.h>
#include <string.h>
+#include <limits.h>
#include <errno.h>
#include <time.h>
/* common */
+#include "chartype.h"
#include "check.h"
#include "print.h"
#include "version.h"
#include "fileio.h"
#include "global.h"
#include "lineinfo.h"
+#include "memarea.h"
#include "o65.h"
+#include "spool.h"
#define MF_CPU_6502 0x0000 /* Executable is for the 6502 */
#define MF_CPU_MASK 0x8000 /* Mask to extract CPU type */
+#define MF_RELOC_PAGE 0x4000 /* Page wise relocation */
+#define MF_RELOC_BYTE 0x0000 /* Byte wise relocation */
+#define MF_RELOC_MASK 0x4000 /* Mask to extract relocation type */
+
#define MF_SIZE_32BIT 0x2000 /* All size words are 32bit */
#define MF_SIZE_16BIT 0x0000 /* All size words are 16bit */
#define MF_SIZE_MASK 0x2000 /* Mask to extract size */
+#define MF_FTYPE_OBJ 0x1000 /* Object file */
+#define MF_FTYPE_EXE 0x0000 /* Executable file */
+#define MF_FTYPE_MASK 0x1000 /* Mask to extract type */
+
+#define MF_ADDR_SIMPLE 0x0800 /* Simple addressing */
+#define MF_ADDR_DEFAULT 0x0000 /* Default addressing */
+#define MF_ADDR_MASK 0x0800 /* Mask to extract addressing */
+
#define MF_ALIGN_1 0x0000 /* Bytewise alignment */
#define MF_ALIGN_2 0x0001 /* Align words */
#define MF_ALIGN_4 0x0002 /* Align longwords */
typedef struct O65Option O65Option;
struct O65Option {
O65Option* Next; /* Next in option list */
- unsigned char Type; /* Type of option */
- unsigned char Len; /* Data length */
- unsigned char Data [1]; /* Data, dynamically allocated */
+ unsigned char Type; /* Type of option */
+ unsigned char Len; /* Data length */
+ unsigned char Data [1]; /* Data, dynamically allocated */
};
/* A o65 relocation table */
-#define RELOC_BLOCKSIZE 4096
typedef struct O65RelocTab O65RelocTab;
struct O65RelocTab {
- unsigned Size; /* Size of the table */
- unsigned Fill; /* Amount used */
- unsigned char* Buf; /* Buffer, dynamically allocated */
+ unsigned Size; /* Size of the table */
+ unsigned Fill; /* Amount used */
+ unsigned char* Buf; /* Buffer, dynamically allocated */
};
/* Structure describing the format */
struct O65Desc {
- O65Header Header; /* File header */
- O65Option* Options; /* List of file options */
- ExtSymTab* Exports; /* Table with exported symbols */
- ExtSymTab* Imports; /* Table with imported symbols */
- unsigned Undef; /* Count of undefined symbols */
- FILE* F; /* The file we're writing to */
- char* Filename; /* Name of the output file */
- O65RelocTab* TextReloc; /* Relocation table for text segment */
- O65RelocTab* DataReloc; /* Relocation table for data segment */
-
- unsigned TextCount; /* Number of segments assigned to .text */
- SegDesc** TextSeg; /* Array of text segments */
- unsigned DataCount; /* Number of segments assigned to .data */
- SegDesc** DataSeg; /* Array of data segments */
- unsigned BssCount; /* Number of segments assigned to .bss */
- SegDesc** BssSeg; /* Array of bss segments */
- unsigned ZPCount; /* Number of segments assigned to .zp */
- SegDesc** ZPSeg; /* Array of zp segments */
+ O65Header Header; /* File header */
+ O65Option* Options; /* List of file options */
+ ExtSymTab* Exports; /* Table with exported symbols */
+ ExtSymTab* Imports; /* Table with imported symbols */
+ unsigned Undef; /* Count of undefined symbols */
+ FILE* F; /* The file we're writing to */
+ const char* Filename; /* Name of the output file */
+ O65RelocTab* TextReloc; /* Relocation table for text segment */
+ O65RelocTab* DataReloc; /* Relocation table for data segment */
+
+ unsigned TextCount; /* Number of segments assigned to .text */
+ SegDesc** TextSeg; /* Array of text segments */
+ unsigned DataCount; /* Number of segments assigned to .data */
+ SegDesc** DataSeg; /* Array of data segments */
+ unsigned BssCount; /* Number of segments assigned to .bss */
+ SegDesc** BssSeg; /* Array of bss segments */
+ unsigned ZPCount; /* Number of segments assigned to .zp */
+ SegDesc** ZPSeg; /* Array of zp segments */
/* Temporary data for writing segments */
unsigned long SegSize;
O65Desc* D; /* File format descriptor */
long Val; /* The offset value */
int TooComplex; /* Expression too complex */
- Section* SegRef; /* Section referenced if any */
+ MemoryArea* MemRef; /* Memory reference if any */
+ Segment* SegRef; /* Segment reference if any */
+ Section* SecRef; /* Section reference if any */
ExtSym* ExtRef; /* External reference if any */
};
ED->D = D;
ED->Val = 0;
ED->TooComplex = 0;
+ ED->MemRef = 0;
ED->SegRef = 0;
+ ED->SecRef = 0;
ED->ExtRef = 0;
return ED;
}
+static void CvtMemoryToSegment (ExprDesc* ED)
+/* Convert a memory area into a segment by searching the list of run segments
+ * in this memory area and assigning the nearest one.
+ */
+{
+ /* Get the memory area from the expression */
+ MemoryArea* M = ED->MemRef;
+
+ /* Remember the "nearest" segment and its offset */
+ Segment* Nearest = 0;
+ unsigned long Offs = ULONG_MAX;
+
+ /* Walk over all segments */
+ unsigned I;
+ for (I = 0; I < CollCount (&M->SegList); ++I) {
+
+ /* Get the segment and check if it's a run segment */
+ SegDesc* S = CollAtUnchecked (&M->SegList, I);
+ if (S->Run == M) {
+
+ unsigned long O;
+
+ /* Get the segment from the segment descriptor */
+ Segment* Seg = S->Seg;
+
+ /* Check the PC. */
+ if ((long) Seg->PC <= ED->Val && (O = (ED->Val - Seg->PC)) < Offs) {
+ /* This is the nearest segment for now */
+ Offs = O;
+ Nearest = Seg;
+
+ /* If we found an exact match, don't look further */
+ if (Offs == 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ /* If we found a segment, use it and adjust the offset */
+ if (Nearest) {
+ ED->SegRef = Nearest;
+ ED->MemRef = 0;
+ ED->Val -= Nearest->PC;
+ }
+}
+
+
+
static const SegDesc* FindSeg (SegDesc** const List, unsigned Count, const Segment* S)
/* Search for a segment in the given list of segment descriptors and return
* the descriptor for a segment if we found it, and NULL if not.
/*****************************************************************************/
-/* Expression handling */
+/* Expression handling */
/*****************************************************************************/
switch (Expr->Op) {
case EXPR_LITERAL:
- if (Sign < 0) {
- D->Val -= Expr->V.Val;
- } else {
- D->Val += Expr->V.Val;
- }
+ D->Val += (Sign * Expr->V.IVal);
break;
case EXPR_SYMBOL:
}
break;
- case EXPR_SEGMENT:
+ case EXPR_SECTION:
+ if (D->SecRef) {
+ /* We cannot handle more than one segment reference in o65 */
+ D->TooComplex = 1;
+ } else {
+ /* Remember the segment reference */
+ D->SecRef = GetExprSection (Expr);
+ /* Add the offset of the section to the constant value */
+ D->Val += Sign * (D->SecRef->Offs + D->SecRef->Seg->PC);
+ }
+ break;
+
+ case EXPR_SEGMENT:
if (D->SegRef) {
/* We cannot handle more than one segment reference in o65 */
D->TooComplex = 1;
} else {
/* Remember the segment reference */
- D->SegRef = GetExprSection (Expr);
+ D->SegRef = Expr->V.Seg;
+ /* Add the offset of the segment to the constant value */
+ D->Val += (Sign * D->SegRef->PC);
+ }
+ break;
+
+ case EXPR_MEMAREA:
+ if (D->MemRef) {
+ /* We cannot handle more than one memory reference in o65 */
+ D->TooComplex = 1;
+ } else {
+ /* Remember the memory area reference */
+ D->MemRef = Expr->V.Mem;
+ /* Add the start address of the memory area to the constant
+ * value
+ */
+ D->Val += (Sign * D->MemRef->Start);
}
break;
O65RelocTab* R = xmalloc (sizeof (O65RelocTab));
/* Initialize the data */
- R->Size = RELOC_BLOCKSIZE;
+ R->Size = 0;
R->Fill = 0;
- R->Buf = xmalloc (RELOC_BLOCKSIZE);
+ R->Buf = 0;
/* Return the created struct */
return R;
/* Do we have enough space in the buffer? */
if (R->Fill == R->Size) {
/* We need to grow the buffer */
- unsigned char* NewBuf = xmalloc (R->Size + RELOC_BLOCKSIZE);
- memcpy (NewBuf, R->Buf, R->Size);
- xfree (R->Buf);
- R->Buf = NewBuf;
+ if (R->Size) {
+ R->Size *= 2;
+ } else {
+ R->Size = 1024; /* Initial size */
+ }
+ R->Buf = xrealloc (R->Buf, R->Size);
}
/* Put the byte into the buffer */
O65Option* O;
-
/* Write the fixed header */
WriteData (D->F, Trailer, sizeof (Trailer));
Write8 (D->F, D->Header.Version);
* table.
*/
{
- long Diff;
- long BinVal;
- ExprNode* Expr;
- ExprDesc ED;
+ long Diff;
+ unsigned RefCount;
+ long BinVal;
+ ExprNode* Expr;
+ ExprDesc ED;
unsigned char RelocType;
/* Cast the Data pointer to its real type, an O65Desc */
/* Recursively collect information about this expression */
O65ParseExpr (Expr, InitExprDesc (&ED, D), 1);
- /* We cannot handle both, an imported symbol and a segment ref */
- if (ED.SegRef != 0 && ED.ExtRef != 0) {
+ /* We cannot handle more than one external reference */
+ RefCount = (ED.MemRef != 0) + (ED.SegRef != 0) +
+ (ED.SecRef != 0) + (ED.ExtRef != 0);
+ if (RefCount > 1) {
ED.TooComplex = 1;
}
+ /* If we have a memory area reference, we need to convert it into a
+ * segment reference. If we cannot do that, we cannot handle the
+ * expression.
+ */
+ if (ED.MemRef) {
+ CvtMemoryToSegment (&ED);
+ if (ED.SegRef == 0) {
+ return SEG_EXPR_TOO_COMPLEX;
+ }
+ }
+
/* Bail out if we cannot handle the expression */
if (ED.TooComplex) {
return SEG_EXPR_TOO_COMPLEX;
}
- /* Safety: Check that we are really referencing a symbol or a segment */
- CHECK (ED.SegRef != 0 || ED.ExtRef != 0);
+ /* Safety: Check that we have exactly one reference */
+ CHECK (RefCount == 1);
/* Write out the offset that goes into the segment. */
BinVal = ED.Val;
switch (Size) {
case 1:
- RelocType = O65RELOC_LOW;
- break;
+ RelocType = O65RELOC_LOW;
+ break;
case 2:
RelocType = O65RELOC_WORD;
- break;
+ break;
case 3:
- RelocType = O65RELOC_SEGADR;
- break;
+ RelocType = O65RELOC_SEGADR;
+ break;
case 4:
- /* 4 byte expression not supported by o65 */
- return SEG_EXPR_TOO_COMPLEX;
+ /* 4 byte expression not supported by o65 */
+ return SEG_EXPR_TOO_COMPLEX;
default:
- Internal ("O65WriteExpr: Invalid expression size: %u", Size);
- RelocType = 0; /* Avoid gcc warnings */
+ Internal ("O65WriteExpr: Invalid expression size: %u", Size);
+ RelocType = 0; /* Avoid gcc warnings */
}
}
/* Determine which segment we're referencing */
- if (ED.ExtRef) {
+ if (ED.SegRef || ED.SecRef) {
+
+ const SegDesc* Seg;
+
+ /* Segment or section reference. */
+ if (ED.SecRef) {
+ /* Get segment from section */
+ ED.SegRef = ED.SecRef->Seg;
+ }
+
+ /* Search for the segment and map it to it's o65 segmentID */
+ Seg = O65FindSeg (D, ED.SegRef);
+ if (Seg == 0) {
+ /* For some reason, we didn't find this segment in the list of
+ * segments written to the o65 file.
+ */
+ return SEG_EXPR_INVALID;
+ }
+ RelocType |= O65SegType (Seg);
+ O65RelocPutByte (D->CurReloc, RelocType);
+
+ /* Output additional data if needed */
+ switch (RelocType & O65RELOC_MASK) {
+ case O65RELOC_HIGH:
+ O65RelocPutByte (D->CurReloc, ED.Val & 0xFF);
+ break;
+ case O65RELOC_SEG:
+ O65RelocPutWord (D->CurReloc, ED.Val & 0xFFFF);
+ break;
+ }
+
+ } else if (ED.ExtRef) {
/* Imported symbol */
RelocType |= O65SEG_UNDEF;
O65RelocPutByte (D->CurReloc, RelocType);
/* Put the number of the imported symbol into the table */
O65RelocPutWord (D->CurReloc, ExtSymNum (ED.ExtRef));
+
} else {
- /* Segment reference. Search for the segment and map it to it's
- * o65 segmentID
- */
- const SegDesc* Seg = O65FindSeg (D, ED.SegRef->Seg);
- if (Seg == 0) {
- /* For some reason, we didn't find this segment in the list of
- * segments written to the o65 file.
- */
- return SEG_EXPR_INVALID;
- }
- RelocType |= O65SegType (Seg);
- O65RelocPutByte (D->CurReloc, RelocType);
-
- /* Output additional data if needed */
- switch (RelocType & O65RELOC_MASK) {
- case O65RELOC_HIGH:
- O65RelocPutByte (D->CurReloc, ED.Val & 0xFF);
- break;
- case O65RELOC_SEG:
- O65RelocPutWord (D->CurReloc, ED.Val & 0xFFFF);
- break;
- }
+
+ /* OOPS - something bad happened */
+ Internal ("External reference not handled");
+
}
/* Success */
S = Seg [I];
/* Keep the user happy */
- Print (stdout, 1, " Writing `%s'\n", S->Name);
+ Print (stdout, 1, " Writing `%s'\n", GetString (S->Name));
/* Write this segment */
if (DoWrite) {
- RelocLineInfo (S->Seg);
- SegWrite (D->F, S->Seg, O65WriteExpr, D);
+ SegWrite (D->Filename, D->F, S->Seg, O65WriteExpr, D);
}
/* Mark the segment as dumped */
-static void O65WriteTextSeg (O65Desc* D, Memory* M attribute ((unused)))
+static void O65WriteTextSeg (O65Desc* D)
/* Write the code segment to the o65 output file */
{
/* Initialize variables */
-static void O65WriteDataSeg (O65Desc* D, Memory* M attribute ((unused)))
+static void O65WriteDataSeg (O65Desc* D)
/* Write the data segment to the o65 output file */
{
/* Initialize variables */
-static void O65WriteBssSeg (O65Desc* D, Memory* M attribute ((unused)))
+static void O65WriteBssSeg (O65Desc* D)
/* "Write" the bss segments to the o65 output file. This will only update
* the relevant header fields.
*/
-static void O65WriteZPSeg (O65Desc* D, Memory* M attribute ((unused)))
+static void O65WriteZPSeg (O65Desc* D)
/* "Write" the zeropage segments to the o65 output file. This will only update
* the relevant header fields.
*/
S = ExtSymList (D->Imports);
while (S) {
/* Get the name */
- const char* Name = ExtSymName (S);
+ const char* Name = GetString (ExtSymName (S));
/* And write it to the output file */
WriteData (D->F, Name, strlen (Name) + 1);
/* Next symbol */
ExprDesc ED;
/* Get the name */
- const char* Name = ExtSymName (S);
+ unsigned NameIdx = ExtSymName (S);
+ const char* Name = GetString (NameIdx);
/* Get the export for this symbol. We've checked before that this
* export does really exist, so if it is unresolved, or if we don't
* find it, there is an error in the linker code.
*/
- Export* E = FindExport (Name);
+ Export* E = FindExport (NameIdx);
if (E == 0 || IsUnresolvedExport (E)) {
Internal ("Unresolved export `%s' found in O65WriteExports", Name);
}
/* Recursively collect information about this expression */
O65ParseExpr (Expr, InitExprDesc (&ED, D), 1);
- /* We cannot handle expressions with imported symbols here */
- if (ED.ExtRef != 0) {
+ /* We cannot handle expressions with imported symbols, or expressions
+ * with more than one segment reference here
+ */
+ if (ED.ExtRef != 0 || (ED.SegRef != 0 && ED.SecRef != 0)) {
ED.TooComplex = 1;
}
}
/* Determine the segment id for the expression */
- if (ED.SegRef == 0) {
- /* Absolute value */
- SegmentID = O65SEG_ABS;
- } else {
- /* Segment reference. Search for the segment and map it to it's
- * o65 segmentID
- */
- const SegDesc* Seg = O65FindSeg (D, ED.SegRef->Seg);
+ if (ED.SegRef != 0 || ED.SecRef != 0) {
+
+ const SegDesc* Seg;
+
+ /* Segment or section reference */
+ if (ED.SecRef != 0) {
+ ED.SegRef = ED.SecRef->Seg; /* Get segment from section */
+ }
+
+ /* Search for the segment and map it to it's o65 segmentID */
+ Seg = O65FindSeg (D, ED.SegRef);
if (Seg == 0) {
/* For some reason, we didn't find this segment in the list of
* segments written to the o65 file.
Error ("Segment for symbol `%s' is undefined", Name);
}
SegmentID = O65SegType (Seg);
+
+ } else {
+
+ /* Absolute value */
+ SegmentID = O65SEG_ABS;
+
}
/* Write the name to the output file */
-void O65SetAlignment (O65Desc* D, unsigned Align)
+void O65SetAlignment (O65Desc* D, unsigned Alignment)
/* Set the executable alignment */
{
/* Remove all alignment bits from the mode word */
D->Header.Mode &= ~MF_ALIGN_MASK;
/* Set the alignment bits */
- switch (Align) {
+ switch (Alignment) {
case 1: D->Header.Mode |= MF_ALIGN_1; break;
case 2: D->Header.Mode |= MF_ALIGN_2; break;
case 4: D->Header.Mode |= MF_ALIGN_4; break;
case 256: D->Header.Mode |= MF_ALIGN_256; break;
- default: Error ("Invalid alignment for O65 format: %u", Align);
+ default: Error ("Invalid alignment for O65 format: %u", Alignment);
}
}
/* Write the correct option length */
switch (OS) {
- case O65OS_OSA65:
- case O65OS_LUNIX:
- /* No id for these two */
- O65SetOption (D, O65OPT_OS, Opt, 2);
- break;
case O65OS_CC65:
/* Set the 16 bit id */
break;
default:
- Internal ("Trying to set invalid O65 operating system: %u", OS);
+ /* No id for OS/A65, Lunix, and unknown OSes */
+ O65SetOption (D, O65OPT_OS, Opt, 2);
+ break;
+
}
}
-ExtSym* O65GetImport (O65Desc* D, const char* Ident)
+ExtSym* O65GetImport (O65Desc* D, unsigned Ident)
/* Return the imported symbol or NULL if not found */
{
/* Retrieve the symbol from the table */
-void O65SetImport (O65Desc* D, const char* Ident)
+void O65SetImport (O65Desc* D, unsigned Ident)
/* Set an imported identifier */
{
/* Insert the entry into the table */
-ExtSym* O65GetExport (O65Desc* D, const char* Ident)
+ExtSym* O65GetExport (O65Desc* D, unsigned Ident)
/* Return the exported symbol or NULL if not found */
{
/* Retrieve the symbol from the table */
-void O65SetExport (O65Desc* D, const char* Ident)
+void O65SetExport (O65Desc* D, unsigned Ident)
/* Set an exported identifier */
{
/* Get the export for this symbol and check if it does exist and is
*/
Export* E = FindExport (Ident);
if (E == 0 || IsUnresolvedExport (E)) {
- Error ("Unresolved export: `%s'", Ident);
+ Error ("Unresolved export: `%s'", GetString (Ident));
}
/* Insert the entry into the table */
-static void O65SetupSegments (O65Desc* D, Memory* M)
+static void O65SetupSegments (O65Desc* D, File* F)
/* Setup segment assignments */
{
- MemListNode* N;
- SegDesc* S;
+ unsigned I;
unsigned TextIdx, DataIdx, BssIdx, ZPIdx;
/* Initialize the counters */
D->BssCount = 0;
D->ZPCount = 0;
- /* Walk through the segment list and count the segment types */
- N = M->SegList;
- while (N) {
-
- /* Get the segment from the list node */
- S = N->Seg;
-
- /* Check the segment type. */
- switch (O65SegType (S)) {
- case O65SEG_TEXT: D->TextCount++; break;
- case O65SEG_DATA: D->DataCount++; break;
- case O65SEG_BSS: D->BssCount++; break;
- case O65SEG_ZP: D->ZPCount++; break;
- default: Internal ("Invalid return from O65SegType");
- }
-
- /* Next segment node */
- N = N->Next;
+ /* Walk over the memory list */
+ for (I = 0; I < CollCount (&F->MemoryAreas); ++I) {
+ /* Get this entry */
+ MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, I);
+
+ /* Walk through the segment list and count the segment types */
+ unsigned J;
+ for (J = 0; J < CollCount (&M->SegList); ++J) {
+
+ /* Get the segment */
+ SegDesc* S = CollAtUnchecked (&M->SegList, J);
+
+ /* Check the segment type. */
+ switch (O65SegType (S)) {
+ case O65SEG_TEXT: D->TextCount++; break;
+ case O65SEG_DATA: D->DataCount++; break;
+ case O65SEG_BSS: D->BssCount++; break;
+ case O65SEG_ZP: D->ZPCount++; break;
+ default: Internal ("Invalid return from O65SegType");
+ }
+ }
}
/* Allocate memory according to the numbers */
/* Walk again through the list and setup the segment arrays */
TextIdx = DataIdx = BssIdx = ZPIdx = 0;
- N = M->SegList;
- while (N) {
-
- /* Get the segment from the list node */
- S = N->Seg;
-
- /* Check the segment type. */
- switch (O65SegType (S)) {
- case O65SEG_TEXT: D->TextSeg [TextIdx++] = S; break;
- case O65SEG_DATA: D->DataSeg [DataIdx++] = S; break;
- case O65SEG_BSS: D->BssSeg [BssIdx++] = S; break;
- case O65SEG_ZP: D->ZPSeg [ZPIdx++] = S; break;
- default: Internal ("Invalid return from O65SegType");
- }
-
- /* Next segment node */
- N = N->Next;
+ for (I = 0; I < CollCount (&F->MemoryAreas); ++I) {
+ /* Get this entry */
+ MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, I);
+
+ /* Walk over the segment list and check the segment types */
+ unsigned J;
+ for (J = 0; J < CollCount (&M->SegList); ++J) {
+
+ /* Get the segment */
+ SegDesc* S = CollAtUnchecked (&M->SegList, J);
+
+ /* Check the segment type. */
+ switch (O65SegType (S)) {
+ case O65SEG_TEXT: D->TextSeg [TextIdx++] = S; break;
+ case O65SEG_DATA: D->DataSeg [DataIdx++] = S; break;
+ case O65SEG_BSS: D->BssSeg [BssIdx++] = S; break;
+ case O65SEG_ZP: D->ZPSeg [ZPIdx++] = S; break;
+ default: Internal ("Invalid return from O65SegType");
+ }
+ }
}
}
-static int O65Unresolved (const char* Name, void* D)
+static int O65Unresolved (unsigned Name, void* D)
/* Called if an unresolved symbol is encountered */
{
/* Check if the symbol is an imported o65 symbol */
+static void O65SetupHeader (O65Desc* D)
+/* Set additional stuff in the header */
+{
+ /* Set the base addresses of the segments */
+ if (D->TextCount > 0) {
+ SegDesc* FirstSeg = D->TextSeg [0];
+ D->Header.TextBase = FirstSeg->Seg->PC;
+ }
+ if (D->DataCount > 0) {
+ SegDesc* FirstSeg = D->DataSeg [0];
+ D->Header.DataBase = FirstSeg->Seg->PC;
+ }
+ if (D->BssCount > 0) {
+ SegDesc* FirstSeg = D->BssSeg [0];
+ D->Header.BssBase = FirstSeg->Seg->PC;
+ }
+ if (D->ZPCount > 0) {
+ SegDesc* FirstSeg = D->ZPSeg [0];
+ D->Header.ZPBase = FirstSeg->Seg->PC;
+ }
+
+ /* If we have byte wise relocation and an alignment of 1, we can set
+ * the "simple addressing" bit in the header.
+ */
+ if ((D->Header.Mode & MF_RELOC_MASK) == MF_RELOC_BYTE &&
+ (D->Header.Mode & MF_ALIGN_MASK) == MF_ALIGN_1) {
+ D->Header.Mode = (D->Header.Mode & ~MF_ADDR_MASK) | MF_ADDR_SIMPLE;
+ }
+}
+
+
+
void O65WriteTarget (O65Desc* D, File* F)
/* Write an o65 output file */
{
- Memory* M;
- char OptBuf [256]; /* Buffer for option strings */
- time_t T;
+ char OptBuf [256]; /* Buffer for option strings */
+ unsigned OptLen;
+ time_t T;
/* Place the filename in the control structure */
- D->Filename = F->Name;
-
- /* The o65 format uses only one memory area per file. Check that. */
- M = F->MemList;
- if (M->Next != 0) {
- Warning ("Cannot handle more than one memory area for o65 format");
- }
+ D->Filename = GetString (F->Name);
/* Check for unresolved symbols. The function O65Unresolved is called
* if we get an unresolved symbol.
*/
D->Undef = 0; /* Reset the counter */
- CheckExports (O65Unresolved, D);
+ CheckUnresolvedImports (O65Unresolved, 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);
}
/* Setup the segment arrays */
- O65SetupSegments (D, M);
+ O65SetupSegments (D, F);
+
+ /* Setup additional stuff in the header */
+ O65SetupHeader (D);
/* 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);
/* Define some more options: A timestamp and the linker version */
T = time (0);
strcpy (OptBuf, ctime (&T));
- O65SetOption (D, O65OPT_TIMESTAMP, OptBuf, strlen (OptBuf) + 1);
- sprintf (OptBuf, "ld65 V%u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH);
+ OptLen = strlen (OptBuf);
+ while (OptLen > 0 && IsControl (OptBuf[OptLen-1])) {
+ --OptLen;
+ }
+ OptBuf[OptLen] = '\0';
+ O65SetOption (D, O65OPT_TIMESTAMP, OptBuf, OptLen + 1);
+ sprintf (OptBuf, "ld65 V%s", GetVersionAsString ());
O65SetOption (D, O65OPT_ASM, OptBuf, strlen (OptBuf) + 1);
/* Write the header */
O65WriteHeader (D);
/* Write the text segment */
- O65WriteTextSeg (D, M);
+ O65WriteTextSeg (D);
/* Write the data segment */
- O65WriteDataSeg (D, M);
+ O65WriteDataSeg (D);
/* "Write" the bss segments */
- O65WriteBssSeg (D, M);
+ O65WriteBssSeg (D);
/* "Write" the zeropage segments */
- O65WriteZPSeg (D, M);
+ O65WriteZPSeg (D);
/* Write the undefined references list */
O65WriteImports (D);
/* 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 */
+