1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-26 05:29:30 +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:
<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>

View 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 */
@ -62,10 +62,64 @@
/* 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)
/* Read the header of the object file checking the signature */
static void LibSeek (Library* L, unsigned long Offs)
/* Do a seek in the library checking for errors */
{
O->Header.Magic = Read32 (Lib);
if (O->Header.Magic != OBJ_MAGIC) {
Error ("Object file `%s' in library `%s' is invalid",
GetObjFileName (O), LibName);
if (fseek (L->F, Offs, SEEK_SET) != 0) {
Error ("Seek error in `%s' (%lu): %s",
GetString (L->Name), Offs, strerror (errno));
}
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 */
{
/* 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)
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)
/* Add files from the library to the list if there are references that could
* be satisfied.
*/
{
unsigned LibName;
int HaveAdditions;
unsigned I;
LibHeader Header;
/* Add the library to the list of open libraries */
LibOpen (F, Name);
/* 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);
}
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.
/* 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.
*/
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 */
ObjReadFiles (Lib, O->Start + O->Header.FileOffs, O);
/* Seek to the start of the debug info and read the debug info */
ObjReadDbgSyms (Lib, O->Start + O->Header.DbgSymOffs, O);
/* Seek to the start of the line infos and read them */
ObjReadLineInfos (Lib, O->Start + O->Header.LineInfoOffs, O);
/* Read the assertions from the object file */
ObjReadAssertions (Lib, O->Start + O->Header.AssertOffs, O);
/* 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.
* This must be last, since the data here may reference other
* stuff.
*/
ObjReadSections (Lib, O->Start + O->Header.SegOffs, 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 {
/* Unreferenced object file, remove it */
FreeObjData (O);
}
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");
}
/* 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 */
/* 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 */

View 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 ();