X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fld65%2Fo65.c;h=6845efed112d8acad023b1d3efaa7f289eb284fa;hb=4786caf496bd8e6989abee74017aa098df860c41;hp=f6fe27b6187a4fb2214865062421fe8d6831155f;hpb=effacc8d8bcf7743ebf90ebfc31ed7668321110c;p=cc65 diff --git a/src/ld65/o65.c b/src/ld65/o65.c index f6fe27b61..6845efed1 100644 --- a/src/ld65/o65.c +++ b/src/ld65/o65.c @@ -6,10 +6,10 @@ /* */ /* */ /* */ -/* (C) 1999-2001 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ -/* EMail: uz@cc65.org */ +/* (C) 1999-2010, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ /* */ /* */ /* This software is provided 'as-is', without any expressed or implied */ @@ -35,10 +35,12 @@ #include #include +#include #include #include /* common */ +#include "chartype.h" #include "check.h" #include "print.h" #include "version.h" @@ -51,7 +53,9 @@ #include "fileio.h" #include "global.h" #include "lineinfo.h" +#include "memarea.h" #include "o65.h" +#include "spool.h" @@ -132,7 +136,6 @@ struct O65Option { }; /* A o65 relocation table */ -#define RELOC_BLOCKSIZE 4096 typedef struct O65RelocTab O65RelocTab; struct O65RelocTab { unsigned Size; /* Size of the table */ @@ -148,7 +151,7 @@ struct O65Desc { 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 */ + const char* Filename; /* Name of the output file */ O65RelocTab* TextReloc; /* Relocation table for text segment */ O65RelocTab* DataReloc; /* Relocation table for data segment */ @@ -173,7 +176,9 @@ struct ExprDesc { 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 */ }; @@ -191,7 +196,9 @@ static ExprDesc* InitExprDesc (ExprDesc* ED, O65Desc* D) ED->D = D; ED->Val = 0; ED->TooComplex = 0; + ED->MemRef = 0; ED->SegRef = 0; + ED->SecRef = 0; ED->ExtRef = 0; return ED; } @@ -232,6 +239,55 @@ static unsigned O65SegType (const SegDesc* S) +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. @@ -277,7 +333,7 @@ static const SegDesc* O65FindSeg (const O65Desc* D, const Segment* S) /*****************************************************************************/ -/* Expression handling */ +/* Expression handling */ /*****************************************************************************/ @@ -289,16 +345,11 @@ static void O65ParseExpr (ExprNode* Expr, ExprDesc* D, int Sign) */ { Export* E; - unsigned long Val; 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: @@ -328,20 +379,41 @@ static void O65ParseExpr (ExprNode* Expr, ExprDesc* D, int Sign) } break; - case EXPR_SEGMENT: - if (D->SegRef) { + 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->SegRef = GetExprSection (Expr); + D->SecRef = GetExprSection (Expr); /* Add the offset of the section to the constant value */ - Val = D->SegRef->Offs + D->SegRef->Seg->PC; - if (Sign < 0) { - D->Val -= Val; - } else { - D->Val += Val; - } + 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 = 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; @@ -378,9 +450,9 @@ static O65RelocTab* NewO65RelocTab (void) 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; @@ -403,10 +475,12 @@ static void O65RelocPutByte (O65RelocTab* R, unsigned B) /* 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 */ @@ -522,10 +596,11 @@ static unsigned O65WriteExpr (ExprNode* E, int Signed, unsigned Size, * 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 */ @@ -564,18 +639,31 @@ static unsigned O65WriteExpr (ExprNode* E, int Signed, unsigned Size, /* 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; @@ -602,57 +690,71 @@ static unsigned O65WriteExpr (ExprNode* E, int Signed, unsigned Size, 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 */ @@ -677,13 +779,15 @@ static void O65WriteSeg (O65Desc* D, SegDesc** Seg, unsigned Count, int DoWrite) /* Get the segment from the list node */ S = Seg [I]; + /* Relocate line info for this segment */ + RelocLineInfo (S->Seg); + /* 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 */ @@ -783,7 +887,7 @@ static void O65WriteImports (O65Desc* D) 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 */ @@ -826,13 +930,14 @@ static void O65WriteExports (O65Desc* D) 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); } @@ -843,8 +948,10 @@ static void O65WriteExports (O65Desc* D) /* 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; } @@ -854,14 +961,17 @@ static void O65WriteExports (O65Desc* D) } /* 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. @@ -869,6 +979,12 @@ static void O65WriteExports (O65Desc* D) Error ("Segment for symbol `%s' is undefined", Name); } SegmentID = O65SegType (Seg); + + } else { + + /* Absolute value */ + SegmentID = O65SEG_ABS; + } /* Write the name to the output file */ @@ -1037,11 +1153,6 @@ void O65SetOS (O65Desc* D, unsigned OS, unsigned Version, unsigned Id) /* 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 */ @@ -1051,13 +1162,16 @@ void O65SetOS (O65Desc* D, unsigned OS, unsigned Version, unsigned 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 */ @@ -1066,7 +1180,7 @@ ExtSym* O65GetImport (O65Desc* D, const char* Ident) -void O65SetImport (O65Desc* D, const char* Ident) +void O65SetImport (O65Desc* D, unsigned Ident) /* Set an imported identifier */ { /* Insert the entry into the table */ @@ -1075,7 +1189,7 @@ void O65SetImport (O65Desc* D, const char* Ident) -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 */ @@ -1084,7 +1198,7 @@ ExtSym* O65GetExport (O65Desc* D, const char* Ident) -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 @@ -1092,7 +1206,7 @@ void O65SetExport (O65Desc* D, const char* Ident) */ 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 */ @@ -1104,9 +1218,7 @@ void O65SetExport (O65Desc* D, const char* Ident) static void O65SetupSegments (O65Desc* D, File* F) /* Setup segment assignments */ { - Memory* M; - MemListNode* N; - SegDesc* S; + unsigned I; unsigned TextIdx, DataIdx, BssIdx, ZPIdx; /* Initialize the counters */ @@ -1116,14 +1228,16 @@ static void O65SetupSegments (O65Desc* D, File* F) D->ZPCount = 0; /* Walk over the memory list */ - M = F->MemList; - while (M) { + 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 */ - N = M->SegList; - while (N) { + unsigned J; + for (J = 0; J < CollCount (&M->SegList); ++J) { - /* Get the segment from the list node */ - S = N->Seg; + /* Get the segment */ + SegDesc* S = CollAtUnchecked (&M->SegList, J); /* Check the segment type. */ switch (O65SegType (S)) { @@ -1131,14 +1245,9 @@ static void O65SetupSegments (O65Desc* D, File* F) case O65SEG_DATA: D->DataCount++; break; case O65SEG_BSS: D->BssCount++; break; case O65SEG_ZP: D->ZPCount++; break; - default: Internal ("Invalid return from O65SegType"); + default: Internal ("Invalid return from O65SegType"); } - - /* Next segment node */ - N = N->Next; } - /* Next memory area */ - M = M->FNext; } /* Allocate memory according to the numbers */ @@ -1149,14 +1258,16 @@ static void O65SetupSegments (O65Desc* D, File* F) /* Walk again through the list and setup the segment arrays */ TextIdx = DataIdx = BssIdx = ZPIdx = 0; - M = F->MemList; - while (M) { + for (I = 0; I < CollCount (&F->MemoryAreas); ++I) { + /* Get this entry */ + MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, I); - N = M->SegList; - while (N) { + /* Walk over the segment list and check the segment types */ + unsigned J; + for (J = 0; J < CollCount (&M->SegList); ++J) { - /* Get the segment from the list node */ - S = N->Seg; + /* Get the segment */ + SegDesc* S = CollAtUnchecked (&M->SegList, J); /* Check the segment type. */ switch (O65SegType (S)) { @@ -1166,18 +1277,13 @@ static void O65SetupSegments (O65Desc* D, File* F) 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; } } -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 */ @@ -1228,17 +1334,18 @@ static void O65SetupHeader (O65Desc* D) void O65WriteTarget (O65Desc* D, File* F) /* Write an o65 output file */ { - 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; + 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); @@ -1251,19 +1358,24 @@ void O65WriteTarget (O65Desc* D, File* F) 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 */ @@ -1299,7 +1411,7 @@ void O65WriteTarget (O65Desc* D, File* F) /* 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 */ @@ -1309,3 +1421,4 @@ void O65WriteTarget (O65Desc* D, File* F) +