/* */
/* */
/* */
-/* (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);
+}
-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;
-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 */
/*****************************************************************************/
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 */
-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");
+ }
}
{
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"
" --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"
" --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);
+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 */
+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 */
{
{ "--config", 1, OptConfig },
{ "--dbgfile", 1, OptDbgFile },
{ "--dump-config", 1, OptDumpConfig },
+ { "--end-group", 0, OptEndGroup },
{ "--help", 0, OptHelp },
{ "--lib", 1, OptLib },
{ "--lib-path", 1, OptLibPath },
{ "--obj", 1, OptObj },
{ "--obj-path", 1, OptObjPath },
{ "--start-addr", 1, OptStartAddr },
+ { "--start-group", 0, OptStartGroup },
{ "--target", 1, OptTarget },
{ "--version", 0, OptVersion },
};
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);
Error ("Memory configuration missing");
}
+ /* Check if we have open library groups */
+ LibCheckGroup ();
+
/* Read the config file */
CfgRead ();