The ARM C++ exception ABI uses an address ordered index table to
locate the correct frame data and this requires the EXIDX sections are
loaded in the order the order the matching text is loaded.

The EXIDX sections set the SHF_LINK_ORDER flag and link field. This patch
adds support to load those flagged sections in the linked-to section
order.

Updates #2955.
Closes #2959
---
 cpukit/libdl/include/sys/exec_elf.h |  10 ++-
 cpukit/libdl/rtl-elf.c              |  14 +++-
 cpukit/libdl/rtl-obj.c              | 156 +++++++++++++++++++++++++++++-------
 cpukit/libdl/rtl-obj.h              |  16 +++-
 4 files changed, 163 insertions(+), 33 deletions(-)

diff --git a/cpukit/libdl/include/sys/exec_elf.h 
b/cpukit/libdl/include/sys/exec_elf.h
index 08da7e809e..4242415f54 100644
--- a/cpukit/libdl/include/sys/exec_elf.h
+++ b/cpukit/libdl/include/sys/exec_elf.h
@@ -459,6 +459,10 @@ typedef struct {
 #define        SHF_WRITE       0x1             /* Section contains writable 
data */
 #define        SHF_ALLOC       0x2             /* Section occupies memory */
 #define        SHF_EXECINSTR   0x4             /* Section contains executable 
insns */
+#define        SHF_MERGE       0x10            /* Section contains data that 
can be merged */
+#define        SHF_STRINGS     0x20            /* Section contains 
null-terminated strings */
+#define        SHF_INFO_LINK   0x40            /* Section header's sh_info 
holds table index */
+#define        SHF_LINK_ORDER  0x80            /* Section has special ordering 
requirements */
 
 #define        SHF_MASKOS      0x0f000000      /* Operating system specific 
values */
 #define        SHF_MASKPROC    0xf0000000      /* Processor-specific values */
@@ -949,13 +953,13 @@ typedef struct {
 #define        SYMINFO_NUM             2
 
 /*
- * These constants are used for Elf32_Verdef struct's version number.  
+ * These constants are used for Elf32_Verdef struct's version number.
  */
 #define VER_DEF_NONE           0
 #define        VER_DEF_CURRENT         1
 
 /*
- * These constants are used for Elf32_Verdef struct's vd_flags.  
+ * These constants are used for Elf32_Verdef struct's vd_flags.
  */
 #define VER_FLG_BASE           0x1
 #define        VER_FLG_WEAK            0x2
@@ -967,7 +971,7 @@ typedef struct {
 #define        VER_NDX_GLOBAL          1
 
 /*
- * These constants are used for Elf32_Verneed struct's version number.  
+ * These constants are used for Elf32_Verneed struct's version number.
  */
 #define        VER_NEED_NONE           0
 #define        VER_NEED_CURRENT        1
diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c
index 37775ff776..be2f06a7ba 100644
--- a/cpukit/libdl/rtl-elf.c
+++ b/cpukit/libdl/rtl-elf.c
@@ -656,6 +656,11 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int 
fd, Elf_Ehdr* ehdr)
 
     flags = 0;
 
+    if (rtems_rtl_trace (RTEMS_RTL_TRACE_DETAIL))
+      printf ("rtl: section: %2d: type=%d flags=%08x link=%d info=%d\n",
+              section, (int) shdr.sh_type, (unsigned int) shdr.sh_flags,
+              (int) shdr.sh_link, (int) shdr.sh_info);
+
     switch (shdr.sh_type)
     {
       case SHT_NULL:
@@ -712,7 +717,7 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, 
Elf_Ehdr* ehdr)
 
       default:
         /*
-         * See there are architecture specific flags?
+         * See if there are architecture specific flags?
          */
         flags = rtems_rtl_elf_section_flags (obj, &shdr);
         if (flags == 0)
@@ -729,6 +734,13 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int 
fd, Elf_Ehdr* ehdr)
       char*  name;
       size_t len;
 
+      /*
+       * If link ordering this section must appear in the same order in memory
+       * as the linked-to section relative to the sections it loads with.
+       */
+      if ((shdr.sh_flags & SHF_LINK_ORDER) != 0)
+        flags |= RTEMS_RTL_OBJ_SECT_LINK;
+
       len = RTEMS_RTL_ELF_STRING_MAX;
       if (!rtems_rtl_obj_cache_read (strings, fd,
                                      sectstroff + shdr.sh_name,
diff --git a/cpukit/libdl/rtl-obj.c b/cpukit/libdl/rtl-obj.c
index b27f28b9a9..4d5e1d6836 100644
--- a/cpukit/libdl/rtl-obj.c
+++ b/cpukit/libdl/rtl-obj.c
@@ -601,12 +601,12 @@ typedef struct
 static bool
 rtems_rtl_obj_sect_sync_handler (rtems_chain_node* node, void* data)
 {
-  rtems_rtl_obj_sect_t*   sect = (rtems_rtl_obj_sect_t*) node;
+  rtems_rtl_obj_sect_t*          sect = (rtems_rtl_obj_sect_t*) node;
   rtems_rtl_obj_sect_sync_ctx_t* sync_ctx = data;
-  uintptr_t old_end;
-  uintptr_t new_start;
+  uintptr_t                      old_end;
+  uintptr_t                      new_start;
 
-  if ( !(sect->flags & sync_ctx->mask) || !sect->size)
+  if ((sect->flags & sync_ctx->mask) == 0 || sect->size == 0)
     return true;
 
   if (sync_ctx->end_va == sync_ctx->start_va)
@@ -632,7 +632,7 @@ rtems_rtl_obj_sect_sync_handler (rtems_chain_node* node, 
void* data)
 }
 
 void
-rtems_rtl_obj_synchronize_cache (rtems_rtl_obj_t*    obj)
+rtems_rtl_obj_synchronize_cache (rtems_rtl_obj_t* obj)
 {
   rtems_rtl_obj_sect_sync_ctx_t sync_ctx;
 
@@ -643,7 +643,7 @@ rtems_rtl_obj_synchronize_cache (rtems_rtl_obj_t*    obj)
 
   sync_ctx.mask = RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_CONST |
                   RTEMS_RTL_OBJ_SECT_DATA | RTEMS_RTL_OBJ_SECT_BSS |
-                  RTEMS_RTL_OBJ_SECT_EXEC;
+                  RTEMS_RTL_OBJ_SECT_EH   | RTEMS_RTL_OBJ_SECT_EXEC;
 
   sync_ctx.start_va = 0;
   sync_ctx.end_va = sync_ctx.start_va;
@@ -667,6 +667,87 @@ rtems_rtl_obj_load_symbols (rtems_rtl_obj_t*             
obj,
   return rtems_rtl_obj_section_handler (mask, obj, fd, handler, data);
 }
 
+static int
+rtems_rtl_obj_sections_linked_to_order(rtems_rtl_obj_t* obj,
+                                       int              section,
+                                       uint32_t         visited_mask)
+{
+  rtems_chain_control* sections = &obj->sections;
+  rtems_chain_node*    node = rtems_chain_first (sections);
+  /*
+   * Find the section being linked-to. If the linked-to link field is 0 we have
+   * the end and the section's order is the position we are after.
+   */
+  while (!rtems_chain_is_tail (sections, node))
+  {
+    rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
+    if (sect->section == section)
+    {
+      const uint32_t mask = sect->flags & RTEMS_RTL_OBJ_SECT_TYPES;
+      int            order = 0;
+      if (sect->link != 0)
+      {
+        /*
+         * Have we already visited this type of section? Avoid nesting for
+         * ever.
+         */
+        if ((sect->flags & visited_mask) != 0)
+        {
+          rtems_rtl_set_error (errno, "section link loop");
+          return -1;
+        }
+        return rtems_rtl_obj_sections_linked_to_order (obj,
+                                                       sect->link,
+                                                       visited_mask | mask);
+      }
+      node = rtems_chain_first (sections);
+      while (!rtems_chain_is_tail (sections, node))
+      {
+        sect = (rtems_rtl_obj_sect_t*) node;
+        if ((sect->flags & mask) == mask)
+        {
+          if (sect->section == section)
+            return order;
+          ++order;
+        }
+        node = rtems_chain_next (node);
+      }
+    }
+    node = rtems_chain_next (node);
+  }
+  rtems_rtl_set_error (errno, "section link not found");
+  return -1;
+}
+
+static void
+rtems_rtl_obj_sections_link_order(uint32_t mask, rtems_rtl_obj_t* obj)
+{
+  rtems_chain_control* sections = &obj->sections;
+  rtems_chain_node*    node = rtems_chain_first (sections);
+  int                  order = 0;
+  while (!rtems_chain_is_tail (sections, node))
+  {
+    rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
+    if ((sect->flags & mask) == mask)
+    {
+      /*
+       * If the section is linked in order find the linked-to section's order
+       * and move the section in the section list to
+       */
+      if (sect->link == 0)
+        sect->load_order = order++;
+      else
+      {
+        sect->load_order =
+          rtems_rtl_obj_sections_linked_to_order (obj,
+                                                  sect->link,
+                                                  mask);
+      }
+    }
+    node = rtems_chain_next (node);
+  }
+}
+
 static size_t
 rtems_rtl_obj_sections_loader (uint32_t                     mask,
                                rtems_rtl_obj_t*             obj,
@@ -679,6 +760,8 @@ rtems_rtl_obj_sections_loader (uint32_t                     
mask,
   rtems_chain_node*    node = rtems_chain_first (sections);
   size_t               base_offset = 0;
   bool                 first = true;
+  int                  order = 0;
+
   while (!rtems_chain_is_tail (sections, node))
   {
     rtems_rtl_obj_sect_t* sect = (rtems_rtl_obj_sect_t*) node;
@@ -686,35 +769,46 @@ rtems_rtl_obj_sections_loader (uint32_t                   
  mask,
     if ((sect->size != 0) && ((sect->flags & mask) != 0))
     {
       if (!first)
+      {
         base_offset = rtems_rtl_sect_align (base_offset, sect->alignment);
+        first = false;
+      }
 
-      sect->base = base + base_offset;
+      if (sect->load_order == order)
+      {
+        sect->base = base + base_offset;
 
-      if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
-        printf ("rtl: loading: %s -> %8p (l:%zi m:%04lx)\n",
-                sect->name, sect->base, sect->size, sect->flags);
+        if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
+          printf ("rtl: loading:%2d: %s -> %8p (s:%zi f:%04lx l:%02d)\n",
+                  order, sect->name, sect->base, sect->size,
+                  sect->flags, sect->link);
 
-      if ((sect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == RTEMS_RTL_OBJ_SECT_LOAD)
-      {
-        if (!handler (obj, fd, sect, data))
+        if ((sect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == RTEMS_RTL_OBJ_SECT_LOAD)
+        {
+          if (!handler (obj, fd, sect, data))
+          {
+            sect->base = 0;
+            return false;
+          }
+        }
+        else if ((sect->flags & RTEMS_RTL_OBJ_SECT_ZERO) == 
RTEMS_RTL_OBJ_SECT_ZERO)
+        {
+          memset (base + base_offset, 0, sect->size);
+        }
+        else
         {
           sect->base = 0;
+          rtems_rtl_set_error (errno, "section has no load/clear op");
           return false;
         }
-      }
-      else if ((sect->flags & RTEMS_RTL_OBJ_SECT_ZERO) == 
RTEMS_RTL_OBJ_SECT_ZERO)
-      {
-        memset (base + base_offset, 0, sect->size);
-      }
-      else
-      {
-        sect->base = 0;
-        rtems_rtl_set_error (errno, "section has no load op");
-        return false;
-      }
 
-      base_offset += sect->size;
-      first = false;
+        base_offset += sect->size;
+
+        ++order;
+
+        node = rtems_chain_first (sections);
+        continue;
+      }
     }
 
     node = rtems_chain_next (node);
@@ -763,7 +857,7 @@ rtems_rtl_obj_load_sections (rtems_rtl_obj_t*             
obj,
     return false;
   }
 
-  obj->exec_size = text_size + const_size + data_size + bss_size;
+  obj->exec_size = text_size + const_size + eh_size + data_size + bss_size;
 
   if (rtems_rtl_trace (RTEMS_RTL_TRACE_LOAD_SECT))
   {
@@ -780,6 +874,14 @@ rtems_rtl_obj_load_sections (rtems_rtl_obj_t*             
obj,
   }
 
   /*
+   * Determine the load order.
+   */
+  rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_TEXT,  obj);
+  rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_CONST, obj);
+  rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_EH,    obj);
+  rtems_rtl_obj_sections_link_order (RTEMS_RTL_OBJ_SECT_DATA,  obj);
+
+  /*
    * Load all text then data then bss sections in seperate operations so each
    * type of section is grouped together.
    */
diff --git a/cpukit/libdl/rtl-obj.h b/cpukit/libdl/rtl-obj.h
index 9ec184be1a..6a35a72822 100644
--- a/cpukit/libdl/rtl-obj.h
+++ b/cpukit/libdl/rtl-obj.h
@@ -102,8 +102,19 @@ typedef struct rtems_rtl_loader_table_s
 #define RTEMS_RTL_OBJ_SECT_WRITE (1 << 11) /**< Section is writable, ie data. 
*/
 #define RTEMS_RTL_OBJ_SECT_EXEC  (1 << 12) /**< Section is executable. */
 #define RTEMS_RTL_OBJ_SECT_ZERO  (1 << 13) /**< Section is preset to zero. */
-#define RTEMS_RTL_OBJ_SECT_CTOR  (1 << 14) /**< Section contains constructors. 
*/
-#define RTEMS_RTL_OBJ_SECT_DTOR  (1 << 15) /**< Section contains destructors. 
*/
+#define RTEMS_RTL_OBJ_SECT_LINK  (1 << 14) /**< Section is link-ordered. */
+#define RTEMS_RTL_OBJ_SECT_CTOR  (1 << 15) /**< Section contains constructors. 
*/
+#define RTEMS_RTL_OBJ_SECT_DTOR  (1 << 16) /**< Section contains destructors. 
*/
+#define RTEMS_RTL_OBJ_SECT_LOCD  (1 << 17) /**< Section has been located. */
+
+/**
+ * Section types mask.
+ */
+#define RTEMS_RTL_OBJ_SECT_TYPES (RTEMS_RTL_OBJ_SECT_TEXT | \
+                                  RTEMS_RTL_OBJ_SECT_CONST | \
+                                  RTEMS_RTL_OBJ_SECT_DATA | \
+                                  RTEMS_RTL_OBJ_SECT_BSS | \
+                                  RTEMS_RTL_OBJ_SECT_EH)
 
 /**
  * An object file is made up of sections and the can be more than
@@ -124,6 +135,7 @@ struct rtems_rtl_obj_sect_s
   uint32_t         flags;       /**< The section's flags. */
   void*            base;        /**< The base address of the section in
                                  *   memory. */
+  int              load_order;  /**< Order we load sections. */
 };
 
 /**
-- 
2.11.0

_______________________________________________
devel mailing list
devel@rtems.org
http://lists.rtems.org/mailman/listinfo/devel

Reply via email to