X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fld65%2Fo65.c;h=8fe7cef4c2a0b7bdbf91817016bd59acfa2a8ecc;hb=dbbce2e939af8fd78f659e5c66eea8b002369ba2;hp=a30d5916451bbf55d24ad50958e63e89001aaa3d;hpb=2767f66146ff0af2d26933a2f9cae6282c4bd6b6;p=cc65 diff --git a/src/ld65/o65.c b/src/ld65/o65.c index a30d59164..8fe7cef4c 100644 --- a/src/ld65/o65.c +++ b/src/ld65/o65.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 1999 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@musoftware.de */ +/* (C) 1999-2001 Ullrich von Bassewitz */ +/* Wacholderweg 14 */ +/* D-70597 Stuttgart */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -38,14 +38,20 @@ #include #include -#include "../common/version.h" -#include "../common/xmalloc.h" +/* common */ +#include "chartype.h" +#include "check.h" +#include "print.h" +#include "version.h" +#include "xmalloc.h" +/* ld65 */ #include "error.h" #include "exports.h" #include "expr.h" #include "fileio.h" #include "global.h" +#include "lineinfo.h" #include "o65.h" @@ -57,8 +63,31 @@ /* Header mode bits */ +#define MF_CPU_65816 0x8000 /* Executable is for 65816 */ +#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_CPU_816 0x8000 /* Executable is for 65816 */ +#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 */ +#define MF_ALIGN_256 0x0003 /* Align pages (256 bytes) */ +#define MF_ALIGN_MASK 0x0003 /* Mask to extract alignment */ /* The four o65 segment types. Note: These values are identical to the values * needed for the segmentID in the o65 spec. @@ -68,18 +97,19 @@ #define O65SEG_TEXT 0x02 #define O65SEG_DATA 0x03 #define O65SEG_BSS 0x04 -#define O65SEG_ZP 0x05 +#define O65SEG_ZP 0x05 /* Relocation type codes for the o65 format */ #define O65RELOC_WORD 0x80 #define O65RELOC_HIGH 0x40 #define O65RELOC_LOW 0x20 -#define O65RELOC_SEGADR 0xc0 -#define O65RELOC_SEG 0xa0 +#define O65RELOC_SEGADR 0xC0 +#define O65RELOC_SEG 0xA0 +#define O65RELOC_MASK 0xE0 /* O65 executable file header */ -typedef struct O65Header_ O65Header; -struct O65Header_ { +typedef struct O65Header O65Header; +struct O65Header { unsigned Version; /* Version number for o65 format */ unsigned Mode; /* Mode word */ unsigned long TextBase; /* Base address of text segment */ @@ -94,75 +124,90 @@ struct O65Header_ { }; /* An o65 option */ -typedef struct O65Option_ O65Option; -struct O65Option_ { +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 */ +typedef struct O65RelocTab O65RelocTab; +struct O65RelocTab { + 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 */ +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 */ /* Temporary data for writing segments */ unsigned long SegSize; O65RelocTab* CurReloc; - long LastOffs; + long LastOffs; }; /* Structure for parsing expression trees */ -typedef struct ExprDesc_ ExprDesc; -struct ExprDesc_ { - O65Desc* D; /* File format descriptor */ - long Val; /* The offset value */ +typedef struct ExprDesc ExprDesc; +struct ExprDesc { + O65Desc* D; /* File format descriptor */ + long Val; /* The offset value */ int TooComplex; /* Expression too complex */ - Section* SegRef; /* Section referenced if any */ - ExtSym* ExtRef; /* External reference if any */ + Segment* SegRef; /* Segment reference if any */ + Section* SecRef; /* Section reference if any */ + ExtSym* ExtRef; /* External reference if any */ }; /*****************************************************************************/ -/* Helper functions */ +/* Helper functions */ /*****************************************************************************/ +static ExprDesc* InitExprDesc (ExprDesc* ED, O65Desc* D) +/* Initialize an ExprDesc structure for use with O65ParseExpr */ +{ + ED->D = D; + ED->Val = 0; + ED->TooComplex = 0; + ED->SegRef = 0; + ED->SecRef = 0; + ED->ExtRef = 0; + return ED; +} + + + static void WriteSize (const O65Desc* D, unsigned long Val) /* Write a "size" word to the file */ { - if (D->Header.Mode & MF_SIZE_32BIT) { - Write32 (D->F, Val); - } else { - Write16 (D->F, (unsigned) Val); + switch (D->Header.Mode & MF_SIZE_MASK) { + case MF_SIZE_16BIT: Write16 (D->F, (unsigned) Val); break; + case MF_SIZE_32BIT: Write32 (D->F, Val); break; + default: Internal ("Invalid size in header: %04X", D->Header.Mode); } } @@ -178,20 +223,64 @@ static unsigned O65SegType (const SegDesc* S) * to check SF_ZP first. */ if (S->Flags & SF_RO) { - return O65SEG_TEXT; + return O65SEG_TEXT; } else if (S->Flags & SF_ZP) { - return O65SEG_ZP; + return O65SEG_ZP; } else if (S->Flags & SF_BSS) { - return O65SEG_BSS; + return O65SEG_BSS; } else { - return O65SEG_DATA; + return O65SEG_DATA; + } +} + + + +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. + */ +{ + unsigned I; + + for (I = 0; I < Count; ++I) { + if (List[I]->Seg == S) { + /* Found */ + return List[I]; + } + } + + /* Not found */ + return 0; +} + + + +static const SegDesc* O65FindSeg (const O65Desc* D, const Segment* S) +/* Search for a segment in the segment lists and return it's segment descriptor */ +{ + const SegDesc* SD; + + if ((SD = FindSeg (D->TextSeg, D->TextCount, S)) != 0) { + return SD; + } + if ((SD = FindSeg (D->DataSeg, D->DataCount, S)) != 0) { + return SD; + } + if ((SD = FindSeg (D->BssSeg, D->BssCount, S)) != 0) { + return SD; } + if ((SD = FindSeg (D->ZPSeg, D->ZPCount, S)) != 0) { + return SD; + } + + /* Not found */ + return 0; } /*****************************************************************************/ -/* Expression handling */ +/* Expression handling */ /*****************************************************************************/ @@ -203,6 +292,7 @@ static void O65ParseExpr (ExprNode* Expr, ExprDesc* D, int Sign) */ { Export* E; + unsigned long Val; switch (Expr->Op) { @@ -236,18 +326,42 @@ static void O65ParseExpr (ExprNode* Expr, ExprDesc* D, int Sign) } } else { MarkExport (E); - O65ParseExpr (E->Expr, D, Sign); + O65ParseExpr (E->Expr, D, Sign); UnmarkExport (E); } 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 */ + Val = D->SecRef->Offs + D->SecRef->Seg->PC; + if (Sign < 0) { + D->Val -= Val; + } else { + D->Val += Val; + } + } + 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); + /* Remember the segment reference */ + D->SegRef = Expr->V.Seg; + /* Add the offset of the segment to the constant value */ + Val = D->SegRef->PC; + if (Sign < 0) { + D->Val -= Val; + } else { + D->Val += Val; + } } break; @@ -339,7 +453,7 @@ static void O65WriteReloc (O65RelocTab* R, FILE* F) /*****************************************************************************/ -/* Option handling */ +/* Option handling */ /*****************************************************************************/ @@ -376,7 +490,7 @@ static void FreeO65Option (O65Option* O) /*****************************************************************************/ -/* Subroutines to write o65 sections */ +/* Subroutines to write o65 sections */ /*****************************************************************************/ @@ -390,7 +504,6 @@ static void O65WriteHeader (O65Desc* D) O65Option* O; - /* Write the fixed header */ WriteData (D->F, Trailer, sizeof (Trailer)); Write8 (D->F, D->Header.Version); @@ -423,16 +536,17 @@ static void O65WriteHeader (O65Desc* D) static unsigned O65WriteExpr (ExprNode* E, int Signed, unsigned Size, - unsigned long Offs, void* Data) + unsigned long Offs, void* Data) /* Called from SegWrite for an expression. Evaluate the expression, check the * range and write the expression value to the file, update the relocation * 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 */ @@ -448,11 +562,11 @@ static unsigned O65WriteExpr (ExprNode* E, int Signed, unsigned Size, * Calculate the number of bytes between this entry and the last one, and * setup all necessary intermediate bytes in the relocation table. */ - Offs += D->SegSize; /* Calulate full offset */ + Offs += D->SegSize; /* Calulate full offset */ Diff = ((long) Offs) - D->LastOffs; while (Diff > 0xFE) { - O65RelocPutByte (D->CurReloc, 0xFF); - Diff -= 0xFE; + O65RelocPutByte (D->CurReloc, 0xFF); + Diff -= 0xFE; } O65RelocPutByte (D->CurReloc, (unsigned char) Diff); @@ -461,86 +575,119 @@ static unsigned O65WriteExpr (ExprNode* E, int Signed, unsigned Size, /* Determine the expression to relocate */ Expr = E; - if (E->Op == EXPR_LOBYTE || E->Op == EXPR_HIBYTE) { - /* Use the real expression */ + if (E->Op == EXPR_BYTE0 || E->Op == EXPR_BYTE1 || + E->Op == EXPR_BYTE2 || E->Op == EXPR_BYTE3 || + E->Op == EXPR_WORD0 || E->Op == EXPR_WORD1) { + /* Use the real expression */ Expr = E->Left; } - /* Initialize the descriptor for expression parsing */ - ED.D = D; - ED.Val = 0; - ED.TooComplex = 0; - ED.SegRef = 0; - ED.ExtRef = 0; - /* Recursively collect information about this expression */ - O65ParseExpr (Expr, &ED, 1); + O65ParseExpr (Expr, InitExprDesc (&ED, D), 1); - /* We cannot handle both, an imported symbol and a segment ref */ - if (ED.SegRef != 0 && ED.ExtRef != 0) { - ED.TooComplex = 1; + /* We cannot handle more than one external reference */ + RefCount = (ED.SegRef != 0) + (ED.SecRef != 0) + (ED.ExtRef != 0); + if (RefCount > 1) { + ED.TooComplex = 1; } /* Bail out if we cannot handle the expression */ if (ED.TooComplex) { - return SEG_EXPR_TOO_COMPLEX; + 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; - if (E->Op == EXPR_LOBYTE) { - BinVal &= 0x00FF; - } else if (E->Op == EXPR_HIBYTE) { - BinVal = (BinVal >> 8) & 0x00FF; + switch (E->Op) { + case EXPR_BYTE0: BinVal &= 0xFF; break; + case EXPR_BYTE1: BinVal = (BinVal >> 8) & 0xFF; break; + case EXPR_BYTE2: BinVal = (BinVal >> 16) & 0xFF; break; + case EXPR_BYTE3: BinVal = (BinVal >> 24) & 0xFF; break; + case EXPR_WORD0: BinVal &= 0xFFFF; break; + case EXPR_WORD1: BinVal = (BinVal >> 16) & 0xFFFF; break; } WriteVal (D->F, BinVal, Size); /* Determine the actual type of relocation entry needed from the * information gathered about the expression. */ - if (E->Op == EXPR_LOBYTE) { - RelocType = O65RELOC_LOW; - } else if (E->Op == EXPR_HIBYTE) { - RelocType = O65RELOC_HIGH; + if (E->Op == EXPR_BYTE0) { + RelocType = O65RELOC_LOW; + } else if (E->Op == EXPR_BYTE1) { + RelocType = O65RELOC_HIGH; + } else if (E->Op == EXPR_BYTE2) { + RelocType = O65RELOC_SEG; } else { - switch (Size) { + switch (Size) { - case 1: - RelocType = O65RELOC_LOW; - break; + case 1: + RelocType = O65RELOC_LOW; + break; - case 2: - RelocType = O65RELOC_WORD; - break; + case 2: + RelocType = O65RELOC_WORD; + break; - case 3: - RelocType = O65RELOC_SEGADR; - break; + case 3: + RelocType = O65RELOC_SEGADR; + break; - case 4: - /* 4 byte expression not supported by o65 */ - return SEG_EXPR_TOO_COMPLEX; + case 4: + /* 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 */ - } + default: + Internal ("O65WriteExpr: Invalid expression size: %u", Size); + RelocType = 0; /* Avoid gcc warnings */ + } } /* Determine which segment we're referencing */ - if (ED.ExtRef) { - /* Imported symbol */ - RelocType |= O65SEG_UNDEF; + 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 */ + } else { + /* OOPS - something bad happened */ + Internal ("External reference not handled"); } @@ -567,37 +714,36 @@ static void O65WriteSeg (O65Desc* D, SegDesc** Seg, unsigned Count, int DoWrite) S = Seg [I]; /* Keep the user happy */ - if (Verbose) { - printf (" Writing `%s'\n", S->Name); - } + Print (stdout, 1, " Writing `%s'\n", S->Name); /* Write this segment */ - if (DoWrite) { + if (DoWrite) { + RelocLineInfo (S->Seg); SegWrite (D->F, S->Seg, O65WriteExpr, D); - } + } - /* Mark the segment as dumped */ - S->Seg->Dumped = 1; + /* Mark the segment as dumped */ + S->Seg->Dumped = 1; - /* Calculate the total size */ - D->SegSize += S->Seg->Size; + /* Calculate the total size */ + D->SegSize += S->Seg->Size; } - /* Terminate the relocation table for the this segment */ + /* Terminate the relocation table for this segment */ if (D->CurReloc) { O65RelocPutByte (D->CurReloc, 0); } /* Check the size of the segment for overflow */ - if ((D->Header.Mode & MF_SIZE_32BIT) == 0 && D->SegSize > 0xFFFF) { - Error ("Segment overflow in file `%s'", D->Filename); + if ((D->Header.Mode & MF_SIZE_MASK) == MF_SIZE_16BIT && D->SegSize > 0xFFFF) { + Error ("Segment overflow in file `%s'", D->Filename); } } -static void O65WriteTextSeg (O65Desc* D, Memory* M) +static void O65WriteTextSeg (O65Desc* D) /* Write the code segment to the o65 output file */ { /* Initialize variables */ @@ -612,7 +758,7 @@ static void O65WriteTextSeg (O65Desc* D, Memory* M) -static void O65WriteDataSeg (O65Desc* D, Memory* M) +static void O65WriteDataSeg (O65Desc* D) /* Write the data segment to the o65 output file */ { /* Initialize variables */ @@ -627,7 +773,7 @@ static void O65WriteDataSeg (O65Desc* D, Memory* M) -static void O65WriteBssSeg (O65Desc* D, Memory* M) +static void O65WriteBssSeg (O65Desc* D) /* "Write" the bss segments to the o65 output file. This will only update * the relevant header fields. */ @@ -644,7 +790,7 @@ static void O65WriteBssSeg (O65Desc* D, Memory* M) -static void O65WriteZPSeg (O65Desc* D, Memory* M) +static void O65WriteZPSeg (O65Desc* D) /* "Write" the zeropage segments to the o65 output file. This will only update * the relevant header fields. */ @@ -664,20 +810,20 @@ static void O65WriteZPSeg (O65Desc* D, Memory* M) static void O65WriteImports (O65Desc* D) /* Write the list of imported symbols to the O65 file */ { - const ExtSym* E; + const ExtSym* S; - /* Write the number of external symbols */ + /* Write the number of imports */ WriteSize (D, ExtSymCount (D->Imports)); /* Write out the symbol names, zero terminated */ - E = ExtSymList (D->Imports); - while (E) { - /* Get the name */ - const char* Name = ExtSymName (E); - /* And write it to the output file */ - WriteData (D->F, Name, strlen (Name) + 1); - /* Next symbol */ - E = ExtSymNext (E); + S = ExtSymList (D->Imports); + while (S) { + /* Get the name */ + const char* Name = ExtSymName (S); + /* And write it to the output file */ + WriteData (D->F, Name, strlen (Name) + 1); + /* Next symbol */ + S = ExtSymNext (S); } } @@ -702,8 +848,86 @@ static void O65WriteDataReloc (O65Desc* D) static void O65WriteExports (O65Desc* D) /* Write the list of exports */ { - /* For now... */ - WriteSize (D, 0); + const ExtSym* S; + + /* Write the number of exports */ + WriteSize (D, ExtSymCount (D->Exports)); + + /* Write out the symbol information */ + S = ExtSymList (D->Exports); + while (S) { + + ExprNode* Expr; + unsigned char SegmentID; + ExprDesc ED; + + /* Get the name */ + const char* Name = ExtSymName (S); + + /* 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); + if (E == 0 || IsUnresolvedExport (E)) { + Internal ("Unresolved export `%s' found in O65WriteExports", Name); + } + + /* Get the expression for the symbol */ + Expr = E->Expr; + + /* Recursively collect information about this expression */ + O65ParseExpr (Expr, InitExprDesc (&ED, D), 1); + + /* 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; + } + + /* Bail out if we cannot handle the expression */ + if (ED.TooComplex) { + Error ("Expression for symbol `%s' is too complex", Name); + } + + /* Determine the segment id for the expression */ + 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 */ + WriteData (D->F, Name, strlen (Name) + 1); + + /* Output the segment id followed by the literal value */ + Write8 (D->F, SegmentID); + WriteSize (D, ED.Val); + + /* Next symbol */ + S = ExtSymNext (S); + } } @@ -787,10 +1011,26 @@ void FreeO65Desc (O65Desc* D) -void O65Set816 (O65Desc* D) +void O65Set6502 (O65Desc* D) +/* Enable 6502 mode */ +{ + D->Header.Mode = (D->Header.Mode & ~MF_CPU_MASK) | MF_CPU_6502; +} + + + +void O65Set65816 (O65Desc* D) /* Enable 816 mode */ { - D->Header.Mode |= MF_CPU_816; + D->Header.Mode = (D->Header.Mode & ~MF_CPU_MASK) | MF_CPU_65816; +} + + + +void O65SetSmallModel (O65Desc* D) +/* Enable a small memory model executable */ +{ + D->Header.Mode = (D->Header.Mode & ~MF_SIZE_MASK) | MF_SIZE_16BIT; } @@ -798,7 +1038,7 @@ void O65Set816 (O65Desc* D) void O65SetLargeModel (O65Desc* D) /* Enable a large memory model executable */ { - D->Header.Mode |= MF_SIZE_32BIT; + D->Header.Mode = (D->Header.Mode & ~MF_SIZE_MASK) | MF_SIZE_32BIT; } @@ -807,14 +1047,14 @@ void O65SetAlignment (O65Desc* D, unsigned Align) /* Set the executable alignment */ { /* Remove all alignment bits from the mode word */ - D->Header.Mode &= ~0x0003; + D->Header.Mode &= ~MF_ALIGN_MASK; /* Set the alignment bits */ switch (Align) { - case 1: break; - case 2: D->Header.Mode |= 0x01; break; - case 4: D->Header.Mode |= 0x02; break; - case 256: D->Header.Mode |= 0x03; break; + 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); } } @@ -834,26 +1074,31 @@ void O65SetOption (O65Desc* D, unsigned Type, const void* Data, unsigned DataLen -void O65SetOS (O65Desc* D, unsigned OS) +void O65SetOS (O65Desc* D, unsigned OS, unsigned Version, unsigned Id) /* Set an option describing the target operating system */ { - static const unsigned char OSA65 [2] = { O65OS_OSA65, 0 }; - static const unsigned char Lunix [2] = { O65OS_LUNIX, 0 }; + /* Setup the option data */ + unsigned char Opt[4]; + Opt[0] = OS; + Opt[1] = Version; - /* Write the correct option */ + /* Write the correct option length */ switch (OS) { - case O65OS_OSA65: - O65SetOption (D, O65OPT_OS, OSA65, sizeof (OSA65)); + case O65OS_LUNIX: + /* No id for these two */ + O65SetOption (D, O65OPT_OS, Opt, 2); break; - case O65OS_LUNIX: - O65SetOption (D, O65OPT_OS, Lunix, sizeof (Lunix)); + case O65OS_CC65: + /* Set the 16 bit id */ + Opt[2] = (unsigned char) Id; + Opt[3] = (unsigned char) (Id >> 8); + O65SetOption (D, O65OPT_OS, Opt, 4); break; default: Internal ("Trying to set invalid O65 operating system: %u", OS); - } } @@ -889,15 +1134,24 @@ ExtSym* O65GetExport (O65Desc* D, const char* Ident) void O65SetExport (O65Desc* D, const char* Ident) /* Set an exported identifier */ { + /* Get the export for this symbol and check if it does exist and is + * a resolved symbol. + */ + Export* E = FindExport (Ident); + if (E == 0 || IsUnresolvedExport (E)) { + Error ("Unresolved export: `%s'", Ident); + } + /* Insert the entry into the table */ NewExtSym (D->Exports, Ident); } -static void O65SetupSegments (O65Desc* D, Memory* M) +static void O65SetupSegments (O65Desc* D, File* F) /* Setup segment assignments */ { + Memory* M; MemListNode* N; SegDesc* S; unsigned TextIdx, DataIdx, BssIdx, ZPIdx; @@ -908,24 +1162,30 @@ static void O65SetupSegments (O65Desc* D, Memory* M) D->BssCount = 0; D->ZPCount = 0; - /* Walk through the memory 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 */ + M = F->MemList; + while (M) { + /* 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; + } + /* Next memory area */ + M = M->FNext; } /* Allocate memory according to the numbers */ @@ -936,23 +1196,29 @@ static void O65SetupSegments (O65Desc* D, Memory* M) /* 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; + M = F->MemList; + while (M) { + + 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; + } + /* Next memory area */ + M = M->FNext; } } @@ -974,22 +1240,48 @@ static int O65Unresolved (const char* Name, void* D) +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"); - } - /* Check for unresolved symbols. The function O65Unresolved is called * if we get an unresolved symbol. */ @@ -1001,7 +1293,10 @@ void O65WriteTarget (O65Desc* D, File* F) } /* 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"); @@ -1010,14 +1305,17 @@ void O65WriteTarget (O65Desc* D, File* F) } /* Keep the user happy */ - if (Verbose) { - printf ("Opened `%s'...\n", F->Name); - } + Print (stdout, 1, "Opened `%s'...\n", F->Name); /* 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); + 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%u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH); O65SetOption (D, O65OPT_ASM, OptBuf, strlen (OptBuf) + 1); @@ -1025,16 +1323,16 @@ void O65WriteTarget (O65Desc* D, File* F) 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); @@ -1064,4 +1362,3 @@ void O65WriteTarget (O65Desc* D, File* F) -