summaryrefslogtreecommitdiffstats
path: root/cpukit/libdl/rtl-unresolved.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libdl/rtl-unresolved.c')
-rw-r--r--cpukit/libdl/rtl-unresolved.c160
1 files changed, 132 insertions, 28 deletions
diff --git a/cpukit/libdl/rtl-unresolved.c b/cpukit/libdl/rtl-unresolved.c
index f42fc7d03d..4e81c3c64e 100644
--- a/cpukit/libdl/rtl-unresolved.c
+++ b/cpukit/libdl/rtl-unresolved.c
@@ -51,11 +51,17 @@ rtems_rtl_unresolved_block_alloc (rtems_rtl_unresolved* unresolved)
}
static size_t
-rtems_rtl_unresolved_name_recs (const char* name)
+rtems_rtl_unresolved_symbol_rec_count (size_t length)
{
- size_t length = strlen (name);
- return ((length + sizeof(rtems_rtl_unresolv_name) - 1) /
- sizeof(rtems_rtl_unresolv_name));
+ return ((length + sizeof(rtems_rtl_unresolv_symbol) - 1) /
+ sizeof(rtems_rtl_unresolv_symbol));
+}
+
+
+static size_t
+rtems_rtl_unresolved_symbol_recs (const char* name)
+{
+ return rtems_rtl_unresolved_symbol_rec_count (strlen (name));
}
static int
@@ -83,12 +89,11 @@ rtems_rtl_unresolved_rec_next (rtems_rtl_unresolv_rec* rec)
rec = NULL;
break;
- case rtems_rtl_unresolved_name:
+ case rtems_rtl_unresolved_symbol:
/*
* Determine how many records the name occupies. Round up.
*/
- rec += ((rec->rec.name.length + sizeof(rtems_rtl_unresolv_name) - 1) /
- sizeof(rtems_rtl_unresolv_name));
+ rec += rtems_rtl_unresolved_symbol_rec_count (rec->rec.name.length);
break;
case rtems_rtl_unresolved_reloc:
@@ -132,7 +137,7 @@ rtems_rtl_unresolved_find_name (rtems_rtl_unresolved* unresolved,
while (!rtems_rtl_unresolved_rec_is_last (block, rec))
{
- if (rec->type == rtems_rtl_unresolved_name)
+ if (rec->type == rtems_rtl_unresolved_symbol)
{
if ((rec->rec.name.length == length)
&& (strcmp (rec->rec.name.name, name) == 0))
@@ -168,7 +173,9 @@ rtems_rtl_unresolved_resolve_reloc (rtems_rtl_unresolv_rec* rec,
{
if (rec->type == rtems_rtl_unresolved_reloc)
{
+ rtems_chain_control* pending;
rtems_rtl_unresolved_reloc_data* rd;
+
rd = (rtems_rtl_unresolved_reloc_data*) data;
if (rec->rec.reloc.name == rd->name && rec->rec.reloc.obj != NULL)
@@ -179,7 +186,18 @@ rtems_rtl_unresolved_resolve_reloc (rtems_rtl_unresolv_rec* rec,
rtems_rtl_obj_relocate_unresolved (&rec->rec.reloc, rd->sym);
/*
- * Set the object pointer to NULL to indicate the record is not used
+ * If all unresolved externals are resolved add the obj module
+ * to the pending queue. This will flush the object module's
+ * data from the cache and call it's constructors.
+ */
+ if (rec->rec.reloc.obj->unresolved == 0)
+ {
+ pending = rtems_rtl_pending_unprotected ();
+ rtems_chain_append (pending, &rec->rec.reloc.obj->link);
+ }
+
+ /*
+ * Check Set the object pointer to NULL to indicate the record is not used
* anymore. Update the reference count of the name. The sweep after
* relocating will remove the reloc records with obj set to NULL and
* names with a reference count of 0.
@@ -196,7 +214,7 @@ static bool
rtems_rtl_unresolved_resolve_iterator (rtems_rtl_unresolv_rec* rec,
void* data)
{
- if (rec->type == rtems_rtl_unresolved_name)
+ if (rec->type == rtems_rtl_unresolved_symbol)
{
rtems_rtl_unresolved_reloc_data* rd;
rd = (rtems_rtl_unresolved_reloc_data*) data;
@@ -215,7 +233,7 @@ rtems_rtl_unresolved_resolve_iterator (rtems_rtl_unresolv_rec* rec,
rd->name_rec = rec;
- rtems_rtl_unresolved_interate (rtems_rtl_unresolved_resolve_reloc, rd);
+ rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_resolve_reloc, rd);
rd->name_rec = NULL;
rd->sym = NULL;
@@ -225,6 +243,57 @@ rtems_rtl_unresolved_resolve_iterator (rtems_rtl_unresolv_rec* rec,
return false;
}
+/**
+ * Struct to pass archive relocation data in the iterator.
+ */
+typedef struct rtems_rtl_unresolved_archive_reloc_data
+{
+ uint16_t name; /**< Name index. */
+ bool loaded; /**< Object file loaded. */
+ rtems_rtl_archives* archives; /**< The archives to search. */
+} rtems_rtl_unresolved_archive_reloc_data;
+
+static bool
+rtems_rtl_unresolved_archive_iterator (rtems_rtl_unresolv_rec* rec,
+ void* data)
+{
+ if (rec->type == rtems_rtl_unresolved_symbol)
+ {
+ rtems_rtl_unresolved_archive_reloc_data* ard;
+ ard = (rtems_rtl_unresolved_archive_reloc_data*) data;
+
+ ++ard->name;
+
+ if ((rec->rec.name.flags & RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE) != 0)
+ {
+ rtems_rtl_archive_search load;
+
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
+ printf ("rtl: unresolv: archive lookup: %d: %s\n",
+ ard->name, rec->rec.name.name);
+
+ load = rtems_rtl_archive_obj_load (ard->archives,
+ rec->rec.name.name, true);
+ if (load == rtems_rtl_archive_search_loaded)
+ {
+ ard->loaded = true;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool
+rtems_rtl_unresolved_archive_search_iterator (rtems_rtl_unresolv_rec* rec,
+ void* data)
+{
+ if (rec->type == rtems_rtl_unresolved_symbol)
+ rec->rec.name.flags = RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE;
+ return false;
+}
+
static void
rtems_rtl_unresolved_clean_block (rtems_rtl_unresolv_block* block,
rtems_rtl_unresolv_rec* rec,
@@ -248,8 +317,8 @@ rtems_rtl_unresolved_compact (void)
if (unresolved)
{
/*
- * Iterate over the blocks removing any empty strings. If a string is removed
- * update the indexes of all strings above this level.
+ * Iterate over the blocks removing any empty strings. If a string is
+ * removed update the indexes of all strings above this level.
*/
rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
uint16_t index = 0;
@@ -261,7 +330,7 @@ rtems_rtl_unresolved_compact (void)
while (!rtems_rtl_unresolved_rec_is_last (block, rec))
{
bool next_rec = true;
- if (rec->type == rtems_rtl_unresolved_name)
+ if (rec->type == rtems_rtl_unresolved_symbol)
{
++index;
if (rec->rec.name.refs == 0)
@@ -305,7 +374,7 @@ rtems_rtl_unresolved_compact (void)
/*
* Compact the block removing the name record.
*/
- name_recs = rtems_rtl_unresolved_name_recs (rec->rec.name.name);
+ name_recs = rtems_rtl_unresolved_symbol_recs (rec->rec.name.name);
rtems_rtl_unresolved_clean_block (block, rec, name_recs,
unresolved->block_recs);
--index;
@@ -360,14 +429,14 @@ rtems_rtl_unresolved_table_close (rtems_rtl_unresolved* unresolved)
while (!rtems_chain_is_tail (&unresolved->blocks, node))
{
rtems_chain_node* next = rtems_chain_next (node);
- free (node);
+ rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_EXTERNAL, node);
node = next;
}
}
bool
-rtems_rtl_unresolved_interate (rtems_rtl_unresolved_iterator iterator,
- void* data)
+rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_iterator iterator,
+ void* data)
{
rtems_rtl_unresolved* unresolved = rtems_rtl_unresolved_unprotected ();
if (unresolved)
@@ -438,7 +507,7 @@ rtems_rtl_unresolved_add (rtems_rtl_obj* obj,
}
name_index = rtems_rtl_unresolved_find_name (unresolved, name, true);
- name_recs = rtems_rtl_unresolved_name_recs (name);
+ name_recs = rtems_rtl_unresolved_symbol_recs (name);
/*
* An index less than 0 means the name is present and "0 - index" is the next
@@ -459,8 +528,9 @@ rtems_rtl_unresolved_add (rtems_rtl_obj* obj,
}
rec = rtems_rtl_unresolved_rec_first_free (name_block);
- rec->type = rtems_rtl_unresolved_name;
+ rec->type = rtems_rtl_unresolved_symbol;
rec->rec.name.refs = 1;
+ rec->rec.name.flags = RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE;
rec->rec.name.length = strlen (name) + 1;
memcpy ((void*) &rec->rec.name.name[0], name, rec->rec.name.length + 1);
block->recs += name_recs;
@@ -496,14 +566,41 @@ rtems_rtl_unresolved_add (rtems_rtl_obj* obj,
void
rtems_rtl_unresolved_resolve (void)
{
- rtems_rtl_unresolved_reloc_data rd;
+ bool resolving = true;
+
if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
printf ("rtl: unresolv: global resolve\n");
- rd.name = 0;
- rd.name_rec = NULL;
- rd.sym = NULL;
- rtems_rtl_unresolved_interate (rtems_rtl_unresolved_resolve_iterator, &rd);
- rtems_rtl_unresolved_compact ();
+
+ /*
+ * The resolving process is two separate stages, The first stage is to
+ * iterate over the unresolved symbols search the global symbol table. If a
+ * symbol is found iterate over the unresolved relocation records for the
+ * symbol fixing up the relocations. The second stage is to search the
+ * archives for symbols we have not been search before and if a symbol if
+ * found in an archve loaded the object file. Loading an object file stops
+ * the search of the archives for symbols and stage one is performed
+ * again. The process repeats until no more symbols are resolved.
+ */
+ while (resolving)
+ {
+ rtems_rtl_unresolved_reloc_data rd = {
+ .name = 0,
+ .name_rec = NULL,
+ .sym = NULL
+ };
+ rtems_rtl_unresolved_archive_reloc_data ard = {
+ .name = 0,
+ .loaded = false,
+ .archives = rtems_rtl_archives_unprotected ()
+ };
+
+ rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_resolve_iterator, &rd);
+ rtems_rtl_unresolved_compact ();
+ rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_archive_iterator, &ard);
+
+ resolving = ard.loaded;
+ }
+
if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
rtems_rtl_unresolved_dump ();
}
@@ -541,7 +638,7 @@ rtems_rtl_unresolved_dump_iterator (rtems_rtl_unresolv_rec* rec,
case rtems_rtl_unresolved_empty:
printf (" %03zu: 0: empty\n", dd->rec);
break;
- case rtems_rtl_unresolved_name:
+ case rtems_rtl_unresolved_symbol:
++dd->names;
printf (" %3zu: 1: name: %3d refs: %2d: %2d: %s\n",
dd->rec, dd->names,
@@ -563,9 +660,16 @@ rtems_rtl_unresolved_dump_iterator (rtems_rtl_unresolv_rec* rec,
}
void
+rtems_rtl_unresolved_set_archive_search (void)
+{
+ rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_archive_search_iterator,
+ NULL);
+}
+
+void
rtems_rtl_unresolved_dump (void)
{
rtems_rtl_unresolved_dump_data dd = { 0 };
printf ("RTL Unresolved data:\n");
- rtems_rtl_unresolved_interate (rtems_rtl_unresolved_dump_iterator, &dd);
+ rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_dump_iterator, &dd);
}