]> git.sur5r.net Git - cc65/blobdiff - src/ld65/o65.c
For modules, the ZP memory area must be written to the output file. This is
[cc65] / src / ld65 / o65.c
index 8fe7cef4c2a0b7bdbf91817016bd59acfa2a8ecc..6845efed112d8acad023b1d3efaa7f289eb284fa 100644 (file)
@@ -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,6 +35,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <limits.h>
 #include <errno.h>
 #include <time.h>
 
@@ -52,7 +53,9 @@
 #include "fileio.h"
 #include "global.h"
 #include "lineinfo.h"
+#include "memarea.h"
 #include "o65.h"
+#include "spool.h"
 
 
 
@@ -133,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 */
@@ -149,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 */
 
@@ -174,6 +176,7 @@ struct ExprDesc {
     O65Desc*               D;                  /* File format descriptor */
     long                   Val;                /* The offset value */
     int                    TooComplex;         /* Expression too complex */
+    MemoryArea*     MemRef;             /* Memory reference if any */
     Segment*        SegRef;             /* Segment reference if any */
     Section*               SecRef;             /* Section reference if any */
     ExtSym*                ExtRef;             /* External reference if any */
@@ -193,6 +196,7 @@ 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;
@@ -235,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.
@@ -292,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:
@@ -339,12 +387,7 @@ static void O65ParseExpr (ExprNode* Expr, ExprDesc* D, int Sign)
                /* 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;
-                }
+                D->Val += Sign * (D->SecRef->Offs + D->SecRef->Seg->PC);
            }
            break;
 
@@ -356,12 +399,21 @@ static void O65ParseExpr (ExprNode* Expr, ExprDesc* D, int Sign)
                /* 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;
-                }
+                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;
 
@@ -398,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;
@@ -423,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 */
@@ -586,11 +640,23 @@ static unsigned O65WriteExpr (ExprNode* E, int Signed, unsigned Size,
     O65ParseExpr (Expr, InitExprDesc (&ED, D), 1);
 
     /* We cannot handle more than one external reference */
-    RefCount = (ED.SegRef != 0) + (ED.SecRef != 0) + (ED.ExtRef != 0);
+    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;
@@ -713,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 */
@@ -819,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 */
@@ -862,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);
        }
@@ -1084,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 */
@@ -1098,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 */
@@ -1113,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 */
@@ -1122,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 */
@@ -1131,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
@@ -1139,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 */
@@ -1151,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 */
@@ -1163,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)) {
@@ -1178,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 */
@@ -1196,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)) {
@@ -1213,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 */
@@ -1280,13 +1339,13 @@ void O65WriteTarget (O65Desc* D, File* F)
     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);
@@ -1299,13 +1358,13 @@ 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);
@@ -1316,7 +1375,7 @@ void O65WriteTarget (O65Desc* D, File* F)
     }
     OptBuf[OptLen] = '\0';
     O65SetOption (D, O65OPT_TIMESTAMP, OptBuf, OptLen + 1);
-    sprintf (OptBuf, "ld65 V%u.%u.%u", VER_MAJOR, VER_MINOR, VER_PATCH);
+    sprintf (OptBuf, "ld65 V%s", GetVersionAsString ());
     O65SetOption (D, O65OPT_ASM, OptBuf, strlen (OptBuf) + 1);
 
     /* Write the header */
@@ -1352,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 */
@@ -1362,3 +1421,4 @@ void O65WriteTarget (O65Desc* D, File* F)
 
 
 
+