summaryrefslogtreecommitdiffstats
path: root/cpukit/libdl
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2019-01-22 08:48:19 +1100
committerChris Johns <chrisj@rtems.org>2019-02-09 10:06:34 +1100
commit194eb403c39f5ad346e63dc3352e29570857fd93 (patch)
tree3ef4976810a6e4545a0d4c68138c270ed3abd22c /cpukit/libdl
parentlibdl: Add support for trampolines (diff)
downloadrtems-194eb403c39f5ad346e63dc3352e29570857fd93.tar.bz2
libdl: Add support for large memory programs
- Add trampolines to support relocs that are out of range on support architectures. - Support not loading separate text/data sections in an object file if the symbol provided in the section is a duplicate. A base image may have pulled in part of an object and another part needs to be dynamically loaded. - Refactor the unresolved handling to scale to hundreds of unresolved symbols when loading large number of files. Updates #3685
Diffstat (limited to 'cpukit/libdl')
-rw-r--r--cpukit/libdl/rtl-archive.c125
-rw-r--r--cpukit/libdl/rtl-elf.c349
-rw-r--r--cpukit/libdl/rtl-mdreloc-arm.c36
-rw-r--r--cpukit/libdl/rtl-mdreloc-i386.c9
-rw-r--r--cpukit/libdl/rtl-obj.c88
-rw-r--r--cpukit/libdl/rtl-shell.c17
-rw-r--r--cpukit/libdl/rtl-unresolved.c388
-rw-r--r--cpukit/libdl/rtl.c10
8 files changed, 609 insertions, 413 deletions
diff --git a/cpukit/libdl/rtl-archive.c b/cpukit/libdl/rtl-archive.c
index 786c9c6f1d..be1199f62f 100644
--- a/cpukit/libdl/rtl-archive.c
+++ b/cpukit/libdl/rtl-archive.c
@@ -293,32 +293,22 @@ rtems_rtl_archive_obj_finder (rtems_rtl_archive* archive, void* data)
}
else
{
- ssize_t entry = symbols->entries / 2;
- ssize_t offset = entry;
- ssize_t last_entry = -1;
- while (entry >= 0 &&
- entry < symbols->entries &&
- entry != last_entry &&
- offset > 0)
+ rtems_rtl_archive_symbol* match;
+ const rtems_rtl_archive_symbol key = {
+ .entry = -1,
+ .label = search->symbol
+ };
+ match = bsearch (&key,
+ symbols->symbols,
+ symbols->entries,
+ sizeof (symbols->symbols[0]),
+ rtems_rtl_archive_symbol_compare);
+ if (match != NULL)
{
- int cmp = strcmp (search->symbol, symbols->symbols[entry].label);
- if (cmp == 0)
- {
- entry = symbols->symbols[entry].entry;
search->archive = archive;
search->offset =
- rtems_rtl_archive_read_32 (symbols->base + (entry * 4));
+ rtems_rtl_archive_read_32 (symbols->base + (match->entry * 4));
return false;
- }
- last_entry = entry;
- if (offset == 1)
- offset = 0;
- else
- offset = ((offset - 1) / 2) + 1;
- if (cmp < 0)
- entry -= offset;
- else
- entry += offset;
}
}
}
@@ -452,7 +442,7 @@ rtems_rtl_archives_load_config (rtems_rtl_archives* archives)
rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, (void*) archives->config);
archives->config_length = 0;
archives->config =
- rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, sb.st_size, false);
+ rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, sb.st_size + 1, true);
if (archives->config == NULL)
{
if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
@@ -519,45 +509,29 @@ rtems_rtl_archives_load_config (rtems_rtl_archives* archives)
* Remove leading and trailing white space.
*/
s = (char*) archives->config;
- for (r = 0; r < archives->config_length; ++r)
+ r = 0;
+ while (r < archives->config_length)
{
- if (s[r] != '\0')
+ if (s[r] == '\0')
+ {
+ ++r;
+ }
+ else
{
size_t ls = strlen (&s[r]);
size_t b = 0;
while (b < ls && isspace (s[r + b]))
{
+ s[r + b] = '\0';
++b;
}
- if (b > 0)
- memmove (&s[r], &s[r + b], ls - b);
b = ls - 1;
- while (b > 0 && isspace (s[r + b]))
+ while (b > 0 && isspace (s[b]))
{
- s[r + b] = '\0';
+ s[b] = '\0';
--b;
}
- }
- }
-
- /*
- * Compact the lines so there is only a single nul separator.
- */
- s = (char*) archives->config;
- for (r = 0; r < archives->config_length; ++r)
- {
- if (s[r] == '\0')
- {
- size_t e = r + 1;
- while (e < archives->config_length)
- {
- if (s[e] != '\0')
- {
- if (archives->config_length - e - 1 > 0)
- memmove (&s[r + 1], &s[e], archives->config_length - e - 1);
- break;
- }
- }
+ r += ls;
}
}
@@ -565,13 +539,17 @@ rtems_rtl_archives_load_config (rtems_rtl_archives* archives)
{
int line = 1;
printf ("rtl: archive: config:\n");
- s = (char*) archives->config;
- for (r = 0; r < archives->config_length; ++r, ++line)
+ r = 0;
+ while (r < archives->config_length)
{
- size_t len = strlen (s);
- printf (" %3d: %s\n", line, s);
- s += len + 2;
- r += len;
+ const char* cs = &archives->config[r];
+ size_t len = strlen (cs);
+ if (len > 0)
+ {
+ printf (" %3d: %s\n", line, cs);
+ ++line;
+ }
+ r += len + 1;
}
}
}
@@ -740,6 +718,19 @@ rtems_rtl_archive_loader (rtems_rtl_archive* archive, void* data)
archive->symbols.names,
(archive->symbols.entries + 1) * 4,
archive->symbols.symbols);
+
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVE_SYMS) &&
+ archive->symbols.entries > 0)
+ {
+ size_t e;
+ printf ("rtl: archive: symbols: %s\n", archive->name );
+ for (e = 0; e < archive->symbols.entries; ++e)
+ {
+ printf(" %6zu: %6zu %s\n", e + 1,
+ archive->symbols.symbols[e].entry,
+ archive->symbols.symbols[e].label);
+ }
+ }
}
close (fd);
@@ -851,19 +842,16 @@ rtems_rtl_archives_refresh (rtems_rtl_archives* archives)
break;
if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
- printf ("rtl: archive: refresh: checking: %s\n", entry.d_name);
+ printf ("rtl: archive: refresh: checking: %s (pattern: %s)\n",
+ entry.d_name, basename);
if (fnmatch (basename, entry.d_name, 0) == 0)
{
- struct stat sb;
- if (stat (entry.d_name, &sb) == 0)
- {
- rtems_rtl_archive* archive;
- archive = rtems_rtl_archive_get (archives, dirname, entry.d_name);
- if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
- printf ("rtl: archive: refresh: %s: %sfound\n",
- entry.d_name, archive == NULL ? ": not " : "");
- }
+ rtems_rtl_archive* archive;
+ archive = rtems_rtl_archive_get (archives, dirname, entry.d_name);
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
+ printf ("rtl: archive: refresh: %s: %sfound\n",
+ entry.d_name, archive == NULL ? ": not " : "");
}
}
closedir (dir);
@@ -1028,8 +1016,9 @@ rtems_rtl_archive_obj_load (rtems_rtl_archives* archives,
if (!rtems_rtl_obj_load (obj))
{
if (rtems_rtl_trace (RTEMS_RTL_TRACE_ARCHIVES))
- printf ("rtl: archive: loading: error: %s:%s@0x%08jx\n",
- obj->aname, obj->oname, obj->ooffset);
+ printf ("rtl: archive: loading: error: %s:%s@0x%08jx: %s\n",
+ obj->aname, obj->oname, obj->ooffset,
+ rtems_rtl_last_error_unprotected ());
rtems_chain_extract (&obj->link);
rtems_rtl_obj_free (obj);
rtems_rtl_obj_caches_flush ();
diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c
index 96af16cb52..e65c70308d 100644
--- a/cpukit/libdl/rtl-elf.c
+++ b/cpukit/libdl/rtl-elf.c
@@ -21,6 +21,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -64,6 +65,31 @@ rtems_rtl_elf_machine_check (Elf_Ehdr* ehdr)
return true;
}
+static const char*
+rtems_rtl_elf_separated_section (const char* name)
+{
+ struct {
+ const char* label;
+ size_t len;
+ } prefix[] = {
+ #define SEPARATED_PREFIX(_p) { _p, sizeof (_p) - 1 }
+ SEPARATED_PREFIX (".text."),
+ SEPARATED_PREFIX (".rel.text."),
+ SEPARATED_PREFIX (".data."),
+ SEPARATED_PREFIX (".rel.data."),
+ SEPARATED_PREFIX (".rodata."),
+ SEPARATED_PREFIX (".rel.rodata.")
+ };
+ const size_t prefixes = sizeof (prefix) / sizeof (prefix[0]);
+ size_t p;
+ for (p = 0; p < prefixes; ++p)
+ {
+ if (strncmp (name, prefix[p].label, prefix[p].len) == 0)
+ return name + prefix[p].len;
+ }
+ return NULL;
+}
+
static bool
rtems_rtl_elf_find_symbol (rtems_rtl_obj* obj,
const Elf_Sym* sym,
@@ -100,6 +126,7 @@ rtems_rtl_elf_find_symbol (rtems_rtl_obj* obj,
return false;
*value = sym->st_value + (Elf_Addr) sect->base;
+
return true;
}
@@ -141,62 +168,68 @@ rtems_rtl_elf_reloc_parser (rtems_rtl_obj* obj,
rtems_rtl_elf_reloc_data* rd = (rtems_rtl_elf_reloc_data*) data;
/*
- * Check the reloc record to see if a trampoline is needed.
- */
- 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 the symbol has been resolved and there is a symbol name it is a global
- * symbol and from another object file so add it as a dependency.
+ * 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.
*/
if (!resolved)
{
++rd->unresolved;
}
- else if (symname != NULL)
+ else
{
/*
- * 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.
+ * Check the reloc record to see if a trampoline is needed.
*/
- rtems_rtl_obj* sobj = rtems_rtl_find_obj_with_symbol (symbol);
- if (sobj != NULL)
+ 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)
{
/*
- * A dependency is not the base kernel image or itself. Tag the object as
- * having been visited so we count it only once.
+ * 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 (sobj != rtems_rtl_baseimage () && obj != sobj &&
- (sobj->flags & RTEMS_RTL_OBJ_RELOC_TAG) == 0)
+ rtems_rtl_obj* sobj = rtems_rtl_find_obj_with_symbol (symbol);
+ if (sobj != NULL)
{
- sobj->flags |= RTEMS_RTL_OBJ_RELOC_TAG;
- ++rd->dependents;
+ /*
+ * 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;
+ }
}
}
}
+
return true;
}
@@ -313,6 +346,14 @@ rtems_rtl_elf_relocate_worker (rtems_rtl_obj* obj,
if (!targetsect)
return true;
+ /*
+ * The section muct has been loaded. It could be a separate section in an
+ * archive and not loaded.
+ */
+ if ((targetsect->flags & RTEMS_RTL_OBJ_SECT_LOAD) == 0)
+ return true;
+
+
rtems_rtl_obj_caches (&symbols, &strings, &relocs);
if (!symbols || !strings || !relocs)
@@ -379,6 +420,7 @@ 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 ||
+ ELF_ST_TYPE (sym.st_info) == STT_TLS ||
sym.st_shndx == SHN_COMMON)
{
size_t len;
@@ -686,6 +728,12 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj,
symbol.st_shndx,
(int) symbol.st_size);
+ /*
+ * 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) ||
(ELF_ST_TYPE (symbol.st_info) == STT_COMMON) ||
@@ -705,16 +753,24 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj,
{
/*
* 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.
+ * symbol is not weak raise check if the object file being loaded is
+ * from an archive. If the base image is built with text sections a
+ * symbol with it's section will be linked into the base image and not
+ * another symbol. If not an archive rause 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;
+ if (!rtems_rtl_obj_aname_valid (obj))
+ {
+ rtems_rtl_set_error (ENOMEM, "duplicate global symbol: %s", name);
+ return false;
+ }
}
else
{
@@ -784,10 +840,9 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj,
for (sym = 0; sym < (sect->size / sizeof (Elf_Sym)); ++sym)
{
- Elf_Sym symbol;
- off_t off;
- const char* name;
- size_t len;
+ Elf_Sym symbol;
+ off_t off;
+ size_t len;
off = obj->ooffset + sect->offset + (sym * sizeof (symbol));
@@ -811,12 +866,6 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj,
return false;
}
- 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 ((symbol.st_shndx != 0) &&
((ELF_ST_TYPE (symbol.st_info) == STT_OBJECT) ||
(ELF_ST_TYPE (symbol.st_info) == STT_COMMON) ||
@@ -825,62 +874,76 @@ rtems_rtl_elf_symbols (rtems_rtl_obj* obj,
((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* 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)
{
- rtems_rtl_obj_sect* symsect;
- 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)
- {
- 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;
- }
+ 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 = value + (uint8_t*) symsect->base;
- osym->data = symbol.st_info;
+ /*
+ * 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:%-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);
+ 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;
+ }
+
+ /*
+ * 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 = 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);
}
+ }
}
if (globals)
@@ -955,6 +1018,8 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr)
for (section = 0; section < ehdr->e_shnum; ++section)
{
+ char* name;
+ size_t len;
uint32_t flags;
/*
@@ -968,9 +1033,15 @@ 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;
+ len = RTEMS_RTL_ELF_STRING_MAX;
+ if (!rtems_rtl_obj_cache_read (strings, fd,
+ sectstroff + shdr.sh_name,
+ (void**) &name, &len))
+ return false;
+
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,
+ printf ("rtl: section: %2d: name=%s type=%d flags=%08x link=%d info=%d\n",
+ section, name, (int) shdr.sh_type, (unsigned int) shdr.sh_flags,
(int) shdr.sh_link, (int) shdr.sh_info);
flags = 0;
@@ -1010,7 +1081,7 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr)
break;
case SHT_RELA:
- flags = RTEMS_RTL_OBJ_SECT_RELA;
+ flags = RTEMS_RTL_OBJ_SECT_RELA | RTEMS_RTL_OBJ_SECT_LOAD;
break;
case SHT_REL:
@@ -1018,7 +1089,7 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr)
* The sh_link holds the section index for the symbol table. The sh_info
* holds the section index the relocations apply to.
*/
- flags = RTEMS_RTL_OBJ_SECT_REL;
+ flags = RTEMS_RTL_OBJ_SECT_REL | RTEMS_RTL_OBJ_SECT_LOAD;
break;
case SHT_SYMTAB:
@@ -1063,8 +1134,18 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr)
if (flags != 0)
{
- char* name;
- size_t len;
+ /*
+ * If the object file is part of a library check the section's name. If it
+ * starts with '.text.*' see if the last part is a global symbol. If a
+ * global symbol exists we have to assume the symbol in the archive is a
+ * duplicate can can be ignored.
+ */
+ if (rtems_rtl_obj_aname_valid (obj))
+ {
+ const char* symname = rtems_rtl_elf_separated_section (name);
+ if (symname != NULL && rtems_rtl_symbol_global_find (symname))
+ flags &= ~RTEMS_RTL_OBJ_SECT_LOAD;
+ }
/*
* If link ordering this section must appear in the same order in memory
@@ -1074,14 +1155,8 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr)
flags |= RTEMS_RTL_OBJ_SECT_LINK;
/*
- * Some architexctures support a named PROGBIT section for INIT/FINI.
+ * Some architexctures have a named PROGBIT section for INIT/FINI.
*/
- len = RTEMS_RTL_ELF_STRING_MAX;
- if (!rtems_rtl_obj_cache_read (strings, fd,
- sectstroff + shdr.sh_name,
- (void**) &name, &len))
- return false;
-
if (strcmp (".ctors", name) == 0)
flags |= RTEMS_RTL_OBJ_SECT_CTOR;
if (strcmp (".dtors", name) == 0)
@@ -1153,25 +1228,34 @@ rtems_rtl_elf_load_linkmap (rtems_rtl_obj* obj)
{
rtems_chain_control* sections = NULL;
rtems_chain_node* node = NULL;
- size_t mask = 0;
int sec_num = 0;
section_detail* sd;
int i = 0;
+ size_t m;
/*
- * Caculate the size of sections' name.
+ * The section masks to add to the linkmap.
*/
+ const uint32_t sect_mask[] = {
+ RTEMS_RTL_OBJ_SECT_TEXT | RTEMS_RTL_OBJ_SECT_LOAD,
+ RTEMS_RTL_OBJ_SECT_CONST | RTEMS_RTL_OBJ_SECT_LOAD,
+ RTEMS_RTL_OBJ_SECT_DATA | RTEMS_RTL_OBJ_SECT_LOAD,
+ RTEMS_RTL_OBJ_SECT_BSS
+ };
+ const size_t sect_masks = sizeof (sect_mask) / sizeof (sect_mask[0]);
- for (mask = RTEMS_RTL_OBJ_SECT_TEXT;
- mask <= RTEMS_RTL_OBJ_SECT_BSS;
- mask <<= 1)
+ /*
+ * Caculate the size of sections' name.
+ */
+ for (m = 0; m < sect_masks; ++m)
{
sections = &obj->sections;
node = rtems_chain_first (sections);
while (!rtems_chain_is_tail (sections, node))
{
rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node;
- if ((sect->size != 0) && ((sect->flags & mask) != 0))
+ const uint32_t mask = sect_mask[m];
+ if ((sect->size != 0) && ((sect->flags & mask) == mask))
{
++sec_num;
}
@@ -1205,36 +1289,35 @@ rtems_rtl_elf_load_linkmap (rtems_rtl_obj* obj)
sections = &obj->sections;
node = rtems_chain_first (sections);
- for (mask = RTEMS_RTL_OBJ_SECT_TEXT;
- mask <= RTEMS_RTL_OBJ_SECT_BSS;
- mask <<= 1)
+ for (m = 0; m < sect_masks; ++m)
{
sections = &obj->sections;
node = rtems_chain_first (sections);
while (!rtems_chain_is_tail (sections, node))
{
rtems_rtl_obj_sect* sect = (rtems_rtl_obj_sect*) node;
+ const uint32_t mask = sect_mask[m];
- if ((sect->size != 0) && ((sect->flags & mask) != 0))
+ if ((sect->size != 0) && ((sect->flags & mask) == mask))
{
sd[i].name = sect->name;
sd[i].size = sect->size;
- if (mask == RTEMS_RTL_OBJ_SECT_TEXT)
+ if ((mask & RTEMS_RTL_OBJ_SECT_TEXT) != 0)
{
sd[i].rap_id = rap_text;
sd[i].offset = sect->base - obj->text_base;
}
- if (mask == RTEMS_RTL_OBJ_SECT_CONST)
+ if ((mask & RTEMS_RTL_OBJ_SECT_CONST) != 0)
{
sd[i].rap_id = rap_const;
sd[i].offset = sect->base - obj->const_base;
}
- if (mask == RTEMS_RTL_OBJ_SECT_DATA)
+ if ((mask & RTEMS_RTL_OBJ_SECT_DATA) != 0)
{
sd[i].rap_id = rap_data;
sd[i].offset = sect->base - obj->data_base;
}
- if (mask == RTEMS_RTL_OBJ_SECT_BSS)
+ if ((mask & RTEMS_RTL_OBJ_SECT_BSS) != 0)
{
sd[i].rap_id = rap_bss;
sd[i].offset = sect->base - obj->bss_base;
diff --git a/cpukit/libdl/rtl-mdreloc-arm.c b/cpukit/libdl/rtl-mdreloc-arm.c
index a00f0f8825..19a5904a25 100644
--- a/cpukit/libdl/rtl-mdreloc-arm.c
+++ b/cpukit/libdl/rtl-mdreloc-arm.c
@@ -22,6 +22,12 @@
#include "rtl-unwind.h"
/*
+ * Set to 1 to allow untested relocations. If you tested one and it
+ * works or you fixed the relocation please remove the guard.
+ */
+#define ALLOW_UNTESTED_RELOCS 1
+
+/*
* It is possible for the compiler to emit relocations for unaligned data.
* We handle this situation with these inlines.
*/
@@ -341,8 +347,10 @@ rtems_rtl_elf_relor_rel (rtems_rtl_obj* obj,
else {
if (ELF_R_TYPE(rel->r_info) == R_TYPE(THM_JUMP24)) {
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;
+#endif
}
else {
/* THM_CALL bl-->blx */
@@ -440,11 +448,33 @@ rtems_rtl_elf_relor_rel (rtems_rtl_obj* obj,
(void *)*where, where, rtems_rtl_obj_oname (obj));
break;
+ case R_TYPE(TLS_LE32):
+#if ALLOW_UNTESTED_RELOCS
+ if (!parsing) {
+ addend = *where;
+ *where = symvalue + addend;
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+ printf ("rtl: TLS_LE32 %p @ %p in %s\n",
+ (void *)*where, where, rtems_rtl_obj_oname (obj));
+ }
+ break;
+#endif
+ case R_TYPE(TLS_GD32):
+ case R_TYPE(TLS_LDM32):
+ case R_TYPE(TLS_LDO32):
+ case R_TYPE(TLS_IE32):
+ case R_TYPE(TLS_LDO12):
+ case R_TYPE(TLS_LE12):
+ case R_TYPE(TLS_IE12GP):
+ printf("TSL relocations not supported\n");
+
default:
- printf ("rtl: reloc unknown: sym = %" PRIu32 ", type = %" PRIu32 ", offset = %p, "
- "contents = %p\n",
+ printf ("rtl: reloc unknown: sym = %" PRIu32 ", type = %" PRIu32 ", offset = %p",
ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info),
- (void *)rel->r_offset, (void *)*where);
+ (void *)rel->r_offset);
+ if (!parsing)
+ printf("contents = %p", (void *)*where);
+ printf("\n");
rtems_rtl_set_error (EINVAL,
"%s: Unsupported relocation type %" PRIu32 " "
"in non-PLT relocations",
diff --git a/cpukit/libdl/rtl-mdreloc-i386.c b/cpukit/libdl/rtl-mdreloc-i386.c
index 773ef8e916..016f99f379 100644
--- a/cpukit/libdl/rtl-mdreloc-i386.c
+++ b/cpukit/libdl/rtl-mdreloc-i386.c
@@ -7,6 +7,7 @@
#include <sys/cdefs.h>
#include <errno.h>
+#include <inttypes.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -67,7 +68,7 @@ rtems_rtl_elf_relocate_rela (rtems_rtl_obj* obj,
const Elf_Word symvalue)
{
(void) obj;
- (void) rela;
+ (void) rel;
(void) sect;
(void) symname;
(void) syminfo;
@@ -147,12 +148,12 @@ rtems_rtl_elf_relocate_rel (rtems_rtl_obj* obj,
break;
default:
- printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, "
+ printf ("rtl: reloc unknown: sym = %i, type = %" PRIu32 ", offset = %p, "
"contents = %p\n",
- ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info),
+ (int) ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info),
(void *)rel->r_offset, (void *)*where);
rtems_rtl_set_error (EINVAL,
- "%s: Unsupported relocation type %ld "
+ "%s: Unsupported relocation type %" PRIu32 " "
"in non-PLT relocations",
sect->name, (uint32_t) ELF_R_TYPE(rel->r_info));
return false;
diff --git a/cpukit/libdl/rtl-obj.c b/cpukit/libdl/rtl-obj.c
index 6f1f2e4916..0a7763b3b2 100644
--- a/cpukit/libdl/rtl-obj.c
+++ b/cpukit/libdl/rtl-obj.c
@@ -158,6 +158,16 @@ rtems_rtl_obj_unresolved_dependent (rtems_rtl_obj* obj,
return ud->has_unresolved;
}
+static bool
+rtems_rtl_obj_unresolved_object (rtems_chain_node* node, void* data)
+{
+ rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
+ rtems_rtl_obj_unresolved_data* ud;
+ ud = (rtems_rtl_obj_unresolved_data*) data;
+ ud->has_unresolved = (obj->flags & RTEMS_RTL_OBJ_UNRESOLVED) != 0;
+ return !ud->has_unresolved;
+}
+
bool
rtems_rtl_obj_unresolved (rtems_rtl_obj* obj)
{
@@ -169,12 +179,22 @@ rtems_rtl_obj_unresolved (rtems_rtl_obj* obj)
obj->oname, ud.has_unresolved ? "unresolved" : "resolved");
if (!ud.has_unresolved)
{
- rtems_rtl_obj_update_flags (RTEMS_RTL_OBJ_DEP_VISITED, 0);
- obj->flags |= RTEMS_RTL_OBJ_DEP_VISITED;
- rtems_rtl_obj_iterate_dependents (obj,
- rtems_rtl_obj_unresolved_dependent,
- &ud);
- rtems_rtl_obj_update_flags (RTEMS_RTL_OBJ_DEP_VISITED, 0);
+ if ((obj->flags & RTEMS_RTL_OBJ_BASE) != 0)
+ {
+ rtems_rtl_data* rtl = rtems_rtl_data_unprotected ();
+ rtems_rtl_chain_iterate (&rtl->objects,
+ rtems_rtl_obj_unresolved_object,
+ &ud);
+ }
+ else
+ {
+ rtems_rtl_obj_update_flags (RTEMS_RTL_OBJ_DEP_VISITED, 0);
+ obj->flags |= RTEMS_RTL_OBJ_DEP_VISITED;
+ rtems_rtl_obj_iterate_dependents (obj,
+ rtems_rtl_obj_unresolved_dependent,
+ &ud);
+ rtems_rtl_obj_update_flags (RTEMS_RTL_OBJ_DEP_VISITED, 0);
+ }
}
return ud.has_unresolved;
}
@@ -727,49 +747,57 @@ rtems_rtl_obj_iterate_dependents (rtems_rtl_obj* obj,
size_t
rtems_rtl_obj_text_size (const rtems_rtl_obj* obj)
{
- return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_TEXT);
+ const uint32_t flags = RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_TEXT;
+ return rtems_rtl_obj_section_size (obj, flags);
}
uint32_t
rtems_rtl_obj_text_alignment (const rtems_rtl_obj* obj)
{
- return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_TEXT);
+ const uint32_t flags = RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_TEXT;
+ return rtems_rtl_obj_section_alignment (obj, flags);
}
size_t
rtems_rtl_obj_const_size (const rtems_rtl_obj* obj)
{
- return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_CONST);
+ const uint32_t flags = RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_CONST;
+ return rtems_rtl_obj_section_size (obj, flags);
}
uint32_t
-rtems_rtl_obj_eh_alignment (const rtems_rtl_obj* obj)
+rtems_rtl_obj_const_alignment (const rtems_rtl_obj* obj)
{
- return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_EH);
+ const uint32_t flags = RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_CONST;
+ return rtems_rtl_obj_section_alignment (obj, flags);
}
-size_t
-rtems_rtl_obj_eh_size (const rtems_rtl_obj* obj)
+uint32_t
+rtems_rtl_obj_eh_alignment (const rtems_rtl_obj* obj)
{
- return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_EH);
+ const uint32_t flags = RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_EH;
+ return rtems_rtl_obj_section_alignment (obj, flags);
}
-uint32_t
-rtems_rtl_obj_const_alignment (const rtems_rtl_obj* obj)
+size_t
+rtems_rtl_obj_eh_size (const rtems_rtl_obj* obj)
{
- return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_CONST);
+ const uint32_t flags = RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_EH;
+ return rtems_rtl_obj_section_size (obj, flags);
}
size_t
rtems_rtl_obj_data_size (const rtems_rtl_obj* obj)
{
- return rtems_rtl_obj_section_size (obj, RTEMS_RTL_OBJ_SECT_DATA);
+ const uint32_t flags = RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_DATA;
+ return rtems_rtl_obj_section_size (obj, flags);
}
uint32_t
rtems_rtl_obj_data_alignment (const rtems_rtl_obj* obj)
{
- return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_DATA);
+ const uint32_t flags = RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_DATA;
+ return rtems_rtl_obj_section_alignment (obj, flags);
}
size_t
@@ -790,8 +818,10 @@ rtems_rtl_obj_relocate (rtems_rtl_obj* obj,
rtems_rtl_obj_sect_handler handler,
void* data)
{
- uint32_t mask = RTEMS_RTL_OBJ_SECT_REL | RTEMS_RTL_OBJ_SECT_RELA;
- return rtems_rtl_obj_section_handler (mask, obj, fd, handler, data);
+ const uint32_t flags = (RTEMS_RTL_OBJ_SECT_LOAD |
+ RTEMS_RTL_OBJ_SECT_REL |
+ RTEMS_RTL_OBJ_SECT_RELA);
+ return rtems_rtl_obj_section_handler (flags, obj, fd, handler, data);
}
/**
@@ -1012,12 +1042,14 @@ rtems_rtl_obj_sections_loader (uint32_t mask,
}
else
{
+ /*
+ * This section is not to be loaded, clear the base.
+ */
sect->base = 0;
- rtems_rtl_set_error (errno, "section has no load/clear op");
- return false;
}
- base_offset += sect->size;
+ if (sect->base)
+ base_offset += sect->size;
++order;
@@ -1053,9 +1085,11 @@ rtems_rtl_obj_load_sections (rtems_rtl_obj* obj,
/*
* Set the sizes held in the object data. We need this for a fast reference.
*/
- obj->text_size = text_size;
- obj->eh_size = eh_size;
- obj->bss_size = bss_size;
+ obj->text_size = text_size;
+ obj->const_size = const_size;
+ obj->data_size = data_size;
+ obj->eh_size = eh_size;
+ obj->bss_size = bss_size;
/*
* Let the allocator manage the actual allocation. The user can use the
diff --git a/cpukit/libdl/rtl-shell.c b/cpukit/libdl/rtl-shell.c
index c2a1af5ddd..ab5553174b 100644
--- a/cpukit/libdl/rtl-shell.c
+++ b/cpukit/libdl/rtl-shell.c
@@ -129,17 +129,6 @@ typedef struct
} rtems_rtl_obj_print;
/**
- * Return the different between 2 void*.
- */
-static size_t
-rtems_rtl_delta_voids (void* higher, void* lower)
-{
- char* ch = higher;
- char* cl = lower;
- return ch - cl;
-}
-
-/**
* Parse an argument.
*/
static bool
@@ -235,11 +224,11 @@ rtems_rtl_obj_printer (rtems_rtl_obj_print* print, rtems_rtl_obj* obj)
{
printf ("%-*cexec size : %zi\n", print->indent, ' ', obj->exec_size);
printf ("%-*ctext base : %p (%zi)\n", print->indent, ' ',
- obj->text_base, rtems_rtl_delta_voids (obj->const_base, obj->text_base));
+ obj->text_base, obj->text_size);
printf ("%-*cconst base : %p (%zi)\n", print->indent, ' ',
- obj->const_base, rtems_rtl_delta_voids (obj->data_base, obj->const_base));
+ obj->const_base, obj->const_size);
printf ("%-*cdata base : %p (%zi)\n", print->indent, ' ',
- obj->data_base, rtems_rtl_delta_voids (obj->bss_base, obj->data_base));
+ obj->data_base, obj->data_size);
printf ("%-*cbss base : %p (%zi)\n", print->indent, ' ',
obj->bss_base, obj->bss_size);
}
diff --git a/cpukit/libdl/rtl-unresolved.c b/cpukit/libdl/rtl-unresolved.c
index 7e2d920594..0e70c5dacf 100644
--- a/cpukit/libdl/rtl-unresolved.c
+++ b/cpukit/libdl/rtl-unresolved.c
@@ -36,13 +36,13 @@ rtems_rtl_unresolved_block_alloc (rtems_rtl_unresolved* unresolved)
*/
size_t size =
(sizeof(rtems_rtl_unresolv_block) +
- (sizeof(rtems_rtl_unresolv_rec) * (unresolved->block_recs - 1)));
+ (sizeof(rtems_rtl_unresolv_rec) * unresolved->block_recs));
rtems_rtl_unresolv_block* block =
rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_EXTERNAL, size, true);
if (block)
{
if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
- printf ("rtl: unresolv: block-alloc %p\n", block);
+ printf ("rtl: unresolv: block-alloc %p (%p)\n", block, block + size);
rtems_chain_append (&unresolved->blocks, &block->link);
}
else
@@ -53,28 +53,31 @@ rtems_rtl_unresolved_block_alloc (rtems_rtl_unresolved* unresolved)
static size_t
rtems_rtl_unresolved_symbol_rec_count (size_t length)
{
- return ((length + sizeof(rtems_rtl_unresolv_symbol) - 1) /
- sizeof(rtems_rtl_unresolv_symbol));
+ const size_t rec_size = sizeof(rtems_rtl_unresolv_rec);
+ const size_t rec_name_header = offsetof(rtems_rtl_unresolv_rec, rec.name.name);
+ /*
+ * Add on the nul and rmeove 1 to be inside a record.
+ */
+ return ((length + rec_name_header - 1) / rec_size) + 1;
}
-
static size_t
rtems_rtl_unresolved_symbol_recs (const char* name)
{
- return rtems_rtl_unresolved_symbol_rec_count (strlen (name));
+ return rtems_rtl_unresolved_symbol_rec_count (strlen (name) + 1);
}
static int
rtems_rtl_unresolved_rec_index (rtems_rtl_unresolv_block* block,
rtems_rtl_unresolv_rec* rec)
{
- return (rec - &block->rec) / sizeof (rtems_rtl_unresolv_rec);
+ return rec - &block->rec[0];
}
static rtems_rtl_unresolv_rec*
rtems_rtl_unresolved_rec_first (rtems_rtl_unresolv_block* block)
{
- return &block->rec;
+ return &block->rec[0];
}
static rtems_rtl_unresolv_rec*
@@ -83,6 +86,7 @@ rtems_rtl_unresolved_rec_next (rtems_rtl_unresolv_rec* rec)
switch (rec->type)
{
case rtems_rtl_unresolved_empty:
+ default:
/*
* Empty returns NULL. The end of the records in the block.
*/
@@ -99,9 +103,6 @@ rtems_rtl_unresolved_rec_next (rtems_rtl_unresolv_rec* rec)
case rtems_rtl_unresolved_reloc:
++rec;
break;
-
- default:
- break;
}
return rec;
@@ -111,50 +112,121 @@ static bool
rtems_rtl_unresolved_rec_is_last (rtems_rtl_unresolv_block* block,
rtems_rtl_unresolv_rec* rec)
{
- int index = (rec - &block->rec) / sizeof (rec);
- return !rec || (index >= block->recs) || (rec->type == rtems_rtl_unresolved_empty);
+ int index = rtems_rtl_unresolved_rec_index (block, rec);
+ return (rec == NULL ||
+ (index < 0) ||
+ (index >= block->recs) ||
+ (rec->type == rtems_rtl_unresolved_empty));
}
static rtems_rtl_unresolv_rec*
rtems_rtl_unresolved_rec_first_free (rtems_rtl_unresolv_block* block)
{
- return &block->rec + block->recs;
+ return &block->rec[0] + block->recs;
}
-static int
-rtems_rtl_unresolved_find_name (rtems_rtl_unresolved* unresolved,
- const char* name,
- bool update_refcount)
+/**
+ * Name management iterator data.
+ */
+typedef struct
{
- size_t length = strlen (name) + 1;
- int index = 1;
+ const char* name; /**< The name being searched for. */
+ size_t length; /**< The length of the name. */
+ rtems_rtl_unresolv_rec* rec; /**< The record being searched for. */
+ int index; /**< The name's index. */
+ int offset; /**< The offset to move the index. */
+} rtl_unresolved_name_data;
- rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
- while (!rtems_chain_is_tail (&unresolved->blocks, node))
+static bool
+rtems_rtl_unresolved_find_name_iterator (rtems_rtl_unresolv_rec* rec,
+ void* data)
+{
+ rtl_unresolved_name_data* nd = (rtl_unresolved_name_data*) data;
+ if (rec->type == rtems_rtl_unresolved_symbol)
{
- rtems_rtl_unresolv_block* block = (rtems_rtl_unresolv_block*) node;
- rtems_rtl_unresolv_rec* rec = rtems_rtl_unresolved_rec_first (block);
-
- while (!rtems_rtl_unresolved_rec_is_last (block, rec))
+ if ((rec->rec.name.length == nd->length)
+ && (strcmp (rec->rec.name.name, nd->name) == 0))
{
- if (rec->type == rtems_rtl_unresolved_symbol)
- {
- if ((rec->rec.name.length == length)
- && (strcmp (rec->rec.name.name, name) == 0))
- {
- if (update_refcount)
- ++rec->rec.name.refs;
- return index;
- }
- ++index;
- }
- rec = rtems_rtl_unresolved_rec_next (rec);
+ ++rec->rec.name.refs;
+ return true;
}
+ ++nd->index;
+ }
+ return false;
+}
- node = rtems_chain_next (node);
+static int
+rtems_rtl_unresolved_find_name (const char* name)
+{
+ rtl_unresolved_name_data nd = {
+ .name = name,
+ .length = strlen (name) + 1,
+ .rec = NULL,
+ .index = 1,
+ .offset = 0
+ };
+ if (rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_find_name_iterator,
+ &nd))
+ return nd.index;
+ return -1;
+}
+
+static bool
+rtems_rtl_unresolved_find_index_iterator (rtems_rtl_unresolv_rec* rec,
+ void* data)
+{
+ rtl_unresolved_name_data* nd = (rtl_unresolved_name_data*) data;
+ if (rec == nd->rec)
+ return true;
+ if (rec->type == rtems_rtl_unresolved_symbol)
+ ++nd->index;
+ return false;
+}
+
+static int
+rtems_rtl_unresolved_find_index (rtems_rtl_unresolv_rec* rec)
+{
+ rtl_unresolved_name_data nd = {
+ .name = NULL,
+ .length = 0,
+ .rec = rec,
+ .index = 1,
+ .offset = 0
+ };
+ if (rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_find_index_iterator,
+ &nd))
+ return nd.index;
+ return -1;
+}
+
+static bool
+rtems_rtl_unresolved_reindex_iterator (rtems_rtl_unresolv_rec* rec,
+ void* data)
+{
+ rtl_unresolved_name_data* nd = (rtl_unresolved_name_data*) data;
+ /*
+ * Reindexing only effects the reloc records.
+ */
+ if (rec->type == rtems_rtl_unresolved_reloc)
+ {
+ if (rec->rec.reloc.name >= nd->index)
+ rec->rec.reloc.name += nd->offset;
}
+ return false;
+}
- return 0 - index;
+static void
+rtems_rtl_unresolved_reindex_names (uint16_t index, int offset)
+{
+ rtl_unresolved_name_data nd = {
+ .name = NULL,
+ .length = 0,
+ .rec = NULL,
+ .index = index,
+ .offset = offset
+ };
+ rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_reindex_iterator,
+ &nd);
}
/**
@@ -184,29 +256,31 @@ rtems_rtl_unresolved_resolve_reloc (rtems_rtl_unresolv_rec* rec,
printf ("rtl: unresolv: resolve reloc: %s\n",
rd->name_rec->rec.name.name);
- rtems_rtl_obj_relocate_unresolved (&rec->rec.reloc, rd->sym);
-
- /*
- * If all unresolved externals are resolved add the obj module
- * to the pending queue. This will flush the object module's
- * data from the cache and call it's constructors.
- */
- if (rec->rec.reloc.obj->unresolved == 0)
+ if (rtems_rtl_obj_relocate_unresolved (&rec->rec.reloc, rd->sym))
{
- pending = rtems_rtl_pending_unprotected ();
- rtems_chain_extract (&rec->rec.reloc.obj->link);
- rtems_chain_append (pending, &rec->rec.reloc.obj->link);
- }
+ /*
+ * If all unresolved externals are resolved add the obj module
+ * to the pending queue. This will flush the object module's
+ * data from the cache and call it's constructors.
+ */
+ if (rec->rec.reloc.obj->unresolved == 0)
+ {
+ pending = rtems_rtl_pending_unprotected ();
+ rtems_chain_extract (&rec->rec.reloc.obj->link);
+ rtems_chain_append (pending, &rec->rec.reloc.obj->link);
+ }
- /*
- * Check Set the object pointer to NULL to indicate the record is not used
- * anymore. Update the reference count of the name. The sweep after
- * relocating will remove the reloc records with obj set to NULL and
- * names with a reference count of 0.
- */
- rec->rec.reloc.obj = NULL;
- if (rd->name_rec != NULL && rd->name_rec->rec.name.refs > 0)
- --rd->name_rec->rec.name.refs;
+ /*
+ * Set the object pointer to NULL to indicate the record is
+ * not used anymore. Update the reference count of the name so
+ * it can garbage collected if not referenced. The sweep after
+ * relocating will remove the reloc records with obj set to
+ * NULL and names with a reference count of 0.
+ */
+ rec->rec.reloc.obj = NULL;
+ if (rd->name_rec != NULL && rd->name_rec->rec.name.refs > 0)
+ --rd->name_rec->rec.name.refs;
+ }
}
}
return false;
@@ -250,9 +324,9 @@ rtems_rtl_unresolved_resolve_iterator (rtems_rtl_unresolv_rec* rec,
*/
typedef struct rtems_rtl_unresolved_archive_reloc_data
{
- uint16_t name; /**< Name index. */
- bool loaded; /**< Object file loaded. */
- rtems_rtl_archives* archives; /**< The archives to search. */
+ uint16_t name; /**< Name index. */
+ rtems_rtl_archive_search result; /**< The result of the load. */
+ rtems_rtl_archives* archives; /**< The archives to search. */
} rtems_rtl_unresolved_archive_reloc_data;
static bool
@@ -268,17 +342,18 @@ rtems_rtl_unresolved_archive_iterator (rtems_rtl_unresolv_rec* rec,
if ((rec->rec.name.flags & RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE) != 0)
{
- rtems_rtl_archive_search load;
+ rtems_rtl_archive_search result;
if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
printf ("rtl: unresolv: archive lookup: %d: %s\n",
ard->name, rec->rec.name.name);
- load = rtems_rtl_archive_obj_load (ard->archives,
- rec->rec.name.name, true);
- if (load == rtems_rtl_archive_search_loaded)
+ result = rtems_rtl_archive_obj_load (ard->archives,
+ rec->rec.name.name, true);
+ if (result != rtems_rtl_archive_search_not_found)
{
- ard->loaded = true;
+ rec->rec.name.flags &= ~RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE;
+ ard->result = result;
return true;
}
}
@@ -292,10 +367,26 @@ rtems_rtl_unresolved_archive_search_iterator (rtems_rtl_unresolv_rec* rec,
void* data)
{
if (rec->type == rtems_rtl_unresolved_symbol)
- rec->rec.name.flags = RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE;
+ rec->rec.name.flags |= RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE;
return false;
}
+static rtems_rtl_unresolv_block*
+rtems_rtl_unresolved_alloc_recs (rtems_rtl_unresolved* unresolved,
+ size_t count)
+{
+ 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;
+
+ if (block->recs + count <= unresolved->block_recs)
+ return block;
+ node = rtems_chain_next (node);
+ }
+ return NULL;
+}
+
static void
rtems_rtl_unresolved_clean_block (rtems_rtl_unresolv_block* block,
rtems_rtl_unresolv_rec* rec,
@@ -309,7 +400,7 @@ rtems_rtl_unresolved_clean_block (rtems_rtl_unresolv_block* block,
memmove (rec, rec + count, bytes);
block->recs -= count;
bytes = count * sizeof (rtems_rtl_unresolv_rec);
- memset (&block->rec + block->recs, 0, bytes);
+ memset (&block->rec[block->recs], 0, bytes);
}
static void
@@ -328,51 +419,19 @@ rtems_rtl_unresolved_compact (void)
{
rtems_rtl_unresolv_block* block = (rtems_rtl_unresolv_block*) node;
rtems_rtl_unresolv_rec* rec = rtems_rtl_unresolved_rec_first (block);
-
while (!rtems_rtl_unresolved_rec_is_last (block, rec))
{
bool next_rec = true;
+
if (rec->type == rtems_rtl_unresolved_symbol)
{
++index;
if (rec->rec.name.refs == 0)
{
- /*
- * Iterate over the remaining reloc records and update the index.
- */
- rtems_chain_node* reindex_node;
- rtems_rtl_unresolv_rec* reindex_first;
- size_t name_recs;
+ size_t name_recs;
if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
printf ("rtl: unresolv: remove name: %s\n", rec->rec.name.name);
- reindex_node = node;
- reindex_first = rtems_rtl_unresolved_rec_next (rec);
- while (!rtems_chain_is_tail (&unresolved->blocks, reindex_node))
- {
- rtems_rtl_unresolv_rec* reindex_rec;
- rtems_rtl_unresolv_block* reindex_block;
- reindex_block = (rtems_rtl_unresolv_block*) reindex_node;
- if (reindex_first != NULL)
- {
- reindex_rec = reindex_first;
- reindex_first = NULL;
- }
- else
- {
- reindex_rec = rtems_rtl_unresolved_rec_first (reindex_block);
- }
- while (!rtems_rtl_unresolved_rec_is_last (reindex_block,
- reindex_rec))
- {
- if (reindex_rec->type == rtems_rtl_unresolved_reloc)
- {
- if (reindex_rec->rec.reloc.name >= index)
- --reindex_rec->rec.reloc.name;
- }
- reindex_rec = rtems_rtl_unresolved_rec_next (reindex_rec);
- }
- reindex_node = rtems_chain_next (reindex_node);
- }
+ rtems_rtl_unresolved_reindex_names (index, -1);
/*
* Compact the block removing the name record.
*/
@@ -470,11 +529,9 @@ rtems_rtl_unresolved_add (rtems_rtl_obj* obj,
const rtems_rtl_word* rel)
{
rtems_rtl_unresolved* unresolved;
- rtems_chain_node* node;
rtems_rtl_unresolv_block* block;
rtems_rtl_unresolv_rec* rec;
int name_index;
- size_t name_recs;
if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
printf ("rtl: unresolv: add: %s(s:%d) -> %s\n",
@@ -485,69 +542,69 @@ rtems_rtl_unresolved_add (rtems_rtl_obj* obj,
return false;
/*
- * Find the first block with a spare record.
- */
- node = rtems_chain_first (&unresolved->blocks);
- block = NULL;
- while (!rtems_chain_is_tail (&unresolved->blocks, node))
- {
- block = (rtems_rtl_unresolv_block*) node;
- if (block->recs < unresolved->block_recs)
- break;
- block = NULL;
- node = rtems_chain_next (node);
- }
-
- /*
- * No blocks with any spare records, allocate a new block.
+ * Is the name present?
*/
- if (!block)
- {
- block = rtems_rtl_unresolved_block_alloc (unresolved);
- if (!block)
- return false;
- }
-
- name_index = rtems_rtl_unresolved_find_name (unresolved, name, true);
- name_recs = rtems_rtl_unresolved_symbol_recs (name);
+ name_index = rtems_rtl_unresolved_find_name (name);
/*
- * An index less than 0 means the name is present and "0 - index" is the next
- * index to use.
+ * An index less than 0 means the name was not found.
*/
if (name_index < 0)
{
- rtems_rtl_unresolv_block* name_block = block;
+ size_t name_recs;
+
+ name_recs = rtems_rtl_unresolved_symbol_recs (name);
/*
* Is there enough room to fit the name ? It not add a new block.
*/
- if (name_recs > (unresolved->block_recs - block->recs))
+ block = rtems_rtl_unresolved_alloc_recs (unresolved, name_recs);
+ if (block == NULL)
{
- name_block = rtems_rtl_unresolved_block_alloc (unresolved);
- if (!name_block)
+ block = rtems_rtl_unresolved_block_alloc (unresolved);
+ if (!block)
return false;
}
- rec = rtems_rtl_unresolved_rec_first_free (name_block);
+ /*
+ * Find the record in the block.
+ */
+ rec = rtems_rtl_unresolved_rec_first_free (block);
+
+ /*
+ * Enter the new record before reindexing so the iterator can see
+ * it and the iterator is called.
+ */
rec->type = rtems_rtl_unresolved_symbol;
rec->rec.name.refs = 1;
rec->rec.name.flags = RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE;
rec->rec.name.length = strlen (name) + 1;
- memcpy ((void*) &rec->rec.name.name[0], name, rec->rec.name.length + 1);
+ memcpy ((void*) &rec->rec.name.name[0], name, rec->rec.name.length);
block->recs += name_recs;
- name_index = 0 - name_index;
/*
- * If the name block is the reloc block and it is full allocate a new
- * block for the relocation record.
+ * Find the name index for the name and then reindex the names which
+ * are moved up because of the insertion.
*/
- if ((block == name_block) && (block->recs >= unresolved->block_recs))
+ name_index = rtems_rtl_unresolved_find_index (rec);
+ if (name_index < 0)
{
- block = rtems_rtl_unresolved_block_alloc (unresolved);
- if (!block)
- return false;
+ rtems_rtl_set_error (ENOMEM, "internal unresolved block error");
+ return false;
}
+
+ rtems_rtl_unresolved_reindex_names (name_index, 1);
+ }
+
+ /*
+ * Find the first block with a spare record.
+ */
+ 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);
@@ -592,7 +649,7 @@ rtems_rtl_unresolved_resolve (void)
};
rtems_rtl_unresolved_archive_reloc_data ard = {
.name = 0,
- .loaded = false,
+ .result = rtems_rtl_archive_search_not_found,
.archives = rtems_rtl_archives_unprotected ()
};
@@ -600,7 +657,7 @@ rtems_rtl_unresolved_resolve (void)
rtems_rtl_unresolved_compact ();
rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_archive_iterator, &ard);
- resolving = ard.loaded;
+ resolving = ard.result == rtems_rtl_archive_search_loaded;
}
if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
@@ -627,6 +684,7 @@ typedef struct rtems_rtl_unresolved_dump_data
{
size_t rec;
size_t names;
+ bool show_relocs;
} rtems_rtl_unresolved_dump_data;
static bool
@@ -642,16 +700,20 @@ rtems_rtl_unresolved_dump_iterator (rtems_rtl_unresolv_rec* rec,
break;
case rtems_rtl_unresolved_symbol:
++dd->names;
- printf (" %3zu: 1: name: %3d refs: %2d: %2d: %s\n",
+ printf (" %3zu: 1: name: %3d refs:%4d: flags:%04x %s (%d)\n",
dd->rec, dd->names,
- rec->rec.name.refs, rec->rec.name.length, rec->rec.name.name);
+ rec->rec.name.refs,
+ rec->rec.name.flags,
+ rec->rec.name.name,
+ rec->rec.name.length);
break;
case rtems_rtl_unresolved_reloc:
- printf (" %3zu: 2: reloc: obj:%s name:%2d: sect:%d\n",
- dd->rec,
- rec->rec.reloc.obj->oname,
- rec->rec.reloc.name,
- rec->rec.reloc.sect);
+ if (dd->show_relocs)
+ printf (" %3zu: 2: reloc: obj:%s name:%2d: sect:%d\n",
+ dd->rec,
+ rec->rec.reloc.obj == NULL ? "resolved" : rec->rec.reloc.obj->oname,
+ rec->rec.reloc.name,
+ rec->rec.reloc.sect);
break;
default:
printf (" %03zu: %d: unknown\n", dd->rec, rec->type);
@@ -662,16 +724,16 @@ rtems_rtl_unresolved_dump_iterator (rtems_rtl_unresolv_rec* rec,
}
void
-rtems_rtl_unresolved_set_archive_search (void)
-{
- rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_archive_search_iterator,
- NULL);
-}
-
-void
rtems_rtl_unresolved_dump (void)
{
rtems_rtl_unresolved_dump_data dd = { 0 };
printf ("RTL Unresolved data:\n");
rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_dump_iterator, &dd);
}
+
+void
+rtems_rtl_unresolved_set_archive_search (void)
+{
+ rtems_rtl_unresolved_iterate (rtems_rtl_unresolved_archive_search_iterator,
+ NULL);
+}
diff --git a/cpukit/libdl/rtl.c b/cpukit/libdl/rtl.c
index a3664c7e34..e3dba5a206 100644
--- a/cpukit/libdl/rtl.c
+++ b/cpukit/libdl/rtl.c
@@ -144,7 +144,7 @@ rtems_rtl_data_init (void)
/*
* Open the archives.
*/
- rtems_rtl_archives_open (&rtl->archives, "/etc/rtl-libs.conf");
+ rtems_rtl_archives_open (&rtl->archives, "/etc/libdl.conf");
/*
* Open the unresolved table.
@@ -265,6 +265,14 @@ rtems_rtl_global_symbols (void)
return &rtl->globals;
}
+const char*
+rtems_rtl_last_error_unprotected (void)
+{
+ if (!rtl)
+ return NULL;
+ return rtl->last_error;
+}
+
rtems_chain_control*
rtems_rtl_objects_unprotected (void)
{