[PATCH] libdl: Do not access the ELF file while the allocator is locked.

chrisj at rtems.org chrisj at rtems.org
Fri May 3 00:29:55 UTC 2019


From: Chris Johns <chrisj at rtems.org>

- Load symbols before allocation.
- Parse reloc records and place any reloc recs in a cache to use
  while the allocator is locked.
- Relocate symbols after section allocation.
- Split section loading into allocation/locating and loading.
- Update all arch back-ends with a new reloc interface to control
  tramp handling.
- Add `-a` and `-t` to the object list shell command.

Closes #3741
---
 cpukit/include/rtems/rtl/rtl-obj.h        |  38 +-
 cpukit/include/rtems/rtl/rtl-unresolved.h |  22 +-
 cpukit/include/rtems/rtl/rtl.h            |   2 +-
 cpukit/libdl/rtl-allocator.c              |   2 +-
 cpukit/libdl/rtl-elf.c                    | 484 +++++++++++++++-------
 cpukit/libdl/rtl-elf.h                    |  73 ++--
 cpukit/libdl/rtl-mdreloc-arm.c            | 122 ++++--
 cpukit/libdl/rtl-mdreloc-bfin.c           |  22 +-
 cpukit/libdl/rtl-mdreloc-h8300.c          |  22 +-
 cpukit/libdl/rtl-mdreloc-i386.c           |  18 +-
 cpukit/libdl/rtl-mdreloc-lm32.c           |  21 +-
 cpukit/libdl/rtl-mdreloc-m68k.c           | 174 ++++----
 cpukit/libdl/rtl-mdreloc-mips.c           |  24 +-
 cpukit/libdl/rtl-mdreloc-moxie.c          |  20 +-
 cpukit/libdl/rtl-mdreloc-powerpc.c        |  69 ++-
 cpukit/libdl/rtl-mdreloc-sparc.c          |  26 +-
 cpukit/libdl/rtl-mdreloc-v850.c           |  20 +-
 cpukit/libdl/rtl-obj.c                    | 138 ++++--
 cpukit/libdl/rtl-shell.c                  |  59 ++-
 cpukit/libdl/rtl-trampoline.h             |  94 +++++
 cpukit/libdl/rtl-unresolved.c             | 137 ++++--
 cpukit/libdl/rtl.c                        |  31 +-
 testsuites/libtests/dl08/init.c           |   2 +-
 testsuites/libtests/dl09/dl-o1.c          |   1 +
 testsuites/libtests/dl09/dl09.doc         |   2 +-
 testsuites/libtests/dl09/init.c           |   2 +-
 26 files changed, 1098 insertions(+), 527 deletions(-)
 create mode 100644 cpukit/libdl/rtl-trampoline.h

diff --git a/cpukit/include/rtems/rtl/rtl-obj.h b/cpukit/include/rtems/rtl/rtl-obj.h
index 9c2b4f0300..f27ae3259d 100644
--- a/cpukit/include/rtems/rtl/rtl-obj.h
+++ b/cpukit/include/rtems/rtl/rtl-obj.h
@@ -207,7 +207,7 @@ struct rtems_rtl_obj
   size_t              text_size;    /**< The size of the text section. */
   void*               const_base;   /**< The base address of the const section
                                      *   in memory. */
-  size_t              const_size;    /**< The size of the const section. */
+  size_t              const_size;   /**< The size of the const section. */
   void*               eh_base;      /**< The base address of the eh section in
                                      *   memory. */
   size_t              eh_size;      /**< The size of the eh section. */
@@ -227,10 +227,14 @@ struct rtems_rtl_obj
                                      *   obj. */
   void*               trampoline;   /**< Trampoline memory. Used for fixups or
                                      *   veneers */
-  size_t              tramp_size;   /**< Size of the tramopline memory. */
+  size_t              tramp_size;   /**< Size of a tramopline slot. */
+  size_t              tramps_size;  /**< Size of the trampoline memory. */
   void*               tramp_brk;    /**< Trampoline memory allocator. MD
                                      *   relocators can take memory from the
                                      *   break upto the size. */
+  size_t              tramp_relocs; /**< Number of slots reserved for
+                                     *   relocs. The remainder are for
+                                     *   unresolved symbols. */
   struct link_map*    linkmap;      /**< For GDB. */
   void*               loader;       /**< The file details specific to a
                                      *   loader. */
@@ -370,11 +374,35 @@ static inline bool rtems_rtl_obj_has_symbol (const rtems_rtl_obj*     obj,
  * @param size The size to be allocated.
  * @retval bool Returns @true if the space is available.
  */
-static inline bool rtems_rtl_obj_has_ramp_space (const rtems_rtl_obj* obj,
-                                                 const size_t         size)
+static inline bool rtems_rtl_obj_has_tramp_space (const rtems_rtl_obj* obj,
+                                                  const size_t         size)
 {
   return (obj->trampoline != NULL &&
-          ((obj->tramp_brk - obj->trampoline) + size) <= obj->tramp_size);
+          ((obj->tramp_brk - obj->trampoline) + size) <= obj->tramps_size);
+}
+
+/**
+ * Trampoline slots.
+ *
+ * @param obj The object file's descriptor.
+ * @retval size_t The number of trampoline slots.
+ */
+static inline size_t rtems_rtl_obj_trampoline_slots (const rtems_rtl_obj* obj)
+{
+  return obj->trampoline == NULL || obj->tramp_size == 0 ?
+    0 : obj->tramps_size / obj->tramp_size;
+}
+
+/**
+ * Number of trampolines.
+ *
+ * @param obj The object file's descriptor.
+ * @retval size_t The number of trampolines.
+ */
+static inline size_t rtems_rtl_obj_trampolines (const rtems_rtl_obj* obj)
+{
+  return obj->trampoline == NULL || obj->tramp_size == 0 ?
+    0 : (obj->tramp_brk - obj->trampoline) / obj->tramp_size;
 }
 
 /**
diff --git a/cpukit/include/rtems/rtl/rtl-unresolved.h b/cpukit/include/rtems/rtl/rtl-unresolved.h
index efc9ce220f..df07ecb1ba 100644
--- a/cpukit/include/rtems/rtl/rtl-unresolved.h
+++ b/cpukit/include/rtems/rtl/rtl-unresolved.h
@@ -1,5 +1,5 @@
 /*
- *  COPYRIGHT (c) 2012, 2018 Chris Johns <chrisj at rtems.org>
+ *  COPYRIGHT (c) 2012, 2019 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
@@ -73,7 +73,8 @@ typedef enum rtems_rtl_unresolved_rtype
 {
   rtems_rtl_unresolved_empty = 0,  /**< The records is empty. Must always be 0 */
   rtems_rtl_unresolved_symbol = 1, /**< The record is a symbol. */
-  rtems_rtl_unresolved_reloc = 2   /**< The record is a relocation record. */
+  rtems_rtl_unresolved_reloc = 2,  /**< The record is a relocation record. */
+  rtems_rtl_trampoline_reloc = 3   /**< The record is a trampoline relocation record. */
 } rtems_rtl_unresolved_rtype;
 
 /**
@@ -101,7 +102,7 @@ typedef struct rtems_rtl_unresolv_symbol
 
 /**
  * Unresolved externals symbols require the relocation records to be held
- * and references.
+ * and referenced.
  */
 typedef struct rtems_rtl_unresolv_reloc
 {
@@ -112,6 +113,18 @@ typedef struct rtems_rtl_unresolv_reloc
   rtems_rtl_word rel[3];  /**< Relocation record. */
 } rtems_rtl_unresolv_reloc;
 
+/**
+ * Trampolines require the relocation records to be held
+ */
+typedef struct rtems_rtl_tramp_reloc
+{
+  rtems_rtl_obj* obj;      /**< The relocation's object file. */
+  uint16_t       flags;    /**< Format specific flags. */
+  uint16_t       sect;     /**< The target section. */
+  rtems_rtl_word symvalue; /**< The symbol's value. */
+  rtems_rtl_word rel[3];   /**< Relocation record. */
+} rtems_rtl_tramp_reloc;
+
 /**
  * Unresolved externals records.
  */
@@ -121,7 +134,8 @@ typedef struct rtems_rtl_unresolv_rec
   union
   {
     rtems_rtl_unresolv_symbol name;   /**< The symbol, or */
-    rtems_rtl_unresolv_reloc  reloc;  /**< the relocation record. */
+    rtems_rtl_unresolv_reloc  reloc;  /**< The relocation record. */
+    rtems_rtl_tramp_reloc     tramp;  /**< The trampoline relocation record. */
   } rec;
 } rtems_rtl_unresolv_rec;
 
diff --git a/cpukit/include/rtems/rtl/rtl.h b/cpukit/include/rtems/rtl/rtl.h
index f13e33dbcb..67d7e96be3 100644
--- a/cpukit/include/rtems/rtl/rtl.h
+++ b/cpukit/include/rtems/rtl/rtl.h
@@ -72,7 +72,7 @@ extern "C" {
 /**
  * The number of relocation record per block in the unresolved table.
  */
-#define RTEMS_RTL_UNRESOLVED_BLOCK_SIZE (64)
+#define RTEMS_RTL_UNRESOLVED_BLOCK_SIZE (256)
 
 /**
  * The number of dependency record per block in the dependency table.
diff --git a/cpukit/libdl/rtl-allocator.c b/cpukit/libdl/rtl-allocator.c
index 0dca6b2f9a..647c0c89a4 100644
--- a/cpukit/libdl/rtl-allocator.c
+++ b/cpukit/libdl/rtl-allocator.c
@@ -147,7 +147,7 @@ rtems_rtl_alloc_wr_disable (rtems_rtl_alloc_tag tag, void* address)
   rtems_rtl_data* rtl = rtems_rtl_lock ();
 
   if (rtems_rtl_trace (RTEMS_RTL_TRACE_ALLOCATOR))
-    printf ("rtl: alloc: wr-enable: addr=%p\n", address);
+    printf ("rtl: alloc: wr-disable: addr=%p\n", address);
 
   if (rtl != NULL && address != NULL)
     rtl->allocator.allocator (RTEMS_RTL_ALLOC_WR_DISABLE,
diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c
index 963cb4b2f4..0fa639f36f 100644
--- a/cpukit/libdl/rtl-elf.c
+++ b/cpukit/libdl/rtl-elf.c
@@ -1,5 +1,5 @@
 /*
- *  COPYRIGHT (c) 2012-2018 Chris Johns <chrisj at rtems.org>
+ *  COPYRIGHT (c) 2012-2019 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
@@ -31,11 +31,12 @@
 #include "rtl-elf.h"
 #include "rtl-error.h"
 #include <rtems/rtl/rtl-trace.h>
+#include "rtl-trampoline.h"
 #include "rtl-unwind.h"
 #include <rtems/rtl/rtl-unresolved.h>
 
 /**
- * The offsets in the unresolved array.
+ * The offsets in the reloc words.
  */
 #define REL_R_OFFSET (0)
 #define REL_R_INFO   (1)
@@ -166,66 +167,77 @@ rtems_rtl_elf_reloc_parser (rtems_rtl_obj*      obj,
                             void*               data)
 {
   rtems_rtl_elf_reloc_data* rd = (rtems_rtl_elf_reloc_data*) data;
+  rtems_rtl_word            rel_words[3];
+  rtems_rtl_elf_rel_status  rs;
 
   /*
-   * The symbol has to have been resolved to parse the reloc record. Unresolved
-   * symbols are handled in the relocator but we need to count them here so a
-   * trampoline is accounted for. We have to assume the unresolved may be out of
-   * of range.
+   * Check the reloc record to see if a trampoline is needed.
    */
-  if (!resolved)
+  if (is_rela)
   {
-    ++rd->unresolved;
+    const Elf_Rela* rela = (const Elf_Rela*) relbuf;
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+      printf ("rtl: rela tramp: sym: %c:%s(%d)=%08jx type:%d off:%08jx addend:%d\n",
+              ELF_ST_BIND (sym->st_info) == STB_GLOBAL ||
+              ELF_ST_BIND (sym->st_info) == STB_WEAK ? 'G' : 'L',
+              symname, (int) ELF_R_SYM (rela->r_info),
+              (uintmax_t) symvalue, (int) ELF_R_TYPE (rela->r_info),
+              (uintmax_t) rela->r_offset, (int) rela->r_addend);
+    rs = rtems_rtl_elf_relocate_rela_tramp (obj, rela, targetsect,
+                                            symname, sym->st_info, symvalue);
+    rel_words[REL_R_OFFSET] = rela->r_offset;
+    rel_words[REL_R_INFO] = rela->r_info;
+    rel_words[REL_R_ADDEND] = rela->r_addend;
   }
   else
+  {
+    const Elf_Rel* rel = (const Elf_Rel*) relbuf;
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+      printf ("rtl: rel tramp: sym: %c:%s(%d)=%08jx type:%d off:%08jx\n",
+              ELF_ST_BIND (sym->st_info) == STB_GLOBAL ||
+              ELF_ST_BIND (sym->st_info) == STB_WEAK ? 'G' : 'L',
+              symname, (int) ELF_R_SYM (rel->r_info),
+              (uintmax_t) symvalue, (int) ELF_R_TYPE (rel->r_info),
+              (uintmax_t) rel->r_offset);
+    rs = rtems_rtl_elf_relocate_rel_tramp (obj, rel, targetsect,
+                                           symname, sym->st_info, symvalue);
+    rel_words[REL_R_OFFSET] = rel->r_offset;
+    rel_words[REL_R_INFO] = rel->r_info;
+    rel_words[REL_R_ADDEND] = 0;
+  }
+
+  if (rs == rtems_rtl_elf_rel_failure)
+    return false;
+
+  if (rs == rtems_rtl_elf_rel_tramp_cache || rs == rtems_rtl_elf_rel_tramp_add)
+  {
+    uint32_t flags = (is_rela ? 1 : 0) | (resolved ? 0 : 1 << 1) | (sym->st_info << 8);
+    if (!rtems_rtl_trampoline_add (obj, flags,
+                                   targetsect->section, symvalue, rel_words))
+      return false;
+  }
+
+  /*
+   * Handle any dependencies if there is a valid symbol.
+   */
+  if (symname != NULL)
   {
     /*
-     * Check the reloc record to see if a trampoline is needed.
+     * Find the symbol's object file. It cannot be NULL so ignore that result
+     * if returned, it means something is corrupted. We are in an iterator.
      */
-    if (is_rela)
-    {
-      const Elf_Rela* rela = (const Elf_Rela*) relbuf;
-      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
-        printf ("rtl: rela tramp: sym:%s(%d)=%08jx type:%d off:%08jx addend:%d\n",
-                symname, (int) ELF_R_SYM (rela->r_info),
-                (uintmax_t) symvalue, (int) ELF_R_TYPE (rela->r_info),
-                (uintmax_t) rela->r_offset, (int) rela->r_addend);
-      if (!rtems_rtl_elf_relocate_rela_tramp (obj, rela, targetsect,
-                                              symname, sym->st_info, symvalue))
-        return false;
-    }
-    else
-    {
-      const Elf_Rel* rel = (const Elf_Rel*) relbuf;
-      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
-        printf ("rtl: rel tramp: sym:%s(%d)=%08jx type:%d off:%08jx\n",
-                symname, (int) ELF_R_SYM (rel->r_info),
-                (uintmax_t) symvalue, (int) ELF_R_TYPE (rel->r_info),
-                (uintmax_t) rel->r_offset);
-      if (!rtems_rtl_elf_relocate_rel_tramp (obj, rel, targetsect,
-                                             symname, sym->st_info, symvalue))
-        return false;
-    }
-
-    if (symname != NULL)
+    rtems_rtl_obj*  sobj = rtems_rtl_find_obj_with_symbol (symbol);
+    if (sobj != NULL)
     {
       /*
-       * Find the symbol's object file. It cannot be NULL so ignore that result
-       * if returned, it means something is corrupted. We are in an iterator.
+       * A dependency is not the base kernel image or itself. Tag the object as
+       * having been visited so we count it only once.
        */
-      rtems_rtl_obj*  sobj = rtems_rtl_find_obj_with_symbol (symbol);
-      if (sobj != NULL)
+      if (sobj != rtems_rtl_baseimage () && obj != sobj &&
+          (sobj->flags & RTEMS_RTL_OBJ_RELOC_TAG) == 0)
       {
-        /*
-         * A dependency is not the base kernel image or itself. Tag the object as
-         * having been visited so we count it only once.
-         */
-        if (sobj != rtems_rtl_baseimage () && obj != sobj &&
-            (sobj->flags & RTEMS_RTL_OBJ_RELOC_TAG) == 0)
-        {
-          sobj->flags |= RTEMS_RTL_OBJ_RELOC_TAG;
-          ++rd->dependents;
-        }
+        sobj->flags |= RTEMS_RTL_OBJ_RELOC_TAG;
+        ++rd->dependents;
       }
     }
   }
@@ -278,7 +290,8 @@ rtems_rtl_elf_reloc_relocator (rtems_rtl_obj*      obj,
   }
   else
   {
-    rtems_rtl_obj* sobj;
+    rtems_rtl_obj*           sobj;
+    rtems_rtl_elf_rel_status rs;
 
     if (is_rela)
     {
@@ -287,8 +300,9 @@ rtems_rtl_elf_reloc_relocator (rtems_rtl_obj*      obj,
                 symname, (int) ELF_R_SYM (rela->r_info),
                 (uintmax_t) symvalue, (int) ELF_R_TYPE (rela->r_info),
                 (uintmax_t) rela->r_offset, (int) rela->r_addend);
-      if (!rtems_rtl_elf_relocate_rela (obj, rela, targetsect,
-                                        symname, sym->st_info, symvalue))
+      rs = rtems_rtl_elf_relocate_rela (obj, rela, targetsect,
+                                        symname, sym->st_info, symvalue);
+      if (rs != rtems_rtl_elf_rel_no_error)
         return false;
     }
     else
@@ -298,8 +312,9 @@ rtems_rtl_elf_reloc_relocator (rtems_rtl_obj*      obj,
                 symname, (int) ELF_R_SYM (rel->r_info),
                 (uintmax_t) symvalue, (int) ELF_R_TYPE (rel->r_info),
                 (uintmax_t) rel->r_offset);
-      if (!rtems_rtl_elf_relocate_rel (obj, rel, targetsect,
-                                       symname, sym->st_info, symvalue))
+      rs = rtems_rtl_elf_relocate_rel (obj, rel, targetsect,
+                                       symname, sym->st_info, symvalue);
+      if (rs != rtems_rtl_elf_rel_no_error)
         return false;
     }
 
@@ -419,7 +434,10 @@ rtems_rtl_elf_relocate_worker (rtems_rtl_obj*              obj,
     /*
      * Only need the name of the symbol if global or a common symbol.
      */
-    if (ELF_ST_TYPE (sym.st_info) == STT_NOTYPE ||
+    if (ELF_ST_TYPE (sym.st_info) == STT_OBJECT ||
+        ELF_ST_TYPE (sym.st_info) == STT_COMMON ||
+        ELF_ST_TYPE (sym.st_info) == STT_FUNC ||
+        ELF_ST_TYPE (sym.st_info) == STT_NOTYPE ||
         ELF_ST_TYPE (sym.st_info) == STT_TLS ||
         sym.st_shndx == SHN_COMMON)
     {
@@ -491,10 +509,11 @@ bool
 rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc* reloc,
                                    rtems_rtl_obj_sym*        sym)
 {
-  rtems_rtl_obj_sect* sect;
-  bool                is_rela;
-  Elf_Word            symvalue;
-  rtems_rtl_obj*      sobj;
+  rtems_rtl_obj_sect*      sect;
+  bool                     is_rela;
+  Elf_Word                 symvalue;
+  rtems_rtl_obj*           sobj;
+  rtems_rtl_elf_rel_status rs;
 
   is_rela = reloc->flags & 1;
 
@@ -516,8 +535,9 @@ rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc* reloc,
           printf ("rtl: rela: sym:%d type:%d off:%08jx addend:%d\n",
                   (int) ELF_R_SYM (rela.r_info), (int) ELF_R_TYPE (rela.r_info),
                   (uintmax_t) rela.r_offset, (int) rela.r_addend);
-    if (!rtems_rtl_elf_relocate_rela (reloc->obj, &rela, sect,
-                                      sym->name, sym->data, symvalue))
+    rs = rtems_rtl_elf_relocate_rela (reloc->obj, &rela, sect,
+                                      sym->name, sym->data, symvalue);
+    if (rs != rtems_rtl_elf_rel_no_error)
       return false;
   }
   else
@@ -529,8 +549,9 @@ rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc* reloc,
       printf ("rtl: rel: sym:%d type:%d off:%08jx\n",
               (int) ELF_R_SYM (rel.r_info), (int) ELF_R_TYPE (rel.r_info),
               (uintmax_t) rel.r_offset);
-    if (!rtems_rtl_elf_relocate_rel (reloc->obj, &rel, sect,
-                                     sym->name, sym->data, symvalue))
+    rs = rtems_rtl_elf_relocate_rel (reloc->obj, &rel, sect,
+                                     sym->name, sym->data, symvalue);
+    if (rs != rtems_rtl_elf_rel_no_error)
       return false;
   }
 
@@ -621,16 +642,117 @@ rtems_rtl_elf_common (rtems_rtl_obj*      obj,
   return true;
 }
 
+/**
+ * Struct to handle trampoline reloc recs in the unresolved table.
+ */
+typedef struct rtems_rtl_tramp_data
+{
+  bool           failure;
+  rtems_rtl_obj* obj;
+  size_t         count;
+  size_t         total;
+} rtems_rtl_tramp_data;
+
+static bool
+rtems_rtl_elf_tramp_resolve_reloc (rtems_rtl_unresolv_rec* rec,
+                                   void*                   data)
+{
+  rtems_rtl_tramp_data* td = (rtems_rtl_tramp_data*) data;
+  if (rec->type == rtems_rtl_trampoline_reloc)
+  {
+    const rtems_rtl_tramp_reloc* tramp = &rec->rec.tramp;
+
+    ++td->total;
+
+    if (tramp->obj == td->obj)
+    {
+      const rtems_rtl_obj_sect* targetsect;
+      Elf_Byte                  st_info;
+      Elf_Word                  symvalue;
+      rtems_rtl_elf_rel_status  rs;
+      bool*                     failure = (bool*) data;
+      const bool                is_rela = (tramp->flags & 1) == 1;
+      const bool                unresolved = (tramp->flags & (1 << 1)) != 0;
+
+      ++td->count;
+
+      targetsect = rtems_rtl_obj_find_section_by_index (tramp->obj, tramp->sect);
+      st_info = tramp->flags >> 8;
+      symvalue = tramp->symvalue;
+
+      if (is_rela)
+      {
+        Elf_Rela rela = {
+          .r_offset = tramp->rel[REL_R_OFFSET],
+          .r_info   = tramp->rel[REL_R_INFO],
+          .r_addend = tramp->rel[REL_R_ADDEND]
+        };
+        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+          printf ("rtl: rela tramp: check: %c(%d)=%08jx type:%d off:%08jx addend:%d\n",
+                  ELF_ST_BIND (st_info) == STB_GLOBAL ||
+                  ELF_ST_BIND (st_info) == STB_WEAK ? 'G' : 'L',
+                  (int) ELF_R_SYM (rela.r_info),
+                  (uintmax_t) symvalue, (int) ELF_R_TYPE (rela.r_info),
+                  (uintmax_t) rela.r_offset, (int) rela.r_addend);
+        rs = rtems_rtl_elf_relocate_rela_tramp (tramp->obj, &rela, targetsect,
+                                                NULL, st_info, symvalue);
+      }
+      else
+      {
+        Elf_Rel rel = {
+          .r_offset = tramp->rel[REL_R_OFFSET],
+          .r_info   = tramp->rel[REL_R_INFO],
+        };
+        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+          printf ("rtl: rel tramp: check: %c(%d)=%08jx type:%d off:%08jx\n",
+                  ELF_ST_BIND (st_info) == STB_GLOBAL ||
+                  ELF_ST_BIND (st_info) == STB_WEAK ? 'G' : 'L',
+                  (int) ELF_R_SYM (rel.r_info),
+                  (uintmax_t) symvalue, (int) ELF_R_TYPE (rel.r_info),
+                  (uintmax_t) rel.r_offset);
+        rs = rtems_rtl_elf_relocate_rel_tramp (tramp->obj, &rel, targetsect,
+                                               NULL, st_info, symvalue);
+      }
+
+      if (unresolved || rs == rtems_rtl_elf_rel_tramp_add)
+        tramp->obj->tramps_size += tramp->obj->tramp_size;
+      if (rs == rtems_rtl_elf_rel_failure)
+      {
+        *failure = true;
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
 static bool
 rtems_rtl_elf_alloc_trampoline (rtems_rtl_obj* obj, size_t unresolved)
 {
+  rtems_rtl_tramp_data td =  { 0 };
+  td.obj = obj;
+  /*
+   * See which relocs are out of range and need a trampoline.
+   */
+  rtems_rtl_unresolved_iterate (rtems_rtl_elf_tramp_resolve_reloc, &td);
+  if (td.failure)
+    return false;
+  rtems_rtl_trampoline_remove (obj);
+  obj->tramp_relocs = obj->tramp_size == 0 ? 0 : obj->tramps_size / obj->tramp_size;
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+    printf ("rtl: tramp:elf: tramps: %zu count:%zu total:%zu\n",
+            obj->tramp_relocs, td.count, td.total);
   /*
    * Add on enough space to handle the unresolved externals that need to be
    * resolved at some point in time. They could all require fixups and
    * trampolines.
    */
-  obj->tramp_size +=
-    rtems_rtl_elf_relocate_tramp_max_size () * unresolved;
+  obj->tramps_size += obj->tramp_size * unresolved;
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+    printf ("rtl: tramp:elf: slots: %zu (%zu)\n",
+            obj->tramp_size == 0 ? 0 : obj->tramps_size / obj->tramp_size,
+            obj->tramps_size);
   return rtems_rtl_obj_alloc_trampoline (obj);
 }
 
@@ -653,10 +775,10 @@ rtems_rtl_elf_dependents (rtems_rtl_obj* obj, rtems_rtl_elf_reloc_data* reloc)
 }
 
 static bool
-rtems_rtl_elf_symbols (rtems_rtl_obj*      obj,
-                       int                 fd,
-                       rtems_rtl_obj_sect* sect,
-                       void*               data)
+rtems_rtl_elf_symbols_load (rtems_rtl_obj*      obj,
+                            int                 fd,
+                            rtems_rtl_obj_sect* sect,
+                            void*               data)
 {
   rtems_rtl_obj_cache* symbols;
   rtems_rtl_obj_cache* strings;
@@ -720,19 +842,20 @@ rtems_rtl_elf_symbols (rtems_rtl_obj*      obj,
      * we need to make sure there is a valid seciton.
      */
     if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
-      printf ("rtl: sym:elf:%-2d name:%-2d:%-20s bind:%-2d " \
-              "type:%-2d sect:%d size:%d\n",
+      printf ("rtl: sym:elf:%-4d name:%-4d: %-20s: bind:%-2d " \
+              "type:%-2d sect:%-5d size:%-5d value:%d\n",
               sym, (int) symbol.st_name, name,
               (int) ELF_ST_BIND (symbol.st_info),
               (int) ELF_ST_TYPE (symbol.st_info),
               symbol.st_shndx,
-              (int) symbol.st_size);
+              (int) symbol.st_size,
+              (int) symbol.st_value);
 
-            /*
-         * If a duplicate forget it.
-         */
-        if (rtems_rtl_symbol_global_find (name))
-          continue;
+    /*
+     * If a duplicate forget it.
+     */
+    if (rtems_rtl_symbol_global_find (name))
+      continue;
 
     if ((symbol.st_shndx != 0) &&
         ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
@@ -775,7 +898,7 @@ rtems_rtl_elf_symbols (rtems_rtl_obj*      obj,
           else
           {
             if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
-              printf ("rtl: sym:elf:%-2d name:%-2d:%-20s: global\n",
+              printf ("rtl: sym:elf:%-4d name:%-4d: %-20s: global\n",
                       sym, (int) symbol.st_name, name);
             ++globals;
             global_string_space += strlen (name) + 1;
@@ -784,7 +907,7 @@ rtems_rtl_elf_symbols (rtems_rtl_obj*      obj,
         else if (ELF_ST_BIND (symbol.st_info) == STB_LOCAL)
         {
           if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
-            printf ("rtl: sym:elf:%-2d name:%-2d:%-20s: local\n",
+            printf ("rtl: sym:elf:%-4d name:%-4d: %-20s: local\n",
                     sym, (int) symbol.st_name, name);
           ++locals;
           local_string_space += strlen (name) + 1;
@@ -849,14 +972,14 @@ rtems_rtl_elf_symbols (rtems_rtl_obj*      obj,
     if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off,
                                          &symbol, sizeof (symbol)))
     {
-      if (locals)
+      if (obj->local_syms)
       {
         rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->local_table);
         obj->local_table = NULL;
         obj->local_size = 0;
         obj->local_syms = 0;
       }
-      if (globals)
+      if (obj->global_syms)
       {
         rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->global_table);
         obj->global_table = NULL;
@@ -875,78 +998,113 @@ rtems_rtl_elf_symbols (rtems_rtl_obj*      obj,
           (ELF_ST_BIND (symbol.st_info) == STB_WEAK) ||
           (ELF_ST_BIND (symbol.st_info) == STB_LOCAL)))
     {
-      rtems_rtl_obj_sect* symsect;
-      rtems_rtl_obj_sym*  osym;
-      char*               string;
-      Elf_Word            value;
+      rtems_rtl_obj_sym* osym;
+      char*              string;
+      Elf_Word           value;
+      const char*        name;
 
-      symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx);
-      if (symsect)
+      off = obj->ooffset + strtab->offset + symbol.st_name;
+      len = RTEMS_RTL_ELF_STRING_MAX;
+
+      if (!rtems_rtl_obj_cache_read (strings, fd, off, (void**) &name, &len))
+        return false;
+
+      /*
+       * If a duplicate forget it.
+       */
+      if (rtems_rtl_symbol_global_find (name))
+        continue;
+
+      if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
+          (ELF_ST_BIND (symbol.st_info) == STB_WEAK))
+      {
+        osym = gsym;
+        string = gstring;
+        gstring += strlen (name) + 1;
+        ++gsym;
+      }
+      else
       {
-        const char* name;
+        osym = lsym;
+        string = lstring;
+        lstring += strlen (name) + 1;
+        ++lsym;
+      }
 
-        off = obj->ooffset + strtab->offset + symbol.st_name;
-        len = RTEMS_RTL_ELF_STRING_MAX;
+      /*
+       * Allocate any common symbols in the common section.
+       */
+      if (symbol.st_shndx == SHN_COMMON)
+      {
+        size_t value_off = rtems_rtl_obj_align (common_offset,
+                                                symbol.st_value);
+        common_offset = value_off + symbol.st_size;
+        value = value_off;
+      }
+      else
+      {
+        value = symbol.st_value;
+      }
 
-        if (!rtems_rtl_obj_cache_read (strings, fd, off, (void**) &name, &len))
-          return false;
+      rtems_chain_set_off_chain (&osym->node);
+      memcpy (string, name, strlen (name) + 1);
+      osym->name = string;
+      osym->value = (uint8_t*) value;
+      osym->data = symbol.st_shndx;
 
-        /*
-         * If a duplicate forget it.
-         */
-        if (rtems_rtl_symbol_global_find (name))
-          continue;
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
+        printf ("rtl: sym:add:%-4d name:%-4d: %-20s: bind:%-2d " \
+                "type:%-2d val:%-8p sect:%-3d size:%d\n",
+                sym, (int) symbol.st_name, osym->name,
+                (int) ELF_ST_BIND (symbol.st_info),
+                (int) ELF_ST_TYPE (symbol.st_info),
+                osym->value, symbol.st_shndx,
+                (int) symbol.st_size);
+    }
+  }
 
-        if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
-            (ELF_ST_BIND (symbol.st_info) == STB_WEAK))
-        {
-          osym = gsym;
-          string = gstring;
-          gstring += strlen (name) + 1;
-          ++gsym;
-        }
-        else
-        {
-          osym = lsym;
-          string = lstring;
-          lstring += strlen (name) + 1;
-          ++lsym;
-        }
+  return true;
+}
 
-        /*
-         * Allocate any common symbols in the common section.
-         */
-        if (symbol.st_shndx == SHN_COMMON)
-        {
-          size_t value_off = rtems_rtl_obj_align (common_offset,
-                                                  symbol.st_value);
-          common_offset = value_off + symbol.st_size;
-          value = value_off;
-        }
-        else
-        {
-          value = symbol.st_value;
-        }
+static bool
+rtems_rtl_elf_symbols_locate (rtems_rtl_obj*      obj,
+                              int                 fd,
+                              rtems_rtl_obj_sect* sect,
+                              void*               data)
+{
+  int sym;
 
-        rtems_chain_set_off_chain (&osym->node);
-        memcpy (string, name, strlen (name) + 1);
-        osym->name = string;
-        osym->value = value + (uint8_t*) symsect->base;
-        osym->data = symbol.st_info;
+  for (sym = 0; sym < obj->local_syms; ++sym)
+  {
+      rtems_rtl_obj_sym*  osym = &obj->local_table[sym];
+      rtems_rtl_obj_sect* symsect;
+      symsect = rtems_rtl_obj_find_section_by_index (obj, osym->data);
+      if (symsect)
+      {
+        osym->value += (intptr_t) symsect->base;
+        if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
+          printf ("rtl: sym:locate:local :%-4d name: %-20s val:%-8p sect:%-3d (%s, %p)\n",
+                  sym, osym->name, osym->value, osym->data,
+                  symsect->name, symsect->base);
+      }
+  }
 
+  for (sym = 0; sym < obj->global_syms; ++sym)
+  {
+      rtems_rtl_obj_sym*  osym = &obj->global_table[sym];
+      rtems_rtl_obj_sect* symsect;
+      symsect = rtems_rtl_obj_find_section_by_index (obj, osym->data);
+      if (symsect)
+      {
+        osym->value += (intptr_t) symsect->base;
         if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
-          printf ("rtl: sym:add:%-2d name:%-2d:%-20s bind:%-2d " \
-                  "type:%-2d val:%8p sect:%d size:%d\n",
-                  sym, (int) symbol.st_name, osym->name,
-                  (int) ELF_ST_BIND (symbol.st_info),
-                  (int) ELF_ST_TYPE (symbol.st_info),
-                  osym->value, symbol.st_shndx,
-                  (int) symbol.st_size);
+          printf ("rtl: sym:locate:global:%-4d name: %-20s val:%-8p sect:%-3d (%s, %p)\n",
+                  sym, osym->name, osym->value, osym->data,
+                  symsect->name, symsect->base);
       }
-    }
   }
 
-  if (globals)
+  if (obj->global_size)
     rtems_rtl_symbol_obj_add (obj);
 
   return true;
@@ -1434,6 +1592,11 @@ rtems_rtl_elf_file_load (rtems_rtl_obj* obj, int fd)
     return false;
   }
 
+  /*
+   * Set the format's architecture's maximum tramp size.
+   */
+  obj->tramp_size = rtems_rtl_elf_relocate_tramp_max_size ();
+
   /*
    * Parse the section information first so we have the memory map of the object
    * file and the memory allocated. Any further allocations we make to complete
@@ -1443,18 +1606,31 @@ rtems_rtl_elf_file_load (rtems_rtl_obj* obj, int fd)
     return false;
 
   /*
-   * See if there are any common variables and if there are add a common
-   * section.
+   * Set the entry point if there is one.
+   */
+  obj->entry = (void*)(uintptr_t) ehdr.e_entry;
+
+  /*
+   * Load the symbol table.
+   *
+   * 1. See if there are any common variables and if there are add a
+   *    common section.
+   * 2. Add up the common.
+   * 3.
    */
   if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_common, &common))
     return false;
   if (!rtems_rtl_elf_add_common (obj, common.size, common.alignment))
     return false;
+  if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_symbols_load, &ehdr))
+    return false;
 
   /*
-   * Set the entry point if there is one.
+   * Parse the relocation records. It lets us know how many dependents
+   * and fixup trampolines there are.
    */
-  obj->entry = (void*)(uintptr_t) ehdr.e_entry;
+  if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocs_parser, &relocs))
+    return false;
 
   /*
    * Lock the allocator so the section memory and the trampoline memory are as
@@ -1468,17 +1644,7 @@ rtems_rtl_elf_file_load (rtems_rtl_obj* obj, int fd)
   if (!rtems_rtl_obj_alloc_sections (obj, fd, rtems_rtl_elf_arch_alloc, &ehdr))
     return false;
 
-  /*
-   * Load the sections and symbols and then relocation to the base address.
-   */
-  if (!rtems_rtl_obj_load_sections (obj, fd, rtems_rtl_elf_loader, &ehdr))
-    return false;
-
-  /*
-   * Parse the relocation records. It lets us know how many dependents
-   * and fixup trampolines there are.
-   */
-  if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocs_parser, &relocs))
+  if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_symbols_locate, &ehdr))
     return false;
 
   if (!rtems_rtl_elf_dependents (obj, &relocs))
@@ -1492,9 +1658,15 @@ rtems_rtl_elf_file_load (rtems_rtl_obj* obj, int fd)
    */
   rtems_rtl_alloc_unlock ();
 
-  if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_symbols, &ehdr))
+  /*
+   * Load the sections and symbols and then relocation to the base address.
+   */
+  if (!rtems_rtl_obj_load_sections (obj, fd, rtems_rtl_elf_loader, &ehdr))
     return false;
 
+  /*
+   * Fix up the relocations.
+   */
   if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocs_locator, &ehdr))
     return false;
 
diff --git a/cpukit/libdl/rtl-elf.h b/cpukit/libdl/rtl-elf.h
index 73d1e01bb1..660b0c47b4 100644
--- a/cpukit/libdl/rtl-elf.h
+++ b/cpukit/libdl/rtl-elf.h
@@ -51,6 +51,17 @@ extern "C" {
  ** Imported NetBSD ELF Specifics End.
  **/
 
+/**
+ * ELF Relocation status codes.
+ */
+typedef enum rtems_rtl_elf_rel_status
+{
+  rtems_rtl_elf_rel_no_error,    /**< There is no error processing the record. */
+  rtems_rtl_elf_rel_failure,     /**< There was a failure processing the record. */
+  rtems_rtl_elf_rel_tramp_cache, /**< The reloc record may need a trampoliine. */
+  rtems_rtl_elf_rel_tramp_add    /**< Add a trampoliine. */
+} rtems_rtl_elf_rel_status;
+
 /**
  * Relocation trampoline relocation data.
  */
@@ -143,20 +154,19 @@ size_t rtems_rtl_elf_relocate_tramp_max_size (void);
  * relocation record requires a trampoline.
  *
  * @param obj The object file being relocated.
- * @param rel The ELF relocation record.
+ * @param rela The ELF relocation record.
  * @param sect The section of the object file the relocation is for.
  * @param symname The symbol's name.
  * @param syminfo The ELF symbol info field.
  * @param symvalue If a symbol is referenced, this is the symbols value.
- * @retval bool The relocation is valid.
- * @retval bool The relocation is not valid.
+ * @retval rtems_rtl_elf_rel_status The result of the trampoline parsing.
  */
-bool rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
-                                       const Elf_Rel*            rel,
-                                       const rtems_rtl_obj_sect* sect,
-                                       const char*               symname,
-                                       const Elf_Byte            syminfo,
-                                       const Elf_Word            symvalue);
+rtems_rtl_elf_rel_status rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
+                                                           const Elf_Rel*            rel,
+                                                           const rtems_rtl_obj_sect* sect,
+                                                           const char*               symname,
+                                                           const Elf_Byte            syminfo,
+                                                           const Elf_Word            symvalue);
 
 /**
  * Architecture specific relocation handler compiled in for a specific
@@ -169,15 +179,14 @@ bool rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
  * @param symname The symbol's name.
  * @param syminfo The ELF symbol info field.
  * @param symvalue If a symbol is referenced, this is the symbols value.
- * @retval bool The relocation is valid.
- * @retval bool The relocation is not valid.
+ * @retval rtems_rtl_elf_rel_status The result of the trampoline parsing.
  */
-bool rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
-                                        const Elf_Rela*           rela,
-                                        const rtems_rtl_obj_sect* sect,
-                                        const char*               symname,
-                                        const Elf_Byte            syminfo,
-                                        const Elf_Word            symvalue);
+rtems_rtl_elf_rel_status  rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
+                                                             const Elf_Rela*           rela,
+                                                             const rtems_rtl_obj_sect* sect,
+                                                             const char*               symname,
+                                                             const Elf_Byte            syminfo,
+                                                             const Elf_Word            symvalue);
 
 /**
  * Architecture specific relocation handler compiled in for a specific
@@ -190,15 +199,14 @@ bool rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
  * @param symname The symbol's name.
  * @param syminfo The ELF symbol info field.
  * @param symvalue If a symbol is referenced, this is the symbols value.
- * @retval bool The relocation has been applied.
- * @retval bool The relocation could not be applied.
+ * @retval rtems_rtl_elf_rel_status The result of the trampoline parsing.
  */
-bool rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
-                                 const Elf_Rel*            rel,
-                                 const rtems_rtl_obj_sect* sect,
-                                 const char*               symname,
-                                 const Elf_Byte            syminfo,
-                                 const Elf_Word            symvalue);
+rtems_rtl_elf_rel_status rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
+                                                     const Elf_Rel*            rel,
+                                                     const rtems_rtl_obj_sect* sect,
+                                                     const char*               symname,
+                                                     const Elf_Byte            syminfo,
+                                                     const Elf_Word            symvalue);
 
 /**
  * Architecture specific relocation handler compiled in for a specific
@@ -211,15 +219,14 @@ bool rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
  * @param symname The symbol's name.
  * @param syminfo The ELF symbol info field.
  * @param symvalue If a symbol is referenced, this is the symbols value.
- * @retval bool The relocation has been applied.
- * @retval bool The relocation could not be applied.
+ * @retval rtems_rtl_elf_rel_status The result of the trampoline parsing.
  */
-bool rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
-                                  const Elf_Rela*           rela,
-                                  const rtems_rtl_obj_sect* sect,
-                                  const char*               symname,
-                                  const Elf_Byte            syminfo,
-                                  const Elf_Word            symvalue);
+rtems_rtl_elf_rel_status rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
+                                                      const Elf_Rela*           rela,
+                                                      const rtems_rtl_obj_sect* sect,
+                                                      const char*               symname,
+                                                      const Elf_Byte            syminfo,
+                                                      const Elf_Word            symvalue);
 
 /**
  * The ELF format check handler.
diff --git a/cpukit/libdl/rtl-mdreloc-arm.c b/cpukit/libdl/rtl-mdreloc-arm.c
index b0c55c257a..4d5a2456a7 100644
--- a/cpukit/libdl/rtl-mdreloc-arm.c
+++ b/cpukit/libdl/rtl-mdreloc-arm.c
@@ -147,7 +147,7 @@ rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
   return true;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
                                    const Elf_Rela*           rela,
                                    const rtems_rtl_obj_sect* sect,
@@ -162,10 +162,10 @@ rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rela type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
                              const Elf_Rela*           rela,
                              const rtems_rtl_obj_sect* sect,
@@ -180,10 +180,10 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rela type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
-static bool
+static rtems_rtl_elf_rel_status
 rtems_rtl_elf_reloc_rel (rtems_rtl_obj*            obj,
                          const Elf_Rel*            rel,
                          const rtems_rtl_obj_sect* sect,
@@ -209,24 +209,37 @@ rtems_rtl_elf_reloc_rel (rtems_rtl_obj*            obj,
 
     case R_TYPE(CALL):    /* BL/BLX */
     case R_TYPE(JUMP24):  /* B/BL<cond> */
-      insn = *where;
-
-      if (insn & 0x00800000)
-        addend = insn | 0xff000000;
-      else addend = insn & 0x00ffffff;
-
-      if (isThumb(symvalue)) {
-        if ((insn & 0xfe000000) == 0xfa000000);         /* Already blx */
-        else {
-          if ((insn & 0xff000000) == 0xeb000000) {      /* BL <label> */
-            *where = (insn & 0x00ffffff) | 0xfa000000;  /* BL-->BLX */
-          } else {
-            printf("JUMP24 is not suppored from arm to thumb\n");
-            return false;
+      if (parsing)
+      {
+        addend = 0;
+      }
+      else
+      {
+        insn = *where;
+
+        if (insn & 0x00800000)
+          addend = insn | 0xff000000;
+        else addend = insn & 0x00ffffff;
+
+        if (isThumb(symvalue)) {
+          if ((insn & 0xfe000000) == 0xfa000000);         /* Already blx */
+          else {
+            if ((insn & 0xff000000) == 0xeb000000) {      /* BL <label> */
+              *where = (insn & 0x00ffffff) | 0xfa000000;  /* BL-->BLX */
+            } else {
+              printf("JUMP24 is not suppored from arm to thumb\n");
+              return rtems_rtl_elf_rel_failure;
+            }
           }
         }
       }
 
+      if (parsing && sect->base == 0) {
+        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+          printf ("rtl: JUMP24/PC24/CALL tramp cache\n");
+        return rtems_rtl_elf_rel_tramp_cache;
+      }
+
       tmp = symvalue + (addend << 2) - (Elf_Addr)where;
       tmp = (Elf_Sword)tmp >> 2;
 
@@ -235,15 +248,16 @@ rtems_rtl_elf_reloc_rel (rtems_rtl_obj*            obj,
         size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rel->r_info));
 
         if (parsing) {
-          obj->tramp_size += tramp_size;
-          return true;
+          if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+            printf ("rtl: JUMP24/PC24/CALL tramp add\n");
+          return rtems_rtl_elf_rel_tramp_add;
         }
 
-        if (!rtems_rtl_obj_has_ramp_space (obj, tramp_size)) {
+        if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) {
           rtems_rtl_set_error (EINVAL,
                                "%s: CALL/JUMP24: overflow: no tramp memory",
                                sect->name);
-          return false;
+          return rtems_rtl_elf_rel_failure;
         }
 
         tramp_addr = ((Elf_Addr) obj->tramp_brk) | (symvalue & 1);
@@ -286,7 +300,7 @@ rtems_rtl_elf_reloc_rel (rtems_rtl_obj*            obj,
         tmp = (Elf_Sword)tmp >> 16;
         if (((Elf_Sword)tmp > 0x7fff) || ((Elf_Sword)tmp < -0x8000)) {
           printf("MOVT_ABS Overflow\n");
-          return false;
+          return rtems_rtl_elf_rel_failure;
         }
       }
 
@@ -367,13 +381,22 @@ rtems_rtl_elf_reloc_rel (rtems_rtl_obj*            obj,
     case R_TYPE(THM_JUMP24):
       /* same as THM_PC22; insn b.w */
     case R_TYPE(THM_PC22):
-      upper_insn = *(uint16_t *)where;
-      lower_insn = *((uint16_t *)where + 1);
-      sign = (upper_insn & (1 << 10)) >> 10;
-      i1 = ((lower_insn >> 13) & 1) ^ sign ? 0 : 1;
-      i2 = ((lower_insn >> 11) & 1) ^ sign ? 0 : 1;
-      tmp = (i1 << 23) | (i2 << 22) | ((upper_insn & 0x3ff) << 12) | ((lower_insn & 0x7ff) << 1);
-      addend = (tmp | ((sign ? 0 : 1) << 24)) - (1 << 24);
+      if (parsing)
+      {
+        addend = 0;
+        upper_insn = 0;
+        lower_insn = 0;
+      }
+      else
+      {
+        upper_insn = *(uint16_t *)where;
+        lower_insn = *((uint16_t *)where + 1);
+        sign = (upper_insn & (1 << 10)) >> 10;
+        i1 = ((lower_insn >> 13) & 1) ^ sign ? 0 : 1;
+        i2 = ((lower_insn >> 11) & 1) ^ sign ? 0 : 1;
+        tmp = (i1 << 23) | (i2 << 22) | ((upper_insn & 0x3ff) << 12) | ((lower_insn & 0x7ff) << 1);
+        addend = (tmp | ((sign ? 0 : 1) << 24)) - (1 << 24);
+      }
 
       if (isThumb(symvalue)) ;/*Thumb to Thumb call, nothing to care */
       else {
@@ -381,32 +404,40 @@ rtems_rtl_elf_reloc_rel (rtems_rtl_obj*            obj,
           tmp = (tmp + 2) & ~3; /* aligned to 4 bytes only for JUMP24 */
 #if !ALLOW_UNTESTED_RELOCS
           printf("THM_JUMP24 to arm not supported\n");
-          return false;
+          return rtems_rtl_elf_rel_failure;
 #endif
         }
         else {
           /* THM_CALL bl-->blx */
-          lower_insn &=~(1<<12);
+          lower_insn &= ~(1<<12);
         }
       }
 
+      if (parsing && sect->base == 0) {
+        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+          printf ("rtl: THM_CALL/JUMP24 tramp cache\n");
+        return rtems_rtl_elf_rel_tramp_cache;
+      }
+
       tmp = symvalue + addend;
       tmp = tmp - (Elf_Addr)where;
 
       if (((Elf_Sword)tmp > 0x7fffff) || ((Elf_Sword)tmp < -0x800000)) {
-          Elf_Word tramp_addr;
-          size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rel->r_info));
+        Elf_Word tramp_addr;
+        size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rel->r_info));
 
         if (parsing) {
-          obj->tramp_size += tramp_size;
-          return true;
+          if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+            printf ("rtl: THM_CALL/JUMP24 tramp add: %08x - %p = %i\n",
+                    symvalue + addend, where, (Elf_Sword) tmp);
+          return rtems_rtl_elf_rel_tramp_add;
         }
 
-        if (!rtems_rtl_obj_has_ramp_space (obj, tramp_size)) {
+        if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) {
           rtems_rtl_set_error (EINVAL,
                                "%s: THM_CALL/JUMP24: overflow: no tramp memory",
                                sect->name);
-          return false;
+          return rtems_rtl_elf_rel_failure;
         }
 
         tramp_addr = ((Elf_Addr) obj->tramp_brk) | (symvalue & 1);
@@ -438,7 +469,7 @@ rtems_rtl_elf_reloc_rel (rtems_rtl_obj*            obj,
 
       if (!isThumb(symvalue)) {
         printf("THM_JUMP19 to arm not supported\n");
-        return false;
+        return rtems_rtl_elf_rel_failure;
       }
 
       upper_insn = *(uint16_t *)where;
@@ -463,8 +494,7 @@ rtems_rtl_elf_reloc_rel (rtems_rtl_obj*            obj,
         rtems_rtl_set_error (EINVAL, "%s: Overflow %" PRIu32 " "
                              "THM_JUMP19 relocations",
                              sect->name, (uint32_t) ELF_R_TYPE(rel->r_info));
-        return true;
-        return false;
+        return rtems_rtl_elf_rel_failure;
       }
 
       sign = (tmp >> 20) & 0x1;
@@ -511,13 +541,13 @@ rtems_rtl_elf_reloc_rel (rtems_rtl_obj*            obj,
                            "%s: Unsupported relocation type %" PRIu32 " "
                            "in non-PLT relocations",
                            sect->name, (uint32_t) ELF_R_TYPE(rel->r_info));
-      return false;
+      return rtems_rtl_elf_rel_failure;
   }
 
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
                                   const Elf_Rel*            rel,
                                   const rtems_rtl_obj_sect* sect,
@@ -534,7 +564,7 @@ rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
                                   true);
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
                             const Elf_Rel*            rel,
                             const rtems_rtl_obj_sect* sect,
diff --git a/cpukit/libdl/rtl-mdreloc-bfin.c b/cpukit/libdl/rtl-mdreloc-bfin.c
index af130276a4..27f865e5a5 100644
--- a/cpukit/libdl/rtl-mdreloc-bfin.c
+++ b/cpukit/libdl/rtl-mdreloc-bfin.c
@@ -73,7 +73,7 @@ rtems_rtl_elf_relocate_tramp_max_size (void)
   return 0;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
                                    const Elf_Rela*           rela,
                                    const rtems_rtl_obj_sect* sect,
@@ -87,10 +87,10 @@ rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
   (void) symname;
   (void) syminfo;
   (void) symvalue;
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
                              const Elf_Rela*           rela,
                              const rtems_rtl_obj_sect* sect,
@@ -136,7 +136,7 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
 
       if ((tmp & 0xff000000) && (~tmp & 0xff800000)) {
         printf("PCREL24/PCREL24_JU Overflow\n");
-        return false;
+        return rtems_rtl_elf_rel_failure;
       }
 
       tmp = (load_ptr(where) & 0x0000ff00) | ((tmp & 0x0000ffff) << 16) |
@@ -152,7 +152,7 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
 
       if ((tmp & 0xfffff000) && (~tmp & 0xfffff800)) {
         printf("PCREL12_JUMP_S Overflow\n");
-        return false;
+        return rtems_rtl_elf_rel_failure;
       }
 
       tmp = ((*(uint16_t *)where) & 0xf000) | (tmp & 0xfff);
@@ -161,15 +161,15 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
 
     default:
       printf("Unspported rela type\n");
-      return false;
+      return rtems_rtl_elf_rel_failure;
   }
 
   memcpy((void*)where, &tmp, size);
 
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
                                   const Elf_Rel*            rel,
                                   const rtems_rtl_obj_sect* sect,
@@ -184,10 +184,10 @@ rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
                             const Elf_Rel*            rel,
                             const rtems_rtl_obj_sect* sect,
@@ -202,7 +202,7 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
 bool
diff --git a/cpukit/libdl/rtl-mdreloc-h8300.c b/cpukit/libdl/rtl-mdreloc-h8300.c
index 4a12f34f36..f1a52e4f9d 100644
--- a/cpukit/libdl/rtl-mdreloc-h8300.c
+++ b/cpukit/libdl/rtl-mdreloc-h8300.c
@@ -66,7 +66,7 @@ rtems_rtl_elf_relocate_tramp_max_size (void)
   return 0;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
                                    const Elf_Rela*           rela,
                                    const rtems_rtl_obj_sect* sect,
@@ -80,10 +80,10 @@ rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
   (void) symname;
   (void) syminfo;
   (void) symvalue;
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
                              const Elf_Rela*           rela,
                              const rtems_rtl_obj_sect* sect,
@@ -130,7 +130,7 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
       tmp = symvalue + rela->r_addend - (Elf_Addr)where - 1;
       if (((Elf32_Sword)tmp > 0x7f) || ((Elf32_Sword)tmp < -(Elf32_Sword)0x80)){
         printf("PCREL8 overflow\n");
-          return false;
+          return rtems_rtl_elf_rel_failure;
       } else {
         *(uint8_t *)where = tmp;
       }
@@ -141,7 +141,7 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
       tmp = symvalue + rela->r_addend - (Elf_Addr)where - 2;
       if (((Elf32_Sword)tmp > 0x7fff) || ((Elf32_Sword)tmp < -(Elf32_Sword)0x8000)){
         printf("PCREL16 overflow\n");
-       return false;
+       return rtems_rtl_elf_rel_failure;
       } else {
        *(uint16_t *)where = tmp;
       }
@@ -150,12 +150,12 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
     default:
       rtems_rtl_set_error (EINVAL, "rela type record not supported");
       printf("Unsupported reloc types\n");
-      return false;
+      return rtems_rtl_elf_rel_failure;
   }
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*           obj,
                                   const Elf_Rel*            rel,
                                   const rtems_rtl_obj_sect* sect,
@@ -170,10 +170,10 @@ rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*           obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
                             const Elf_Rel*            rel,
                             const rtems_rtl_obj_sect* sect,
@@ -188,7 +188,7 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
 bool
diff --git a/cpukit/libdl/rtl-mdreloc-i386.c b/cpukit/libdl/rtl-mdreloc-i386.c
index 576914cf04..40b09d4be2 100644
--- a/cpukit/libdl/rtl-mdreloc-i386.c
+++ b/cpukit/libdl/rtl-mdreloc-i386.c
@@ -73,7 +73,7 @@ rtems_rtl_elf_relocate_tramp_max_size (void)
   return 0;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
                                    const Elf_Rela*           rela,
                                    const rtems_rtl_obj_sect* sect,
@@ -88,10 +88,10 @@ rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rela type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
                              const Elf_Rela*           rel,
                              const rtems_rtl_obj_sect* sect,
@@ -106,10 +106,10 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rela type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
                                   const Elf_Rel*            rel,
                                   const rtems_rtl_obj_sect* sect,
@@ -123,10 +123,10 @@ rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
   (void) symname;
   (void) syminfo;
   (void) symvalue;
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
                             const Elf_Rel*            rel,
                             const rtems_rtl_obj_sect* sect,
@@ -188,10 +188,10 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
                            "%s: Unsupported relocation type %" PRIu32 " "
                            "in non-PLT relocations",
                            sect->name, (uint32_t) ELF_R_TYPE(rel->r_info));
-      return false;
+      return rtems_rtl_elf_rel_failure;
   }
 
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
 bool
diff --git a/cpukit/libdl/rtl-mdreloc-lm32.c b/cpukit/libdl/rtl-mdreloc-lm32.c
index 9f4606ebad..4d47592e12 100644
--- a/cpukit/libdl/rtl-mdreloc-lm32.c
+++ b/cpukit/libdl/rtl-mdreloc-lm32.c
@@ -66,7 +66,7 @@ rtems_rtl_elf_relocate_tramp_max_size (void)
   return 0;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
                                    const Elf_Rela*           rela,
                                    const rtems_rtl_obj_sect* sect,
@@ -80,10 +80,10 @@ rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
   (void) symname;
   (void) syminfo;
   (void) symvalue;
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
                              const Elf_Rela*           rela,
                              const rtems_rtl_obj_sect* sect,
@@ -151,7 +151,7 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
       tmp = (Elf32_Sword)tmp >> 2;
       if (((Elf32_Sword)tmp > 0x7fff) || ((Elf32_Sword)tmp < -0x8000)){
         printf("BRANCH Overflow\n");
-        return false;
+        return rtems_rtl_elf_rel_failure;
       }
 
       *where = (*where & 0xffff0000) | (tmp & 0xffff);
@@ -164,17 +164,18 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
     default:
       rtems_rtl_set_error (EINVAL, "rela type record not supported");
       printf("Unsupported reloc types\n");
-      return false;
+      return rtems_rtl_elf_rel_failure;
   }
 
   if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) {
       printf("rela relocation type is %ld\n", ELF_R_TYPE(rela->r_info));
       printf("relocated address 0x%08lx\n", (Elf_Addr)where);
   }
-  return true;
+
+  return rtems_rtl_elf_rel_no_error;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
                                   const Elf_Rel*            rel,
                                   const rtems_rtl_obj_sect* sect,
@@ -189,10 +190,10 @@ rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
                             const Elf_Rel*            rel,
                             const rtems_rtl_obj_sect* sect,
@@ -207,7 +208,7 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rela type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
 bool
diff --git a/cpukit/libdl/rtl-mdreloc-m68k.c b/cpukit/libdl/rtl-mdreloc-m68k.c
index 21a60ee62a..873574ef7c 100644
--- a/cpukit/libdl/rtl-mdreloc-m68k.c
+++ b/cpukit/libdl/rtl-mdreloc-m68k.c
@@ -86,7 +86,7 @@ rtems_rtl_elf_relocate_tramp_max_size (void)
   return 0;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
                                    const Elf_Rela*           rela,
                                    const rtems_rtl_obj_sect* sect,
@@ -100,10 +100,10 @@ rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
   (void) symname;
   (void) syminfo;
   (void) symvalue;
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
                              const Elf_Rela*           rela,
                              const rtems_rtl_obj_sect* sect,
@@ -118,91 +118,91 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
   where = (Elf_Addr *)(sect->base + rela->r_offset);
 
   switch (ELF_R_TYPE(rela->r_info)) {
-		case R_TYPE(NONE):
-			break;
-
-    case R_TYPE(PC8):
-      tmp = symvalue + rela->r_addend - (Elf_Addr)where;
-      if (overflow_8_check(tmp))
-        return false;
-
-      *(uint8_t *)where = tmp;
-
-      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
-        printf ("rtl: reloc R_TYPE_8/PC8 in %s --> %p (%p) in %s\n",
-                sect->name, (void*) (symvalue + rela->r_addend),
-                (void *)*where, rtems_rtl_obj_oname (obj));
-      break;
-
-    case R_TYPE(PC16):
-      tmp = symvalue + rela->r_addend - (Elf_Addr)where;
-      if (overflow_16_check(tmp))
-        return false;
-
-      *(uint16_t*)where = tmp;
-
-      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
-        printf ("rtl: reloc R_TYPE_16/PC16 in %s --> %p (%p) in %s\n",
-                sect->name, (void*) (symvalue + rela->r_addend),
-                (void *)*where, rtems_rtl_obj_oname (obj));
-      break;
-		case R_TYPE(PC32):
-      target = (Elf_Addr) symvalue + rela->r_addend;
-      *where += target - (Elf_Addr)where;
-
-      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
-        printf ("rtl: reloc PC32 in %s --> %p (%p) in %s\n",
-                sect->name, (void*) (symvalue + rela->r_addend),
-                (void *)*where, rtems_rtl_obj_oname (obj));
-      break;
-
-		case R_TYPE(GOT32):
-		case R_TYPE(32):
-		case R_TYPE(GLOB_DAT):
-      target = (Elf_Addr) symvalue + rela->r_addend;
-
-			if (*where != target)
-				*where = target;
-
-      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
-        printf ("rtl: reloc 32/GLOB_DAT in %s --> %p in %s\n",
-                sect->name, (void *)*where,
-                rtems_rtl_obj_oname (obj));
-			break;
-
-		case R_TYPE(RELATIVE):
-			*where += (Elf_Addr) sect->base + rela->r_addend;
-      if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
-        printf ("rtl: reloc RELATIVE in %s --> %p\n",
-                rtems_rtl_obj_oname (obj), (void *)*where);
-			break;
-
-		case R_TYPE(COPY):
-			/*
-			 * These are deferred until all other relocations have
-			 * been done.  All we do here is make sure that the
-			 * COPY relocation is not in a shared library.  They
-			 * are allowed only in executable files.
-			 */
-      printf ("rtl: reloc COPY (please report)\n");
-			break;
-
-		default:
-      printf ("rtl: reloc unknown: sym = %u, type = %u, offset = %p, "
-              "contents = %p\n",
-              ELF_R_SYM(rela->r_info), (uint32_t) ELF_R_TYPE(rela->r_info),
-              (void *)rela->r_offset, (void *)*where);
-      rtems_rtl_set_error (EINVAL,
-                           "%s: Unsupported relocation type %d "
-                           "in non-PLT relocations",
-                           sect->name, (uint32_t) ELF_R_TYPE(rela->r_info));
-      return false;
+  case R_TYPE(NONE):
+    break;
+
+  case R_TYPE(PC8):
+    tmp = symvalue + rela->r_addend - (Elf_Addr)where;
+    if (overflow_8_check(tmp))
+      return rtems_rtl_elf_rel_failure;
+
+    *(uint8_t *)where = tmp;
+
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+      printf ("rtl: reloc R_TYPE_8/PC8 in %s --> %p (%p) in %s\n",
+              sect->name, (void*) (symvalue + rela->r_addend),
+              (void *)*where, rtems_rtl_obj_oname (obj));
+    break;
+
+  case R_TYPE(PC16):
+    tmp = symvalue + rela->r_addend - (Elf_Addr)where;
+    if (overflow_16_check(tmp))
+      return rtems_rtl_elf_rel_failure;
+
+    *(uint16_t*)where = tmp;
+
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+      printf ("rtl: reloc R_TYPE_16/PC16 in %s --> %p (%p) in %s\n",
+              sect->name, (void*) (symvalue + rela->r_addend),
+              (void *)*where, rtems_rtl_obj_oname (obj));
+    break;
+  case R_TYPE(PC32):
+    target = (Elf_Addr) symvalue + rela->r_addend;
+    *where += target - (Elf_Addr)where;
+
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+      printf ("rtl: reloc PC32 in %s --> %p (%p) in %s\n",
+              sect->name, (void*) (symvalue + rela->r_addend),
+              (void *)*where, rtems_rtl_obj_oname (obj));
+    break;
+
+  case R_TYPE(GOT32):
+  case R_TYPE(32):
+  case R_TYPE(GLOB_DAT):
+    target = (Elf_Addr) symvalue + rela->r_addend;
+
+    if (*where != target)
+      *where = target;
+
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+      printf ("rtl: reloc 32/GLOB_DAT in %s --> %p in %s\n",
+              sect->name, (void *)*where,
+              rtems_rtl_obj_oname (obj));
+    break;
+
+  case R_TYPE(RELATIVE):
+    *where += (Elf_Addr) sect->base + rela->r_addend;
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+      printf ("rtl: reloc RELATIVE in %s --> %p\n",
+              rtems_rtl_obj_oname (obj), (void *)*where);
+    break;
+
+  case R_TYPE(COPY):
+    /*
+     * These are deferred until all other relocations have
+     * been done.  All we do here is make sure that the
+     * COPY relocation is not in a shared library.  They
+     * are allowed only in executable files.
+     */
+    printf ("rtl: reloc COPY (please report)\n");
+    break;
+
+  default:
+    printf ("rtl: reloc unknown: sym = %u, type = %u, offset = %p, "
+            "contents = %p\n",
+            ELF_R_SYM(rela->r_info), (uint32_t) ELF_R_TYPE(rela->r_info),
+            (void *)rela->r_offset, (void *)*where);
+    rtems_rtl_set_error (EINVAL,
+                         "%s: Unsupported relocation type %d "
+                         "in non-PLT relocations",
+                         sect->name, (uint32_t) ELF_R_TYPE(rela->r_info));
+    return rtems_rtl_elf_rel_failure;
   }
 
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
                                   const Elf_Rel*            rel,
                                   const rtems_rtl_obj_sect* sect,
@@ -217,10 +217,10 @@ rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
                             const Elf_Rel*            rel,
                             const rtems_rtl_obj_sect* sect,
@@ -235,7 +235,7 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
 bool
diff --git a/cpukit/libdl/rtl-mdreloc-mips.c b/cpukit/libdl/rtl-mdreloc-mips.c
index f01a6552a5..c37804880f 100644
--- a/cpukit/libdl/rtl-mdreloc-mips.c
+++ b/cpukit/libdl/rtl-mdreloc-mips.c
@@ -66,7 +66,7 @@ rtems_rtl_elf_relocate_tramp_max_size (void)
   return 0;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
                                    const Elf_Rela*           rela,
                                    const rtems_rtl_obj_sect* sect,
@@ -81,10 +81,10 @@ rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rela type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
                              const Elf_Rela*           rela,
                              const rtems_rtl_obj_sect* sect,
@@ -99,10 +99,10 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rela type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
                                   const Elf_Rel*            rel,
                                   const rtems_rtl_obj_sect* sect,
@@ -116,7 +116,7 @@ rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
   (void) symname;
   (void) syminfo;
   (void) symvalue;
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
 /*
@@ -127,7 +127,7 @@ rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
  * symbol is STT_SECTION, it must be STB_LOCAL. Thus
  * just consider symtype here.
  */
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
                             const Elf_Rel*            rel,
                             const rtems_rtl_obj_sect* sect,
@@ -162,7 +162,7 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
       tmp = symvalue + (int)tmp;
       if ((tmp & 0xffff0000) != 0) {
         printf("R_MIPS_16 Overflow\n");
-        return false;
+        return rtems_rtl_elf_rel_failure;
       }
 
       *where = (tmp & 0xffff) | (*where & 0xffff0000);
@@ -224,7 +224,7 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
       t = ahl + (int16_t)addend;
       tmp = symvalue;
       if (tmp == 0)
-        return false;
+        return rtems_rtl_elf_rel_failure;
 
       addend &= 0xffff0000;
       addend |= (uint16_t)(t + tmp);
@@ -254,7 +254,7 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
       tmp = (Elf_Sword)tmp >> 2;
       if (((Elf_Sword)tmp > 0x7fff) || ((Elf_Sword)tmp < -0x8000)) {
         printf("R_MIPS_PC16 Overflow\n");
-        return false;
+        return rtems_rtl_elf_rel_failure;
       }
 
       *where = (tmp & 0xffff) | (*where & 0xffff0000);
@@ -274,10 +274,10 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
                            "%s: Unsupported relocation type %ld "
                            "in non-PLT relocations",
                            sect->name, (uint32_t) ELF_R_TYPE(rel->r_info));
-      return false;
+      return rtems_rtl_elf_rel_failure;
   }
 
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
 bool
diff --git a/cpukit/libdl/rtl-mdreloc-moxie.c b/cpukit/libdl/rtl-mdreloc-moxie.c
index 68fa2d2a16..8c7169e532 100644
--- a/cpukit/libdl/rtl-mdreloc-moxie.c
+++ b/cpukit/libdl/rtl-mdreloc-moxie.c
@@ -67,7 +67,7 @@ rtems_rtl_elf_relocate_tramp_max_size (void)
   return 0;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
                                    const Elf_Rela*           rela,
                                    const rtems_rtl_obj_sect* sect,
@@ -81,10 +81,10 @@ rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
   (void) symname;
   (void) syminfo;
   (void) symvalue;
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
                              const Elf_Rela*           rela,
                              const rtems_rtl_obj_sect* sect,
@@ -122,7 +122,7 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
       tmp = (Elf_Sword)tmp >> 1;
       if (((Elf32_Sword)tmp > 0x1ff) || ((Elf32_Sword)tmp < -(Elf32_Sword)0x200)){
         printf("Overflow for PCREL10: %ld exceed -0x200:0x1ff\n", tmp);
-        return false;
+        return rtems_rtl_elf_rel_failure;
       }
 
       *(uint16_t *)where = (*(uint16_t *)where & 0xfc00) | (tmp & 0x3ff);
@@ -136,13 +136,13 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
     default:
       rtems_rtl_set_error (EINVAL, "rela type record not supported");
       printf("Unsupported reloc types\n");
-      return false;
+      return rtems_rtl_elf_rel_failure;
   }
 
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
                                   const Elf_Rel*            rel,
                                   const rtems_rtl_obj_sect* sect,
@@ -157,10 +157,10 @@ rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
                             const Elf_Rel*            rel,
                             const rtems_rtl_obj_sect* sect,
@@ -175,7 +175,7 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
 bool
diff --git a/cpukit/libdl/rtl-mdreloc-powerpc.c b/cpukit/libdl/rtl-mdreloc-powerpc.c
index 0a9703984d..48ecee58e5 100644
--- a/cpukit/libdl/rtl-mdreloc-powerpc.c
+++ b/cpukit/libdl/rtl-mdreloc-powerpc.c
@@ -213,7 +213,14 @@ get_veneer_size (int type)
   return rtems_rtl_elf_relocate_tramp_max_size ();
 }
 
-static bool
+/**
+ * The offsets in the reloc words.
+ */
+#define REL_R_OFFSET (0)
+#define REL_R_INFO   (1)
+#define REL_R_ADDEND (2)
+
+static rtems_rtl_elf_rel_status
 rtems_rtl_elf_reloc_rela (rtems_rtl_obj*            obj,
                           const Elf_Rela*           rela,
                           const rtems_rtl_obj_sect* sect,
@@ -226,6 +233,7 @@ rtems_rtl_elf_reloc_rela (rtems_rtl_obj*            obj,
   Elf_Word tmp;
   uint32_t mask = 0;
   uint32_t bits = 0;
+  bool     needs_tramp = false;
 
   where = (Elf_Addr *)(sect->base + rela->r_offset);
   switch (ELF_R_TYPE(rela->r_info)) {
@@ -259,14 +267,29 @@ rtems_rtl_elf_reloc_rela (rtems_rtl_obj*            obj,
         bits = 24;
         mask = 0x3fffffc;
       }
+
+      if (parsing && sect->base == 0) {
+        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+          printf ("rtl: ADDR14/ADDR24 tramp cache\n");
+        return rtems_rtl_elf_rel_tramp_cache;
+      }
+
       tmp = (symvalue + rela->r_addend) >> 2;
       if (tmp > ((1<<bits) - 1 )) {
         Elf_Word tramp_addr;
         size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rela->r_info));
         if (parsing) {
-          obj->tramp_size += tramp_size;
-          return true;
+          if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+            printf ("rtl: ADDR14/ADDR24 tramp add\n");
+          return rtems_rtl_elf_rel_tramp_add;
+        }
+        if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) {
+          if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+            printf ("rtl: ADDR14/ADDR24 no tramp slot: %s\n", rtems_rtl_obj_oname (obj));
+          rtems_rtl_set_error (ENOMEM, "%s: tramp: no slot: ADDR14/ADDR24", sect->name);
+          return rtems_rtl_elf_rel_failure;
         }
+        needs_tramp = true;
         tramp_addr = (Elf_Addr) obj->tramp_brk;
         obj->tramp_brk = set_veneer(obj->tramp_brk,
                                     symvalue + rela->r_addend);
@@ -283,7 +306,8 @@ rtems_rtl_elf_reloc_rela (rtems_rtl_obj*            obj,
       if (!parsing) {
         *where = tmp;
         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
-          printf ("rtl: ADDR14/ADDR24 %p @ %p in %s\n",
+          printf ("rtl: ADDR14/ADDR24%s %p @ %p in %s\n",
+                  needs_tramp ? "(tramp)" : "",
                   (void *)*where, where, rtems_rtl_obj_oname (obj));
       }
       break;
@@ -341,15 +365,29 @@ rtems_rtl_elf_reloc_rela (rtems_rtl_obj*            obj,
         bits = 14;
       }
 
+      if (parsing && sect->base == 0) {
+        if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+          printf ("rtl: REL24/REL14 tramp cache\n");
+        return rtems_rtl_elf_rel_tramp_cache;
+      }
+
       tmp =((int) (symvalue + rela->r_addend - (Elf_Addr)where)) >> 2;
       if (((Elf_Sword)tmp > ((1<<(bits-1)) - 1)) ||
           ((Elf_Sword)tmp < -(1<<(bits-1)))) {
         Elf_Word tramp_addr;
         size_t   tramp_size = get_veneer_size(ELF_R_TYPE(rela->r_info));
         if (parsing) {
-          obj->tramp_size += tramp_size;
-          return true;
+          if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+            printf ("rtl: REL24/REL14 tramp add\n");
+          return rtems_rtl_elf_rel_tramp_add;
+        }
+        if (!rtems_rtl_obj_has_tramp_space (obj, tramp_size)) {
+          if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+            printf ("rtl: REL24/REL14 no tramp slot: %s\n", rtems_rtl_obj_oname (obj));
+          rtems_rtl_set_error (ENOMEM, "%s: tramp: no slot: REL24/REL14", sect->name);
+          return rtems_rtl_elf_rel_failure;
         }
+        needs_tramp = true;
         tramp_addr = (Elf_Addr) obj->tramp_brk;
         obj->tramp_brk = set_veneer(obj->tramp_brk,
                                     symvalue + rela->r_addend);
@@ -367,7 +405,8 @@ rtems_rtl_elf_reloc_rela (rtems_rtl_obj*            obj,
       if (!parsing) {
         *where = tmp;
         if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
-          printf ("rtl: REL24/REL14 %p @ %p in %s\n",
+          printf ("rtl: REL24/REL14%s %p @ %p in %s\n",
+                  needs_tramp ? "(tramp)" : "",
                   (void *)*where, where, rtems_rtl_obj_oname (obj));
       }
       break;
@@ -412,12 +451,12 @@ rtems_rtl_elf_reloc_rela (rtems_rtl_obj*            obj,
                            "%s: Unsupported relocation type %" PRId32
                            "in non-PLT relocations",
                            sect->name, (uint32_t) ELF_R_TYPE(rela->r_info));
-      return false;
+      return rtems_rtl_elf_rel_failure;
   }
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
                                    const Elf_Rela*           rela,
                                    const rtems_rtl_obj_sect* sect,
@@ -434,7 +473,7 @@ rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
                                    true);
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
                              const Elf_Rela*           rela,
                              const rtems_rtl_obj_sect* sect,
@@ -451,7 +490,7 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
                                    false);
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
                                   const Elf_Rel*            rel,
                                   const rtems_rtl_obj_sect* sect,
@@ -466,10 +505,10 @@ rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
                             const Elf_Rel*            rel,
                             const rtems_rtl_obj_sect* sect,
@@ -484,7 +523,7 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
 bool
diff --git a/cpukit/libdl/rtl-mdreloc-sparc.c b/cpukit/libdl/rtl-mdreloc-sparc.c
index f76da575e4..548c24132b 100644
--- a/cpukit/libdl/rtl-mdreloc-sparc.c
+++ b/cpukit/libdl/rtl-mdreloc-sparc.c
@@ -185,7 +185,7 @@ rtems_rtl_elf_relocate_tramp_max_size (void)
   return 0;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
                                    const Elf_Rela*           rela,
                                    const rtems_rtl_obj_sect* sect,
@@ -199,10 +199,10 @@ rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
   (void) symname;
   (void) syminfo;
   (void) symvalue;
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
                              const Elf_Rela*           rela,
                              const rtems_rtl_obj_sect* sect,
@@ -218,22 +218,22 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
 
   type = ELF_R_TYPE(rela->r_info);
   if (type == R_TYPE(NONE))
-    return true;
+    return rtems_rtl_elf_rel_no_error;
 
   /* We do JMP_SLOTs in _rtld_bind() below */
   if (type == R_TYPE(JMP_SLOT))
-    return true;
+    return rtems_rtl_elf_rel_no_error;
 
   /* COPY relocs are also handled elsewhere */
   if (type == R_TYPE(COPY))
-    return true;
+    return rtems_rtl_elf_rel_no_error;
 
   /*
    * We use the fact that relocation types are an `enum'
    * Note: R_SPARC_6 is currently numerically largest.
    */
   if (type > R_TYPE(6))
-    return false;
+    return rtems_rtl_elf_rel_failure;
 
   value = rela->r_addend;
 
@@ -245,7 +245,7 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
     if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
       printf ("rtl: reloc relative in %s --> %p",
               rtems_rtl_obj_oname (obj), (void *)*where);
-    return true;
+    return rtems_rtl_elf_rel_no_error;
   }
 
   if (RELOC_RESOLVE_SYMBOL (type)) {
@@ -315,10 +315,10 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
             reloc_names[ELF_R_TYPE(rela->r_info)],
             (void *)tmp, where, rtems_rtl_obj_oname (obj));
 
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
                                   const Elf_Rel*            rel,
                                   const rtems_rtl_obj_sect* sect,
@@ -333,10 +333,10 @@ rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
                             const Elf_Rel*            rel,
                             const rtems_rtl_obj_sect* sect,
@@ -351,7 +351,7 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   printf ("rtl: rel type record not supported; please report\n");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
 bool
diff --git a/cpukit/libdl/rtl-mdreloc-v850.c b/cpukit/libdl/rtl-mdreloc-v850.c
index 93e531b40e..859225ca6f 100644
--- a/cpukit/libdl/rtl-mdreloc-v850.c
+++ b/cpukit/libdl/rtl-mdreloc-v850.c
@@ -67,7 +67,7 @@ rtems_rtl_elf_relocate_tramp_max_size (void)
   return 0;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
                                    const Elf_Rela*           rela,
                                    const rtems_rtl_obj_sect* sect,
@@ -81,10 +81,10 @@ rtems_rtl_elf_relocate_rela_tramp (rtems_rtl_obj*            obj,
   (void) symname;
   (void) syminfo;
   (void) symvalue;
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
                              const Elf_Rela*           rela,
                              const rtems_rtl_obj_sect* sect,
@@ -125,7 +125,7 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
       tmp =  symvalue + rela->r_addend - (Elf_Addr)where;
       if (((Elf_Sword)tmp > 0x1fffff) || ((Elf_Sword)tmp < -0x200000)) {
         printf("Overflow\n");
-        return false;
+        return rtems_rtl_elf_rel_failure;
       }
 
       ((uint16_t *)where)[0] = (*(uint16_t *)where & 0xffc0) |
@@ -145,13 +145,13 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj*            obj,
     default:
       rtems_rtl_set_error (EINVAL, "rela type record not supported");
       printf("error reloc type\n");
-      return false;
+      return rtems_rtl_elf_rel_failure;
   }
 
-  return true;
+  return rtems_rtl_elf_rel_no_error;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
                                   const Elf_Rel*            rel,
                                   const rtems_rtl_obj_sect* sect,
@@ -166,10 +166,10 @@ rtems_rtl_elf_relocate_rel_tramp (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
-bool
+rtems_rtl_elf_rel_status
 rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
                             const Elf_Rel*            rel,
                             const rtems_rtl_obj_sect* sect,
@@ -184,7 +184,7 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj*            obj,
   (void) syminfo;
   (void) symvalue;
   rtems_rtl_set_error (EINVAL, "rel type record not supported");
-  return false;
+  return rtems_rtl_elf_rel_failure;
 }
 
 bool
diff --git a/cpukit/libdl/rtl-obj.c b/cpukit/libdl/rtl-obj.c
index 378678435d..9acb6f3943 100644
--- a/cpukit/libdl/rtl-obj.c
+++ b/cpukit/libdl/rtl-obj.c
@@ -583,10 +583,10 @@ rtems_rtl_obj_find_section_by_mask (const rtems_rtl_obj* obj,
 bool
 rtems_rtl_obj_alloc_trampoline (rtems_rtl_obj* obj)
 {
-  if (obj->tramp_size == 0)
+  if (obj->tramps_size == 0)
     return true;
   obj->trampoline = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
-                                         obj->tramp_size,
+                                         obj->tramps_size,
                                          true);
   if (obj->trampoline == NULL)
     rtems_rtl_set_error (ENOMEM, "no memory for the trampoline");
@@ -903,7 +903,7 @@ rtems_rtl_obj_synchronize_cache (rtems_rtl_obj* obj)
   if (obj->trampoline != NULL)
   {
     rtems_cache_instruction_sync_after_code_change(obj->trampoline,
-                                                   obj->tramp_size);
+                                                   obj->tramps_size);
   }
 }
 
@@ -998,14 +998,11 @@ rtems_rtl_obj_sections_link_order (uint32_t mask, rtems_rtl_obj* obj)
   }
 }
 
-static bool
-rtems_rtl_obj_sections_loader (uint32_t                   mask,
-                               rtems_rtl_alloc_tag        tag,
-                               rtems_rtl_obj*             obj,
-                               int                        fd,
-                               uint8_t*                   base,
-                               rtems_rtl_obj_sect_handler handler,
-                               void*                      data)
+static void
+rtems_rtl_obj_sections_locate (uint32_t            mask,
+                               rtems_rtl_alloc_tag tag,
+                               rtems_rtl_obj*      obj,
+                               uint8_t*            base)
 {
   rtems_chain_control* sections = &obj->sections;
   rtems_chain_node*    node = rtems_chain_first (sections);
@@ -1013,9 +1010,7 @@ rtems_rtl_obj_sections_loader (uint32_t                   mask,
   int                  order = 0;
 
   if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
-    printf ("rtl: loading section: mask:%08" PRIx32 " base:%p\n", mask, base);
-
-  rtems_rtl_alloc_wr_enable (tag, base);
+    printf ("rtl: locating section: mask:%08" PRIx32 " base:%p\n", mask, base);
 
   while (!rtems_chain_is_tail (sections, node))
   {
@@ -1032,32 +1027,11 @@ rtems_rtl_obj_sections_loader (uint32_t                   mask,
         }
 
         if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
-          printf ("rtl: loading:%2d: %s -> %p (s:%zi f:%04" PRIx32
+          printf ("rtl: locating:%2d: %s -> %p (s:%zi f:%04" PRIx32
                   " a:%" PRIu32 " l:%02d)\n",
                   order, sect->name, sect->base, sect->size,
                   sect->flags, sect->alignment, sect->link);
 
-        if ((sect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == RTEMS_RTL_OBJ_SECT_LOAD)
-        {
-          if (!handler (obj, fd, sect, data))
-          {
-            sect->base = 0;
-            rtems_rtl_alloc_wr_disable (tag, base);
-            return false;
-          }
-        }
-        else if ((sect->flags & RTEMS_RTL_OBJ_SECT_ZERO) == RTEMS_RTL_OBJ_SECT_ZERO)
-        {
-          memset (sect->base, 0, sect->size);
-        }
-        else
-        {
-          /*
-           * This section is not to be loaded, clear the base.
-           */
-          sect->base = 0;
-        }
-
         if (sect->base)
           base_offset += sect->size;
 
@@ -1070,10 +1044,6 @@ rtems_rtl_obj_sections_loader (uint32_t                   mask,
 
     node = rtems_chain_next (node);
   }
-
-  rtems_rtl_alloc_wr_disable (tag, base);
-
-  return true;
 }
 
 bool
@@ -1159,6 +1129,94 @@ rtems_rtl_obj_alloc_sections (rtems_rtl_obj*             obj,
   rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_DATA,  obj);
   rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_BSS,   obj);
 
+  /*
+   * Locate all text, data and bss sections in seperate operations so each type of
+   * section is grouped together.
+   */
+  rtems_rtl_obj_sections_locate (RTEMS_RTL_OBJ_SECT_TEXT,
+                                 rtems_rtl_alloc_text_tag (),
+                                 obj, obj->text_base);
+  rtems_rtl_obj_sections_locate (RTEMS_RTL_OBJ_SECT_CONST,
+                                 rtems_rtl_alloc_const_tag (),
+                                 obj, obj->const_base);
+  rtems_rtl_obj_sections_locate (RTEMS_RTL_OBJ_SECT_EH,
+                                 rtems_rtl_alloc_eh_tag (),
+                                 obj, obj->eh_base);
+  rtems_rtl_obj_sections_locate (RTEMS_RTL_OBJ_SECT_DATA,
+                                 rtems_rtl_alloc_data_tag (),
+                                 obj, obj->data_base);
+  rtems_rtl_obj_sections_locate (RTEMS_RTL_OBJ_SECT_BSS,
+                                 rtems_rtl_alloc_bss_tag (),
+                                 obj, obj->bss_base);
+
+  return true;
+}
+
+static bool
+rtems_rtl_obj_sections_loader (uint32_t                   mask,
+                               rtems_rtl_alloc_tag        tag,
+                               rtems_rtl_obj*             obj,
+                               int                        fd,
+                               uint8_t*                   base,
+                               rtems_rtl_obj_sect_handler handler,
+                               void*                      data)
+{
+  rtems_chain_control* sections = &obj->sections;
+  rtems_chain_node*    node = rtems_chain_first (sections);
+  int                  order = 0;
+
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
+    printf ("rtl: loading section: mask:%08" PRIx32 " base:%p\n", mask, base);
+
+  rtems_rtl_alloc_wr_enable (tag, base);
+
+  while (!rtems_chain_is_tail (sections, node))
+  {
+    rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node;
+
+    if ((sect->size != 0) && ((sect->flags & mask) == mask))
+    {
+      if (sect->load_order == order)
+      {
+        if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
+          printf ("rtl: loading:%2d: %s -> %p (s:%zi f:%04" PRIx32
+                  " a:%" PRIu32 " l:%02d)\n",
+                  order, sect->name, sect->base, sect->size,
+                  sect->flags, sect->alignment, sect->link);
+
+        if ((sect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == RTEMS_RTL_OBJ_SECT_LOAD)
+        {
+          if (!handler (obj, fd, sect, data))
+          {
+            sect->base = 0;
+            rtems_rtl_alloc_wr_disable (tag, base);
+            return false;
+          }
+        }
+        else if ((sect->flags & RTEMS_RTL_OBJ_SECT_ZERO) == RTEMS_RTL_OBJ_SECT_ZERO)
+        {
+          memset (sect->base, 0, sect->size);
+        }
+        else
+        {
+          /*
+           * This section is not to be loaded, clear the base.
+           */
+          sect->base = 0;
+        }
+
+        ++order;
+
+        node = rtems_chain_first (sections);
+        continue;
+      }
+    }
+
+    node = rtems_chain_next (node);
+  }
+
+  rtems_rtl_alloc_wr_disable (tag, base);
+
   return true;
 }
 
diff --git a/cpukit/libdl/rtl-shell.c b/cpukit/libdl/rtl-shell.c
index 56418303ff..4c80ae5db1 100644
--- a/cpukit/libdl/rtl-shell.c
+++ b/cpukit/libdl/rtl-shell.c
@@ -143,6 +143,7 @@ typedef struct
   bool                 memory_map;   /**< Print the memory map. */
   bool                 symbols;      /**< Print the global symbols. */
   bool                 dependencies; /**< Print any dependencies. */
+  bool                 trampolines;  /**< Print trampoline stats. */
   bool                 base;         /**< Include the base object file. */
   const char*          re_name;      /**< Name regx to filter on. */
   const char*          re_symbol;    /**< Symbol regx to filter on. */
@@ -515,6 +516,8 @@ rtems_rtl_obj_printer (rtems_rtl_obj_print* print, rtems_rtl_obj* obj)
     rtems_printf (print->printer, "%-*cunresolved    : %zu\n", indent, ' ', obj->unresolved);
     rtems_printf (print->printer, "%-*cusers         : %zu\n", indent, ' ', obj->users);
     rtems_printf (print->printer, "%-*creferences    : %zu\n", indent, ' ', obj->refs);
+    rtems_printf (print->printer, "%-*ctrampolines   : %zu\n", indent, ' ',
+                  rtems_rtl_obj_trampolines (obj));
     rtems_printf (print->printer, "%-*csymbols       : %zi\n", indent, ' ', obj->global_syms);
     rtems_printf (print->printer, "%-*csymbol memory : %zi\n", indent, ' ', obj->global_size);
   }
@@ -535,6 +538,33 @@ rtems_rtl_obj_printer (rtems_rtl_obj_print* print, rtems_rtl_obj* obj)
     if (!dd.first)
       rtems_printf (print->printer, "\n");
   }
+  if (print->trampolines)
+  {
+    if (obj->tramp_size == 0)
+    {
+      rtems_printf (print->printer, "%-*ctrampolines: not supported\n", indent, ' ');
+    }
+    else
+    {
+      size_t slots = rtems_rtl_obj_trampoline_slots (obj);
+      size_t used = rtems_rtl_obj_trampolines (obj);
+      rtems_printf (print->printer, "%-*ctrampolines:\n", indent, ' ');
+      rtems_printf (print->printer, "%-*cslots     : %zu\n", indent + 4, ' ',
+                    slots);
+      rtems_printf (print->printer, "%-*csize      : %zu\n", indent + 4, ' ',
+                    obj->tramps_size);
+      rtems_printf (print->printer, "%-*cslot size : %zu\n", indent + 4, ' ',
+                    obj->tramp_size);
+      rtems_printf (print->printer, "%-*cused      : %zu\n", indent + 4, ' ',
+                    used);
+      rtems_printf (print->printer, "%-*crelocs    : %zu\n", indent + 4, ' ',
+                    obj->tramp_relocs);
+      rtems_printf (print->printer, "%-*cunresolved: %zu\n", indent + 4, ' ',
+                    slots - obj->tramp_relocs);
+      rtems_printf (print->printer, "%-*cyield     : %zu%%\n", indent + 4, ' ',
+                    slots ? (used * 100) / slots : 0);
+    }
+  }
   return true;
 }
 
@@ -567,18 +597,31 @@ int
 rtems_rtl_shell_list (const rtems_printer* printer, int argc, char* argv[])
 {
   rtems_rtl_obj_print print = { 0 };
-  if (!rtems_rtl_check_opts (printer, "nlmsdb", argc, argv))
+  if (!rtems_rtl_check_opts (printer, "anlmsdbt", argc, argv))
     return 1;
   print.printer = printer;
   print.indent = 1;
   print.oname = true;
-  print.names = rtems_rtl_parse_opt ('n', argc, argv);
-  print.stats = rtems_rtl_parse_opt ('l', argc, argv);;
-  print.memory_map = rtems_rtl_parse_opt ('m', argc, argv);;
-  print.symbols = rtems_rtl_parse_opt ('s', argc, argv);
-  print.dependencies = rtems_rtl_parse_opt ('d', argc, argv);;
-  print.base = rtems_rtl_parse_opt ('b', argc, argv);;
-  print.re_name = rtems_rtl_parse_arg (' ', NULL, argc, argv);
+  if (rtems_rtl_parse_opt ('a', argc, argv))
+  {
+    print.names = true;
+    print.stats = true;
+    print.memory_map = true;
+    print.symbols = true;
+    print.dependencies = true;
+    print.trampolines = true;
+  }
+  else
+  {
+    print.names = rtems_rtl_parse_opt ('n', argc, argv);
+    print.stats = rtems_rtl_parse_opt ('l', argc, argv);;
+    print.memory_map = rtems_rtl_parse_opt ('m', argc, argv);;
+    print.symbols = rtems_rtl_parse_opt ('s', argc, argv);
+    print.dependencies = rtems_rtl_parse_opt ('d', argc, argv);;
+    print.trampolines = rtems_rtl_parse_opt ('t', argc, argv);;
+    print.base = rtems_rtl_parse_opt ('b', argc, argv);;
+    print.re_name = rtems_rtl_parse_arg (' ', NULL, argc, argv);
+  }
   print.re_symbol = NULL;
   print.rtl = rtems_rtl_lock ();
   if (print.rtl == NULL)
diff --git a/cpukit/libdl/rtl-trampoline.h b/cpukit/libdl/rtl-trampoline.h
new file mode 100644
index 0000000000..e04c20863b
--- /dev/null
+++ b/cpukit/libdl/rtl-trampoline.h
@@ -0,0 +1,94 @@
+/*
+ *  COPYRIGHT (c) 2019 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 Object File Trampoline Relocations Table.
+ *
+ * Cache relocation records that could result in a trampoline. The unresolved
+ * symbol table holds variable the symbol name (length string) and the object
+ * file's relocation records that reference the unresolved symbol. The
+ * trampoline cache is an extension to this table to reuse the code and memory
+ * and support trampolines.
+ *
+ * Some architectures require trampolines or veneers to extend the range of
+ * some instructions. The compiler generates small optimized instructions
+ * assuming most destinations are within the range of the instruction. The
+ * instructions are smaller in size and can have a number of encodings with
+ * different ranges. If a relocation record points to a symbol that is out of
+ * range for the instruction a trampoline is used to extend the instruction's
+ * range. A trampoline is a small fragment of architecture specific
+ * instructions located within the range of the relocation record instruction
+ * that can reach the entire address range. The trampoline's execution is
+ * transparent to the execution of the object file.
+ *
+ * An object file that needs a trampoline has a table allocated close to the
+ * text section. It has to be close to ensure the largest possible object file
+ * can be spported. The number of slots in a table depends on:
+ *
+ *  # Location of the code
+ *  # The type of relocation records in the object file
+ *  # The instruction encoding the relocation record points too
+ *  # The landing address of the instruction
+ *
+ * The allocation of the text segment and the trampoline table have to happen
+ * with the allocator lock being locked and held to make sure no other
+ * allocations happen inbetween the text section allocation and the trampoline
+ * table. Holding an allocator lock limits what the link editor can do when
+ * when the default heap allocator is being used. If calls any operating
+ * system services including the file system use the same allocator a deadlock
+ * will occur. This creates a conflict between performing the allocations
+ * together and reading the instructions while holding the allocator lock.
+ *
+ * The trampoline cache holds the parsed relocation records that could result
+ * in a trampoline. These records can be exaimined after the allocation of the
+ * text segment to determine how many relocation record target's are out of
+ * range. The minimum range for a specific type of relocation record has to be
+ * used as the instructions cannot be loaded.
+ */
+
+#if !defined (_RTEMS_RTL_TRAMPOLINE_H_)
+#define _RTEMS_RTL_TRAMPOLINE_H_
+
+#include <rtems/rtl/rtl-unresolved.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * Add a relocation to the list of trampolinr relocations.
+ *
+ * @param obj The object table the relocation record is for.
+ * @param flags Format specific flags.
+ * @param sect The target section number the relocation references.
+ * @param symvalue The symbol's value.
+ * @param rel The format specific relocation data.
+ * @retval true The relocation has been added.
+ * @retval false The relocation could not be added.
+ */
+bool rtems_rtl_trampoline_add (rtems_rtl_obj*        obj,
+                               const uint16_t        flags,
+                               const uint16_t        sect,
+                               const rtems_rtl_word  symvalue,
+                               const rtems_rtl_word* rel);
+
+/**
+ * Remove the relocation records for an object file.
+ *
+ * @param obj The object table the symbols are for.
+ */
+void rtems_rtl_trampoline_remove (rtems_rtl_obj* obj);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/cpukit/libdl/rtl-unresolved.c b/cpukit/libdl/rtl-unresolved.c
index dc21e9bcc1..fbfe909d2e 100644
--- a/cpukit/libdl/rtl-unresolved.c
+++ b/cpukit/libdl/rtl-unresolved.c
@@ -27,6 +27,7 @@
 #include "rtl-error.h"
 #include <rtems/rtl/rtl-unresolved.h>
 #include <rtems/rtl/rtl-trace.h>
+#include "rtl-trampoline.h"
 
 static rtems_rtl_unresolv_block*
 rtems_rtl_unresolved_block_alloc (rtems_rtl_unresolved* unresolved)
@@ -69,7 +70,7 @@ rtems_rtl_unresolved_symbol_recs (const char* name)
 
 static int
 rtems_rtl_unresolved_rec_index (rtems_rtl_unresolv_block* block,
-                                rtems_rtl_unresolv_rec* rec)
+                                rtems_rtl_unresolv_rec*   rec)
 {
   return rec - &block->rec[0];
 }
@@ -101,6 +102,7 @@ rtems_rtl_unresolved_rec_next (rtems_rtl_unresolv_rec* rec)
       break;
 
     case rtems_rtl_unresolved_reloc:
+    case rtems_rtl_trampoline_reloc:
       ++rec;
       break;
   }
@@ -403,6 +405,25 @@ rtems_rtl_unresolved_clean_block (rtems_rtl_unresolv_block* block,
   memset (&block->rec[block->recs], 0, bytes);
 }
 
+static rtems_chain_node*
+rtems_rtl_unresolved_delete_block_if_empty (rtems_chain_control*      blocks,
+                                            rtems_rtl_unresolv_block* block)
+{
+  rtems_chain_node* node = &block->link;
+  rtems_chain_node* next_node = rtems_chain_next (node);
+  /*
+   * Always leave a single block allocated. Eases possible heap fragmentation.
+   */
+  if (block->recs == 0 && !rtems_chain_has_only_one_node (blocks))
+  {
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
+      printf ("rtl: unresolv: block-del %p\n", block);
+    rtems_chain_extract (node);
+    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_EXTERNAL, block);
+  }
+  return next_node;
+}
+
 static void
 rtems_rtl_unresolved_compact (void)
 {
@@ -456,19 +477,8 @@ rtems_rtl_unresolved_compact (void)
           rec = rtems_rtl_unresolved_rec_next (rec);
       }
 
-      if (block->recs == 0)
-      {
-        rtems_chain_node* next_node = rtems_chain_next (node);
-        if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
-          printf ("rtl: unresolv: block-del %p\n", block);
-        rtems_chain_extract (node);
-        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_EXTERNAL, block);
-        node = next_node;
-      }
-      else
-      {
-        node = rtems_chain_next (node);
-      }
+      node = rtems_rtl_unresolved_delete_block_if_empty (&unresolved->blocks,
+                                                         block);
     }
   }
 }
@@ -480,7 +490,7 @@ rtems_rtl_unresolved_table_open (rtems_rtl_unresolved* unresolved,
   unresolved->marker = 0xdeadf00d;
   unresolved->block_recs = block_recs;
   rtems_chain_initialize_empty (&unresolved->blocks);
-  return true;
+  return rtems_rtl_unresolved_block_alloc (unresolved);
 }
 
 void
@@ -632,13 +642,13 @@ rtems_rtl_unresolved_resolve (void)
 
   /*
    * 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
+   * iterate over the unresolved symbols searching 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.
+   * archives for symbols we have not searched before and if a symbol is found
+   * in an archve load 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 or there is an error.
    */
   while (resolving)
   {
@@ -665,18 +675,87 @@ rtems_rtl_unresolved_resolve (void)
 }
 
 bool
-rtems_rtl_unresolved_remove (rtems_rtl_obj*        obj,
-                             const char*           name,
-                             const uint16_t        sect,
-                             const rtems_rtl_word* rel)
+rtems_rtl_trampoline_add (rtems_rtl_obj*        obj,
+                          const uint16_t        flags,
+                          const uint16_t        sect,
+                          const rtems_rtl_word  symvalue,
+                          const rtems_rtl_word* rel)
 {
-  rtems_rtl_unresolved* unresolved;
+  rtems_rtl_unresolved*     unresolved;
+  rtems_rtl_unresolv_block* block;
+  rtems_rtl_unresolv_rec*   rec;
+
+  if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
+    printf ("rtl: tramp: add: %s sect:%d flags:%04x\n",
+            rtems_rtl_obj_oname (obj), sect, flags);
+
   unresolved = rtems_rtl_unresolved_unprotected ();
-  if (unresolved == NULL)
+  if (!unresolved)
     return false;
+
+  block = rtems_rtl_unresolved_alloc_recs (unresolved, 1);
+  if (block == NULL)
+  {
+    block = rtems_rtl_unresolved_block_alloc (unresolved);
+    if (!block)
+      return false;
+  }
+
+  rec = rtems_rtl_unresolved_rec_first_free (block);
+  rec->type = rtems_rtl_trampoline_reloc;
+  rec->rec.tramp.obj = obj;
+  rec->rec.tramp.flags = flags;
+  rec->rec.tramp.sect = sect;
+  rec->rec.tramp.symvalue = symvalue;
+  rec->rec.tramp.rel[0] = rel[0];
+  rec->rec.tramp.rel[1] = rel[1];
+  rec->rec.tramp.rel[2] = rel[2];
+
+  ++block->recs;
+
   return true;
 }
 
+void
+rtems_rtl_trampoline_remove (rtems_rtl_obj* obj)
+{
+  rtems_rtl_unresolved* unresolved = rtems_rtl_unresolved_unprotected ();
+  if (unresolved)
+  {
+    /*
+     * Iterate over the blocks clearing any trampoline records.
+     */
+    rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
+    while (!rtems_chain_is_tail (&unresolved->blocks, node))
+    {
+      rtems_rtl_unresolv_block* block = (rtems_rtl_unresolv_block*) node;
+      rtems_rtl_unresolv_rec*   rec = rtems_rtl_unresolved_rec_first (block);
+
+      /*
+       * Search the table for a trampoline record and if found clean the
+       * record moving the remaining records down the block.
+       */
+      while (!rtems_rtl_unresolved_rec_is_last (block, rec))
+      {
+        bool next_rec = true;
+
+        if (rec->type == rtems_rtl_trampoline_reloc && rec->rec.tramp.obj == obj)
+        {
+            rtems_rtl_unresolved_clean_block (block, rec, 1,
+                                              unresolved->block_recs);
+            next_rec = false;
+        }
+
+        if (next_rec)
+          rec = rtems_rtl_unresolved_rec_next (rec);
+      }
+
+      node = rtems_rtl_unresolved_delete_block_if_empty (&unresolved->blocks,
+                                                         block);
+    }
+  }
+}
+
 /**
  * Struct to pass relocation data in the iterator.
  */
@@ -708,8 +787,10 @@ rtems_rtl_unresolved_dump_iterator (rtems_rtl_unresolv_rec* rec,
             rec->rec.name.length);
     break;
   case rtems_rtl_unresolved_reloc:
+  case rtems_rtl_trampoline_reloc:
     if (dd->show_relocs)
-      printf (" %3zu: 2: reloc: obj:%s name:%2d: sect:%d\n",
+      printf (" %3zu: 2:reloc%c: obj:%s name:%2d: sect:%d\n",
+              rec->type == rtems_rtl_unresolved_reloc ? 'R' : 'T',
               dd->rec,
               rec->rec.reloc.obj == NULL ? "resolved" : rec->rec.reloc.obj->oname,
               rec->rec.reloc.name,
diff --git a/cpukit/libdl/rtl.c b/cpukit/libdl/rtl.c
index e3dba5a206..d4103bace6 100644
--- a/cpukit/libdl/rtl.c
+++ b/cpukit/libdl/rtl.c
@@ -477,21 +477,24 @@ rtems_rtl_find_obj (const char* name)
 rtems_rtl_obj*
 rtems_rtl_find_obj_with_symbol (const rtems_rtl_obj_sym* sym)
 {
-  rtems_chain_node* node = rtems_chain_first (&rtl->objects);
-  while (!rtems_chain_is_tail (&rtl->objects, node))
+  if (sym != NULL)
   {
-    rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
-    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);
+    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 (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);
+    }
   }
   return NULL;
 }
diff --git a/testsuites/libtests/dl08/init.c b/testsuites/libtests/dl08/init.c
index 87f7f9b142..d1f01a56bd 100644
--- a/testsuites/libtests/dl08/init.c
+++ b/testsuites/libtests/dl08/init.c
@@ -56,7 +56,7 @@ static void Init(rtems_task_argument arg)
     exit (1);
   }
 
-  for (i = 0; i < 100; ++i)
+  for (i = 0; i < 4; ++i)
   {
     printf ("--------------------------------------------------\n");
     printf (" Run: %d\n", i);
diff --git a/testsuites/libtests/dl09/dl-o1.c b/testsuites/libtests/dl09/dl-o1.c
index 438c05eee9..9404a45732 100644
--- a/testsuites/libtests/dl09/dl-o1.c
+++ b/testsuites/libtests/dl09/dl-o1.c
@@ -55,6 +55,7 @@ int rtems_main_o1 (void)
   printf (DL_NAME ":       dl01_const1: %4zu: %p: %d\n",   PAINT_VAR (dl01_const1));
   printf (DL_NAME ":       dl01_const2: %4zu: %p: %f\n",   PAINT_VAR (dl01_const2));
   printf (DL_NAME ":        dl01_func1: %4zu: %p\n",       sizeof(dl01_func1), &dl01_func1);
+  printf (DL_NAME ":     rtems_main_o2:       %p\n",       &rtems_main_o2);
 
   rtems_main_o2 ();
 
diff --git a/testsuites/libtests/dl09/dl09.doc b/testsuites/libtests/dl09/dl09.doc
index 4c5d97ef2a..f9df9a276d 100644
--- a/testsuites/libtests/dl09/dl09.doc
+++ b/testsuites/libtests/dl09/dl09.doc
@@ -18,6 +18,6 @@ directives:
 
 concepts:
 
-+ Load modules with a space between then so short address range relative
++ Load modules with a space between them so short address range relative
   instructions require trampolines.
 + Repeat 100 times.
diff --git a/testsuites/libtests/dl09/init.c b/testsuites/libtests/dl09/init.c
index dbcc7ba84c..5343a1dcdf 100644
--- a/testsuites/libtests/dl09/init.c
+++ b/testsuites/libtests/dl09/init.c
@@ -56,7 +56,7 @@ static void Init(rtems_task_argument arg)
     exit (1);
   }
 
-  for (i = 0; i < 100; ++i)
+  for (i = 0; i < 4; ++i)
   {
     printf ("--------------------------------------------------\n");
     printf (" Run: %d\n", i);
-- 
2.19.1




More information about the devel mailing list