[PATCH 04/11] libdl: Add symbol searching and loading from archives.

chrisj at rtems.org chrisj at rtems.org
Tue Feb 5 01:42:57 UTC 2019


From: Chris Johns <chrisj at rtems.org>

- Load archive symbol tables to support searching of archives
  for symbols.
- Search archive symbols and load the object file that contains
  the symbol.
- Search the global and archives until all remaining unresolved symbols
  are not found. Group the loaded object files in the pending queue.
- Run the object file and loaded dependents as a group before adding to the
  main object list.
- Remove orphaned object files after references are removed.

Updates #3686
---
 cpukit/Makefile.am                            |    1 +
 cpukit/include/rtems/rtl/rtl-archive.h        |  196 +++
 cpukit/include/rtems/rtl/rtl-obj.h            |   66 +-
 .../{libdl => include/rtems/rtl}/rtl-shell.h  |    2 -
 cpukit/include/rtems/rtl/rtl-trace.h          |    2 +
 cpukit/include/rtems/rtl/rtl-unresolved.h     |   37 +-
 cpukit/include/rtems/rtl/rtl.h                |   56 +-
 cpukit/libdl/dlfcn.c                          |    4 +-
 cpukit/libdl/rtl-archive.c                    | 1301 +++++++++++++++++
 cpukit/libdl/rtl-elf.c                        |   16 +-
 cpukit/libdl/rtl-obj.c                        |  473 +++---
 cpukit/libdl/rtl-shell.c                      |   15 +-
 cpukit/libdl/rtl-string.h                     |    2 -
 cpukit/libdl/rtl-trace.c                      |    4 +-
 cpukit/libdl/rtl-unresolved.c                 |  160 +-
 cpukit/libdl/rtl.c                            |  277 +++-
 16 files changed, 2175 insertions(+), 437 deletions(-)
 create mode 100644 cpukit/include/rtems/rtl/rtl-archive.h
 rename cpukit/{libdl => include/rtems/rtl}/rtl-shell.h (97%)
 create mode 100644 cpukit/libdl/rtl-archive.c

diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index 7a138c0c6e..8ea7cbbfb0 100644
--- a/cpukit/Makefile.am
+++ b/cpukit/Makefile.am
@@ -1140,6 +1140,7 @@ librtemscpu_a_SOURCES += libdl/rap.c
 librtemscpu_a_SOURCES += libdl/rap-shell.c
 librtemscpu_a_SOURCES += libdl/rtl-allocator.c
 librtemscpu_a_SOURCES += libdl/rtl-alloc-heap.c
+librtemscpu_a_SOURCES += libdl/rtl-archive.c
 librtemscpu_a_SOURCES += libdl/rtl.c
 librtemscpu_a_SOURCES += libdl/rtl-chain-iterator.c
 librtemscpu_a_SOURCES += libdl/rtl-debugger.c
diff --git a/cpukit/include/rtems/rtl/rtl-archive.h b/cpukit/include/rtems/rtl/rtl-archive.h
new file mode 100644
index 0000000000..1fe3aae385
--- /dev/null
+++ b/cpukit/include/rtems/rtl/rtl-archive.h
@@ -0,0 +1,196 @@
+/*
+ *  COPYRIGHT (c) 2018 Chris Johns <chrisj at rtems.org>
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_rtl
+ *
+ * @brief RTEMS Run-Time Linker Archive
+ *
+ * The RTL Archive module manages dependent loading of object files from
+ * archives. The archives need to have a `ranlib` generated symbol table.
+ *
+ * This module reads a configuration file called `rtl-libs.conf` from a default
+ * directory of `/etc`. The file is a line per glob'ed path to archives to
+ * search for symbols.
+ *
+ * The archive symbols are held in a per archive cache for searching.
+ *
+ * @note Errors in the reading of a config file, locating archives, reading
+ *       symbol tables and loading object files are not considered RTL error
+ *       reported to a user. The user error is undefined symbols.
+ */
+
+#if !defined (_RTEMS_RTL_ARCHIVE_H_)
+#define _RTEMS_RTL_ARCHIVE_H_
+
+#include <rtems.h>
+#include <rtems/chain.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * Flags for archives.
+ */
+#define RTEMS_RTL_ARCHIVE_USER_LOAD (1 << 0) /**< User forced load. */
+#define RTEMS_RTL_ARCHIVE_REMOVE    (1 << 1) /**< The achive is not found. */
+#define RTEMS_RTL_ARCHIVE_LOAD      (1 << 2) /**< Load the achive. */
+
+/**
+ * Symbol search and loading results.
+ */
+typedef enum rtems_rtl_archive_search
+{
+  rtems_rtl_archive_search_not_found = 0, /**< The search failed to find the
+                                               symbol. */
+  rtems_rtl_archive_search_found = 1,     /**< The symbols was found. */
+  rtems_rtl_archive_search_loaded = 2,    /**< The symbol was found and the
+                                               object file has been loaded */
+  rtems_rtl_archive_search_error = 3,     /**< There was an error searching or
+                                               loading. */
+  rtems_rtl_archive_search_no_config = 4 /**< There is no config or it is
+                                          *   invalid. */
+} rtems_rtl_archive_search;
+
+/**
+ * RTL Archive symbols.
+ */
+typedef struct rtems_rtl_archive_symbol
+{
+  size_t      entry;  /**< Index in the symbol offset table. */
+  const char* label;  /**< The symbol's label. */
+} rtems_rtl_archive_symbol;
+
+/**
+ * RTL Archive symbols.
+ */
+typedef struct rtems_rtl_archive_symbols
+{
+  void*                     base;     /**< Base of the symbol table. */
+  size_t                    size;     /**< Size of the symbol table. */
+  size_t                    entries;  /**< Entries in the symbol table. */
+  const char*               names;    /**< Start of the symbol names. */
+  rtems_rtl_archive_symbol* symbols;  /**< Sorted symbol table. */
+} rtems_rtl_archive_symbols;
+
+/**
+ * RTL Archive data.
+ */
+typedef struct rtems_rtl_archive
+{
+  rtems_chain_node          node;     /**< Chain link. */
+  const char*               name;     /**< Archive absolute path. */
+  size_t                    size;     /**< Size of the archive. */
+  time_t                    mtime;    /**< Archive's last modified time. */
+  off_t                     enames;   /**< Extended file name offset, lazy load. */
+  rtems_rtl_archive_symbols symbols;  /**< Ranlib symbol table. */
+  size_t                    refs;     /**< Loaded object modules. */
+  uint32_t                  flags;    /**< Some flags. */
+} rtems_rtl_archive;
+
+/**
+ * RTL Archive data.
+ */
+typedef struct rtems_rtl_archives
+{
+  const char*         config_name;    /**< Config file name. */
+  time_t              config_mtime;   /**< Config last modified time. */
+  size_t              config_length;  /**< Length the config data. */
+  const char*         config;         /**< Config file contents. */
+  rtems_chain_control archives;       /**< The located archives. */
+} rtems_rtl_archives;
+
+/**
+ * Error handler call when finding an archive.
+ */
+typedef void (*rtems_rtl_archive_error)(int num, const char* text);
+
+/**
+ * Open the RTL archives support with the specified configration file.
+ *
+ * @param archives The archives data to open.
+ * @param config The path to the configuration file.
+ * @return bool Returns @true is the archives are open.
+ */
+void rtems_rtl_archives_open (rtems_rtl_archives* archives, const char* config);
+
+/**
+ * Close the RTL archives support.
+ *
+ * @param archives The archives data to close.
+ */
+void rtems_rtl_archives_close (rtems_rtl_archives* archives);
+
+/**
+ * Refresh the archives data. Check if the configuration has changes and if it
+ * has reload it. Check each path in the configuration and creates archive
+ * instances for new archives and remove archives not present any more.
+ *
+ * Refreshing is a development aid so reboots can be avoided as users trial
+ * configurations that work.
+ *
+ * @param archives The archives data to refresh.
+ * @retval false The refresh failed, an error will have been set.
+ */
+bool rtems_rtl_archives_refresh (rtems_rtl_archives* archives);
+
+/**
+ * Load an archive.
+ *
+ * @param archives The archives data to search.
+ * @param name     The archive to load.
+ * @retval true    The archive is loaded.
+ */
+bool rtems_rtl_archive_load (rtems_rtl_archives* archives, const char* name);
+
+/**
+ * Search for a symbol and load the first object file that has the symbol.
+ *
+ * @param archives The archives data to search.
+ * @param symbol   The symbol name to search for.
+ * @param load     If @true load the object file the symbol is found in
+ *                 else return the found not found status.
+ */
+rtems_rtl_archive_search rtems_rtl_archive_obj_load (rtems_rtl_archives* archives,
+                                                     const char*         symbol,
+                                                     bool                load);
+
+/**
+ * Find a module in an archive returning the offset in the archive and
+ * the size. If the name field is pointing to a string pointer and
+ * that poniter is NULL and the offset is valid the name is extracted
+ * from the archive and filled in. This is used when loading a file
+ * from the archive after a symbol is found. The file name is not know
+ * and could be extended which requires searching the extended string
+ * table in the archive.
+ *
+ * @param fd Open file handle for the archive.
+ * @param fsize Size of the archive.
+ * @paarm name Pointer to the name string.
+ * @param offset The offset of the file in the archive.
+ * @param size The size of the file in the archive.
+ * @param extended_names The offset in the archive for the extended names.
+ * @param error The error handler called on an error.
+ * @retval true The file was found in the archive.
+ * @retval false The file was not found.
+ */
+bool rtems_rtl_obj_archive_find_obj (int                     fd,
+                                     size_t                  fsize,
+                                     const char**            name,
+                                     off_t*                  offset,
+                                     size_t*                 size,
+                                     off_t*                  extended_names,
+                                     rtems_rtl_archive_error error);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/cpukit/include/rtems/rtl/rtl-obj.h b/cpukit/include/rtems/rtl/rtl-obj.h
index 976d6c293f..bc503887e2 100644
--- a/cpukit/include/rtems/rtl/rtl-obj.h
+++ b/cpukit/include/rtems/rtl/rtl-obj.h
@@ -92,9 +92,8 @@ typedef struct rtems_rtl_loader_table
 #define RTEMS_RTL_OBJ_SECT_DATA  (1 << 2)  /**< Section holds program data. */
 #define RTEMS_RTL_OBJ_SECT_BSS   (1 << 3)  /**< Section holds program bss. */
 #define RTEMS_RTL_OBJ_SECT_EH    (1 << 4)  /**< Section holds exception data. */
-#define RTEMS_RTL_OBJ_SECT_REL   (1 << 5)  /**< Section holds relocation records. */
-#define RTEMS_RTL_OBJ_SECT_RELA  (1 << 6)  /**< Section holds relocation addend
-                                            *   records. */
+#define RTEMS_RTL_OBJ_SECT_REL   (1 << 5)  /**< Section holds relocation recs. */
+#define RTEMS_RTL_OBJ_SECT_RELA  (1 << 6)  /**< Section holds reloc addend recs. */
 #define RTEMS_RTL_OBJ_SECT_SYM   (1 << 7)  /**< Section holds symbols. */
 #define RTEMS_RTL_OBJ_SECT_STR   (1 << 8)  /**< Section holds strings. */
 #define RTEMS_RTL_OBJ_SECT_ALLOC (1 << 9)  /**< Section allocates runtime memory. */
@@ -168,6 +167,7 @@ typedef bool (*rtems_rtl_obj_depends_iterator) (rtems_rtl_obj* obj,
 #define RTEMS_RTL_OBJ_BASE         (1 << 2) /**< The base image. */
 #define RTEMS_RTL_OBJ_RELOC_TAG    (1 << 3) /**< Tag the object as visited when reloc
                                              *   parsing. */
+#define RTEMS_RTL_OBJ_DEP_VISITED  (1 << 4) /**< Dependency loop detection. */
 
 /**
  * RTL Object. There is one for each object module loaded plus one for the base
@@ -337,6 +337,20 @@ static inline size_t rtems_rtl_obj_align (size_t   offset,
   return offset;
 }
 
+/**
+ * Is the symbol in this object's files globa symbol table?
+ *
+ * @param obj The object file's descriptor to search.
+ * @param sym The symbol to check.
+ * @retval bool Returns @true if present else @false is returned.
+ */
+static inline bool rtems_rtl_obj_has_symbol (const rtems_rtl_obj*     obj,
+                                             const rtems_rtl_obj_sym* sym)
+{
+  return (sym >= obj->global_table &&
+          sym < (obj->global_table + obj->global_syms));
+}
+
 /**
  * Allocate an object structure on the heap.
  *
@@ -379,14 +393,6 @@ bool rtems_rtl_parse_name (const char*  name,
                            const char** oname,
                            off_t*       ooffset);
 
-/**
- * Check of the name matches the object file's object name.
- *
- * @param obj The object file's descriptor.
- * @param name The name to match.
- */
-bool rtems_rtl_match_name (rtems_rtl_obj* obj, const char* name);
-
 /**
  * Find an object file on disk that matches the name. The object descriptor is
  * fill in with the various parts of a name. A name can have archive, object
@@ -496,6 +502,15 @@ void rtems_rtl_obj_erase_dependents (rtems_rtl_obj* obj);
  */
 bool rtems_rtl_obj_add_dependent (rtems_rtl_obj* obj, rtems_rtl_obj* dependent);
 
+/**
+ * Remove dependencies. This decrements the dependent object file references.
+ *
+ * @param obj The object file's descriptor.
+ * @retval true The dependencies have been removed.
+ * @retval false There is no space in the table.
+ */
+bool rtems_rtl_obj_remove_dependencies (rtems_rtl_obj* obj);
+
 /**
  * Iterate over the module dependenices.
  *
@@ -689,6 +704,13 @@ bool rtems_rtl_obj_load_sections (rtems_rtl_obj*             obj,
                                   rtems_rtl_obj_sect_handler handler,
                                   void*                      data);
 
+/**
+ * Does the object have constructors to run?
+ *
+ * @return bool True if there are constructors to run.
+ */
+bool rtems_rtl_obj_ctors_to_run (rtems_rtl_obj* obj);
+
 /**
  * Invoke the constructors the object has. Constructors are a table of pointers
  * to "void (*)(void);" where NULL pointers are skipped. The table's size is
@@ -699,6 +721,13 @@ bool rtems_rtl_obj_load_sections (rtems_rtl_obj*             obj,
  */
 void rtems_rtl_obj_run_ctors (rtems_rtl_obj* obj);
 
+/**
+ * Does the object have destructors to run?
+ *
+ * @return bool True if there are destructors to run.
+ */
+bool rtems_rtl_obj_dtors_to_run (rtems_rtl_obj* obj);
+
 /**
  * Invoke the destructors the object has. Destructors are a table of pointers
  * to "void (*)(void);" where NULL pointers are skipped. The table's size is
@@ -709,6 +738,13 @@ void rtems_rtl_obj_run_ctors (rtems_rtl_obj* obj);
  */
 void rtems_rtl_obj_run_dtors (rtems_rtl_obj* obj);
 
+/**
+ * Get the object file reference count.
+ *
+ * @retval int The object file's reference count.
+ */
+size_t rtems_rtl_obj_get_reference (rtems_rtl_obj* obj);
+
 /**
  * Increment the object file reference count.
  *
@@ -723,6 +759,14 @@ void rtems_rtl_obj_inc_reference (rtems_rtl_obj* obj);
  */
 void rtems_rtl_obj_dec_reference (rtems_rtl_obj* obj);
 
+/**
+ * Is the object file orphaned? An orphaned object file is not locked, has no
+ * users and it not being referenced.
+ *
+ * @param obj The object file's descriptor.
+ */
+bool rtems_rtl_obj_orphaned (rtems_rtl_obj* obj);
+
 /**
  * Load the object file, reading all sections into memory, symbols and
  * performing any relocation fixups.
diff --git a/cpukit/libdl/rtl-shell.h b/cpukit/include/rtems/rtl/rtl-shell.h
similarity index 97%
rename from cpukit/libdl/rtl-shell.h
rename to cpukit/include/rtems/rtl/rtl-shell.h
index 9df5ee203f..b0a6e8d8d4 100644
--- a/cpukit/libdl/rtl-shell.h
+++ b/cpukit/include/rtems/rtl/rtl-shell.h
@@ -20,8 +20,6 @@
 extern "C" {
 #endif /* __cplusplus */
 
-#include <stdint.h>
-
 /**
  * The RTL single shell command contains sub-commands.
  *
diff --git a/cpukit/include/rtems/rtl/rtl-trace.h b/cpukit/include/rtems/rtl/rtl-trace.h
index 4b93c8c91c..84e81d5344 100644
--- a/cpukit/include/rtems/rtl/rtl-trace.h
+++ b/cpukit/include/rtems/rtl/rtl-trace.h
@@ -48,6 +48,8 @@ typedef uint32_t rtems_rtl_trace_mask;
 #define RTEMS_RTL_TRACE_ALLOCATOR              (1UL << 9)
 #define RTEMS_RTL_TRACE_UNRESOLVED             (1UL << 10)
 #define RTEMS_RTL_TRACE_CACHE                  (1UL << 11)
+#define RTEMS_RTL_TRACE_ARCHIVES               (1UL << 12)
+#define RTEMS_RTL_TRACE_DEPENDENCY             (1UL << 13)
 #define RTEMS_RTL_TRACE_ALL                    (0xffffffffUL & ~(RTEMS_RTL_TRACE_CACHE))
 
 /**
diff --git a/cpukit/include/rtems/rtl/rtl-unresolved.h b/cpukit/include/rtems/rtl/rtl-unresolved.h
index a69b51ac7f..a425384370 100644
--- a/cpukit/include/rtems/rtl/rtl-unresolved.h
+++ b/cpukit/include/rtems/rtl/rtl-unresolved.h
@@ -71,21 +71,30 @@ typedef uint32_t rtems_rtl_word;
 typedef enum rtems_rtl_unresolved_rtype
 {
   rtems_rtl_unresolved_empty = 0,  /**< The records is empty. Must always be 0 */
-  rtems_rtl_unresolved_name = 1,   /**< The record is a name. */
+  rtems_rtl_unresolved_symbol = 1, /**< The record is a symbol. */
   rtems_rtl_unresolved_reloc = 2   /**< The record is a relocation record. */
 } rtems_rtl_unresolved_rtype;
 
 /**
- * Unresolved externals symbol names. The names are reference counted and
- * separate from the relocation records because a number of records could
- * reference the same symbol name.
+ * Unresolved external symbol flags.
  */
-typedef struct rtems_rtl_unresolv_name
+#define RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE (1 << 0) /**< Search the archive. */
+
+/**
+ * Unresolved externals symbols. The symbols are reference counted and separate
+ * from the relocation records because a number of records could reference the
+ * same symbol.
+ *
+ * The name is extended in the allocator of the record in the unresolved data
+ * block. The 10 is a minimum that is added to by joining more than one record.
+ */
+typedef struct rtems_rtl_unresolv_symbol
 {
   uint16_t   refs;     /**< The number of references to this name. */
+  uint16_t   flags;    /**< Flags to manage the symbol. */
   uint16_t   length;   /**< The length of this name. */
-  const char name[12]; /**< The symbol name. */
-} rtems_rtl_unresolv_name;
+  const char name[10]; /**< The symbol name. */
+} rtems_rtl_unresolv_symbol;
 
 /**
  * Unresolved externals symbols require the relocation records to be held
@@ -108,8 +117,8 @@ typedef struct rtems_rtl_unresolv_rec
   rtems_rtl_unresolved_rtype type;
   union
   {
-    rtems_rtl_unresolv_name  name;   /**< The name, or */
-    rtems_rtl_unresolv_reloc reloc;  /**< the relocation record. */
+    rtems_rtl_unresolv_symbol name;   /**< The symnbol, or */
+    rtems_rtl_unresolv_reloc  reloc;  /**< the relocation record. */
   } rec;
 } rtems_rtl_unresolv_rec;
 
@@ -166,8 +175,8 @@ void rtems_rtl_unresolved_table_close (rtems_rtl_unresolved* unresolved);
 /**
  * Iterate over the table of unresolved entries.
  */
-bool rtems_rtl_unresolved_interate (rtems_rtl_unresolved_iterator iterator,
-                                    void*                         data);
+bool rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_iterator iterator,
+                                   void*                         data);
 
 /**
  * Add a relocation to the list of unresolved relocations.
@@ -205,6 +214,12 @@ bool rtems_rtl_unresolved_remove (rtems_rtl_obj*        obj,
                                   const uint16_t        sect,
                                   const rtems_rtl_word* rel);
 
+/**
+ * Set all symbols to be archive searchable. This is done when the available
+ * archives have been refreshed and there are new archives to search for.
+ */
+void rtems_rtl_unresolved_set_archive_search (void);
+
 /**
  * Dump the RTL unresolved data.
  */
diff --git a/cpukit/include/rtems/rtl/rtl.h b/cpukit/include/rtems/rtl/rtl.h
index 41cb010ef4..debf17cd44 100644
--- a/cpukit/include/rtems/rtl/rtl.h
+++ b/cpukit/include/rtems/rtl/rtl.h
@@ -24,6 +24,7 @@
 #include <rtems/thread.h>
 
 #include <rtems/rtl/rtl-allocator.h>
+#include <rtems/rtl/rtl-archive.h>
 #include <rtems/rtl/rtl-fwd.h>
 #include <rtems/rtl/rtl-obj.h>
 #include <rtems/rtl/rtl-obj-cache.h>
@@ -105,8 +106,10 @@ struct rtems_rtl_data
   rtems_recursive_mutex lock;           /**< The RTL lock */
   rtems_rtl_alloc_data  allocator;      /**< The allocator data. */
   rtems_chain_control   objects;        /**< List if loaded object files. */
+  rtems_chain_control   pending;        /**< Listof object files needing work. */
   const char*           paths;          /**< Search paths for archives. */
   rtems_rtl_symbols     globals;        /**< Global symbol table. */
+  rtems_rtl_archives    archives;       /**< Archive search and loader. */
   rtems_rtl_unresolved  unresolved;     /**< Unresolved symbols. */
   rtems_rtl_obj*        base;           /**< Base object file. */
   rtems_rtl_obj_cache   symbols;        /**< Symbols object file cache. */
@@ -126,8 +129,8 @@ struct rtems_rtl_data
 rtems_rtl_data* rtems_rtl_data_unprotected (void);
 
 /**
- * Get the RTL global symbol table with out locking. This call assmes the RTL
- * is locked.
+ * Get the RTL global symbol table with out locking. This call assumes
+ * the RTL is locked.
  *
  * @return rtems_rtl_symbols* The RTL global symbols after being locked.
  * @retval NULL The RTL data is not initialised.
@@ -135,7 +138,24 @@ rtems_rtl_data* rtems_rtl_data_unprotected (void);
 rtems_rtl_symbols* rtems_rtl_global_symbols (void);
 
 /**
- * Get the RTL resolved table with out locking. This call assmes the RTL
+ * Get the RTL objects table with out locking. This call assumes the RTL
+ * is locked.
+ *
+ * @return rtems_chain_control* The RTL objects chain.
+ * @retval NULL The RTL data is not initialised.
+ */
+rtems_chain_control* rtems_rtl_objects_unprotected (void);
+
+/**
+ * Get the RTL pending with out locking. This call assumes the RTL is locked.
+ *
+ * @return rtems_chain_control* The RTL pending list control.
+ * @retval NULL The RTL data is not initialised.
+ */
+rtems_chain_control* rtems_rtl_pending_unprotected (void);
+
+/**
+ * Get the RTL unresolved table with out locking. This call assumes the RTL
  * is locked.
  *
  * @return rtems_rtl_unresolv* The RTL unresolved symbols and reloc records.
@@ -143,6 +163,14 @@ rtems_rtl_symbols* rtems_rtl_global_symbols (void);
  */
 rtems_rtl_unresolved* rtems_rtl_unresolved_unprotected (void);
 
+/**
+ * Get the RTL archives with out locking. This call assumes the RTL is locked.
+ *
+ * @return rtems_rtl_archives* The RTL acrhives.
+ * @retval NULL The RTL data is not initialised.
+ */
+rtems_rtl_archives* rtems_rtl_archives_unprotected (void);
+
 /**
  * Get the RTL symbols, strings, or relocations object file caches. This call
  * assmes the RTL is locked.
@@ -276,12 +304,26 @@ rtems_rtl_obj* rtems_rtl_load_object (const char* name, int mode);
 bool rtems_rtl_unload_object (rtems_rtl_obj* obj);
 
 /**
- * Run any constructor functions the object file may contain. This call
- * assumes the linker is unlocked.
+ * Load an object file.  This is the user accessable interface to unloading an
+ * object file. See @rtems_rtl_load_object.
+ *
+ * @param name The name of the object file.
+ * @param mode The mode of the load as defined by the dlopen call.
+ * @return rtl_obj* The object file descriptor. NULL is returned if the load fails.
+ */
+rtems_rtl_obj* rtems_rtl_load (const char* name, int mode);
+
+/**
+ * Unload an object file. This is the user accessable interface to unloading an
+ * object file. See @rtems_rtl_unload_object.
+ *
+ * Assumes the RTL has been locked.
  *
- * @param obj The object file.
+ * @param obj The object file descriptor.
+ * @retval true The object file has been unloaded.
+ * @retval false The object file could not be unloaded.
  */
-void rtems_rtl_run_ctors (rtems_rtl_obj* obj);
+bool rtems_rtl_unload (rtems_rtl_obj* obj);
 
 /**
  * Get the last error message clearing it. This operation locks the run time
diff --git a/cpukit/libdl/dlfcn.c b/cpukit/libdl/dlfcn.c
index b97078cbaa..e90ed43668 100644
--- a/cpukit/libdl/dlfcn.c
+++ b/cpukit/libdl/dlfcn.c
@@ -52,7 +52,7 @@ dlopen (const char* name, int mode)
   _rtld_debug_state ();
 
   if (name)
-    obj = rtems_rtl_load_object (name, mode);
+    obj = rtems_rtl_load (name, mode);
   else
     obj = rtems_rtl_baseimage ();
 
@@ -83,7 +83,7 @@ dlclose (void* handle)
   _rtld_debug.r_state = RT_DELETE;
   _rtld_debug_state ();
 
-  r = rtems_rtl_unload_object (obj) ? 0 : -1;
+  r = rtems_rtl_unload (obj) ? 0 : -1;
 
   _rtld_debug.r_state = RT_CONSISTENT;
   _rtld_debug_state ();
diff --git a/cpukit/libdl/rtl-archive.c b/cpukit/libdl/rtl-archive.c
new file mode 100644
index 0000000000..786c9c6f1d
--- /dev/null
+++ b/cpukit/libdl/rtl-archive.c
@@ -0,0 +1,1301 @@
+/*
+ *  COPYRIGHT (c) 2018 Chris Johns <chrisj at rtems.org>
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtl
+ *
+ * @brief RTEMS Run-Time Linker Archive
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <rtems/libio_.h>
+
+#include <rtems/rtl/rtl.h>
+#include "rtl-chain-iterator.h"
+#include <rtems/rtl/rtl-trace.h>
+#include "rtl-string.h"
+#include "rtl-error.h"
+
+/**
+ * The archive symbols threshold after which a sorted symbol table is
+ * created.
+ */
+#define RTEMS_RTL_ARCHIVE_SYMBOLS_SORT (8)
+
+/**
+ * Archive headers.
+ */
+#define RTEMS_RTL_AR_IDENT      "!<arch>\n"
+#define RTEMS_RTL_AR_IDENT_SIZE (sizeof (RTEMS_RTL_AR_IDENT) - 1)
+#define RTEMS_RTL_AR_FHDR_BASE  RTEMS_RTL_AR_IDENT_SIZE
+#define RTEMS_RTL_AR_FNAME      (0)
+#define RTEMS_RTL_AR_FNAME_SIZE (16)
+#define RTEMS_RTL_AR_SIZE       (48)
+#define RTEMS_RTL_AR_SIZE_SIZE  (10)
+#define RTEMS_RTL_AR_MAGIC      (58)
+#define RTEMS_RTL_AR_MAGIC_SIZE (2)
+#define RTEMS_RTL_AR_FHDR_SIZE  (60)
+
+/**
+ * Read a 32bit value from the symbol table.
+ */
+static unsigned int
+rtems_rtl_archive_read_32 (void* data)
+{
+  uint8_t*     b = (uint8_t*) data;
+  unsigned int v = b[0];
+  v = (v << 8) | b[1];
+  v = (v << 8) | b[2];
+  v = (v << 8) | b[3];
+  return v;
+}
+
+static void
+rtems_rtl_archive_set_error (int num, const char* text)
+{
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+    printf ("rtl: archive: error: %3d:  %s\n", num, text);
+}
+
+static uint64_t
+rtems_rtl_scan_decimal (const uint8_t* string, size_t len)
+{
+  uint64_t value = 0;
+
+  while (len && (*string != ' '))
+  {
+    value *= 10;
+    value += *string - '0';
+    ++string;
+    --len;
+  }
+
+  return value;
+}
+
+static bool
+rtems_rtl_seek_read (int fd, off_t off, size_t len, uint8_t* buffer)
+{
+  if (lseek (fd, off, SEEK_SET) < 0)
+    return false;
+  if (read (fd, buffer, len) != len)
+    return false;
+  return true;
+}
+
+/**
+ * Archive iterator.
+ */
+typedef bool (*rtems_rtl_archive_iterator) (rtems_rtl_archive* archive,
+					    void*              data);
+
+/**
+ * Chain iterator data.
+ */
+typedef struct rtems_rtl_archive_chain_data
+{
+  void*                      data;      /**< User's data. */
+  rtems_rtl_archive_iterator iterator;  /**< The actual iterator. */
+} rtems_rtl_archive_chain_data;
+
+static bool
+rtems_rtl_archive_node_iterator (rtems_chain_node* node, void* data)
+{
+  rtems_rtl_archive*            archive;
+  rtems_rtl_archive_chain_data* chain_data;
+  archive    = (rtems_rtl_archive*) node;
+  chain_data = (rtems_rtl_archive_chain_data*) data;
+  return chain_data->iterator (archive, chain_data->data);
+}
+
+static void
+rtems_rtl_archive_iterate_archives (rtems_rtl_archives*        archives,
+                                    rtems_rtl_archive_iterator iterator,
+                                    void*                      data)
+{
+  rtems_rtl_archive_chain_data chain_data = {
+    .data = data,
+    .iterator = iterator
+  };
+  rtems_rtl_chain_iterate (&archives->archives,
+                           rtems_rtl_archive_node_iterator,
+                           &chain_data);
+}
+
+static bool
+rtems_rtl_rchive_name_end (const char c)
+{
+  return c == '\0' || c == '\n' || c == '/';
+}
+
+static const char*
+rtems_rtl_archive_dup_name (const char* name)
+{
+  size_t len = 0;
+  char*  dup;
+  while (!rtems_rtl_rchive_name_end (name[len]))
+    ++len;
+  dup = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, len + 1, true);
+  if (dup != NULL)
+    memcpy (dup, name, len);
+  return dup;
+}
+
+static bool
+rtems_rtl_archive_match_name (const char* file_name, const char* name)
+{
+  if (name != NULL)
+  {
+    while (!rtems_rtl_rchive_name_end (*file_name) &&
+           !rtems_rtl_rchive_name_end (*name) && *file_name == *name)
+    {
+      ++file_name;
+      ++name;
+    }
+    if (((*file_name == '\0') || (*file_name == '\n') || (*file_name == '/')) &&
+        ((*name == '\0') || (*name == '/')))
+      return true;
+  }
+  return false;
+}
+
+static bool
+rtems_rtl_archive_set_flags (rtems_rtl_archive* archive, void* data)
+{
+  uint32_t mask = *((uint32_t*) data);
+  archive->flags |= mask;
+  return true;
+}
+
+typedef struct rtems_rtl_archive_find_data
+{
+  rtems_rtl_archive* archive;
+  const char*        path;
+} rtems_rtl_archive_find_data;
+
+static bool
+rtems_rtl_archive_finder (rtems_rtl_archive* archive, void* data)
+{
+  rtems_rtl_archive_find_data* find;
+  find = (rtems_rtl_archive_find_data*) data;
+  if (strcmp (find->path, archive->name) == 0)
+  {
+    find->archive = archive;
+    return false;
+  }
+  return true;
+}
+
+static rtems_rtl_archive*
+rtems_rtl_archive_find (rtems_rtl_archives* archives,
+                        const char*         path)
+{
+  rtems_rtl_archive_find_data find = {
+    .archive = NULL,
+    .path = path
+  };
+  rtems_rtl_archive_iterate_archives (archives,
+                                      rtems_rtl_archive_finder,
+                                      &find);
+  return find.archive;
+}
+
+/*
+ * Find an object file in archive that contains the symbol we are
+ * searching for.
+ *
+ * The symbol search is performance sensitive. The archive's symbol table being
+ * searched is the symbol table in the archive created by ranlib. This table is
+ * not sorted so a sorted table of pointered to the symbols is generated after
+ * loading if there are enough symbols. For small symbol tables the searc is
+ * linear. The entire table is held in memory. At the time of writing this code
+ * the symbol table for the SPARC architecture's libc is 16k.
+ *
+ * The ranlib table is:
+ *
+ *    [4]                - size of table in bytes
+ *    [0..(entries x 4)] - 4 byte binary offsets into the archive
+ *                         for each symbol
+ *    [0..m]             - variable length table of strings, nul
+ *                         separated and sorted
+ *
+ * Note: The loading of an object file from an archive uses an offset in the
+ *       file name to speed the loading.
+ */
+typedef struct rtems_rtl_archive_obj_data
+{
+  const char*        symbol;   /**< The symbol to search for. */
+  rtems_rtl_archive* archive;  /**< The archive the symbol is found
+                                *   in. */
+  off_t              offset;   /**< The offset in the archive if found
+                                *   else 0 */
+} rtems_rtl_archive_obj_data;
+
+static int
+rtems_rtl_archive_symbol_compare (const void* a, const void* b)
+{
+  const rtems_rtl_archive_symbol* sa;
+  const rtems_rtl_archive_symbol* sb;
+  sa = (const rtems_rtl_archive_symbol*) a;
+  sb = (const rtems_rtl_archive_symbol*) b;
+  return strcmp (sa->label, sb->label);
+}
+
+static bool
+rtems_rtl_archive_obj_finder (rtems_rtl_archive* archive, void* data)
+{
+  const rtems_rtl_archive_symbols* symbols = &archive->symbols;
+
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+    printf ("rtl: archive: finder: %s: entries: %zu\n",
+            archive->name, symbols->entries);
+
+  /*
+   * Make sure there is a valid symbol table.
+   */
+  if (symbols->base != NULL)
+  {
+    /*
+     * Perform a linear search if there is no sorted symbol table.
+     */
+    rtems_rtl_archive_obj_data* search = (rtems_rtl_archive_obj_data*) data;
+    if (symbols->symbols == NULL)
+    {
+      const char* symbol = symbols->names;
+      size_t      entry;
+      for (entry = 0; entry < symbols->entries; ++entry)
+      {
+        if (strcmp (search->symbol, symbol) == 0)
+        {
+          search->archive = archive;
+          search->offset =
+            rtems_rtl_archive_read_32 (symbols->base + (entry * 4));
+          return false;
+        }
+        symbol += strlen (symbol) + 1;
+      }
+    }
+    else
+    {
+      ssize_t entry = symbols->entries / 2;
+      ssize_t offset = entry;
+      ssize_t last_entry = -1;
+      while (entry >= 0 &&
+             entry < symbols->entries &&
+             entry != last_entry &&
+             offset > 0)
+      {
+        int cmp = strcmp (search->symbol, symbols->symbols[entry].label);
+        if (cmp == 0)
+        {
+          entry = symbols->symbols[entry].entry;
+          search->archive = archive;
+          search->offset =
+            rtems_rtl_archive_read_32 (symbols->base + (entry * 4));
+          return false;
+        }
+        last_entry = entry;
+        if (offset == 1)
+          offset = 0;
+        else
+          offset = ((offset - 1) / 2) + 1;
+        if (cmp < 0)
+          entry -= offset;
+        else
+          entry += offset;
+      }
+    }
+  }
+
+  /*
+   * Next archive.
+   */
+  return true;
+}
+
+static rtems_rtl_archive*
+rtems_rtl_archive_new (rtems_rtl_archives* archives,
+                       const char*         path,
+                       const char*         name)
+{
+  rtems_rtl_archive* archive;
+  size_t             path_size;
+  size_t             size;
+  /*
+   * Handle the case of the path being just '/', do not create '//'.
+   */
+  path_size = strlen (path);
+  size = sizeof(rtems_rtl_archive) + path_size + strlen (name) + 1;
+  if (path_size > 1)
+    ++size;
+  archive = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, size, true);
+  if (archive == NULL)
+  {
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+      printf ("rtl: archive: new: %s: no memory\n", name);
+  }
+  else
+  {
+    char* aname;
+    archive->name = ((const char*) archive) + sizeof(rtems_rtl_archive);
+    aname = (char*) archive->name;
+    strcpy (aname, path);
+    if (path_size > 1)
+      strcat (aname, "/");
+    strcat (aname, name);
+    rtems_chain_set_off_chain (&archive->node);
+    archive->flags |= RTEMS_RTL_ARCHIVE_LOAD;
+  }
+  return archive;
+}
+
+static void
+rtems_rtl_archive_del (rtems_rtl_archive* archive)
+{
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+    printf ("rtl: archive: del: %s\n",  archive->name);
+  rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, archive->symbols.base);
+  rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, archive->symbols.symbols);
+  if (!rtems_chain_is_node_off_chain (&archive->node))
+    rtems_chain_extract (&archive->node);
+  rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, archive);
+}
+
+static rtems_rtl_archive*
+rtems_rtl_archive_get (rtems_rtl_archives* archives,
+                       const char*         path,
+                       const char*         name)
+{
+  rtems_rtl_archive* archive;
+  /*
+   * Getting a new archive turns the path and name into a single path the stat
+   * function can use. No matter how you try some memory is needed so it is
+   * easier to get a new archive object and delete it if it exists.
+   */
+  archive = rtems_rtl_archive_new (archives, path, name);
+  if (archive != NULL)
+  {
+    struct stat sb;
+    if (stat (archive->name, &sb) == 0)
+    {
+      if (S_ISREG (sb.st_mode))
+      {
+        rtems_rtl_archive* find_archive;
+        find_archive = rtems_rtl_archive_find (archives, archive->name);
+        if (find_archive == NULL)
+        {
+          rtems_chain_append (&archives->archives, &archive->node);
+        }
+        else
+        {
+          rtems_rtl_archive_del (archive);
+          archive = find_archive;
+        }
+        archive->flags &= ~RTEMS_RTL_ARCHIVE_REMOVE;
+        if (archive->mtime != sb.st_mtime)
+        {
+          archive->flags |= RTEMS_RTL_ARCHIVE_LOAD;
+          archive->size = sb.st_size;
+          archive->mtime = sb.st_mtime;
+        }
+      }
+    }
+  }
+  return archive;
+}
+
+static bool
+rtems_rtl_archives_load_config (rtems_rtl_archives* archives)
+{
+  struct stat sb;
+
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+    printf ("rtl: archive: config load: %s\n", archives->config_name);
+
+  if (archives->config_name == NULL)
+    return false;
+
+  if (stat (archives->config_name, &sb) < 0)
+  {
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+      printf ("rtl: archive: no config: %s\n", archives->config_name);
+    return false;
+  }
+
+  /*
+   * If the configuration has change reload it.
+   */
+  if (sb.st_mtime != archives->config_mtime)
+  {
+    int     fd;
+    ssize_t r;
+    char*   s;
+    bool    in_comment;
+
+    archives->config_mtime = sb.st_mtime;
+    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) archives->config);
+    archives->config_length = 0;
+    archives->config =
+      rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, sb.st_size, false);
+    if (archives->config == NULL)
+    {
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+        printf ("rtl: archive: no memory for config\n");
+      return false;
+    }
+
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+      printf ("rtl: archive: config load: read %s\n", archives->config_name);
+
+    fd = open (archives->config_name, O_RDONLY);
+    if (fd < 0)
+    {
+      rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) archives->config);
+      archives->config = NULL;
+      archives->config_length = 0;
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+        printf ("rtl: archive: config open error: %s\n", strerror (errno));
+      return false;
+    }
+
+    r = read (fd, (void*) archives->config, sb.st_size);
+    if (r < 0)
+    {
+      close (fd);
+      rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) archives->config);
+      archives->config = NULL;
+      archives->config_length = 0;
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+        printf ("rtl: archive: config read error: %s\n", strerror (errno));
+    }
+
+    close (fd);
+    archives->config_length = r;
+
+    /*
+     * Remove comments.
+     */
+    s = (char*) archives->config;
+    in_comment = false;
+    for (r = 0; r < archives->config_length; ++r, ++s)
+    {
+      if (*s == '#')
+        in_comment = true;
+      if (in_comment)
+      {
+        if (*s == '\n')
+          in_comment = false;
+        *s = '\0';
+      }
+    }
+
+    /*
+     * Create lines by turning '\r' and '\n' to '\0'.
+     */
+    s = (char*) archives->config;
+    for (r = 0; r < archives->config_length; ++r, ++s)
+    {
+      if (*s == '\r' || *s == '\n')
+        *s = '\0';
+    }
+
+    /*
+     * Remove leading and trailing white space.
+     */
+    s = (char*) archives->config;
+    for (r = 0; r < archives->config_length; ++r)
+    {
+      if (s[r] != '\0')
+      {
+        size_t ls = strlen (&s[r]);
+        size_t b = 0;
+        while (b < ls && isspace (s[r + b]))
+        {
+          ++b;
+        }
+        if (b > 0)
+          memmove (&s[r], &s[r + b], ls - b);
+        b = ls - 1;
+        while (b > 0 && isspace (s[r + b]))
+        {
+          s[r + b] = '\0';
+          --b;
+        }
+      }
+    }
+
+    /*
+     * Compact the lines so there is only a single nul separator.
+     */
+    s = (char*) archives->config;
+    for (r = 0; r < archives->config_length; ++r)
+    {
+      if (s[r] == '\0')
+      {
+        size_t e = r + 1;
+        while (e < archives->config_length)
+        {
+          if (s[e] != '\0')
+          {
+            if (archives->config_length - e - 1 > 0)
+              memmove (&s[r + 1], &s[e], archives->config_length - e - 1);
+            break;
+          }
+        }
+      }
+    }
+
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+    {
+      int line = 1;
+      printf ("rtl: archive: config:\n");
+      s = (char*) archives->config;
+      for (r = 0; r < archives->config_length; ++r, ++line)
+      {
+        size_t len = strlen (s);
+        printf (" %3d: %s\n", line, s);
+        s += len + 2;
+        r += len;
+      }
+    }
+  }
+
+  return true;
+}
+
+void
+rtems_rtl_archives_open (rtems_rtl_archives* archives, const char* config)
+{
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+    printf ("rtl: archive: open: %s\n", config);
+  memset (archives, 0, sizeof (rtems_rtl_archives));
+  archives->config_name = rtems_rtl_strdup (config);
+  rtems_chain_initialize_empty (&archives->archives);
+}
+
+void
+rtems_rtl_archives_close (rtems_rtl_archives* archives)
+{
+  rtems_chain_node* node;
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+    printf ("rtl: archive: close: count=%ds\n",
+            rtems_chain_node_count_unprotected (&archives->archives));
+  node = rtems_chain_first (&archives->archives);
+  while (!rtems_chain_is_tail (&archives->archives, node))
+  {
+    rtems_rtl_archive* archive = (rtems_rtl_archive*) node;
+    rtems_chain_node*  next_node = rtems_chain_next (node);
+    rtems_rtl_archive_del (archive);
+    node = next_node;
+  }
+  rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) archives->config);
+  rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, archives);
+}
+
+static void
+rtems_rtl_archives_remove (rtems_rtl_archives* archives)
+{
+  rtems_chain_node* node = rtems_chain_first (&archives->archives);
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+    printf ("rtl: archive: refresh: remove: checking %d archive(s)\n",
+            rtems_chain_node_count_unprotected (&archives->archives));
+  while (!rtems_chain_is_tail (&archives->archives, node))
+  {
+    rtems_rtl_archive* archive = (rtems_rtl_archive*) node;
+    rtems_chain_node*  next_node = rtems_chain_next (node);
+    if ((archive->flags & RTEMS_RTL_ARCHIVE_REMOVE) != 0)
+    {
+      archive->flags &= ~RTEMS_RTL_ARCHIVE_REMOVE;
+      if ((archive->flags & RTEMS_RTL_ARCHIVE_USER_LOAD) == 0)
+        rtems_rtl_archive_del (archive);
+    }
+    node = next_node;
+  }
+}
+
+static bool
+rtems_rtl_archive_loader (rtems_rtl_archive* archive, void* data)
+{
+  int* loaded = (int*) data;
+
+  if ((archive->flags & RTEMS_RTL_ARCHIVE_LOAD) != 0)
+  {
+    int         fd;
+    off_t       offset = 0;
+    size_t      size = 0;
+    const char* name = "/";
+
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+      printf ("rtl: archive: loader: %s\n", archive->name);
+
+    fd = open (archive->name, O_RDONLY);
+    if (fd < 0)
+    {
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+        printf ("rtl: archive: loader: open error: %s: %s\n",
+                archive->name, strerror (errno));
+      rtems_rtl_archive_set_error (errno, "opening archive file");
+      return true;
+    }
+
+    if (rtems_rtl_obj_archive_find_obj (fd,
+                                        archive->size,
+                                        &name,
+                                        &offset,
+                                        &size,
+                                        &archive->enames,
+                                        rtems_rtl_archive_set_error))
+    {
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+        printf ("rtl: archive: loader: symbols: off=0x%08jx size=%zu\n",
+                offset, size);
+
+      /*
+       * Reallocation the symbol table memory if it has changed size.
+       * Note, an updated library may have te same symbol table.
+       */
+      if (archive->symbols.size != size)
+      {
+        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, archive->symbols.base);
+        archive->symbols.base = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
+                                                     size,
+                                                     false);
+        if (archive->symbols.base == NULL)
+        {
+          close (fd);
+          memset (&archive->symbols, 0, sizeof (archive->symbols));
+          rtems_rtl_archive_set_error (ENOMEM, "symbol table memory");
+          return true;
+        }
+      }
+
+      /*
+       * Read the symbol table into memory and hold.
+       */
+      if (!rtems_rtl_seek_read (fd, offset, size, archive->symbols.base))
+      {
+        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, archive->symbols.base);
+        close (fd);
+        memset (&archive->symbols, 0, sizeof (archive->symbols));
+        rtems_rtl_archive_set_error (errno, "reading symbols");
+        return true;
+      }
+
+      /*
+       * The first 4 byte value is the number of entries.
+       */
+      archive->symbols.entries =
+        rtems_rtl_archive_read_32 (archive->symbols.base);
+      archive->symbols.size   = size;
+      archive->symbols.names  = archive->symbols.base;
+      archive->symbols.names += (archive->symbols.entries + 1) * 4;
+
+      /*
+       * Created a sorted symbol table if over the threshold number of symbols.
+       */
+      if (archive->symbols.entries > RTEMS_RTL_ARCHIVE_SYMBOLS_SORT)
+      {
+        const size_t size =
+          archive->symbols.entries * sizeof (rtems_rtl_archive_symbol);
+        archive->symbols.symbols =
+          rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL, size, true);
+        if (archive->symbols.symbols != NULL)
+        {
+          const char* symbol = archive->symbols.names;
+          size_t      e;
+          for (e = 0; e < archive->symbols.entries; ++e)
+          {
+            archive->symbols.symbols[e].entry = e + 1;
+            archive->symbols.symbols[e].label = symbol;
+            symbol += strlen (symbol) + 1;
+          }
+          qsort (archive->symbols.symbols,
+                 archive->symbols.entries,
+                 sizeof (rtems_rtl_archive_symbol),
+                 rtems_rtl_archive_symbol_compare);
+        }
+      }
+
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+        printf ("rtl: archive: loader: symbols: " \
+                "base=%p entries=%zu names=%p (0x%08x) symbols=%p\n",
+                archive->symbols.base,
+                archive->symbols.entries,
+                archive->symbols.names,
+                (archive->symbols.entries + 1) * 4,
+                archive->symbols.symbols);
+    }
+
+    close (fd);
+
+    archive->flags &= ~RTEMS_RTL_ARCHIVE_LOAD;
+
+    ++(*loaded);
+  }
+
+  return true;
+}
+
+static bool
+rtems_rtl_archives_load (rtems_rtl_archives* archives)
+{
+  int loaded = 0;
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+    printf ("rtl: archive: archive: load\n");
+  rtems_rtl_archive_iterate_archives (archives,
+                                      rtems_rtl_archive_loader,
+                                      &loaded);
+  return loaded > 0;
+}
+
+bool
+rtems_rtl_archives_refresh (rtems_rtl_archives* archives)
+{
+  size_t   config_path = 0;
+  uint32_t flags = RTEMS_RTL_ARCHIVE_REMOVE;
+
+  /*
+   * Reload the configuration file if it has not been loaded or has been
+   * updated.
+   */
+  if (!rtems_rtl_archives_load_config (archives))
+    return false;
+
+  /*
+   * Assume all existing archives are to be removed. If an existing archive
+   * is ccnfigured and found teh remove flags is cleared. At the of the
+   * refresh end remove any archives with this flag still set.
+   */
+  rtems_rtl_archive_iterate_archives (archives,
+                                      rtems_rtl_archive_set_flags,
+                                      &flags);
+
+  while (config_path < archives->config_length)
+  {
+    const char* dirname = &archives->config[config_path];
+    char*       basename;
+    const char  root[2] = { '/', '\0' };
+    DIR*        dir;
+
+    if (*dirname == '\0')
+    {
+      ++config_path;
+      continue;
+    }
+
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+      printf ("rtl: archive: refresh: %s\n", dirname);
+
+    config_path += strlen (dirname);
+
+    /*
+     * Relative paths do not work in the config. Must be absolute.
+     */
+    if (dirname[0] != '/')
+    {
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+        printf ("rtl: archive: refresh: relative paths ignored: %s\n", dirname);
+      continue;
+    }
+
+    /*
+     * Scan the parent directory of the glob path matching file names.
+     */
+    basename = strrchr (dirname, '/');
+    if (basename == NULL)
+      continue;
+
+    if (basename == dirname)
+      dirname = &root[0];
+
+    *basename = '\0';
+    ++basename;
+
+    dir = opendir (dirname);
+
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+      printf ("rtl: archive: refresh: %s %sfound\n",
+              dirname, dir == NULL ? ": not " : "");
+
+    if (dir != NULL)
+    {
+      while (true)
+      {
+        struct dirent  entry;
+        struct dirent* result = NULL;
+
+        if (readdir_r (dir, &entry, &result) != 0)
+        {
+          if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+            printf ("rtl: archive: refresh: readdir error\n");
+          break;
+        }
+
+        if (result == NULL)
+          break;
+
+        if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+          printf ("rtl: archive: refresh: checking: %s\n", entry.d_name);
+
+        if (fnmatch (basename, entry.d_name, 0) == 0)
+        {
+          struct stat sb;
+          if (stat (entry.d_name, &sb) == 0)
+          {
+            rtems_rtl_archive* archive;
+            archive = rtems_rtl_archive_get (archives, dirname, entry.d_name);
+            if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+              printf ("rtl: archive: refresh: %s: %sfound\n",
+                      entry.d_name, archive == NULL ? ": not " : "");
+          }
+        }
+      }
+      closedir (dir);
+    }
+
+    --basename;
+    *basename = '/';
+  }
+
+  /*
+   * Remove all archives flagged to be removed.
+   */
+  rtems_rtl_archives_remove (archives);
+
+  /*
+   * Load any new archives. If any are loaded set the archive search flag in
+   * any unresolved external symbols so the archives are searched. The archive
+   * search flag avoids searching for symbols we know are not in the known
+   * archives,
+   */
+  if (rtems_rtl_archives_load (archives))
+    rtems_rtl_unresolved_set_archive_search ();
+
+  return true;
+}
+
+bool
+rtems_rtl_archive_load (rtems_rtl_archives* archives, const char* name)
+{
+  if (archives != NULL)
+  {
+    rtems_rtl_archive* archive;
+    int                loaded = 0;
+
+    archive = rtems_rtl_archive_get (archives, "", name);
+    if (archive == NULL)
+    {
+      rtems_rtl_set_error (ENOENT, "archive not found");
+      return false;
+    }
+
+    archive->flags |= RTEMS_RTL_ARCHIVE_USER_LOAD;
+
+    rtems_rtl_archive_loader (archive, &loaded);
+    if (loaded == 0)
+    {
+      rtems_rtl_archive_del (archive);
+      rtems_rtl_set_error (ENOENT, "archive load falied");
+    }
+
+    return true;
+  }
+  return false;
+}
+
+rtems_rtl_archive_search
+rtems_rtl_archive_obj_load (rtems_rtl_archives* archives,
+                            const char*         symbol,
+                            bool                load)
+{
+  rtems_rtl_obj*       obj;
+  rtems_chain_control* pending;
+  int                  fd;
+  size_t               archive_count;
+
+  rtems_rtl_archive_obj_data search = {
+    .symbol  = symbol,
+    .archive = NULL,
+    .offset  = 0
+  };
+
+  archive_count = rtems_chain_node_count_unprotected (&archives->archives);
+
+  if (archive_count == 0)
+  {
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+      printf ("rtl: archive: load: no archives\n");
+    return rtems_rtl_archive_search_no_config;
+  }
+
+  pending = rtems_rtl_pending_unprotected ();
+  if (pending == NULL)
+  {
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+      printf ("rtl: archive: load: no pending list\n");
+    return rtems_rtl_archive_search_not_found;
+  }
+
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+    printf ("rtl: archive: load: searching %zu archives\n", archive_count);
+
+  rtems_rtl_archive_iterate_archives (archives,
+                                      rtems_rtl_archive_obj_finder,
+                                      &search);
+
+  if (search.archive == NULL)
+  {
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+      printf ("rtl: archive: load: not found: %s\n", symbol);
+    return rtems_rtl_archive_search_not_found;
+  }
+
+  if (!load)
+  {
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+      printf ("rtl: archive: load: found (no load): %s\n", symbol);
+    return rtems_rtl_archive_search_found;
+  }
+
+  obj = rtems_rtl_obj_alloc ();
+  if (obj == NULL)
+  {
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+      printf ("rtl: archive: alloc: no memory: %s\n",
+              search.archive->name);
+    return rtems_rtl_archive_search_error;
+  }
+
+  obj->aname = rtems_rtl_strdup (search.archive->name);
+
+  fd = open (obj->aname, O_RDONLY);
+  if (fd < 0)
+  {
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+      printf ("rtl: archive: load: open error: %s: %s\n",
+              obj->aname, strerror (errno));
+    rtems_rtl_obj_free (obj);
+    return rtems_rtl_archive_search_error;
+  }
+
+  obj->oname = NULL;
+  obj->ooffset = search.offset;
+
+  if (!rtems_rtl_obj_archive_find_obj (fd,
+                                       search.archive->size,
+                                       &obj->oname,
+                                       &obj->ooffset,
+                                       &obj->fsize,
+                                       &search.archive->enames,
+                                       rtems_rtl_archive_set_error))
+  {
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+      printf ("rtl: archive: load: load error: %s:%s\n",
+              obj->aname, obj->oname);
+    close (fd);
+    rtems_rtl_obj_free (obj);
+    return rtems_rtl_archive_search_error;
+  }
+
+  obj->fname = rtems_rtl_strdup (obj->aname);
+  obj->ooffset -= RTEMS_RTL_AR_FHDR_SIZE;
+  obj->fsize = search.archive->size;
+
+  close (fd);
+
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+    printf ("rtl: archive: loading: %s:%s at 0x%08jx size:%zu\n",
+            obj->aname, obj->oname, obj->ooffset, obj->fsize);
+
+  rtems_chain_append (pending, &obj->link);
+
+  if (!rtems_rtl_obj_load (obj))
+  {
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+      printf ("rtl: archive: loading: error: %s:%s at 0x%08jx\n",
+              obj->aname, obj->oname, obj->ooffset);
+    rtems_chain_extract (&obj->link);
+    rtems_rtl_obj_free (obj);
+    rtems_rtl_obj_caches_flush ();
+    return rtems_rtl_archive_search_error;
+  }
+
+  rtems_rtl_obj_caches_flush ();
+
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+    printf ("rtl: archive: loading: loaded: %s:%s at 0x%08jx\n",
+            obj->aname, obj->oname, obj->ooffset);
+
+  return rtems_rtl_archive_search_loaded;
+}
+
+bool
+rtems_rtl_obj_archive_find_obj (int                     fd,
+                                size_t                  fsize,
+                                const char**            name,
+                                off_t*                  ooffset,
+                                size_t*                 osize,
+                                off_t*                  extended_file_names,
+                                rtems_rtl_archive_error error)
+{
+  uint8_t header[RTEMS_RTL_AR_FHDR_SIZE];
+  bool    scanning;
+
+  if (name == NULL)
+  {
+    error (errno, "invalid object name");
+    *ooffset = 0;
+    *osize = 0;
+    return false;
+  }
+
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+    printf ("rtl: archive: find obj: %s @ 0x%08jx\n", *name, *ooffset);
+
+  if (read (fd, &header[0], RTEMS_RTL_AR_IDENT_SIZE) !=  RTEMS_RTL_AR_IDENT_SIZE)
+  {
+    error (errno, "reading archive identifer");
+    *ooffset = 0;
+    *osize = 0;
+    return false;
+  }
+
+  if (memcmp (header, RTEMS_RTL_AR_IDENT, RTEMS_RTL_AR_IDENT_SIZE) != 0)
+  {
+    error (EINVAL, "invalid archive identifer");
+    *ooffset = 0;
+    *osize = 0;
+    return false;
+  }
+
+  /*
+   * Seek to the current offset in the archive and if we have a valid archive
+   * file header present check the file name for a match with the oname field
+   * of the object descriptor. If the archive header is not valid and it is the
+   * first pass reset the offset and start the search again in case the offset
+   * provided is not valid any more.
+   *
+   * The archive can have a symbol table at the start. Ignore it. A symbol
+   * table has the file name '/'.
+   *
+   * The archive can also have the GNU extended file name table. This
+   * complicates the processing. If the object's file name starts with '/' the
+   * remainder of the file name is an offset into the extended file name
+   * table. To find the extended file name table we need to scan from start of
+   * the archive for a file name of '//'. Once found we remeber the table's
+   * start and can direct seek to file name location. In other words the scan
+   * only happens once.
+   *
+   * If the name had the offset encoded we go straight to that location.
+   */
+
+  if (*ooffset != 0)
+    scanning = false;
+  else
+  {
+    if (*name == NULL)
+    {
+      error (errno, "invalid object name and archive offset");
+      *ooffset = 0;
+      *osize = 0;
+      return false;
+    }
+    scanning = true;
+    *ooffset = RTEMS_RTL_AR_FHDR_BASE;
+    *osize = 0;
+  }
+
+  while (*ooffset < fsize)
+  {
+    /*
+     * Clean up any existing data.
+     */
+    memset (header, 0, sizeof (header));
+
+    if (!rtems_rtl_seek_read (fd, *ooffset, RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
+    {
+      error (errno, "seek/read archive file header");
+      *ooffset = 0;
+      *osize = 0;
+      return false;
+    }
+
+    if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) ||
+        (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a))
+    {
+      if (scanning)
+      {
+        error (EINVAL, "invalid archive file header");
+        *ooffset = 0;
+        *osize = 0;
+        return false;
+      }
+
+      scanning = true;
+      *ooffset = RTEMS_RTL_AR_FHDR_BASE;
+      continue;
+    }
+
+    /*
+     * The archive header is always aligned to an even address.
+     */
+    *osize = (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
+                                      RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;
+
+    /*
+     * Check for the GNU extensions.
+     */
+    if (header[0] == '/')
+    {
+      off_t extended_off;
+
+      switch (header[1])
+      {
+        case ' ':
+          /*
+           * SVR4/GNU Symbols table. Nothing more to do.
+           */
+          *ooffset += RTEMS_RTL_AR_FHDR_SIZE;
+          return true;
+        case '/':
+          /*
+           * Extended file names table. Remember. If asked to find this file
+           * return the result.
+           */
+          *extended_file_names = *ooffset + RTEMS_RTL_AR_FHDR_SIZE;
+          if (*name[0] == '/' && *name[1] == '/')
+          {
+            *ooffset = *ooffset + RTEMS_RTL_AR_FHDR_SIZE;
+            return true;
+          }
+          break;
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+          /*
+           * Offset into the extended file name table. If we do not have the
+           * offset to the extended file name table find it.
+           */
+          extended_off =
+            rtems_rtl_scan_decimal (&header[1], RTEMS_RTL_AR_FNAME_SIZE);
+
+          if (*extended_file_names == 0)
+          {
+            off_t off = RTEMS_RTL_AR_IDENT_SIZE;
+            while (*extended_file_names == 0)
+            {
+              off_t esize;
+
+              if (!rtems_rtl_seek_read (fd, off,
+                                        RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
+              {
+                error (errno, "seeking/reading archive ext file name header");
+                *ooffset = 0;
+                *osize = 0;
+                return false;
+              }
+
+              if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) ||
+                  (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a))
+              {
+                error (errno, "invalid archive file header");
+                *ooffset = 0;
+                *osize = 0;
+                return false;
+              }
+
+              if ((header[0] == '/') && (header[1] == '/'))
+              {
+                *extended_file_names = off + RTEMS_RTL_AR_FHDR_SIZE;
+                break;
+              }
+
+              esize =
+                (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
+                                         RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;
+              off += esize + RTEMS_RTL_AR_FHDR_SIZE;
+            }
+          }
+
+          if (*extended_file_names != 0)
+          {
+            /*
+             * We know the offset in the archive to the extended file. Read the
+             * name from the table and compare with the name we are after.
+             */
+            #define RTEMS_RTL_MAX_FILE_SIZE (256)
+            char ename[RTEMS_RTL_MAX_FILE_SIZE];
+
+            if (!rtems_rtl_seek_read (fd, *extended_file_names + extended_off,
+                                      RTEMS_RTL_MAX_FILE_SIZE, (uint8_t*) &ename[0]))
+            {
+              error (errno, "invalid archive ext file seek/read");
+              *ooffset = 0;
+              *osize = 0;
+              return false;
+            }
+
+            /*
+             * If there is no name memory the user is asking us to return the
+             * name in the archive at the offset.
+             */
+            if (*name == NULL)
+              *name = rtems_rtl_archive_dup_name (ename);
+            if (rtems_rtl_archive_match_name (*name, ename))
+            {
+              *ooffset += RTEMS_RTL_AR_FHDR_SIZE;
+              return true;
+            }
+          }
+          break;
+        default:
+          /*
+           * Ignore the file because we do not know what it it.
+           */
+          break;
+      }
+    }
+    else
+    {
+      const char* ename = (const char*) &header[RTEMS_RTL_AR_FNAME];
+      if (*name == NULL)
+        *name = rtems_rtl_archive_dup_name (ename);
+      if (rtems_rtl_archive_match_name (*name, ename))
+      {
+        *ooffset += RTEMS_RTL_AR_FHDR_SIZE;
+        return true;
+      }
+    }
+
+    *ooffset += *osize + RTEMS_RTL_AR_FHDR_SIZE;
+  }
+
+  error (ENOENT, "object file not found");
+  *ooffset = 0;
+  *osize = 0;
+  return false;
+
+}
diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c
index 762130b9e7..caa37e6bab 100644
--- a/cpukit/libdl/rtl-elf.c
+++ b/cpukit/libdl/rtl-elf.c
@@ -248,6 +248,13 @@ rtems_rtl_elf_reloc_relocator (rtems_rtl_obj*      obj,
     }
 
     sobj = rtems_rtl_find_obj_with_symbol (symbol);
+
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_DEPENDENCY))
+      printf ("rtl: depend: %s -> %s:%s\n",
+              obj->oname,
+              sobj == NULL ? "not-found" : sobj->oname,
+              symname);
+
     if (sobj != NULL)
     {
       if (rtems_rtl_obj_add_dependent (obj, sobj))
@@ -471,6 +478,13 @@ rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc* reloc,
   }
 
   sobj = rtems_rtl_find_obj_with_symbol (sym);
+
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_DEPENDENCY))
+    printf ("rtl: depend: %s -> %s:%s\n",
+            reloc->obj->oname,
+            sobj == NULL ? "not-found" : sobj->oname,
+            sym->name);
+
   if (sobj != NULL)
   {
     if (rtems_rtl_obj_add_dependent (reloc->obj, sobj))
@@ -1274,8 +1288,6 @@ rtems_rtl_elf_file_load (rtems_rtl_obj* obj, int fd)
   if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocs_locator, &ehdr))
     return false;
 
-  rtems_rtl_obj_synchronize_cache (obj);
-
   rtems_rtl_symbol_obj_erase_local (obj);
 
   if (!rtems_rtl_elf_load_linkmap (obj))
diff --git a/cpukit/libdl/rtl-obj.c b/cpukit/libdl/rtl-obj.c
index 28a5242ac3..858713dee1 100644
--- a/cpukit/libdl/rtl-obj.c
+++ b/cpukit/libdl/rtl-obj.c
@@ -106,7 +106,7 @@ rtems_rtl_obj_free_names (rtems_rtl_obj* obj)
 bool
 rtems_rtl_obj_free (rtems_rtl_obj* obj)
 {
-  if (obj->users || ((obj->flags & RTEMS_RTL_OBJ_LOCKED) != 0))
+  if (obj->users > 0 || ((obj->flags & RTEMS_RTL_OBJ_LOCKED) != 0))
   {
     rtems_rtl_set_error (EINVAL, "cannot free obj still in use");
     return false;
@@ -119,18 +119,63 @@ rtems_rtl_obj_free (rtems_rtl_obj* obj)
   rtems_rtl_obj_erase_dependents (obj);
   rtems_rtl_symbol_obj_erase (obj);
   rtems_rtl_obj_free_names (obj);
-  if (obj->sec_num)
+  if (obj->sec_num != NULL)
     free (obj->sec_num);
-  if (obj->linkmap)
+  if (obj->linkmap != NULL)
     rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) obj->linkmap);
   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, obj);
   return true;
 }
 
+typedef struct rtems_rtl_obj_unresolved_data
+{
+  bool has_unresolved;
+} rtems_rtl_obj_unresolved_data;
+
+static bool
+rtems_rtl_obj_unresolved_dependent (rtems_rtl_obj* obj,
+                                    rtems_rtl_obj* dependent,
+                                    void*          data)
+{
+  rtems_rtl_obj_unresolved_data* ud;
+  ud = (rtems_rtl_obj_unresolved_data*) data;
+  if ((dependent->flags & RTEMS_RTL_OBJ_DEP_VISITED) == 0)
+  {
+    dependent->flags |= RTEMS_RTL_OBJ_DEP_VISITED;
+    if ((dependent->flags & RTEMS_RTL_OBJ_UNRESOLVED) != 0)
+      ud->has_unresolved = true;
+    else
+    {
+      rtems_rtl_obj_iterate_dependents (dependent,
+                                        rtems_rtl_obj_unresolved_dependent,
+                                        ud);
+    }
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
+      printf ("rtl: obj: unresolved: dep: %s is %s\n",
+              dependent->oname, ud->has_unresolved ? "unresolved" : "resolved");
+  }
+  return ud->has_unresolved;
+}
+
 bool
 rtems_rtl_obj_unresolved (rtems_rtl_obj* obj)
 {
-  return (obj->flags & RTEMS_RTL_OBJ_UNRESOLVED) != 0 ? true : false;
+  rtems_rtl_obj_unresolved_data ud = {
+    .has_unresolved = (obj->flags & RTEMS_RTL_OBJ_UNRESOLVED) != 0
+  };
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
+    printf ("rtl: obj: unresolved: dep: %s is %s\n",
+            obj->oname, ud.has_unresolved ? "unresolved" : "resolved");
+  if (!ud.has_unresolved)
+  {
+    rtems_rtl_obj_update_flags (RTEMS_RTL_OBJ_DEP_VISITED, 0);
+    obj->flags |= RTEMS_RTL_OBJ_DEP_VISITED;
+    rtems_rtl_obj_iterate_dependents (obj,
+                                      rtems_rtl_obj_unresolved_dependent,
+                                      &ud);
+    rtems_rtl_obj_update_flags (RTEMS_RTL_OBJ_DEP_VISITED, 0);
+  }
+  return ud.has_unresolved;
 }
 
 bool
@@ -148,6 +193,9 @@ rtems_rtl_parse_name (const char*  name,
    * Parse the name to determine if the object file is part of an archive or it
    * is an object file. If an archive check the name for a '@' to see if the
    * archive contains an offset.
+   *
+   * Note, if an archive the object file oofset may be know but the
+   *       object file is not. Leave the object name as a NULL.
    */
   end = name + strlen (name);
   colon = strrchr (name, ':');
@@ -155,7 +203,7 @@ rtems_rtl_parse_name (const char*  name,
     colon = end;
 
   loname = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, colon - name + 1, true);
-  if (!oname)
+  if (!loname)
   {
     rtems_rtl_set_error (ENOMEM, "no memory for object file name");
     return false;
@@ -219,35 +267,6 @@ rtems_rtl_obj_parse_name (rtems_rtl_obj* obj, const char* name)
   return rtems_rtl_parse_name (name, &(obj->aname), &(obj->oname), &(obj->ooffset));
 }
 
-static bool
-rtems_rtl_seek_read (int fd, off_t off, size_t len, uint8_t* buffer)
-{
-  if (lseek (fd, off, SEEK_SET) < 0)
-    return false;
-  if (read (fd, buffer, len) != len)
-    return false;
-  return true;
-}
-
-/**
- * Scan the decimal number returning the value found.
- */
-static uint64_t
-rtems_rtl_scan_decimal (const uint8_t* string, size_t len)
-{
-  uint64_t value = 0;
-
-  while (len && (*string != ' '))
-  {
-    value *= 10;
-    value += *string - '0';
-    ++string;
-    --len;
-  }
-
-  return value;
-}
-
 /**
  * Section size summer iterator data.
  */
@@ -339,22 +358,6 @@ rtems_rtl_obj_section_handler (uint32_t                   mask,
   return true;
 }
 
-bool
-rtems_rtl_match_name (rtems_rtl_obj* obj, const char* name)
-{
-  const char* n1 = obj->oname;
-  while ((*n1 != '\0') && (*n1 != '\n') && (*n1 != '/') &&
-         (*name != '\0') && (*name != '/') && (*n1 == *name))
-  {
-    ++n1;
-    ++name;
-  }
-  if (((*n1 == '\0') || (*n1 == '\n') || (*n1 == '/')) &&
-      ((*name == '\0') || (*name == '/')))
-    return true;
-  return false;
-}
-
 bool
 rtems_rtl_obj_find_file (rtems_rtl_obj* obj, const char* name)
 {
@@ -596,9 +599,15 @@ rtems_rtl_obj_add_dependent (rtems_rtl_obj* obj, rtems_rtl_obj* dependent)
 {
   rtems_rtl_obj**   free_slot;
   rtems_chain_node* node;
+
   if (obj == dependent || dependent == rtems_rtl_baseimage ())
     return false;
+
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_DEPENDENCY))
+    printf ("rtl: depend: add: %s -> %s\n", obj->oname, dependent->oname);
+
   free_slot = NULL;
+
   node = rtems_chain_first (&obj->dependents);
   while (!rtems_chain_is_tail (&obj->dependents, node))
   {
@@ -613,6 +622,7 @@ rtems_rtl_obj_add_dependent (rtems_rtl_obj* obj, rtems_rtl_obj* dependent)
     }
     node = rtems_chain_next (node);
   }
+
   if (free_slot == NULL)
   {
     if (rtems_rtl_obj_alloc_dependents (obj,
@@ -629,11 +639,47 @@ rtems_rtl_obj_add_dependent (rtems_rtl_obj* obj, rtems_rtl_obj* dependent)
       }
     }
   }
+
   if (free_slot != NULL)
     *free_slot = dependent;
+
   return free_slot != NULL;
 }
 
+
+bool
+rtems_rtl_obj_remove_dependencies (rtems_rtl_obj* obj)
+{
+  /*
+   * If there are no references unload the object.
+   */
+  if (obj->refs == 0)
+  {
+    /*
+     * Remove the refences from the object files this file depend on. The
+     * unload happens once the list of objects to be unloaded has been made and
+     * the destructors have been called for all those modules.
+     */
+    rtems_chain_node* node = rtems_chain_first (&obj->dependents);
+    while (!rtems_chain_is_tail (&obj->dependents, node))
+    {
+      rtems_rtl_obj_depends* depends = (rtems_rtl_obj_depends*) node;
+      size_t                 d;
+      for (d = 0; d < depends->dependents; ++d)
+      {
+        if (depends->depends[d] != NULL)
+        {
+          rtems_rtl_obj_dec_reference (depends->depends[d]);
+          depends->depends[d] = NULL;
+        }
+      }
+      node = rtems_chain_next (node);
+    }
+    return true;
+  }
+  return false;
+}
+
 bool
 rtems_rtl_obj_iterate_dependents (rtems_rtl_obj*                 obj,
                                   rtems_rtl_obj_depends_iterator iterator,
@@ -1065,244 +1111,42 @@ rtems_rtl_obj_run_cdtors (rtems_rtl_obj* obj, uint32_t mask)
   }
 }
 
-void
-rtems_rtl_obj_run_ctors (rtems_rtl_obj* obj)
+static bool
+rtems_rtl_obj_cdtors_to_run (rtems_rtl_obj* obj, uint32_t mask)
 {
-  return rtems_rtl_obj_run_cdtors (obj, RTEMS_RTL_OBJ_SECT_CTOR);
+  rtems_chain_node* node = rtems_chain_first (&obj->sections);
+  while (!rtems_chain_is_tail (&obj->sections, node))
+  {
+    rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node;
+    if ((sect->flags & mask) == mask)
+      return true;
+    node = rtems_chain_next (node);
+  }
+  return false;
 }
 
-void
-rtems_rtl_obj_run_dtors (rtems_rtl_obj* obj)
+bool
+rtems_rtl_obj_ctors_to_run (rtems_rtl_obj* obj)
 {
-  return rtems_rtl_obj_run_cdtors (obj, RTEMS_RTL_OBJ_SECT_DTOR);
+  return rtems_rtl_obj_cdtors_to_run (obj, RTEMS_RTL_OBJ_SECT_CTOR);
 }
 
-/**
- * Find a module in an archive returning the offset in the archive in the
- * object descriptor.
- */
-static bool
-rtems_rtl_obj_archive_find (rtems_rtl_obj* obj, int fd)
-{
-#define RTEMS_RTL_AR_IDENT      "!<arch>\n"
-#define RTEMS_RTL_AR_IDENT_SIZE (sizeof (RTEMS_RTL_AR_IDENT) - 1)
-#define RTEMS_RTL_AR_FHDR_BASE  RTEMS_RTL_AR_IDENT_SIZE
-#define RTEMS_RTL_AR_FNAME      (0)
-#define RTEMS_RTL_AR_FNAME_SIZE (16)
-#define RTEMS_RTL_AR_SIZE       (48)
-#define RTEMS_RTL_AR_SIZE_SIZE  (10)
-#define RTEMS_RTL_AR_MAGIC      (58)
-#define RTEMS_RTL_AR_MAGIC_SIZE (2)
-#define RTEMS_RTL_AR_FHDR_SIZE  (60)
-
-  size_t  fsize = obj->fsize;
-  off_t   extended_file_names;
-  uint8_t header[RTEMS_RTL_AR_FHDR_SIZE];
-  bool    scanning;
-
-  if (read (fd, &header[0], RTEMS_RTL_AR_IDENT_SIZE) !=  RTEMS_RTL_AR_IDENT_SIZE)
-  {
-    rtems_rtl_set_error (errno, "reading archive identifer");
-    return false;
-  }
-
-  if (memcmp (header, RTEMS_RTL_AR_IDENT, RTEMS_RTL_AR_IDENT_SIZE) != 0)
-  {
-    rtems_rtl_set_error (EINVAL, "invalid archive identifer");
-    return false;
-  }
-
-  /*
-   * Seek to the current offset in the archive and if we have a valid archive
-   * file header present check the file name for a match with the oname field
-   * of the object descriptor. If the archive header is not valid and it is the
-   * first pass reset the offset and start the search again in case the offset
-   * provided is not valid any more.
-   *
-   * The archive can have a symbol table at the start. Ignore it. A symbol
-   * table has the file name '/'.
-   *
-   * The archive can also have the GNU extended file name table. This
-   * complicates the processing. If the object's file name starts with '/' the
-   * remainder of the file name is an offset into the extended file name
-   * table. To find the extended file name table we need to scan from start of
-   * the archive for a file name of '//'. Once found we remeber the table's
-   * start and can direct seek to file name location. In other words the scan
-   * only happens once.
-   *
-   * If the name had the offset encoded we go straight to that location.
-   */
-
-  if (obj->ooffset != 0)
-    scanning = false;
-  else
-  {
-    scanning = true;
-    obj->ooffset = RTEMS_RTL_AR_FHDR_BASE;
-  }
-
-  extended_file_names = 0;
-
-  while (obj->ooffset < fsize)
-  {
-    /*
-     * Clean up any existing data.
-     */
-    memset (header, 0, sizeof (header));
-
-    if (!rtems_rtl_seek_read (fd, obj->ooffset, RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
-    {
-      rtems_rtl_set_error (errno, "seek/read archive file header");
-      obj->ooffset = 0;
-      obj->fsize = 0;
-      return false;
-    }
-
-    if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) ||
-        (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a))
-    {
-      if (scanning)
-      {
-        rtems_rtl_set_error (EINVAL, "invalid archive file header");
-        obj->ooffset = 0;
-        obj->fsize = 0;
-        return false;
-      }
-
-      scanning = true;
-      obj->ooffset = RTEMS_RTL_AR_FHDR_BASE;
-      continue;
-    }
-
-    /*
-     * The archive header is always aligned to an even address.
-     */
-    obj->fsize = (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
-                                          RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;
-
-    /*
-     * Check for the GNU extensions.
-     */
-    if (header[0] == '/')
-    {
-      off_t extended_off;
-
-      switch (header[1])
-      {
-        case ' ':
-          /*
-           * Symbols table. Ignore the table.
-           */
-          break;
-        case '/':
-          /*
-           * Extended file names table. Remember.
-           */
-          extended_file_names = obj->ooffset + RTEMS_RTL_AR_FHDR_SIZE;
-          break;
-        case '0':
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7':
-        case '8':
-        case '9':
-          /*
-           * Offset into the extended file name table. If we do not have the
-           * offset to the extended file name table find it.
-           */
-          extended_off =
-            rtems_rtl_scan_decimal (&header[1], RTEMS_RTL_AR_FNAME_SIZE);
-
-          if (extended_file_names == 0)
-          {
-            off_t off = obj->ooffset;
-            while (extended_file_names == 0)
-            {
-              off_t esize =
-                (rtems_rtl_scan_decimal (&header[RTEMS_RTL_AR_SIZE],
-                                         RTEMS_RTL_AR_SIZE_SIZE) + 1) & ~1;
-              off += esize + RTEMS_RTL_AR_FHDR_SIZE;
-
-              if (!rtems_rtl_seek_read (fd, off,
-                                        RTEMS_RTL_AR_FHDR_SIZE, &header[0]))
-              {
-                rtems_rtl_set_error (errno,
-                                     "seeking/reading archive ext file name header");
-                obj->ooffset = 0;
-                obj->fsize = 0;
-                return false;
-              }
-
-              if ((header[RTEMS_RTL_AR_MAGIC] != 0x60) ||
-                  (header[RTEMS_RTL_AR_MAGIC + 1] != 0x0a))
-              {
-                rtems_rtl_set_error (errno, "invalid archive file header");
-                obj->ooffset = 0;
-                obj->fsize = 0;
-                return false;
-              }
-
-              if ((header[0] == '/') && (header[1] == '/'))
-              {
-                extended_file_names = off + RTEMS_RTL_AR_FHDR_SIZE;
-                break;
-              }
-            }
-          }
-
-          if (extended_file_names)
-          {
-            /*
-             * We know the offset in the archive to the extended file. Read the
-             * name from the table and compare with the name we are after.
-             */
-#define RTEMS_RTL_MAX_FILE_SIZE (256)
-            char name[RTEMS_RTL_MAX_FILE_SIZE];
-
-            if (!rtems_rtl_seek_read (fd, extended_file_names + extended_off,
-                                      RTEMS_RTL_MAX_FILE_SIZE, (uint8_t*) &name[0]))
-            {
-              rtems_rtl_set_error (errno,
-                                   "invalid archive ext file seek/read");
-              obj->ooffset = 0;
-              obj->fsize = 0;
-              return false;
-            }
-
-            if (rtems_rtl_match_name (obj, name))
-            {
-              obj->ooffset += RTEMS_RTL_AR_FHDR_SIZE;
-              return true;
-            }
-          }
-          break;
-        default:
-          /*
-           * Ignore the file because we do not know what it it.
-           */
-          break;
-      }
-    }
-    else
-    {
-      if (rtems_rtl_match_name (obj, (const char*) &header[RTEMS_RTL_AR_FNAME]))
-      {
-        obj->ooffset += RTEMS_RTL_AR_FHDR_SIZE;
-        return true;
-      }
-    }
+void
+rtems_rtl_obj_run_ctors (rtems_rtl_obj* obj)
+{
+  rtems_rtl_obj_run_cdtors (obj, RTEMS_RTL_OBJ_SECT_CTOR);
+}
 
-    obj->ooffset += obj->fsize + RTEMS_RTL_AR_FHDR_SIZE;
-  }
+bool
+rtems_rtl_obj_dtors_to_run (rtems_rtl_obj* obj)
+{
+  return rtems_rtl_obj_cdtors_to_run (obj, RTEMS_RTL_OBJ_SECT_DTOR);
+}
 
-  rtems_rtl_set_error (ENOENT, "object file not found");
-  obj->ooffset = 0;
-  obj->fsize = 0;
-  return false;
+void
+rtems_rtl_obj_run_dtors (rtems_rtl_obj* obj)
+{
+  rtems_rtl_obj_run_cdtors (obj, RTEMS_RTL_OBJ_SECT_DTOR);
 }
 
 static bool
@@ -1323,31 +1167,16 @@ rtems_rtl_obj_file_load (rtems_rtl_obj* obj, int fd)
   return false;
 }
 
-static bool
-rtems_rtl_obj_file_unload (rtems_rtl_obj* obj)
+static void
+rtems_rtl_obj_set_error (int num, const char* text)
 {
-  if (obj->format >= 0 && obj->format < RTEMS_RTL_LOADERS)
-  {
-    rtems_chain_node* node;
-
-    if (!loaders[obj->format].unload (obj))
-      return false;
-
-    node = rtems_chain_first (&obj->dependents);
-    while (!rtems_chain_is_tail (&obj->dependents, node))
-    {
-      rtems_rtl_obj_depends* depends = (rtems_rtl_obj_depends*) node;
-      size_t                 d;
-      for (d = 0; d < depends->dependents; ++d)
-      {
-        if (depends->depends[d] != NULL)
-          rtems_rtl_obj_dec_reference (depends->depends[d]);
-      }
-      node = rtems_chain_next (node);
-    }
-  }
+  rtems_rtl_set_error (num, text);
+}
 
-  return false;
+size_t
+rtems_rtl_obj_get_reference (rtems_rtl_obj* obj)
+{
+  return obj->refs;
 }
 
 void
@@ -1363,6 +1192,14 @@ rtems_rtl_obj_dec_reference (rtems_rtl_obj* obj)
     --obj->refs;
 }
 
+bool
+rtems_rtl_obj_orphaned (rtems_rtl_obj* obj)
+{
+  return ((obj->flags & RTEMS_RTL_OBJ_LOCKED) == 0 &&
+          obj->users == 0 &&
+          rtems_rtl_obj_get_reference (obj) == 0);
+}
+
 bool
 rtems_rtl_obj_load (rtems_rtl_obj* obj)
 {
@@ -1377,7 +1214,7 @@ rtems_rtl_obj_load (rtems_rtl_obj* obj)
   fd = open (rtems_rtl_obj_fname (obj), O_RDONLY);
   if (fd < 0)
   {
-    rtems_rtl_set_error (ENOMEM, "opening for object file");
+    rtems_rtl_set_error (errno, "opening for object file");
     return false;
   }
 
@@ -1387,7 +1224,14 @@ rtems_rtl_obj_load (rtems_rtl_obj* obj)
    */
   if (rtems_rtl_obj_aname_valid (obj))
   {
-    if (!rtems_rtl_obj_archive_find (obj, fd))
+    off_t enames = 0;
+    if (!rtems_rtl_obj_archive_find_obj (fd,
+                                         obj->fsize,
+                                         &obj->oname,
+                                         &obj->ooffset,
+                                         &obj->fsize,
+                                         &enames,
+                                         rtems_rtl_obj_set_error))
     {
       close (fd);
       return false;
@@ -1403,7 +1247,10 @@ rtems_rtl_obj_load (rtems_rtl_obj* obj)
     return false;
   }
 
-  if (!_rtld_linkmap_add (obj)) /* For GDB */
+   /*
+    * For GDB
+    */
+  if (!_rtld_linkmap_add (obj))
   {
     close (fd);
     return false;
@@ -1417,7 +1264,15 @@ rtems_rtl_obj_load (rtems_rtl_obj* obj)
 bool
 rtems_rtl_obj_unload (rtems_rtl_obj* obj)
 {
-  _rtld_linkmap_delete(obj);
-  rtems_rtl_obj_file_unload (obj);
-  return true;
+  bool ok = false;
+  if (obj->format >= 0 && obj->format < RTEMS_RTL_LOADERS)
+  {
+    _rtld_linkmap_delete(obj);
+    ok = loaders[obj->format].unload (obj);
+  }
+  else
+  {
+    rtems_rtl_set_error (EINVAL, "invalid object loader format");
+  }
+  return ok;
 }
diff --git a/cpukit/libdl/rtl-shell.c b/cpukit/libdl/rtl-shell.c
index f3471d8d8e..c2a1af5ddd 100644
--- a/cpukit/libdl/rtl-shell.c
+++ b/cpukit/libdl/rtl-shell.c
@@ -26,9 +26,9 @@
 #include <string.h>
 
 #include <rtems/rtl/rtl.h>
-#include "rtl-chain-iterator.h"
-#include "rtl-shell.h"
+#include <rtems/rtl/rtl-shell.h>
 #include <rtems/rtl/rtl-trace.h>
+#include "rtl-chain-iterator.h"
 
 /**
  * The type of the shell handlers we have.
@@ -119,6 +119,7 @@ typedef struct
 {
   rtems_rtl_data* rtl;          /**< The RTL data. */
   int             indent;       /**< Spaces to indent. */
+  bool            sep1;         /**< Print a separator. */
   bool            oname;        /**< Print object names. */
   bool            names;        /**< Print details of all names. */
   bool            memory_map;   /**< Print the memory map. */
@@ -206,6 +207,10 @@ rtems_rtl_obj_printer (rtems_rtl_obj_print* print, rtems_rtl_obj* obj)
   if (!print->base && (obj == print->rtl->base))
       return true;
 
+  if (print->sep1)
+  {
+    printf ("%-*c--------------\n", print->indent, ' ');
+  }
   if (print->oname)
   {
     printf ("%-*cobject name   : %s\n",
@@ -279,7 +284,7 @@ rtems_rtl_unresolved_printer (rtems_rtl_unresolv_rec* rec,
                               void*                   data)
 {
   rtems_rtl_obj_print* print = (rtems_rtl_obj_print*) data;
-  if (rec->type == rtems_rtl_unresolved_name)
+  if (rec->type == rtems_rtl_unresolved_symbol)
     printf ("%-*c%s\n", print->indent + 2, ' ', rec->rec.name.name);
   return false;
 }
@@ -301,6 +306,7 @@ rtems_rtl_shell_list (rtems_rtl_data* rtl, int argc, char *argv[])
   rtems_rtl_obj_print print;
   print.rtl = rtl;
   print.indent = 1;
+  print.sep1 = true;
   print.oname = true;
   print.names = true;
   print.memory_map = true;
@@ -319,6 +325,7 @@ rtems_rtl_shell_sym (rtems_rtl_data* rtl, int argc, char *argv[])
   rtems_rtl_obj_print print;
   print.rtl = rtl;
   print.indent = 1;
+  print.sep1 = true;
   print.oname = true;
   print.names = false;
   print.memory_map = false;
@@ -329,7 +336,7 @@ rtems_rtl_shell_sym (rtems_rtl_data* rtl, int argc, char *argv[])
                            rtems_rtl_obj_print_iterator,
                            &print);
   printf ("Unresolved:\n");
-  rtems_rtl_unresolved_interate (rtems_rtl_unresolved_printer, &print);
+  rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_printer, &print);
   return 0;
 }
 
diff --git a/cpukit/libdl/rtl-string.h b/cpukit/libdl/rtl-string.h
index bb61b83683..1aa2624fdf 100644
--- a/cpukit/libdl/rtl-string.h
+++ b/cpukit/libdl/rtl-string.h
@@ -16,8 +16,6 @@
 #if !defined (_RTEMS_RTL_STRING_H_)
 #define _RTEMS_RTL_STRING_H_
 
-#include <rtems/rtl/rtl-indirect-ptr.h>
-
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
diff --git a/cpukit/libdl/rtl-trace.c b/cpukit/libdl/rtl-trace.c
index d5e4b9e5ec..e09ec06758 100644
--- a/cpukit/libdl/rtl-trace.c
+++ b/cpukit/libdl/rtl-trace.c
@@ -69,7 +69,9 @@ rtems_rtl_trace_shell_command (int argc, char *argv[])
     "load-sect",
     "allocator",
     "unresolved",
-    "cache"
+    "cache",
+    "archives",
+    "dependency"
   };
 
   rtems_rtl_trace_mask set_value = 0;
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,
@@ -562,10 +659,17 @@ rtems_rtl_unresolved_dump_iterator (rtems_rtl_unresolv_rec* rec,
   return false;
 }
 
+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);
 }
diff --git a/cpukit/libdl/rtl.c b/cpukit/libdl/rtl.c
index fdf4c1229f..f331cbbf02 100644
--- a/cpukit/libdl/rtl.c
+++ b/cpukit/libdl/rtl.c
@@ -27,9 +27,10 @@
 
 #include <rtems/rtl/rtl.h>
 #include <rtems/rtl/rtl-allocator.h>
+#include <rtems/rtl/rtl-trace.h>
+#include "rtl-chain-iterator.h"
 #include "rtl-error.h"
 #include "rtl-string.h"
-#include <rtems/rtl/rtl-trace.h>
 
 /**
  * Symbol table cache size. They can be big so the cache needs space to work.
@@ -123,10 +124,14 @@ rtems_rtl_data_init (void)
       rtems_recursive_mutex_lock (&rtl->lock);
 
       /*
-       * Initialise the objects list and create any required services.
+       * Initialise the objects and pending list.
        */
       rtems_chain_initialize_empty (&rtl->objects);
+      rtems_chain_initialize_empty (&rtl->pending);
 
+      /*
+       * Open the global symbol table.
+       */
       if (!rtems_rtl_symbol_table_open (&rtl->globals,
                                         RTEMS_RTL_SYMS_GLOBAL_BUCKETS))
       {
@@ -136,6 +141,14 @@ rtems_rtl_data_init (void)
         return false;
       }
 
+      /*
+       * Open the archives.
+       */
+      rtems_rtl_archives_open (&rtl->archives, "/etc/rtl-libs.conf");
+
+      /*
+       * Open the unresolved table.
+       */
       if (!rtems_rtl_unresolved_table_open (&rtl->unresolved,
                                             RTEMS_RTL_UNRESOLVED_BLOCK_SIZE))
       {
@@ -252,6 +265,28 @@ rtems_rtl_global_symbols (void)
   return &rtl->globals;
 }
 
+rtems_chain_control*
+rtems_rtl_objects_unprotected (void)
+{
+  if (!rtl)
+  {
+    rtems_rtl_set_error (ENOENT, "no rtl");
+    return NULL;
+  }
+  return &rtl->objects;
+}
+
+rtems_chain_control*
+rtems_rtl_pending_unprotected (void)
+{
+  if (!rtl)
+  {
+    rtems_rtl_set_error (ENOENT, "no rtl");
+    return NULL;
+  }
+  return &rtl->pending;
+}
+
 rtems_rtl_unresolved*
 rtems_rtl_unresolved_unprotected (void)
 {
@@ -263,6 +298,17 @@ rtems_rtl_unresolved_unprotected (void)
   return &rtl->unresolved;
 }
 
+rtems_rtl_archives*
+rtems_rtl_archives_unprotected (void)
+{
+  if (!rtl)
+  {
+    rtems_rtl_set_error (ENOENT, "no rtl");
+    return NULL;
+  }
+  return &rtl->archives;
+}
+
 void
 rtems_rtl_obj_caches (rtems_rtl_obj_cache** symbols,
                       rtems_rtl_obj_cache** strings,
@@ -317,19 +363,34 @@ rtems_rtl_obj_decompress (rtems_rtl_obj_comp** decomp,
   }
 }
 
+typedef struct rtems_rtl_obj_flags_data
+{
+  uint32_t clear;   /**< Flags to clear, do not invert. */
+  uint32_t set;     /**< Flags to set, applied after clearing. */
+} rtems_rtl_obj_flags_data;
+
+static bool
+rtems_rtl_obj_flags_iterator (rtems_chain_node* node, void* data)
+{
+  rtems_rtl_obj* obj              = (rtems_rtl_obj*) node;
+  rtems_rtl_obj_flags_data* flags = (rtems_rtl_obj_flags_data*) data;
+  if (flags->clear != 0)
+    obj->flags &= ~flags->clear;
+  if (flags->set != 0)
+    obj->flags |= flags->set;
+  return true;
+}
+
 void
 rtems_rtl_obj_update_flags (uint32_t clear, uint32_t set)
 {
-  rtems_chain_node* node  = rtems_chain_first (&rtl->objects);
-  while (!rtems_chain_is_tail (&rtl->objects, node))
-  {
-    rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
-    if (clear != 0)
-      obj->flags &= ~clear;
-    if (set != 0)
-      obj->flags |= set;
-    node = rtems_chain_next (node);
-  }
+  rtems_rtl_obj_flags_data flags = {
+    .clear = clear,
+    .set   = set
+  };
+  rtems_rtl_chain_iterate (&rtl->objects,
+                           rtems_rtl_obj_flags_iterator,
+                           &flags);
 }
 
 rtems_rtl_data*
@@ -390,16 +451,16 @@ rtems_rtl_find_obj (const char* name)
         (aname != NULL &&
          strcmp (obj->aname, aname) == 0 && strcmp (obj->oname, oname) == 0))
     {
-        found = obj;
-        break;
+      found = obj;
+      break;
     }
     node = rtems_chain_next (node);
   }
 
-  if (!aname)
+  if (aname != NULL)
     rtems_rtl_alloc_del(RTEMS_RTL_ALLOC_OBJECT, (void*) aname);
 
-  if (!oname)
+  if (oname != NULL)
     rtems_rtl_alloc_del(RTEMS_RTL_ALLOC_OBJECT, (void*) oname);
 
   return found;
@@ -412,8 +473,15 @@ rtems_rtl_find_obj_with_symbol (const rtems_rtl_obj_sym* sym)
   while (!rtems_chain_is_tail (&rtl->objects, node))
   {
     rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
-    if (sym >= obj->global_table &&
-        sym < (obj->global_table + obj->global_syms))
+    if (rtems_rtl_obj_has_symbol (obj, sym))
+      return obj;
+    node = rtems_chain_next (node);
+  }
+  node = rtems_chain_first (&rtl->pending);
+  while (!rtems_chain_is_tail (&rtl->pending, node))
+  {
+    rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
+    if (rtems_rtl_obj_has_symbol (obj, sym))
       return obj;
     node = rtems_chain_next (node);
   }
@@ -455,18 +523,17 @@ rtems_rtl_load_object (const char* name, int mode)
       return NULL;
     }
 
-    rtems_chain_append (&rtl->objects, &obj->link);
+    rtems_chain_append (&rtl->pending, &obj->link);
 
     if (!rtems_rtl_obj_load (obj))
     {
+      rtems_chain_extract (&obj->link);
       rtems_rtl_obj_free (obj);
       rtems_rtl_obj_caches_flush ();
       return NULL;
     }
 
     rtems_rtl_obj_caches_flush ();
-
-    rtems_rtl_unresolved_resolve ();
   }
 
   /*
@@ -474,25 +541,67 @@ rtems_rtl_load_object (const char* name, int mode)
    */
   ++obj->users;
 
+  return obj;
+}
+
+rtems_rtl_obj*
+rtems_rtl_load (const char* name, int mode)
+{
+  rtems_rtl_obj* obj;
+
   /*
-   * FIXME: Resolving existing unresolved symbols could add more constructors
-   *        lists that need to be called. Make a list in the obj load layer and
-   *        invoke the list here.
+   * Refesh the archives.
    */
+  rtems_rtl_archives_refresh (&rtl->archives);
 
   /*
-   * Run any local constructors if this is the first user because the object
-   * file will have just been loaded. Unlock the linker to avoid any dead locks
-   * if the object file needs to load files or update the symbol table. We also
-   * do not want a constructor to unload this object file.
+   * Collect the loaded object files.
    */
-  if (obj->users == 1)
+  rtems_chain_initialize_empty (&rtl->pending);
+
+  obj = rtems_rtl_load_object (name, mode);
+  if (obj != NULL)
   {
-    obj->flags |= RTEMS_RTL_OBJ_LOCKED;
-    rtems_rtl_unlock ();
-    rtems_rtl_obj_run_ctors (obj);
-    rtems_rtl_lock ();
-    obj->flags &= ~RTEMS_RTL_OBJ_LOCKED;
+    rtems_chain_node* node;
+
+    rtems_rtl_unresolved_resolve ();
+
+    /*
+     * Iterator over the pending list of object files that have been loaded.
+     */
+    node = rtems_chain_first (&rtl->pending);
+    while (!rtems_chain_is_tail (&rtl->pending, node))
+    {
+      rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
+
+      /*
+       * Move to the next pending object file and place this object file on the
+       * RTL's objects list.
+       */
+      node = rtems_chain_next (&obj->link);
+      rtems_chain_extract (&obj->link);
+      rtems_chain_append (&rtl->objects, &obj->link);
+
+      /*
+       * Make sure the object file and cache is synchronized.
+       */
+      rtems_rtl_obj_synchronize_cache (obj);
+
+      /*
+       * Run any local constructors if this is the first user because the
+       * object file will have just been loaded. Unlock the linker to avoid any
+       * dead locks if the object file needs to load files or update the symbol
+       * table. We also do not want a constructor to unload this object file.
+       */
+      if (obj->users == 1)
+      {
+        obj->flags |= RTEMS_RTL_OBJ_LOCKED;
+        rtems_rtl_unlock ();
+        rtems_rtl_obj_run_ctors (obj);
+        rtems_rtl_lock ();
+        obj->flags &= ~RTEMS_RTL_OBJ_LOCKED;
+      }
+    }
   }
 
   return obj;
@@ -501,55 +610,107 @@ rtems_rtl_load_object (const char* name, int mode)
 bool
 rtems_rtl_unload_object (rtems_rtl_obj* obj)
 {
-  bool ok = true;
-
   if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD))
-    printf ("rtl: unloading '%s'\n", rtems_rtl_obj_fname (obj));
+    printf ("rtl: unload object '%s'\n", rtems_rtl_obj_fname (obj));
 
   /*
    * If the object is locked it cannot be unloaded and the unload fails.
    */
   if ((obj->flags & RTEMS_RTL_OBJ_LOCKED) == RTEMS_RTL_OBJ_LOCKED)
   {
-    rtems_rtl_set_error (EINVAL, "cannot unload when locked");
+    rtems_rtl_set_error (EINVAL, "object file is locked");
     return false;
   }
 
   /*
-   * Check the number of users in a safe manner. If this is the last user unload the
-   * object file from memory.
+   * Move the object file from the objects list to the pending list if unloaded.
+   */
+  if (rtems_rtl_obj_get_reference (obj) > 0)
+  {
+    rtems_rtl_set_error (EINVAL, "object file has references to it");
+    return false;
+  }
+
+  /*
+   * Check the number of users in a safe manner. If this is the last user unload
+   * the object file from memory.
    */
   if (obj->users > 0)
     --obj->users;
 
-  if (obj->users == 0)
+  return true;
+}
+
+bool
+rtems_rtl_unload (rtems_rtl_obj* obj)
+{
+  bool ok = rtems_rtl_unload_object (obj);
+  if (ok && obj->users == 0)
   {
-    if (obj->refs != 0)
+    rtems_chain_control unloading;
+    rtems_chain_node*   node;
+
+    /*
+     * Remove the orphaned object files from the objects list. This makes the
+     * list private and any changes in any desctructors will effect the run.
+     */
+    rtems_chain_initialize_empty (&unloading);
+
+    node = rtems_chain_first (&rtl->objects);
+    while (!rtems_chain_is_tail (&rtl->objects, node))
     {
-      rtems_rtl_set_error (EBUSY, "object file referenced");
-      return false;
+      rtems_chain_node* next_node = rtems_chain_next (node);
+      rtems_rtl_obj* uobj = (rtems_rtl_obj*) node;
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD))
+        printf ("rtl: unload object: %s: %s\n",
+                rtems_rtl_obj_oname (obj),
+                rtems_rtl_obj_orphaned (uobj) ? "orphaned" : "inuse");
+      if (rtems_rtl_obj_orphaned (uobj))
+      {
+        rtems_rtl_obj_remove_dependencies (uobj);
+        rtems_chain_extract (&uobj->link);
+        rtems_chain_append (&unloading, &uobj->link);
+        uobj->flags |= RTEMS_RTL_OBJ_LOCKED;
+      }
+      node = next_node;
     }
-    obj->flags |= RTEMS_RTL_OBJ_LOCKED;
+
+    /*
+     * Call the desctructors unlocked. An RTL call will not deadlock.
+     */
     rtems_rtl_unlock ();
-    rtems_rtl_obj_run_dtors (obj);
-    rtems_rtl_lock ();
-    obj->flags &= ~RTEMS_RTL_OBJ_LOCKED;
 
-    ok = rtems_rtl_obj_unload (obj);
+    node = rtems_chain_first (&unloading);
+    while (!rtems_chain_is_tail (&unloading, node))
+    {
+      rtems_rtl_obj* uobj = (rtems_rtl_obj*) node;
+      rtems_rtl_obj_run_dtors (uobj);
+      node = rtems_chain_next (node);
+    }
 
-    rtems_rtl_obj_free (obj);
-    rtems_rtl_obj_caches_flush ();
-  }
+    rtems_rtl_lock ();
 
+    /*
+     * Unload the object files.
+     */
+    node = rtems_chain_first (&unloading);
+    while (!rtems_chain_is_tail (&unloading, node))
+    {
+      rtems_chain_node* next_node = rtems_chain_next (node);
+      rtems_rtl_obj*    uobj = (rtems_rtl_obj*) node;
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD))
+        printf ("rtl: unloading '%s'\n", rtems_rtl_obj_oname (uobj));
+      uobj->flags &= ~RTEMS_RTL_OBJ_LOCKED;
+      if (!rtems_rtl_obj_unload (uobj))
+        ok = false;
+      rtems_rtl_obj_free (uobj);
+      rtems_rtl_obj_caches_flush ();
+      node = next_node;
+    }
+  }
   return ok;
 }
 
-void
-rtems_rtl_run_ctors (rtems_rtl_obj* obj)
-{
-  rtems_rtl_obj_run_ctors (obj);
-}
-
 static bool
 rtems_rtl_path_update (bool prepend, const char* path)
 {
-- 
2.19.1




More information about the devel mailing list