[rtems commit] libdl: Add a local symbol table to the object module.

Chris Johns chrisj at rtems.org
Tue Nov 4 01:04:28 UTC 2014


Module:    rtems
Branch:    master
Commit:    a2e1e30d9862b0f926f694d146ab0e7450aa759b
Changeset: http://git.rtems.org/rtems/commit/?id=a2e1e30d9862b0f926f694d146ab0e7450aa759b

Author:    Chris Johns <chrisj at rtems.org>
Date:      Tue Nov  4 12:12:25 2014 +1100

libdl: Add a local symbol table to the object module.

Adding a local symbol lets the relocator find local symbols referenced
in relocation records. The local symbol table is erased once the object
module has been loaded.

---

 cpukit/libdl/rtl-elf.c   |  235 ++++++++++++++++++++++++++++++----------------
 cpukit/libdl/rtl-obj.h   |    3 +
 cpukit/libdl/rtl-sym.c   |   30 +++++-
 cpukit/libdl/rtl-sym.h   |    9 ++-
 cpukit/libdl/rtl-trace.h |    3 +-
 5 files changed, 193 insertions(+), 87 deletions(-)

diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c
index e4f1ffc..46f5613 100644
--- a/cpukit/libdl/rtl-elf.c
+++ b/cpukit/libdl/rtl-elf.c
@@ -1,5 +1,5 @@
 /*
- *  COPYRIGHT (c) 2012 Chris Johns <chrisj at rtems.org>
+ *  COPYRIGHT (c) 2012-2014 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,10 @@ rtems_rtl_elf_find_symbol (rtems_rtl_obj_t* obj,
 
   if (ELF_ST_TYPE(sym->st_info) == STT_NOTYPE)
   {
-    rtems_rtl_obj_sym_t* symbol = rtems_rtl_symbol_global_find (symname);
+    /*
+     * Search the object file then the global table for the symbol.
+     */
+    rtems_rtl_obj_sym_t* symbol = rtems_rtl_symbol_obj_find (obj, symname);
     if (!symbol)
     {
       rtems_rtl_set_error (EINVAL, "global symbol not found: %s", symname);
@@ -337,9 +340,14 @@ rtems_rtl_elf_symbols (rtems_rtl_obj_t*      obj,
   rtems_rtl_obj_cache_t* symbols;
   rtems_rtl_obj_cache_t* strings;
   rtems_rtl_obj_sect_t*  strtab;
+  int                    locals;
+  int                    local_string_space;
+  rtems_rtl_obj_sym_t*   lsym;
+  char*                  lstring;
   int                    globals;
-  int                    string_space;
-  char*                  string;
+  int                    global_string_space;
+  rtems_rtl_obj_sym_t*   gsym;
+  char*                  gstring;
   int                    sym;
 
   strtab = rtems_rtl_obj_find_section (obj, ".strtab");
@@ -359,8 +367,10 @@ rtems_rtl_elf_symbols (rtems_rtl_obj_t*      obj,
    * needed. Also check for duplicate symbols.
    */
 
-  globals      = 0;
-  string_space = 0;
+  globals             = 0;
+  global_string_space = 0;
+  locals              = 0;
+  local_string_space  = 0;
 
   for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym)
   {
@@ -382,121 +392,181 @@ rtems_rtl_elf_symbols (rtems_rtl_obj_t*      obj,
       return false;
 
     /*
-     * Only keep the functions and global or weak symbols.
+     * Only keep the functions and global or weak symbols so place them in a
+     * separate table to local symbols. Local symbols are not needed after the
+     * object file has been loaded. Undefined symbols are NOTYPE so for locals
+     * we need to make sure there is a valid seciton.
      */
-    if ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
-        (ELF_ST_TYPE (symbol.st_info) == STT_FUNC))
+    if ((symbol.st_shndx != 0) &&
+        ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
+         (ELF_ST_TYPE (symbol.st_info) == STT_FUNC) ||
+         (ELF_ST_TYPE (symbol.st_info) == STT_NOTYPE)))
     {
-      if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
-          (ELF_ST_BIND (symbol.st_info) == STB_WEAK))
+      rtems_rtl_obj_sect_t* symsect;
+
+      symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx);
+      if (symsect)
       {
-        /*
-         * If there is a globally exported symbol already present and this
-         * symbol is not weak raise an error. If the symbol is weak and present
-         * globally ignore this symbol and use the global one and if it is not
-         * present take this symbol global or weak. We accept the first weak
-         * symbol we find and make it globally exported.
-         */
-        if (rtems_rtl_symbol_global_find (name) &&
-            (ELF_ST_BIND (symbol.st_info) != STB_WEAK))
+        if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
+            (ELF_ST_BIND (symbol.st_info) == STB_WEAK))
         {
-          rtems_rtl_set_error (ENOMEM, "duplicate global symbol: %s", name);
-          return false;
+          /*
+           * If there is a globally exported symbol already present and this
+           * symbol is not weak raise an error. If the symbol is weak and
+           * present globally ignore this symbol and use the global one and if
+           * it is not present take this symbol global or weak. We accept the
+           * first weak symbol we find and make it globally exported.
+           */
+          if (rtems_rtl_symbol_global_find (name) &&
+              (ELF_ST_BIND (symbol.st_info) != STB_WEAK))
+          {
+            rtems_rtl_set_error (ENOMEM, "duplicate global symbol: %s", name);
+            return false;
+          }
+          else
+          {
+            ++globals;
+            global_string_space += strlen (name) + 1;
+          }
         }
-        else
+        else if (ELF_ST_BIND (symbol.st_info) == STB_LOCAL)
         {
-          ++globals;
-          string_space += strlen (name) + 1;
+          ++locals;
+          local_string_space += strlen (name) + 1;
         }
       }
     }
   }
 
-  if (globals)
+  if (locals)
   {
-    rtems_rtl_obj_sym_t* gsym;
+    obj->local_size = locals * sizeof (rtems_rtl_obj_sym_t) + local_string_space;
+    obj->local_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
+                                            obj->local_size, true);
+    if (!obj->local_table)
+    {
+      obj->local_size = 0;
+      rtems_rtl_set_error (ENOMEM, "no memory for obj local syms");
+      return false;
+    }
+
+    obj->local_syms = locals;
+  }
 
-    obj->global_size = globals * sizeof (rtems_rtl_obj_sym_t) + string_space;
+  if (globals)
+  {
+    obj->global_size = globals * sizeof (rtems_rtl_obj_sym_t) + global_string_space;
     obj->global_table = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_SYMBOL,
                                              obj->global_size, true);
     if (!obj->global_table)
     {
+      if (locals)
+      {
+        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->local_table);
+        obj->local_size = 0;
+        obj->local_syms = 0;
+      }
       obj->global_size = 0;
       rtems_rtl_set_error (ENOMEM, "no memory for obj global syms");
       return false;
     }
 
     obj->global_syms = globals;
+  }
 
-    for (sym = 0,
-           gsym = obj->global_table,
-           string = (((char*) obj->global_table) +
-                     (globals * sizeof (rtems_rtl_obj_sym_t)));
-         sym < (sect->size / sizeof (Elf_Sym));
-         ++sym)
-    {
-      Elf_Sym     symbol;
-      off_t       off;
-      const char* name;
-      size_t      len;
+  lsym = obj->local_table;
+  lstring =
+    (((char*) obj->local_table) + (locals * sizeof (rtems_rtl_obj_sym_t)));
+  gsym = obj->global_table;
+  gstring =
+    (((char*) obj->global_table) + (globals * sizeof (rtems_rtl_obj_sym_t)));
+
+  for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym)
+  {
+    Elf_Sym     symbol;
+    off_t       off;
+    const char* name;
+    size_t      len;
 
-      off = obj->ooffset + sect->offset + (sym * sizeof (symbol));
+    off = obj->ooffset + sect->offset + (sym * sizeof (symbol));
 
-      if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off,
-                                           &symbol, sizeof (symbol)))
+    if (!rtems_rtl_obj_cache_read_byval (symbols, fd, off,
+                                         &symbol, sizeof (symbol)))
+    {
+      if (locals)
       {
-        free (obj->global_table);
+        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)
+      {
+        rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->global_table);
         obj->global_table = NULL;
         obj->global_syms = 0;
         obj->global_size = 0;
-        return false;
       }
+      return false;
+    }
 
-      off = obj->ooffset + strtab->offset + symbol.st_name;
-      len = RTEMS_RTL_ELF_STRING_MAX;
+    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 (!rtems_rtl_obj_cache_read (strings, fd, off, (void**) &name, &len))
+      return false;
 
-      if (((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
-           (ELF_ST_TYPE (symbol.st_info) == STT_FUNC)) &&
-          ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
-           (ELF_ST_BIND (symbol.st_info) == STB_WEAK)))
+    if ((symbol.st_shndx != 0) &&
+        ((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
+         (ELF_ST_TYPE (symbol.st_info) == STT_FUNC) ||
+         (ELF_ST_TYPE (symbol.st_info) == STT_NOTYPE)) &&
+         ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
+          (ELF_ST_BIND (symbol.st_info) == STB_WEAK) ||
+          (ELF_ST_BIND (symbol.st_info) == STB_LOCAL)))
       {
         rtems_rtl_obj_sect_t* symsect;
+        rtems_rtl_obj_sym_t*  osym;
+        char*                 string;
+
         symsect = rtems_rtl_obj_find_section_by_index (obj, symbol.st_shndx);
-        if (!symsect)
+        if (symsect)
         {
-          free (obj->global_table);
-          obj->global_table = NULL;
-          obj->global_syms = 0;
-          obj->global_size = 0;
-          rtems_rtl_set_error (EINVAL, "sym section not found");
-          return false;
+          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;
+          }
+
+          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->data = symbol.st_info;
+
+          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);
         }
-
-        rtems_chain_set_off_chain (&gsym->node);
-
-        memcpy (string, name, strlen (name) + 1);
-        gsym->name = string;
-        string += strlen (name) + 1;
-        gsym->value = symbol.st_value + (uint8_t*) symsect->base;
-        gsym->data = symbol.st_info;
-
-        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, gsym->name,
-                  (int) ELF_ST_BIND (symbol.st_info),
-                  (int) ELF_ST_TYPE (symbol.st_info),
-                  gsym->value, symbol.st_shndx,
-                  (int) symbol.st_size);
-
-        ++gsym;
       }
-    }
+  }
 
+  if (globals)
     rtems_rtl_symbol_obj_add (obj);
-  }
 
   return true;
 }
@@ -631,8 +701,9 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj_t* obj, int fd, Elf_Ehdr* ehdr)
         break;
 
       default:
-        printf ("rtl: unsupported section: %2d: type=%02d flags=%02x\n",
-                section, (int) shdr.sh_type, (int) shdr.sh_flags);
+        if (rtems_rtl_trace (RTEMS_RTL_TRACE_WARNING))
+          printf ("rtl: unsupported section: %2d: type=%02d flags=%02x\n",
+                  section, (int) shdr.sh_type, (int) shdr.sh_flags);
         break;
     }
 
@@ -867,6 +938,8 @@ rtems_rtl_elf_file_load (rtems_rtl_obj_t* obj, int fd)
   if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocator, &ehdr))
     return false;
 
+  rtems_rtl_symbol_obj_erase_local (obj);
+
   if (!rtems_rtl_elf_load_details (obj))
   {
     return false;
diff --git a/cpukit/libdl/rtl-obj.h b/cpukit/libdl/rtl-obj.h
index 0550723..96c7680 100644
--- a/cpukit/libdl/rtl-obj.h
+++ b/cpukit/libdl/rtl-obj.h
@@ -145,6 +145,9 @@ struct rtems_rtl_obj_s
   size_t               fsize;        /**< Size of the object file. */
   rtems_chain_control  sections;     /**< The sections of interest in the
                                       *   object file. */
+  rtems_rtl_obj_sym_t* local_table;  /**< Local symbol table. */
+  size_t               local_syms;   /**< Local symbol count. */
+  size_t               local_size;   /**< Local symbol memory usage. */
   rtems_rtl_obj_sym_t* global_table; /**< Global symbol table. */
   size_t               global_syms;  /**< Global symbol count. */
   size_t               global_size;  /**< Global symbol memory usage. */
diff --git a/cpukit/libdl/rtl-sym.c b/cpukit/libdl/rtl-sym.c
index f806394..ebd6841 100644
--- a/cpukit/libdl/rtl-sym.c
+++ b/cpukit/libdl/rtl-sym.c
@@ -1,5 +1,5 @@
 /*
- *  COPYRIGHT (c) 2012 Chris Johns <chrisj at rtems.org>
+ *  COPYRIGHT (c) 2012-2014 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
@@ -208,9 +208,18 @@ rtems_rtl_symbol_obj_find (rtems_rtl_obj_t* obj, const char* name)
    * Check the object file's symbols first. If not found search the
    * global symbol table.
    */
-  for (s = 0, sym = obj->global_table; s < obj->global_syms; ++s, ++sym)
-    if (strcmp (name, sym->name) == 0)
-      return sym;
+  if (obj->local_syms)
+  {
+    for (s = 0, sym = obj->local_table; s < obj->local_syms; ++s, ++sym)
+      if (strcmp (name, sym->name) == 0)
+        return sym;
+  }
+  if (obj->global_syms)
+  {
+    for (s = 0, sym = obj->global_table; s < obj->global_syms; ++s, ++sym)
+      if (strcmp (name, sym->name) == 0)
+        return sym;
+  }
   return rtems_rtl_symbol_global_find (name);
 }
 
@@ -228,8 +237,21 @@ rtems_rtl_symbol_obj_add (rtems_rtl_obj_t* obj)
 }
 
 void
+rtems_rtl_symbol_obj_erase_local (rtems_rtl_obj_t* obj)
+{
+  if (obj->local_table)
+  {
+    rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_SYMBOL, obj->local_table);
+    obj->local_table = NULL;
+    obj->local_size = 0;
+    obj->local_syms = 0;
+  }
+}
+
+void
 rtems_rtl_symbol_obj_erase (rtems_rtl_obj_t* obj)
 {
+  rtems_rtl_symbol_obj_erase_local (obj);
   if (obj->global_table)
   {
     rtems_rtl_obj_sym_t* sym;
diff --git a/cpukit/libdl/rtl-sym.h b/cpukit/libdl/rtl-sym.h
index b793a54..9bd40ec 100644
--- a/cpukit/libdl/rtl-sym.h
+++ b/cpukit/libdl/rtl-sym.h
@@ -1,5 +1,5 @@
 /*
- *  COPYRIGHT (c) 2012 Chris Johns <chrisj at rtems.org>
+ *  COPYRIGHT (c) 2012-2014 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
@@ -115,6 +115,13 @@ rtems_rtl_obj_sym_t* rtems_rtl_symbol_obj_find (rtems_rtl_obj_t* obj,
 void rtems_rtl_symbol_obj_add (rtems_rtl_obj_t* obj);
 
 /**
+ * Erase the object file's local symbols.
+ *
+ * @param obj The object file the local symbols are to be erased from.
+ */
+void rtems_rtl_symbol_obj_erase_local (rtems_rtl_obj_t* obj);
+
+/**
  * Erase the object file's symbols.
  *
  * @param obj The object file the symbols are to be erased from.
diff --git a/cpukit/libdl/rtl-trace.h b/cpukit/libdl/rtl-trace.h
index 1a5ee97..141b376 100644
--- a/cpukit/libdl/rtl-trace.h
+++ b/cpukit/libdl/rtl-trace.h
@@ -1,5 +1,5 @@
 /*
- *  COPYRIGHT (c) 2012 Chris Johns <chrisj at rtems.org>
+ *  COPYRIGHT (c) 2012-2014 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
@@ -47,6 +47,7 @@ typedef uint32_t rtems_rtl_trace_mask;
 #define RTEMS_RTL_TRACE_ALLOCATOR              (1UL << 7)
 #define RTEMS_RTL_TRACE_UNRESOLVED             (1UL << 8)
 #define RTEMS_RTL_TRACE_DETAIL                 (1UL << 9)
+#define RTEMS_RTL_TRACE_WARNING                (1UL << 10)
 
 /**
  * Call to check if this part is bring traced. If RTEMS_RTL_TRACE is defined to



More information about the vc mailing list