]> git.sur5r.net Git - cc65/commitdiff
Added library groups
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sat, 26 Mar 2005 16:26:11 +0000 (16:26 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sat, 26 Mar 2005 16:26:11 +0000 (16:26 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@3420 b7a2c559-68d2-44c3-8de9-860c34a00d81

doc/ld65.sgml
src/ld65/library.c
src/ld65/library.h
src/ld65/main.c

index 21aeae788036047171d705be6157dab6182eca9a..c1ac2dd1ef5542fa19b11351276278c3b6d5d37d 100644 (file)
@@ -91,6 +91,26 @@ Long options:
 Here is a description of all the command line options:
 
 <descrip>
+  
+  <label id="option--start-group">
+  <tag><tt>-(, --start-group</tt></tag>
+
+  Start a library group. The libraries specified within a group are searched
+  multiple times to resolve crossreferences within the libraries. Normally,
+  crossreferences are only resolved within a library, that is the library is
+  searched multiple times. Libraries specified later on the command line
+  cannot reference otherwise unreferenced symbols in libraries specified
+  earlier, because the linker has already handled them. Library groups are
+  a solution for this problem, because the linker will search repeatedly
+  through all libraries specified in the group, until all possible open
+  symbol references have been satisfied.
+
+
+  <tag><tt>-), --end-group</tt></tag>
+
+  End a library group. See the explanation of the <tt><ref
+  id="option--start-group" name="--start-group"></tt> option.
+
 
   <tag><tt>-h, --help</tt></tag>
 
index f5e2bb2da84aae6a08c6c3e9296785a6875e82b7..0086c212f6424b86f41e6459417006f90249ef7b 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                          */
 /*                                                                          */
 /*                                                                          */
-/* (C) 1998-2003 Ullrich von Bassewitz                                       */
+/* (C) 1998-2005 Ullrich von Bassewitz                                       */
 /*               Römerstraße 52                                              */
 /*               D-70794 Filderstadt                                         */
 /* EMail:        uz@cc65.org                                                 */
 
 
 
-/* Library data */
-static FILE*           Lib             = 0;
-static unsigned                ModuleCount     = 0;
-static ObjData**       Index           = 0;
+/* Library data structure */
+typedef struct Library Library;
+struct Library {
+    Library*    Next;
+    unsigned    Name;           /* String id of the name */
+    FILE*       F;              /* Open file stream */
+    LibHeader   Header;         /* Library header */
+    unsigned    ModCount;       /* Number of modules in the library */
+    ObjData**   Modules;        /* Modules */
+};
+
+/* List of open libraries */
+static Collection OpenLibs = 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->Next     = 0;
+    L->Name     = GetStringId (Name);
+    L->F        = F;
+    L->ModCount = 0;
+    L->Modules  = 0;
+
+    /* Return the new struct */
+    return L;
+}
+
+
+
+static void FreeLibrary (Library* L)
+/* Free a library structure */
+{
+    /* Close the library file */
+    if (fclose (L->F) != 0) {
+        Error ("Error closing `%s': %s", GetString (L->Name), strerror (errno));
+    }
+
+    /* Free the module index */
+    xfree (L->Modules);
+
+    /* Free the library structure */
+    xfree (L);
+}
 
 
 
@@ -75,69 +129,95 @@ static ObjData**   Index           = 0;
 
 
 
-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);
+              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);
+              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.AssertOffs   = Read32 (Lib);
-    O->Header.AssertSize   = Read32 (Lib);
-    O->Header.ScopeOffs    = Read32 (Lib);
-    O->Header.ScopeSize    = 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);
 }
 
 
 
-static ObjData* ReadIndexEntry (void)
+static ObjData* ReadIndexEntry (Library* L)
 /* Read one entry in the index */
 {
     /* Create a new entry and insert it into the list */
     ObjData* O = NewObjData ();
 
     /* 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 */
 
     /* Read the string pool */
-    ObjReadStrPool (Lib, FileGetPos (Lib), O);
+    ObjReadStrPool (L->F, FileGetPos (L->F), O);
 
     /* Skip the export size, then read the exports */
-    (void) ReadVar (Lib);
-    ObjReadExports (Lib, FileGetPos (Lib), O);
+    (void) ReadVar (L->F);
+    ObjReadExports (L->F, FileGetPos (L->F), O);
 
     /* Skip the import size, then read the imports */
-    (void) ReadVar (Lib);
-    ObjReadImports (Lib, FileGetPos (Lib), O);
+    (void) ReadVar (L->F);
+    ObjReadImports (L->F, FileGetPos (L->F), O);
 
     /* Done */
     return O;
@@ -145,25 +225,28 @@ static ObjData* ReadIndexEntry (void)
 
 
 
-static void ReadIndex (void)
+static void LibReadIndex (Library* L)
 /* Read the index of a library file */
 {
     unsigned 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 (Index[0]));
+    L->ModCount = ReadVar (L->F);
+    L->Modules  = xmalloc (L->ModCount * sizeof (L->Modules[0]));
 
     /* Read all entries in the index */
-    for (I = 0; I < ModuleCount; ++I) {
-               Index[I] = ReadIndexEntry ();
+    for (I = 0; I < L->ModCount; ++I) {
+               L->Modules[I] = ReadIndexEntry (L);
     }
 }
 
 
 
 /*****************************************************************************/
-/*                            High level stuff                              */
+/*                            High level stuff                              */
 /*****************************************************************************/
 
 
@@ -179,9 +262,8 @@ static void LibCheckExports (ObjData* O)
     for (I = 0; I < O->ExportCount; ++I) {
        if (IsUnresolved (O->Exports[I]->Name)) {
            /* We need this module */
-           O->Flags |= OBJ_REF;
-           break;
-       }
+           O->Flags |= OBJ_REF;            break;
+       }
     }
 
     /* If we need this module, insert the imports and exports */
@@ -192,111 +274,199 @@ static void LibCheckExports (ObjData* O)
 
 
 
-void LibAdd (FILE* F, const char* Name)
-/* Add files from the library to the list if there are references that could
- * be satisfied.
- */
+static void LibOpen (FILE* F, const char* Name)
+/* Open the library for use */
 {
-    unsigned LibName;
-    int HaveAdditions;
-    unsigned I;
-    LibHeader Header;
-
-    /* Store the parameters, so they're visible for other routines */
-    Lib     = F;
-    LibName = GetStringId (Name);
+    /* Create a new library structure */
+    Library* L = NewLibrary (F, 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);
-    }
-    Header.Flags   = Read16 (Lib);
-    Header.IndexOffs = Read32 (Lib);
+    LibReadHeader (L);
 
     /* Seek to the index position and read the index */
-    fseek (Lib, Header.IndexOffs, SEEK_SET);
-    ReadIndex ();
+    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 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.
+    /* Walk repeatedly over all open libraries until there's nothing more
+     * to add.
      */
     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) {
+        Additions = 0;
+
+        /* Walk over all libraries */
+        for (I = 0; I < CollCount (&OpenLibs); ++I) {
 
-        /* Get the object data */
-       ObjData* O = Index [I];
+            /* Get the next library */
+            Library* L = CollAt (&OpenLibs, I);
 
-        /* Is this object file referenced? */
-       if (O->Flags & OBJ_REF) {
+            /* 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 < L->ModCount; ++J) {
+
+                /* Get the next module */
+                ObjData* O = 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;
+                    }
+                }
+            }
+        }
 
-           /* Seek to the start of the object file and read the header */
-           fseek (Lib, O->Start, SEEK_SET);
-           LibReadObjHeader (O, Name);
+    } while (Additions > 0);
 
-           /* Seek to the start of the files list and read the files list */
-           ObjReadFiles (Lib, O->Start + O->Header.FileOffs, O);
+    /* 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) {
 
-           /* Seek to the start of the debug info and read the debug info */
-                   ObjReadDbgSyms (Lib, O->Start + O->Header.DbgSymOffs, O);
+        /* Get the next library */
+        Library* L = CollAt (&OpenLibs, I);
 
-           /* Seek to the start of the line infos and read them */
-           ObjReadLineInfos (Lib, O->Start + O->Header.LineInfoOffs, O);
+        /* Walk over all modules in this library and add the files list and
+         * sections for all referenced modules.
+         */
+        for (J = 0; J < L->ModCount; ++J) {
 
-            /* Read the assertions from the object file */
-            ObjReadAssertions (Lib, O->Start + O->Header.AssertOffs, O);
+            /* Get the object data */
+            ObjData* O = L->Modules[J];
 
-            /* Read the scope table from the object file */
-            ObjReadScopes (Lib, O->Start + O->Header.ScopeOffs, O);
+            /* Is this object file referenced? */
+            if (O->Flags & OBJ_REF) {
 
-           /* Seek to the start of the segment list and read the segments.
-            * This must be last, since the data here may reference other
-            * stuff.
-            */
-           ObjReadSections (Lib, O->Start + O->Header.SegOffs, O);
+                /* Seek to the start of the object file and read the header */
+                LibSeek (L, O->Start);
+                LibReadObjHeader (L, O);
 
-            /* Add a pointer to the library name */
-            O->LibName = LibName;
+                /* Seek to the start of the files list and read the files list */
+                ObjReadFiles (L->F, O->Start + O->Header.FileOffs, O);
 
-            /* All references to strings are now resolved, so we can delete
-             * the module string pool.
-             */
-            FreeObjStrings (O);
+                /* Seek to the start of the debug info and read the debug info */
+                ObjReadDbgSyms (L->F, O->Start + O->Header.DbgSymOffs, O);
+
+                /* Seek to the start of the line infos and read them */
+                ObjReadLineInfos (L->F, O->Start + O->Header.LineInfoOffs, O);
+
+                /* Read the assertions from the object file */
+                ObjReadAssertions (L->F, O->Start + O->Header.AssertOffs, O);
+
+                /* Read the scope table from the object file */
+                ObjReadScopes (L->F, O->Start + O->Header.ScopeOffs, 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.
+                 */
+                ObjReadSections (L->F, O->Start + O->Header.SegOffs, O);
+
+                /* Remember from which library this module is */
+                O->LibName = L->Name;
+
+                /* 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);
+                /* Insert the object into the list of all used object files */
+                InsertObjData (O);
 
-        } else {
+            } else {
 
-            /* Unreferenced object file, remove it */
-            FreeObjData (O);
+                /* Unreferenced object file, remove it */
+                FreeObjData (O);
 
+            }
         }
+
+        /* Close the file and delete the library data */
+        FreeLibrary (L);
     }
 
-    /* Done. Close the file, release allocated memory */
-    fclose (F);
-    xfree (Index);
-    Lib                = 0;
-    ModuleCount = 0;
-    Index      = 0;
+    /* We're done with all open libraries, clear the OpenLibs collection */
+    CollDeleteAll (&OpenLibs);
+}
+
+
+
+void LibAdd (FILE* F, const char* Name)
+/* Add files from the library to the list if there are references that could
+ * be satisfied.
+ */
+{
+    /* 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 ();
+    }
+}
+
+
+
+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");
+    }
+
+    /* Start a new group */
+    Grouping = 1;
+}
+
+
+
+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");
+    }
+
+    /* 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");
+    }
 }
 
 
index f4c528121cf59d924e36e712c267e4f6c3dd565d..6360106c9f8a274cc8b23a6e06d497e37f57215c 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998     Ullrich von Bassewitz                                        */
-/*              Wacholderweg 14                                              */
-/*              D-70597 Stuttgart                                            */
-/* EMail:       uz@musoftware.de                                             */
+/* (C) 1998-2005 Ullrich von Bassewitz                                       */
+/*               Römerstraße 52                                              */
+/*               D-70794 Filderstadt                                         */
+/* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
@@ -49,6 +49,21 @@ void LibAdd (FILE* F, const char* Name);
  * be satisfied.
  */
 
+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.
+ */
+
+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.
+ */
+
+void LibCheckGroup (void);
+/* Check if there are open library groups */
+
 
 
 /* End of library.h */
index 1af45165caf32abd54fc9dae45b31d19bba56f22..41246a296cad5532a7c3319406d3078143cd7950 100644 (file)
@@ -91,6 +91,8 @@ static void Usage (void)
 {
     printf ("Usage: %s [options] module ...\n"
             "Short options:\n"
+            "  -(\t\t\tStart a library group\n"
+            "  -)\t\t\tEnd a library group\n"
             "  -C name\t\tUse linker config file\n"
             "  -L path\t\tSpecify a library search path\n"
             "  -Ln name\t\tCreate a VICE label file\n"
@@ -108,6 +110,7 @@ static void Usage (void)
             "  --config name\t\tUse linker config file\n"
             "  --dbgfile name\tGenerate debug information\n"
             "  --dump-config name\tDump a builtin configuration\n"
+            "  --end-group\t\tEnd a library group\n"
             "  --help\t\tHelp (this text)\n"
             "  --lib file\t\tLink this library\n"
             "  --lib-path path\tSpecify a library search path\n"
@@ -116,6 +119,7 @@ static void Usage (void)
             "  --obj file\t\tLink this object file\n"
             "  --obj-path path\tSpecify an object file search path\n"
             "  --start-addr addr\tSet the default start address\n"
+            "  --start-group\t\tStart a library group\n"
             "  --target sys\t\tSet the target system\n"
             "  --version\t\tPrint the linker version\n",
             ProgName);
@@ -273,6 +277,15 @@ static void OptDumpConfig (const char* Opt attribute ((unused)), const char* Arg
 
 
 
+static void OptEndGroup (const char* Opt attribute ((unused)),
+                        const char* Arg attribute ((unused)))
+/* End a library group */
+{
+    LibEndGroup ();
+}
+
+
+
 static void OptHelp (const char* Opt attribute ((unused)),
                     const char* Arg attribute ((unused)))
 /* Print usage information and exit */
@@ -344,6 +357,15 @@ static void OptStartAddr (const char* Opt, const char* Arg)
 
 
 
+static void OptStartGroup (const char* Opt attribute ((unused)),
+                          const char* Arg attribute ((unused)))
+/* Start a library group */
+{
+    LibStartGroup ();
+}
+
+
+
 static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
 /* Set the target system */
 {
@@ -385,6 +407,7 @@ int main (int argc, char* argv [])
                { "--config",           1,      OptConfig               },
        { "--dbgfile",          1,      OptDbgFile              },
                { "--dump-config",      1,      OptDumpConfig           },
+        { "--end-group",        0,      OptEndGroup             },
        { "--help",             0,      OptHelp                 },
         { "--lib",              1,      OptLib                  },
                { "--lib-path",         1,      OptLibPath              },
@@ -393,6 +416,7 @@ int main (int argc, char* argv [])
         { "--obj",              1,      OptObj                  },
                { "--obj-path",         1,      OptObjPath              },
        { "--start-addr",       1,      OptStartAddr            },
+        { "--start-group",      0,      OptStartGroup           },
        { "--target",           1,      OptTarget               },
        { "--version",          0,      OptVersion              },
     };
@@ -426,6 +450,14 @@ int main (int argc, char* argv [])
                    LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
                    break;
 
+                case '(':
+                    OptStartGroup (Arg, 0);
+                    break;
+
+                case ')':
+                    OptEndGroup (Arg, 0);
+                    break;
+
                case 'h':
                case '?':
                    OptHelp (Arg, 0);
@@ -500,6 +532,9 @@ int main (int argc, char* argv [])
                Error ("Memory configuration missing");
     }
 
+    /* Check if we have open library groups */
+    LibCheckGroup ();
+
     /* Read the config file */
     CfgRead ();