[PATCH 1/3] libdl: Manage the allocation of common uninitialised variables.

chrisj at rtems.org chrisj at rtems.org
Wed Nov 21 06:11:04 UTC 2018


From: Chris Johns <chrisj at rtems.org>

The use of separate text and data results in uninitialised variables
being placed in the common section. There is no section in ELF for
the common variables so the loader needs to create the section and
allocate the variables in that section. This patch does that.

The patch adds a second pass over the symbols.

The issue can also be seen as a section 65522 error.

Updates #3604
---
 cpukit/include/rtems/rtl/rtl-obj.h |  33 ++++++++
 cpukit/libdl/rtl-elf.c             | 150 ++++++++++++++++++++++++++++++++++---
 cpukit/libdl/rtl-obj.c             |  63 +++++++++++-----
 3 files changed, 220 insertions(+), 26 deletions(-)

diff --git a/cpukit/include/rtems/rtl/rtl-obj.h b/cpukit/include/rtems/rtl/rtl-obj.h
index ff7b2a197d..be77a81c9d 100644
--- a/cpukit/include/rtems/rtl/rtl-obj.h
+++ b/cpukit/include/rtems/rtl/rtl-obj.h
@@ -293,6 +293,23 @@ static inline bool rtems_rtl_obj_text_inside (const rtems_rtl_obj* obj,
     (address < (obj->text_base + obj->text_size));
 }
 
+/**
+ * Align the size to the next alignment point. Assume the alignment is a
+ * positive integral power of 2 if not 0 or 1. If 0 or 1 then there is no
+ * alignment.
+ *
+ * @param offset Offset to align up from.
+ * @param alignment The alignment.
+ * @return size_t Aligned offset.
+ */
+static inline size_t rtems_rtl_obj_align (size_t   offset,
+                                          uint32_t alignment)
+{
+  if ((alignment > 1) && ((offset & (alignment - 1)) != 0))
+    offset = (offset + alignment) & ~(alignment - 1);
+  return offset;
+}
+
 /**
  * Allocate an object structure on the heap.
  *
@@ -409,6 +426,22 @@ rtems_rtl_obj_sect* rtems_rtl_obj_find_section (const rtems_rtl_obj* obj,
 rtems_rtl_obj_sect* rtems_rtl_obj_find_section_by_index (const rtems_rtl_obj* obj,
                                                          int                  index);
 
+/**
+ * Find a section given a section's mask. The index is the section after which
+ * the mask is matched. An index of -1 starts the search from the beginning of
+ * the section list. You can find multiple matches for a mask by passing the
+ * index of the last section that matched the mask on a subsequent call.
+ *
+ * @param obj The object file's descriptor.
+ * @param index The section's index to start searching from, -1 for the start.
+ * @param mask The section's mask to match against the section's flags.
+ * @retval NULL The section was not found.
+ * @return rtems_rtl_obj_sect_t* The found section.
+ */
+rtems_rtl_obj_sect* rtems_rtl_obj_find_section_by_mask (const rtems_rtl_obj* obj,
+                                                        int                  index,
+                                                        uint32_t             mask);
+
 /**
  * The text section size. Only use once all the sections has been added. It
  * includes alignments between sections that are part of the object's text
diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c
index 53f43aaeac..c1821bcfda 100644
--- a/cpukit/libdl/rtl-elf.c
+++ b/cpukit/libdl/rtl-elf.c
@@ -72,7 +72,8 @@ rtems_rtl_elf_find_symbol (rtems_rtl_obj* obj,
 {
   rtems_rtl_obj_sect* sect;
 
-  if (ELF_ST_TYPE(sym->st_info) == STT_NOTYPE)
+  if (ELF_ST_TYPE(sym->st_info) == STT_NOTYPE ||
+      sym->st_shndx == SHN_COMMON)
   {
     /*
      * Search the object file then the global table for the symbol.
@@ -185,9 +186,10 @@ rtems_rtl_elf_relocator (rtems_rtl_obj*      obj,
       return false;
 
     /*
-     * Only need the name of the symbol if global.
+     * 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_NOTYPE ||
+        sym.st_shndx == SHN_COMMON)
     {
       size_t len;
       off = obj->ooffset + strtab->offset + sym.st_name;
@@ -337,6 +339,68 @@ rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc* reloc,
   return true;
 }
 
+/**
+ * Common symbol iterator data.
+ */
+typedef struct
+{
+  size_t   size;      /**< The size of the common section */
+  uint32_t alignment; /**< The alignment of the common section. */
+} rtems_rtl_elf_common_data;
+
+static bool
+rtems_rtl_elf_common (rtems_rtl_obj*      obj,
+                      int                 fd,
+                      rtems_rtl_obj_sect* sect,
+                      void*               data)
+{
+  rtems_rtl_elf_common_data* common = (rtems_rtl_elf_common_data*) data;
+  rtems_rtl_obj_cache*       symbols;
+  int                        sym;
+
+  rtems_rtl_obj_caches (&symbols, NULL, NULL);
+
+  if (!symbols)
+    return false;
+
+  /*
+   * Find the number size of the common section by finding all symbols that
+   * reference the SHN_COMMON section.
+   */
+  for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym)
+  {
+    Elf_Sym symbol;
+    off_t   off;
+
+    off = obj->ooffset + sect->offset + (sym * sizeof (symbol));
+
+    if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off,
+                                         &symbol, sizeof (symbol)))
+      return false;
+
+    if ((symbol.st_shndx == SHN_COMMON) &&
+        ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
+         (ELF_ST_TYPE (symbol.st_info) == STT_COMMON)))
+    {
+      if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
+        printf ("rtl: com:elf:%-2d bind:%-2d type:%-2d size:%d value:%d\n",
+                sym, (int) ELF_ST_BIND (symbol.st_info),
+                (int) ELF_ST_TYPE (symbol.st_info),
+                (int) symbol.st_size, (int) symbol.st_value);
+      /*
+       * If the size is zero this is the first entry, it defines the common
+       * section's aligment. The symbol's value is the alignment.
+       */
+      if (common->size == 0)
+        common->alignment = symbol.st_value;
+      common->size +=
+        rtems_rtl_obj_align (common->size, symbol.st_value) + symbol.st_size;
+    }
+  }
+
+  return true;
+}
+
 static bool
 rtems_rtl_elf_symbols (rtems_rtl_obj*      obj,
                        int                 fd,
@@ -354,6 +418,7 @@ rtems_rtl_elf_symbols (rtems_rtl_obj*      obj,
   int                  global_string_space;
   rtems_rtl_obj_sym*   gsym;
   char*                gstring;
+  size_t               common_offset;
   int                  sym;
 
   strtab = rtems_rtl_obj_find_section (obj, ".strtab");
@@ -403,15 +468,28 @@ rtems_rtl_elf_symbols (rtems_rtl_obj*      obj,
      * object file has been loaded. Undefined symbols are NOTYPE so for locals
      * 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",
+              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);
+
     if ((symbol.st_shndx != 0) &&
         ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
+         (ELF_ST_TYPE (symbol.st_info) == STT_COMMON) ||
          (ELF_ST_TYPE (symbol.st_info) == STT_FUNC) ||
          (ELF_ST_TYPE (symbol.st_info) == STT_NOTYPE)))
     {
+      /*
+       * There needs to be a valid section for the symbol.
+       */
       rtems_rtl_obj_sect* symsect;
 
       symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx);
-      if (symsect)
+      if (symsect != NULL)
       {
         if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
             (ELF_ST_BIND (symbol.st_info) == STB_WEAK))
@@ -431,12 +509,18 @@ 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",
+                      sym, (int) symbol.st_name, name);
             ++globals;
             global_string_space += strlen (name) + 1;
           }
         }
         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",
+                    sym, (int) symbol.st_name, name);
           ++locals;
           local_string_space += strlen (name) + 1;
         }
@@ -487,6 +571,8 @@ rtems_rtl_elf_symbols (rtems_rtl_obj*      obj,
   gstring =
     (((char*) obj->global_table) + (globals * sizeof (rtems_rtl_obj_sym)));
 
+  common_offset = 0;
+
   for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym)
   {
     Elf_Sym     symbol;
@@ -524,6 +610,7 @@ rtems_rtl_elf_symbols (rtems_rtl_obj*      obj,
 
     if ((symbol.st_shndx != 0) &&
         ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
+         (ELF_ST_TYPE (symbol.st_info) == STT_COMMON) ||
          (ELF_ST_TYPE (symbol.st_info) == STT_FUNC) ||
          (ELF_ST_TYPE (symbol.st_info) == STT_NOTYPE)) &&
          ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
@@ -533,6 +620,7 @@ rtems_rtl_elf_symbols (rtems_rtl_obj*      obj,
         rtems_rtl_obj_sect* symsect;
         rtems_rtl_obj_sym*  osym;
         char*               string;
+        Elf_Word            value;
 
         symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx);
         if (symsect)
@@ -553,10 +641,25 @@ rtems_rtl_elf_symbols (rtems_rtl_obj*      obj,
             ++lsym;
           }
 
+          /*
+           * 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;
+          }
+
           rtems_chain_set_off_chain (&osym->node);
           memcpy (string, name, strlen (name) + 1);
           osym->name = string;
-          osym->value = symbol.st_value + (uint8_t*) symsect->base;
+          osym->value = value + (uint8_t*) symsect->base;
           osym->data = symbol.st_info;
 
           if (rtems_rtl_trace (RTEMS_RTL_TRACE_SYMBOL))
@@ -656,13 +759,13 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr)
     if (!rtems_rtl_obj_cache_read_byval (sects, fd, off, &shdr, sizeof (shdr)))
       return false;
 
-    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);
 
+    flags = 0;
+
     switch (shdr.sh_type)
     {
       case SHT_NULL:
@@ -771,6 +874,19 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr)
   return true;
 }
 
+static bool
+rtems_rtl_elf_add_common (rtems_rtl_obj* obj, size_t size, uint32_t alignment)
+{
+  if (size > 0)
+  {
+    if (!rtems_rtl_obj_add_section (obj, SHN_COMMON, ".common.rtems.rtl",
+                                    size, 0, alignment, 0, 0,
+                                    RTEMS_RTL_OBJ_SECT_BSS | RTEMS_RTL_OBJ_SECT_ZERO))
+      return false;
+  }
+  return true;
+}
+
 bool
 rtems_rtl_elf_file_check (rtems_rtl_obj* obj, int fd)
 {
@@ -906,8 +1022,9 @@ rtems_rtl_elf_load_linkmap (rtems_rtl_obj* obj)
 bool
 rtems_rtl_elf_file_load (rtems_rtl_obj* obj, int fd)
 {
-  rtems_rtl_obj_cache* header;
-  Elf_Ehdr             ehdr;
+  rtems_rtl_obj_cache*      header;
+  Elf_Ehdr                  ehdr;
+  rtems_rtl_elf_common_data common = { .size = 0, .alignment = 0 };
 
   rtems_rtl_obj_caches (&header, NULL, NULL);
 
@@ -965,8 +1082,23 @@ rtems_rtl_elf_file_load (rtems_rtl_obj* obj, int fd)
   if (!rtems_rtl_elf_parse_sections (obj, fd, &ehdr))
     return false;
 
+  /*
+   * See if there are any common variables and if there are add a common
+   * section.
+   */
+  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;
+
+  /*
+   * Set the entry point if there is one.
+   */
   obj->entry = (void*)(uintptr_t) ehdr.e_entry;
 
+  /*
+   * 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;
 
diff --git a/cpukit/libdl/rtl-obj.c b/cpukit/libdl/rtl-obj.c
index 45deccfb44..7109b86fe8 100644
--- a/cpukit/libdl/rtl-obj.c
+++ b/cpukit/libdl/rtl-obj.c
@@ -245,19 +245,6 @@ rtems_rtl_scan_decimal (const uint8_t* string, size_t len)
   return value;
 }
 
-/**
- * Align the size to the next alignment point. Assume the alignment is a
- * positive integral power of 2 if not 0 or 1. If 0 or 1 then there is no
- * alignment.
- */
-static size_t
-rtems_rtl_sect_align (size_t offset, uint32_t alignment)
-{
-  if ((alignment > 1) && ((offset & (alignment - 1)) != 0))
-    offset = (offset + alignment) & ~(alignment - 1);
-  return offset;
-}
-
 /**
  * Section size summer iterator data.
  */
@@ -274,7 +261,7 @@ rtems_rtl_obj_sect_summer (rtems_chain_node* node, void* data)
   rtems_rtl_obj_sect_summer_data* summer = data;
   if ((sect->flags & summer->mask) == summer->mask)
     summer->size =
-      rtems_rtl_sect_align (summer->size, sect->alignment) + sect->size;
+      rtems_rtl_obj_align (summer->size, sect->alignment) + sect->size;
   return true;
 }
 
@@ -438,9 +425,9 @@ rtems_rtl_obj_add_section (rtems_rtl_obj* obj,
     rtems_chain_append (&obj->sections, &sect->node);
 
     if (rtems_rtl_trace (RTEMS_RTL_TRACE_SECTION))
-      printf ("rtl: sect: %-2d: %s (%zu)\n", section, name, size);
+      printf ("rtl: sect: add: %-2d: %s (%zu) 0x%08lx\n",
+              section, name, size, flags);
   }
-
   return true;
 }
 
@@ -467,6 +454,8 @@ typedef struct
   rtems_rtl_obj_sect*  sect;  /**< The matching section. */
   const char*          name;  /**< The name to match. */
   int                  index; /**< The index to match. */
+  uint32_t             mask;  /**< The mask to match. */
+  unsigned int         flags; /**< The flags to use when matching. */
 } rtems_rtl_obj_sect_finder;
 
 static bool
@@ -489,6 +478,8 @@ rtems_rtl_obj_find_section (const rtems_rtl_obj* obj,
   rtems_rtl_obj_sect_finder match;
   match.sect = NULL;
   match.name = name;
+  match.mask = 0;
+  match.flags = 0;
   rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
                            rtems_rtl_obj_sect_match_name,
                            &match);
@@ -515,12 +506,50 @@ rtems_rtl_obj_find_section_by_index (const rtems_rtl_obj* obj,
   rtems_rtl_obj_sect_finder match;
   match.sect = NULL;
   match.index = index;
+  match.mask = 0;
+  match.flags = 0;
   rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
                            rtems_rtl_obj_sect_match_index,
                            &match);
   return match.sect;
 }
 
+static bool
+rtems_rtl_obj_sect_match_mask (rtems_chain_node* node, void* data)
+{
+  rtems_rtl_obj_sect*        sect = (rtems_rtl_obj_sect*) node;
+  rtems_rtl_obj_sect_finder* match = data;
+  if (match->flags == 0)
+  {
+    if (match->index < 0 || sect->section == match->index)
+      match->flags = 1;
+    if (match->index >= 0)
+      return true;
+  }
+  if ((sect->flags & match->mask) != 0)
+  {
+    match->sect = sect;
+    return false;
+  }
+  return true;
+}
+
+rtems_rtl_obj_sect*
+rtems_rtl_obj_find_section_by_mask (const rtems_rtl_obj* obj,
+                                    int                  index,
+                                    uint32_t             mask)
+{
+  rtems_rtl_obj_sect_finder match;
+  match.sect = NULL;
+  match.index = index;
+  match.mask = mask;
+  match.flags = 0;
+  rtems_rtl_chain_iterate ((rtems_chain_control*) &obj->sections,
+                           rtems_rtl_obj_sect_match_mask,
+                           &match);
+  return match.sect;
+}
+
 size_t
 rtems_rtl_obj_text_size (const rtems_rtl_obj* obj)
 {
@@ -775,7 +804,7 @@ rtems_rtl_obj_sections_loader (uint32_t                   mask,
       if (sect->load_order == order)
       {
         if (!first)
-          base_offset = rtems_rtl_sect_align (base_offset, sect->alignment);
+          base_offset = rtems_rtl_obj_align (base_offset, sect->alignment);
 
         first = false;
 
-- 
2.14.1



More information about the devel mailing list