summaryrefslogtreecommitdiffstats
path: root/cpukit/libdl/rtl-elf.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libdl/rtl-elf.c')
-rw-r--r--cpukit/libdl/rtl-elf.c349
1 files changed, 216 insertions, 133 deletions
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;