]> git.sur5r.net Git - cc65/blobdiff - src/ld65/library.c
Removed (pretty inconsistently used) tab chars from source code base.
[cc65] / src / ld65 / library.c
index 98ff05e0bfd47721a150a689e73c398b26e7a028..c81ee6f91f8444b7fdc35f11e35c0c17aa010e5d 100644 (file)
@@ -1,34 +1,34 @@
 /*****************************************************************************/
-/*                                                                          */
-/*                                library.c                                 */
-/*                                                                          */
-/*         Library data structures and helpers for the ld65 linker          */
-/*                                                                          */
-/*                                                                          */
-/*                                                                          */
-/* (C) 1998-2003 Ullrich von Bassewitz                                       */
-/*               Römerstrasse 52                                             */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
-/*                                                                          */
-/*                                                                          */
-/* This software is provided 'as-is', without any expressed or implied      */
+/*                                                                           */
+/*                                 library.c                                 */
+/*                                                                           */
+/*          Library data structures and helpers for the ld65 linker          */
+/*                                                                           */
+/*                                                                           */
+/*                                                                           */
+/* (C) 1998-2011, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
+/*                                                                           */
+/*                                                                           */
+/* This software is provided 'as-is', without any expressed or implied       */
 /* warranty.  In no event will the authors be held liable for any damages    */
-/* arising from the use of this software.                                   */
-/*                                                                          */
+/* arising from the use of this software.                                    */
+/*                                                                           */
 /* Permission is granted to anyone to use this software for any purpose,     */
 /* including commercial applications, and to alter it and redistribute it    */
-/* freely, subject to the following restrictions:                           */
-/*                                                                          */
+/* freely, subject to the following restrictions:                            */
+/*                                                                           */
 /* 1. The origin of this software must not be misrepresented; you must not   */
 /*    claim that you wrote the original software. If you use this software   */
 /*    in a product, an acknowledgment in the product documentation would be  */
-/*    appreciated but is not required.                                      */
+/*    appreciated but is not required.                                       */
 /* 2. Altered source versions must be plainly marked as such, and must not   */
-/*    be misrepresented as being the original software.                             */
-/* 3. This notice may not be removed or altered from any source                     */
-/*    distribution.                                                         */
-/*                                                                          */
+/*    be misrepresented as being the original software.                      */
+/* 3. This notice may not be removed or altered from any source              */
+/*    distribution.                                                          */
+/*                                                                           */
 /*****************************************************************************/
 
 
@@ -38,8 +38,8 @@
 #include <errno.h>
 
 /* common */
+#include "coll.h"
 #include "exprdefs.h"
-#include "filepos.h"
 #include "libdefs.h"
 #include "objdefs.h"
 #include "symdefs.h"
 
 
 /*****************************************************************************/
-/*                                  Data                                    */
+/*                                   Data                                    */
 /*****************************************************************************/
 
 
 
-/* Library data */
-static FILE*           Lib             = 0;
-static unsigned                ModuleCount     = 0;
-static ObjData**       Index           = 0;
+/* Library data structure */
+typedef struct Library Library;
+struct Library {
+    unsigned    Id;             /* Id of library */
+    unsigned    Name;           /* String id of the name */
+    FILE*       F;              /* Open file stream */
+    LibHeader   Header;         /* Library header */
+    Collection  Modules;        /* Modules */
+};
+
+/* List of open libraries */
+static Collection OpenLibs = STATIC_COLLECTION_INITIALIZER;
+
+/* List of used libraries */
+static Collection LibraryList = STATIC_COLLECTION_INITIALIZER;
+
+/* Flag for library grouping */
+static int Grouping = 0;
+
+
+
+/*****************************************************************************/
+/*                              struct Library                               */
+/*****************************************************************************/
+
+
+
+static Library* NewLibrary (FILE* F, const char* Name)
+/* Create a new Library structure and return it */
+{
+    /* Allocate memory */
+    Library* L = xmalloc (sizeof (*L));
+
+    /* Initialize the fields */
+    L->Id       = ~0U;
+    L->Name     = GetStringId (Name);
+    L->F        = F;
+    L->Modules  = EmptyCollection;
+
+    /* Return the new struct */
+    return L;
+}
+
+
+
+static void CloseLibrary (Library* L)
+/* Close a library file and remove the list of modules */
+{
+    /* Close the library file */
+    if (fclose (L->F) != 0) {
+        Error ("Error closing `%s': %s", GetString (L->Name), strerror (errno));
+    }
+    L->F = 0;
+}
+
+
+
+static void FreeLibrary (Library* L)
+/* Free a library structure */
+{
+    /* Close the library */
+    CloseLibrary (L);
+
+    /* Free the module index */
+    DoneCollection (&L->Modules);
+
+    /* Free the library structure */
+    xfree (L);
+}
 
 
 
 /*****************************************************************************/
-/*                      Reading file data structures                        */
+/*                       Reading file data structures                        */
 /*****************************************************************************/
 
 
 
-static void LibReadObjHeader (ObjData* O, const char* LibName)
+static void LibSeek (Library* L, unsigned long Offs)
+/* Do a seek in the library checking for errors */
+{
+    if (fseek (L->F, Offs, SEEK_SET) != 0) {
+        Error ("Seek error in `%s' (%lu): %s",
+               GetString (L->Name), Offs, strerror (errno));
+    }
+}
+
+
+
+static void LibReadHeader (Library* L)
+/* Read a library header */
+{
+    /* Read the remaining header fields (magic is already read) */
+    L->Header.Magic   = LIB_MAGIC;
+    L->Header.Version = Read16 (L->F);
+    if (L->Header.Version != LIB_VERSION) {
+        Error ("Wrong data version in `%s'", GetString (L->Name));
+    }
+    L->Header.Flags   = Read16 (L->F);
+    L->Header.IndexOffs = Read32 (L->F);
+}
+
+
+
+static void LibReadObjHeader (Library* L, ObjData* O)
 /* Read the header of the object file checking the signature */
 {
-    O->Header.Magic = Read32 (Lib);
+    O->Header.Magic = Read32 (L->F);
     if (O->Header.Magic != OBJ_MAGIC) {
-       Error ("Object file `%s' in library `%s' is invalid",
-              GetObjFileName (O), LibName);
+        Error ("Object file `%s' in library `%s' is invalid",
+               GetObjFileName (O), GetString (L->Name));
     }
-    O->Header.Version = Read16 (Lib);
+    O->Header.Version = Read16 (L->F);
     if (O->Header.Version != OBJ_VERSION) {
-       Error ("Object file `%s' in library `%s' has wrong version",
-              GetObjFileName (O), LibName);
+        Error ("Object file `%s' in library `%s' has wrong version",
+               GetObjFileName (O), GetString (L->Name));
     }
-    O->Header.Flags               = Read16 (Lib);
-    O->Header.OptionOffs   = Read32 (Lib);
-    O->Header.OptionSize   = Read32 (Lib);
-    O->Header.FileOffs    = Read32 (Lib);
-    O->Header.FileSize    = Read32 (Lib);
-    O->Header.SegOffs     = Read32 (Lib);
-    O->Header.SegSize     = Read32 (Lib);
-    O->Header.ImportOffs   = Read32 (Lib);
-    O->Header.ImportSize   = Read32 (Lib);
-    O->Header.ExportOffs   = Read32 (Lib);
-    O->Header.ExportSize   = Read32 (Lib);
-    O->Header.DbgSymOffs   = Read32 (Lib);
-    O->Header.DbgSymSize   = Read32 (Lib);
-    O->Header.LineInfoOffs = Read32 (Lib);
-    O->Header.LineInfoSize = Read32 (Lib);
-    O->Header.StrPoolOffs  = Read32 (Lib);
-    O->Header.StrPoolSize  = Read32 (Lib);
+    O->Header.Flags        = Read16 (L->F);
+    O->Header.OptionOffs   = Read32 (L->F);
+    O->Header.OptionSize   = Read32 (L->F);
+    O->Header.FileOffs     = Read32 (L->F);
+    O->Header.FileSize     = Read32 (L->F);
+    O->Header.SegOffs      = Read32 (L->F);
+    O->Header.SegSize      = Read32 (L->F);
+    O->Header.ImportOffs   = Read32 (L->F);
+    O->Header.ImportSize   = Read32 (L->F);
+    O->Header.ExportOffs   = Read32 (L->F);
+    O->Header.ExportSize   = Read32 (L->F);
+    O->Header.DbgSymOffs   = Read32 (L->F);
+    O->Header.DbgSymSize   = Read32 (L->F);
+    O->Header.LineInfoOffs = Read32 (L->F);
+    O->Header.LineInfoSize = Read32 (L->F);
+    O->Header.StrPoolOffs  = Read32 (L->F);
+    O->Header.StrPoolSize  = Read32 (L->F);
+    O->Header.AssertOffs   = Read32 (L->F);
+    O->Header.AssertSize   = Read32 (L->F);
+    O->Header.ScopeOffs    = Read32 (L->F);
+    O->Header.ScopeSize    = Read32 (L->F);
+    O->Header.SpanOffs     = Read32 (L->F);
+    O->Header.SpanSize     = Read32 (L->F);
 }
 
 
 
-static ObjData* ReadIndexEntry (void)
+static ObjData* ReadIndexEntry (Library* L)
 /* Read one entry in the index */
 {
-    unsigned I;
-
     /* Create a new entry and insert it into the list */
-    ObjData* O = NewObjData ();
+    ObjData* O  = NewObjData ();
+
+    /* Remember from which library this module is */
+    O->Lib = L;
 
     /* Module name */
-    O->Name = ReadStr (Lib);
+    O->Name = ReadStr (L->F);
 
     /* Module flags/MTime/Start/Size */
-    O->Flags   = Read16 (Lib);
-    O->MTime    = Read32 (Lib);
-    O->Start   = Read32 (Lib);
-    Read32 (Lib);                      /* Skip Size */
+    O->Flags    = Read16 (L->F);
+    O->MTime    = Read32 (L->F);
+    O->Start    = Read32 (L->F);
+    Read32 (L->F);                      /* Skip Size */
+
+    /* Done */
+    return O;
+}
+
+
+
+static void ReadBasicData (Library* L, ObjData* O)
+/* Read basic data for an object file that is necessary to resolve external
+ * references.
+ */
+{
+    /* Seek to the start of the object file and read the header */
+    LibSeek (L, O->Start);
+    LibReadObjHeader (L, O);
 
     /* Read the string pool */
-    ObjReadStrPool (Lib, O);
-
-    /* Skip the export size, then read the exports */
-    (void) ReadVar (Lib);
-    O->ExportCount = ReadVar (Lib);
-    O->Exports = xmalloc (O->ExportCount * sizeof (Export*));
-    for (I = 0; I < O->ExportCount; ++I) {
-       O->Exports[I] = ReadExport (Lib, O);
-    }
+    ObjReadStrPool (L->F, O->Start + O->Header.StrPoolOffs, O);
 
-    /* Skip the import size, then read the imports */
-    (void) ReadVar (Lib);
-    O->ImportCount = ReadVar (Lib);
-    O->Imports = xmalloc (O->ImportCount * sizeof (Import*));
-    for (I = 0; I < O->ImportCount; ++I) {
-               O->Imports[I] = ReadImport (Lib, O);
-    }
+    /* Read the files list */
+    ObjReadFiles (L->F, O->Start + O->Header.FileOffs, O);
 
-    /* Done */
-    return O;
+    /* Read the line infos */
+    ObjReadLineInfos (L->F, O->Start + O->Header.LineInfoOffs, O);
+
+    /* Read the imports */
+    ObjReadImports (L->F, O->Start + O->Header.ImportOffs, O);
+
+    /* Read the exports */
+    ObjReadExports (L->F, O->Start + O->Header.ExportOffs, O);
 }
 
 
 
-static void ReadIndex (void)
+static void LibReadIndex (Library* L)
 /* Read the index of a library file */
 {
-    unsigned I;
+    unsigned ModuleCount, I;
+
+    /* Seek to the start of the index */
+    LibSeek (L, L->Header.IndexOffs);
 
     /* Read the object file count and allocate memory */
-    ModuleCount = ReadVar (Lib);
-    Index = xmalloc (ModuleCount * sizeof (ObjData*));
+    ModuleCount = ReadVar (L->F);
+    CollGrow (&L->Modules, ModuleCount);
 
     /* Read all entries in the index */
-    for (I = 0; I < ModuleCount; ++I) {
-               Index[I] = ReadIndexEntry ();
+    while (ModuleCount--) {
+        CollAppend (&L->Modules, ReadIndexEntry (L));
+    }
+
+    /* Walk over the index and read basic data for all object files in the
+     * library.
+     */
+    for (I = 0; I < CollCount (&L->Modules); ++I) {
+        ReadBasicData (L, CollAtUnchecked (&L->Modules, I));
     }
 }
 
 
 
 /*****************************************************************************/
-/*                            High level stuff                              */
+/*                             High level stuff                              */
 /*****************************************************************************/
 
 
@@ -182,25 +298,155 @@ static void LibCheckExports (ObjData* O)
     unsigned I;
 
     /* Check all exports */
-    for (I = 0; I < O->ExportCount; ++I) {
-       if (IsUnresolved (O->Exports[I]->Name)) {
-           /* We need this module */
-           O->Flags |= OBJ_REF;
-           break;
-       }
+    for (I = 0; I < CollCount (&O->Exports); ++I) {
+        const Export* E = CollConstAt (&O->Exports, I);
+        if (IsUnresolved (E->Name)) {
+           /* We need this module, insert the imports and exports */
+            O->Flags |= OBJ_REF;
+            InsertObjGlobals (O);
+            break;
+        }
     }
+}
+
+
+
+static void LibOpen (FILE* F, const char* Name)
+/* Open the library for use */
+{
+    /* Create a new library structure */
+    Library* L = NewLibrary (F, Name);
+
+    /* Read the remaining header fields (magic is already read) */
+    LibReadHeader (L);
+
+    /* Seek to the index position and read the index */
+    LibReadIndex (L);
+
+    /* Add the library to the list of open libraries */
+    CollAppend (&OpenLibs, L);
+}
+
+
+
+static void LibResolve (void)
+/* Resolve all externals from the list of all currently open libraries */
+{
+    unsigned I, J;
+    unsigned Additions;
+
+    /* Walk repeatedly over all open libraries until there's nothing more
+     * to add.
+     */
+    do {
+
+        Additions = 0;
+
+        /* Walk over all libraries */
+        for (I = 0; I < CollCount (&OpenLibs); ++I) {
+
+            /* Get the next library */
+            Library* L = CollAt (&OpenLibs, I);
+
+            /* Walk through all modules in this library and check for each
+             * module if there are unresolved externals in existing modules
+             * that may be resolved by adding the module.
+             */
+            for (J = 0; J < CollCount (&L->Modules); ++J) {
+
+                /* Get the next module */
+                ObjData* O = CollAtUnchecked (&L->Modules, J);
+
+                /* We only need to check this module if it wasn't added before */
+                if ((O->Flags & OBJ_REF) == 0) {
+                    LibCheckExports (O);
+                    if (O->Flags & OBJ_REF) {
+                        /* The routine added the file */
+                        ++Additions;
+                    }
+                }
+            }
+        }
+
+    } while (Additions > 0);
+
+    /* We do know now which modules must be added, so we can load the data
+     * for these modues into memory. Since we're walking over all modules
+     * anyway, we will also remove data for unneeded modules.
+     */
+    for (I = 0; I < CollCount (&OpenLibs); ++I) {
+
+        /* Get the next library */
+        Library* L = CollAt (&OpenLibs, I);
+
+        /* Walk over all modules in this library and add the files list and
+         * sections for all referenced modules.
+         */
+        J = 0;
+        while (J < CollCount (&L->Modules)) {
+
+            /* Get the object data */
+            ObjData* O = CollAtUnchecked (&L->Modules, J);
+
+            /* Is this object file referenced? */
+            if (O->Flags & OBJ_REF) {
+
+                /* Seek to the start of the debug info and read the debug info */
+                ObjReadDbgSyms (L->F, O->Start + O->Header.DbgSymOffs, O);
+
+                /* Read the assertions from the object file */
+                ObjReadAssertions (L->F, O->Start + O->Header.AssertOffs, O);
+
+                /* Seek to the start of the segment list and read the segments.
+                 * This must be late, since the data here may reference other
+                 * stuff.
+                 */
+                ObjReadSections (L->F, O->Start + O->Header.SegOffs, O);
 
-    /* If we need this module, insert the imports and exports */
-    if (O->Flags & OBJ_REF) {
-       /* Insert the exports */
-       for (I = 0; I < O->ExportCount; ++I) {
-           InsertExport (O->Exports[I]);
-       }
-       /* Insert the imports */
-       for (I = 0; I < O->ImportCount; ++I) {
-           InsertImport (O->Imports[I]);
-       }
+                /* Read the scope table from the object file. Scopes reference
+                 * segments, so we must read them after the sections.
+                 */
+                ObjReadScopes (L->F, O->Start + O->Header.ScopeOffs, O);
+
+                /* Read the spans */
+                ObjReadSpans (L->F, O->Start + O->Header.SpanOffs, O);
+
+                /* All references to strings are now resolved, so we can delete
+                 * the module string pool.
+                 */
+                FreeObjStrings (O);
+
+                /* Insert the object into the list of all used object files */
+                InsertObjData (O);
+
+                /* Process next object file in library */
+                ++J;
+
+            } else {
+
+                /* Unreferenced object file, remove it */
+                FreeObjData (O);
+                CollDelete (&L->Modules, J);
+
+            }
+        }
+
+        /* If we have referenced modules in this library, assign it an id
+         * (which is the index in the library collection) and keep it.
+         */
+        if (CollCount (&L->Modules) > 0) {
+            CloseLibrary (L);
+            L->Id = CollCount (&LibraryList);
+            CollAppend (&LibraryList, L);
+        } else {
+            /* Delete the library */
+            FreeLibrary (L);
+            CollDelete (&OpenLibs, I);
+        }
     }
+
+    /* We're done with all open libraries, clear the OpenLibs collection */
+    CollDeleteAll (&OpenLibs);
 }
 
 
@@ -210,105 +456,104 @@ void LibAdd (FILE* F, const char* Name)
  * be satisfied.
  */
 {
-    unsigned LibName;
-    int HaveAdditions;
-    unsigned I;
-    LibHeader Header;
+    /* Add the library to the list of open libraries */
+    LibOpen (F, Name);
+
+    /* If there is no library group open, just resolve all open symbols and
+     * close the library. Otherwise we will do nothing because resolving will
+     * be done when the group is closed.
+     */
+    if (!Grouping) {
+        LibResolve ();
+    }
+}
 
-    /* Store the parameters, so they're visible for other routines */
-    Lib     = F;
-    LibName = GetStringId (Name);
 
-    /* Read the remaining header fields (magic is already read) */
-    Header.Magic   = LIB_MAGIC;
-    Header.Version = Read16 (Lib);
-    if (Header.Version != LIB_VERSION) {
-               Error ("Wrong data version in `%s'", Name);
+
+void LibStartGroup (void)
+/* Start a library group. Objects within a library group may reference each
+ * other, and libraries are searched repeatedly until all references are
+ * satisfied.
+ */
+{
+    /* We cannot already have a group open */
+    if (Grouping) {
+        Error ("There's already a library group open");
     }
-    Header.Flags   = Read16 (Lib);
-    Header.IndexOffs = Read32 (Lib);
 
-    /* Seek to the index position and read the index */
-    fseek (Lib, Header.IndexOffs, SEEK_SET);
-    ReadIndex ();
+    /* Start a new group */
+    Grouping = 1;
+}
 
-    /* Walk through all library modules and check for each module if there
-     * are unresolved externals in existing modules that may be resolved
-     * by adding the module. Repeat this step until no more object files
-     * were added.
-     */
-    do {
-       HaveAdditions = 0;
-       for (I = 0; I < ModuleCount; ++I) {
-           ObjData* O = Index [I];
-           if ((O->Flags & OBJ_REF) == 0) {
-               LibCheckExports (O);
-               if (O->Flags & OBJ_REF) {
-                   /* The routine added the file */
-                   HaveAdditions = 1;
-               }
-           }
-       }
-    } while (HaveAdditions);
-
-    /* Add the files list and sections for all requested modules */
-    for (I = 0; I < ModuleCount; ++I) {
-
-        /* Get the object data */
-       ObjData* O = Index [I];
-
-        /* Is this object file referenced? */
-       if (O->Flags & OBJ_REF) {
-
-           /* Seek to the start of the object file and read the header */
-           fseek (Lib, O->Start, SEEK_SET);
-           LibReadObjHeader (O, Name);
-
-           /* Seek to the start of the files list and read the files list */
-           fseek (Lib, O->Start + O->Header.FileOffs, SEEK_SET);
-           ObjReadFiles (Lib, O);
-
-           /* Seek to the start of the debug info and read the debug info */
-           fseek (Lib, O->Start + O->Header.DbgSymOffs, SEEK_SET);
-                   ObjReadDbgSyms (Lib, O);
-
-           /* Seek to the start of the line infos and read them */
-           fseek (Lib, O->Start + O->Header.LineInfoOffs, SEEK_SET);
-           ObjReadLineInfos (Lib, O);
-
-           /* Seek to the start of the segment list and read the segments.
-            * This must be last, since the data here may reference other
-            * stuff.
-            */
-           fseek (Lib, O->Start + O->Header.SegOffs, SEEK_SET);
-           ObjReadSections (Lib, O);
-
-            /* Add a pointer to the library name */
-            O->LibName = LibName;
-
-            /* All references to strings are now resolved, so we can delete
-             * the module string pool.
-             */
-            FreeObjStrings (O);
 
-            /* Insert the object into the list of all used object files */
-            InsertObjData (O);
 
-        } else {
+void LibEndGroup (void)
+/* End a library group and resolve all open references. Objects within a
+ * library group may reference each other, and libraries are searched
+ * repeatedly until all references are satisfied.
+ */
+{
+    /* We must have a library group open */
+    if (!Grouping) {
+        Error ("There's no library group open");
+    }
 
-            /* Unreferenced object file, remove it */
-            FreeObjData (O);
+    /* Resolve symbols, end the group */
+    LibResolve ();
+    Grouping = 0;
+}
 
-        }
+
+
+void LibCheckGroup (void)
+/* Check if there are open library groups */
+{
+    if (Grouping) {
+        Error ("Library group was never closed");
     }
+}
+
+
 
-    /* Done. Close the file, release allocated memory */
-    fclose (F);
-    xfree (Index);
-    Lib                = 0;
-    ModuleCount = 0;
-    Index      = 0;
+const char* GetLibFileName (const Library* L)
+/* Get the name of a library */
+{
+    return GetString (L->Name);
 }
 
 
 
+unsigned GetLibId (const Library* L)
+/* Get the id of a library file. */
+{
+    return L->Id;
+}
+
+
+
+unsigned LibraryCount (void)
+/* Return the total number of libraries */
+{
+    return CollCount (&LibraryList);
+}
+
+
+
+void PrintDbgLibraries (FILE* F)
+/* Output the libraries to a debug info file */
+{
+    unsigned I;
+
+    /* Output information about all libraries */
+    for (I = 0; I < CollCount (&LibraryList); ++I) {
+        /* Get the library */
+        const Library* L = CollAtUnchecked (&LibraryList, I);
+
+        /* Output the info */
+        fprintf (F, "lib\tid=%u,name=\"%s\"\n", L->Id, GetString (L->Name));
+    }
+}
+
+
+
+