summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2014-11-04 12:12:25 +1100
committerChris Johns <chrisj@rtems.org>2014-11-04 12:12:25 +1100
commita2e1e30d9862b0f926f694d146ab0e7450aa759b (patch)
treec064ceac36598376aa81b20feb12823841d74275
parentBSP for several Beagle products (diff)
downloadrtems-a2e1e30d9862b0f926f694d146ab0e7450aa759b.tar.bz2
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.
-rw-r--r--cpukit/libdl/rtl-elf.c235
-rw-r--r--cpukit/libdl/rtl-obj.h3
-rw-r--r--cpukit/libdl/rtl-sym.c30
-rw-r--r--cpukit/libdl/rtl-sym.h9
-rw-r--r--cpukit/libdl/rtl-trace.h3
5 files changed, 193 insertions, 87 deletions
diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c
index e4f1ffc007..46f5613014 100644
--- a/cpukit/libdl/rtl-elf.c
+++ b/cpukit/libdl/rtl-elf.c
@@ -1,5 +1,5 @@
/*
- * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org>
+ * COPYRIGHT (c) 2012-2014 Chris Johns <chrisj@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 05507232ca..96c76808ab 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 f8063948bd..ebd68412c0 100644
--- a/cpukit/libdl/rtl-sym.c
+++ b/cpukit/libdl/rtl-sym.c
@@ -1,5 +1,5 @@
/*
- * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org>
+ * COPYRIGHT (c) 2012-2014 Chris Johns <chrisj@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 b793a547dc..9bd40ec241 100644
--- a/cpukit/libdl/rtl-sym.h
+++ b/cpukit/libdl/rtl-sym.h
@@ -1,5 +1,5 @@
/*
- * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org>
+ * COPYRIGHT (c) 2012-2014 Chris Johns <chrisj@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 1a5ee973a5..141b3769a5 100644
--- a/cpukit/libdl/rtl-trace.h
+++ b/cpukit/libdl/rtl-trace.h
@@ -1,5 +1,5 @@
/*
- * COPYRIGHT (c) 2012 Chris Johns <chrisj@rtems.org>
+ * COPYRIGHT (c) 2012-2014 Chris Johns <chrisj@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