1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-28 19:29:53 +00:00

Added library groups

git-svn-id: svn://svn.cc65.org/cc65/trunk@3420 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2005-03-26 16:26:11 +00:00
parent 98e9934b89
commit fe2d8f26ed
4 changed files with 398 additions and 158 deletions

View File

@ -91,6 +91,26 @@ Long options:
Here is a description of all the command line options: Here is a description of all the command line options:
<descrip> <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> <tag><tt>-h, --help</tt></tag>

View File

@ -6,7 +6,7 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998-2003 Ullrich von Bassewitz */ /* (C) 1998-2005 Ullrich von Bassewitz */
/* Römerstraße 52 */ /* Römerstraße 52 */
/* D-70794 Filderstadt */ /* D-70794 Filderstadt */
/* EMail: uz@cc65.org */ /* EMail: uz@cc65.org */
@ -62,10 +62,64 @@
/* Library data */ /* Library data structure */
static FILE* Lib = 0; typedef struct Library Library;
static unsigned ModuleCount = 0; struct Library {
static ObjData** Index = 0; 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)
/* Read the header of the object file checking the signature */ /* Do a seek in the library checking for errors */
{ {
O->Header.Magic = Read32 (Lib); if (fseek (L->F, Offs, SEEK_SET) != 0) {
if (O->Header.Magic != OBJ_MAGIC) { Error ("Seek error in `%s' (%lu): %s",
Error ("Object file `%s' in library `%s' is invalid", GetString (L->Name), Offs, strerror (errno));
GetObjFileName (O), LibName);
} }
O->Header.Version = Read16 (Lib);
if (O->Header.Version != OBJ_VERSION) {
Error ("Object file `%s' in library `%s' has wrong version",
GetObjFileName (O), LibName);
}
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);
} }
static ObjData* ReadIndexEntry (void) 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 (L->F);
if (O->Header.Magic != OBJ_MAGIC) {
Error ("Object file `%s' in library `%s' is invalid",
GetObjFileName (O), GetString (L->Name));
}
O->Header.Version = Read16 (L->F);
if (O->Header.Version != OBJ_VERSION) {
Error ("Object file `%s' in library `%s' has wrong version",
GetObjFileName (O), GetString (L->Name));
}
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 (Library* L)
/* Read one entry in the index */ /* Read one entry in the index */
{ {
/* Create a new entry and insert it into the list */ /* Create a new entry and insert it into the list */
ObjData* O = NewObjData (); ObjData* O = NewObjData ();
/* Module name */ /* Module name */
O->Name = ReadStr (Lib); O->Name = ReadStr (L->F);
/* Module flags/MTime/Start/Size */ /* Module flags/MTime/Start/Size */
O->Flags = Read16 (Lib); O->Flags = Read16 (L->F);
O->MTime = Read32 (Lib); O->MTime = Read32 (L->F);
O->Start = Read32 (Lib); O->Start = Read32 (L->F);
Read32 (Lib); /* Skip Size */ Read32 (L->F); /* Skip Size */
/* Read the string pool */ /* Read the string pool */
ObjReadStrPool (Lib, FileGetPos (Lib), O); ObjReadStrPool (L->F, FileGetPos (L->F), O);
/* Skip the export size, then read the exports */ /* Skip the export size, then read the exports */
(void) ReadVar (Lib); (void) ReadVar (L->F);
ObjReadExports (Lib, FileGetPos (Lib), O); ObjReadExports (L->F, FileGetPos (L->F), O);
/* Skip the import size, then read the imports */ /* Skip the import size, then read the imports */
(void) ReadVar (Lib); (void) ReadVar (L->F);
ObjReadImports (Lib, FileGetPos (Lib), O); ObjReadImports (L->F, FileGetPos (L->F), O);
/* Done */ /* Done */
return O; 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 */ /* Read the index of a library file */
{ {
unsigned I; unsigned I;
/* Seek to the start of the index */
LibSeek (L, L->Header.IndexOffs);
/* Read the object file count and allocate memory */ /* Read the object file count and allocate memory */
ModuleCount = ReadVar (Lib); L->ModCount = ReadVar (L->F);
Index = xmalloc (ModuleCount * sizeof (Index[0])); L->Modules = xmalloc (L->ModCount * sizeof (L->Modules[0]));
/* Read all entries in the index */ /* Read all entries in the index */
for (I = 0; I < ModuleCount; ++I) { for (I = 0; I < L->ModCount; ++I) {
Index[I] = ReadIndexEntry (); 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) { for (I = 0; I < O->ExportCount; ++I) {
if (IsUnresolved (O->Exports[I]->Name)) { if (IsUnresolved (O->Exports[I]->Name)) {
/* We need this module */ /* We need this module */
O->Flags |= OBJ_REF; O->Flags |= OBJ_REF; break;
break; }
}
} }
/* If we need this module, insert the imports and exports */ /* If we need this module, insert the imports and exports */
@ -192,111 +274,199 @@ static void LibCheckExports (ObjData* O)
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 < 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;
}
}
}
}
} 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.
*/
for (J = 0; J < L->ModCount; ++J) {
/* Get the object data */
ObjData* O = L->Modules[J];
/* Is this object file referenced? */
if (O->Flags & OBJ_REF) {
/* Seek to the start of the object file and read the header */
LibSeek (L, O->Start);
LibReadObjHeader (L, O);
/* Seek to the start of the files list and read the files list */
ObjReadFiles (L->F, O->Start + O->Header.FileOffs, 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);
} else {
/* Unreferenced object file, remove it */
FreeObjData (O);
}
}
/* Close the file and delete the library data */
FreeLibrary (L);
}
/* We're done with all open libraries, clear the OpenLibs collection */
CollDeleteAll (&OpenLibs);
}
void LibAdd (FILE* F, const char* Name) void LibAdd (FILE* F, const char* Name)
/* Add files from the library to the list if there are references that could /* Add files from the library to the list if there are references that could
* be satisfied. * be satisfied.
*/ */
{ {
unsigned LibName; /* Add the library to the list of open libraries */
int HaveAdditions; LibOpen (F, Name);
unsigned I;
LibHeader Header;
/* Store the parameters, so they're visible for other routines */ /* If there is no library group open, just resolve all open symbols and
Lib = F; * close the library. Otherwise we will do nothing because resolving will
LibName = GetStringId (Name); * be done when the group is closed.
/* 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);
/* Seek to the index position and read the index */
fseek (Lib, Header.IndexOffs, SEEK_SET);
ReadIndex ();
/* 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 { if (!Grouping) {
HaveAdditions = 0; LibResolve ();
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 */ void LibStartGroup (void)
HaveAdditions = 1; /* Start a library group. Objects within a library group may reference each
} * other, and libraries are searched repeatedly until all references are
} * satisfied.
} */
} while (HaveAdditions); {
/* We cannot already have a group open */
/* Add the files list and sections for all requested modules */ if (Grouping) {
for (I = 0; I < ModuleCount; ++I) { Error ("There's already a library group open");
}
/* Get the object data */
ObjData* O = Index [I]; /* Start a new group */
Grouping = 1;
/* 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); void LibEndGroup (void)
LibReadObjHeader (O, Name); /* End a library group and resolve all open references. Objects within a
* library group may reference each other, and libraries are searched
/* Seek to the start of the files list and read the files list */ * repeatedly until all references are satisfied.
ObjReadFiles (Lib, O->Start + O->Header.FileOffs, O); */
{
/* Seek to the start of the debug info and read the debug info */ /* We must have a library group open */
ObjReadDbgSyms (Lib, O->Start + O->Header.DbgSymOffs, O); if (!Grouping) {
Error ("There's no library group open");
/* Seek to the start of the line infos and read them */ }
ObjReadLineInfos (Lib, O->Start + O->Header.LineInfoOffs, O);
/* Resolve symbols, end the group */
/* Read the assertions from the object file */ LibResolve ();
ObjReadAssertions (Lib, O->Start + O->Header.AssertOffs, O); Grouping = 0;
}
/* Read the scope table from the object file */
ObjReadScopes (Lib, O->Start + O->Header.ScopeOffs, O);
/* Seek to the start of the segment list and read the segments. void LibCheckGroup (void)
* This must be last, since the data here may reference other /* Check if there are open library groups */
* stuff. {
*/ if (Grouping) {
ObjReadSections (Lib, O->Start + O->Header.SegOffs, O); Error ("Library group was never closed");
/* 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 {
/* Unreferenced object file, remove it */
FreeObjData (O);
}
} }
/* Done. Close the file, release allocated memory */
fclose (F);
xfree (Index);
Lib = 0;
ModuleCount = 0;
Index = 0;
} }

View File

@ -6,10 +6,10 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998 Ullrich von Bassewitz */ /* (C) 1998-2005 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Römerstraße 52 */
/* D-70597 Stuttgart */ /* D-70794 Filderstadt */
/* EMail: uz@musoftware.de */ /* EMail: uz@cc65.org */
/* */ /* */
/* */ /* */
/* This software is provided 'as-is', without any expressed or implied */ /* This software is provided 'as-is', without any expressed or implied */
@ -49,6 +49,21 @@ void LibAdd (FILE* F, const char* Name);
* be satisfied. * 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 */ /* End of library.h */

View File

@ -91,6 +91,8 @@ static void Usage (void)
{ {
printf ("Usage: %s [options] module ...\n" printf ("Usage: %s [options] module ...\n"
"Short options:\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" " -C name\t\tUse linker config file\n"
" -L path\t\tSpecify a library search path\n" " -L path\t\tSpecify a library search path\n"
" -Ln name\t\tCreate a VICE label file\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" " --config name\t\tUse linker config file\n"
" --dbgfile name\tGenerate debug information\n" " --dbgfile name\tGenerate debug information\n"
" --dump-config name\tDump a builtin configuration\n" " --dump-config name\tDump a builtin configuration\n"
" --end-group\t\tEnd a library group\n"
" --help\t\tHelp (this text)\n" " --help\t\tHelp (this text)\n"
" --lib file\t\tLink this library\n" " --lib file\t\tLink this library\n"
" --lib-path path\tSpecify a library search path\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 file\t\tLink this object file\n"
" --obj-path path\tSpecify an object file search path\n" " --obj-path path\tSpecify an object file search path\n"
" --start-addr addr\tSet the default start address\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" " --target sys\t\tSet the target system\n"
" --version\t\tPrint the linker version\n", " --version\t\tPrint the linker version\n",
ProgName); 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)), static void OptHelp (const char* Opt attribute ((unused)),
const char* Arg attribute ((unused))) const char* Arg attribute ((unused)))
/* Print usage information and exit */ /* 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) static void OptTarget (const char* Opt attribute ((unused)), const char* Arg)
/* Set the target system */ /* Set the target system */
{ {
@ -385,6 +407,7 @@ int main (int argc, char* argv [])
{ "--config", 1, OptConfig }, { "--config", 1, OptConfig },
{ "--dbgfile", 1, OptDbgFile }, { "--dbgfile", 1, OptDbgFile },
{ "--dump-config", 1, OptDumpConfig }, { "--dump-config", 1, OptDumpConfig },
{ "--end-group", 0, OptEndGroup },
{ "--help", 0, OptHelp }, { "--help", 0, OptHelp },
{ "--lib", 1, OptLib }, { "--lib", 1, OptLib },
{ "--lib-path", 1, OptLibPath }, { "--lib-path", 1, OptLibPath },
@ -393,6 +416,7 @@ int main (int argc, char* argv [])
{ "--obj", 1, OptObj }, { "--obj", 1, OptObj },
{ "--obj-path", 1, OptObjPath }, { "--obj-path", 1, OptObjPath },
{ "--start-addr", 1, OptStartAddr }, { "--start-addr", 1, OptStartAddr },
{ "--start-group", 0, OptStartGroup },
{ "--target", 1, OptTarget }, { "--target", 1, OptTarget },
{ "--version", 0, OptVersion }, { "--version", 0, OptVersion },
}; };
@ -426,6 +450,14 @@ int main (int argc, char* argv [])
LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0])); LongOption (&I, OptTab, sizeof(OptTab)/sizeof(OptTab[0]));
break; break;
case '(':
OptStartGroup (Arg, 0);
break;
case ')':
OptEndGroup (Arg, 0);
break;
case 'h': case 'h':
case '?': case '?':
OptHelp (Arg, 0); OptHelp (Arg, 0);
@ -500,6 +532,9 @@ int main (int argc, char* argv [])
Error ("Memory configuration missing"); Error ("Memory configuration missing");
} }
/* Check if we have open library groups */
LibCheckGroup ();
/* Read the config file */ /* Read the config file */
CfgRead (); CfgRead ();