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

@@ -92,6 +92,26 @@ 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>
Print the short option summary shown above. Print the short option summary shown above.

View File

@@ -6,7 +6,7 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998-2003 Ullrich von Bassewitz */ /* (C) 1998-2005 Ullrich von Bassewitz */
/* R<>merstra<72>e 52 */ /* R<>merstra<72>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,18 +225,21 @@ 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);
} }
} }
@@ -179,8 +262,7 @@ 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;
} }
} }
@@ -192,88 +274,112 @@ static void LibCheckExports (ObjData* O)
void LibAdd (FILE* F, const char* Name) static void LibOpen (FILE* F, const char* Name)
/* Add files from the library to the list if there are references that could /* Open the library for use */
* be satisfied.
*/
{ {
unsigned LibName; /* Create a new library structure */
int HaveAdditions; Library* L = NewLibrary (F, Name);
unsigned I;
LibHeader Header;
/* Store the parameters, so they're visible for other routines */
Lib = F;
LibName = GetStringId (Name);
/* Read the remaining header fields (magic is already read) */ /* Read the remaining header fields (magic is already read) */
Header.Magic = LIB_MAGIC; LibReadHeader (L);
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 */ /* Seek to the index position and read the index */
fseek (Lib, Header.IndexOffs, SEEK_SET); LibReadIndex (L);
ReadIndex ();
/* Walk through all library modules and check for each module if there /* Add the library to the list of open libraries */
* are unresolved externals in existing modules that may be resolved CollAppend (&OpenLibs, L);
* by adding the module. Repeat this step until no more object files }
* were added.
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 { do {
HaveAdditions = 0;
for (I = 0; I < ModuleCount; ++I) { Additions = 0;
ObjData* O = Index [I];
/* 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) { if ((O->Flags & OBJ_REF) == 0) {
LibCheckExports (O); LibCheckExports (O);
if (O->Flags & OBJ_REF) { if (O->Flags & OBJ_REF) {
/* The routine added the file */ /* The routine added the file */
HaveAdditions = 1; ++Additions;
}
} }
} }
} }
} while (HaveAdditions);
/* Add the files list and sections for all requested modules */ } while (Additions > 0);
for (I = 0; I < ModuleCount; ++I) {
/* 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 */ /* Get the object data */
ObjData* O = Index [I]; ObjData* O = L->Modules[J];
/* Is this object file referenced? */ /* Is this object file referenced? */
if (O->Flags & OBJ_REF) { if (O->Flags & OBJ_REF) {
/* Seek to the start of the object file and read the header */ /* Seek to the start of the object file and read the header */
fseek (Lib, O->Start, SEEK_SET); LibSeek (L, O->Start);
LibReadObjHeader (O, Name); LibReadObjHeader (L, O);
/* Seek to the start of the files list and read the files list */ /* Seek to the start of the files list and read the files list */
ObjReadFiles (Lib, O->Start + O->Header.FileOffs, O); ObjReadFiles (L->F, O->Start + O->Header.FileOffs, O);
/* Seek to the start of the debug info and read the debug info */ /* Seek to the start of the debug info and read the debug info */
ObjReadDbgSyms (Lib, O->Start + O->Header.DbgSymOffs, O); ObjReadDbgSyms (L->F, O->Start + O->Header.DbgSymOffs, O);
/* Seek to the start of the line infos and read them */ /* Seek to the start of the line infos and read them */
ObjReadLineInfos (Lib, O->Start + O->Header.LineInfoOffs, O); ObjReadLineInfos (L->F, O->Start + O->Header.LineInfoOffs, O);
/* Read the assertions from the object file */ /* Read the assertions from the object file */
ObjReadAssertions (Lib, O->Start + O->Header.AssertOffs, O); ObjReadAssertions (L->F, O->Start + O->Header.AssertOffs, O);
/* Read the scope table from the object file */ /* Read the scope table from the object file */
ObjReadScopes (Lib, O->Start + O->Header.ScopeOffs, O); ObjReadScopes (L->F, O->Start + O->Header.ScopeOffs, O);
/* Seek to the start of the segment list and read the segments. /* Seek to the start of the segment list and read the segments.
* This must be last, since the data here may reference other * This must be last, since the data here may reference other
* stuff. * stuff.
*/ */
ObjReadSections (Lib, O->Start + O->Header.SegOffs, O); ObjReadSections (L->F, O->Start + O->Header.SegOffs, O);
/* Add a pointer to the library name */ /* Remember from which library this module is */
O->LibName = LibName; O->LibName = L->Name;
/* All references to strings are now resolved, so we can delete /* All references to strings are now resolved, so we can delete
* the module string pool. * the module string pool.
@@ -291,12 +397,76 @@ void LibAdd (FILE* F, const char* Name)
} }
} }
/* Done. Close the file, release allocated memory */ /* Close the file and delete the library data */
fclose (F); FreeLibrary (L);
xfree (Index); }
Lib = 0;
ModuleCount = 0; /* We're done with all open libraries, clear the OpenLibs collection */
Index = 0; 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");
}
} }

View File

@@ -6,10 +6,10 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998 Ullrich von Bassewitz */ /* (C) 1998-2005 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* R<>merstra<72>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 ();