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
This commit is contained in:
Chris Johns
2019-01-22 08:48:19 +11:00
parent d8c70ba65b
commit 194eb403c3
16 changed files with 687 additions and 460 deletions

View File

@@ -92,19 +92,20 @@ typedef struct rtems_rtl_loader_table
#define RTEMS_RTL_OBJ_SECT_DATA (1 << 2) /**< Section holds program data. */
#define RTEMS_RTL_OBJ_SECT_BSS (1 << 3) /**< Section holds program bss. */
#define RTEMS_RTL_OBJ_SECT_EH (1 << 4) /**< Section holds exception data. */
#define RTEMS_RTL_OBJ_SECT_REL (1 << 5) /**< Section holds relocation recs. */
#define RTEMS_RTL_OBJ_SECT_RELA (1 << 6) /**< Section holds reloc addend recs. */
#define RTEMS_RTL_OBJ_SECT_SYM (1 << 7) /**< Section holds symbols. */
#define RTEMS_RTL_OBJ_SECT_STR (1 << 8) /**< Section holds strings. */
#define RTEMS_RTL_OBJ_SECT_ALLOC (1 << 9) /**< Section allocates runtime memory. */
#define RTEMS_RTL_OBJ_SECT_LOAD (1 << 10) /**< Section is loaded from object file. */
#define RTEMS_RTL_OBJ_SECT_WRITE (1 << 11) /**< Section is writable, ie data. */
#define RTEMS_RTL_OBJ_SECT_EXEC (1 << 12) /**< Section is executable. */
#define RTEMS_RTL_OBJ_SECT_ZERO (1 << 13) /**< Section is preset to zero. */
#define RTEMS_RTL_OBJ_SECT_LINK (1 << 14) /**< Section is link-ordered. */
#define RTEMS_RTL_OBJ_SECT_CTOR (1 << 15) /**< Section contains constructors. */
#define RTEMS_RTL_OBJ_SECT_DTOR (1 << 16) /**< Section contains destructors. */
#define RTEMS_RTL_OBJ_SECT_LOCD (1 << 17) /**< Section has been located. */
#define RTEMS_RTL_OBJ_SECT_TLS (1 << 5) /**< Section holds TLS data. */
#define RTEMS_RTL_OBJ_SECT_REL (1 << 6) /**< Section holds relocation recs. */
#define RTEMS_RTL_OBJ_SECT_RELA (1 << 7) /**< Section holds reloc addend recs. */
#define RTEMS_RTL_OBJ_SECT_SYM (1 << 8) /**< Section holds symbols. */
#define RTEMS_RTL_OBJ_SECT_STR (1 << 9) /**< Section holds strings. */
#define RTEMS_RTL_OBJ_SECT_ALLOC (1 << 10 /**< Section allocates runtime memory. */
#define RTEMS_RTL_OBJ_SECT_LOAD (1 << 11) /**< Section is loaded from object file. */
#define RTEMS_RTL_OBJ_SECT_WRITE (1 << 12) /**< Section is writable, ie data. */
#define RTEMS_RTL_OBJ_SECT_EXEC (1 << 13) /**< Section is executable. */
#define RTEMS_RTL_OBJ_SECT_ZERO (1 << 14) /**< Section is preset to zero. */
#define RTEMS_RTL_OBJ_SECT_LINK (1 << 15) /**< Section is link-ordered. */
#define RTEMS_RTL_OBJ_SECT_CTOR (1 << 16) /**< Section contains constructors. */
#define RTEMS_RTL_OBJ_SECT_DTOR (1 << 17) /**< Section contains destructors. */
#define RTEMS_RTL_OBJ_SECT_LOCD (1 << 18) /**< Section has been located. */
/**
* Section types mask.
@@ -113,6 +114,7 @@ typedef struct rtems_rtl_loader_table
RTEMS_RTL_OBJ_SECT_CONST | \
RTEMS_RTL_OBJ_SECT_DATA | \
RTEMS_RTL_OBJ_SECT_BSS | \
RTEMS_RTL_OBJ_SECT_TLS | \
RTEMS_RTL_OBJ_SECT_EH)
/**
@@ -204,11 +206,13 @@ struct rtems_rtl_obj
size_t text_size; /**< The size of the text section. */
void* const_base; /**< The base address of the const section
* in memory. */
size_t const_size; /**< The size of the const section. */
void* eh_base; /**< The base address of the eh section in
* memory. */
size_t eh_size; /**< The size of the eh section. */
void* data_base; /**< The base address of the data section
* in memory. */
size_t data_size; /**< The size of the data section. */
void* bss_base; /**< The base address of the bss section in
* memory. */
size_t bss_size; /**< The size of the bss section. */

View File

@@ -49,8 +49,11 @@ typedef uint32_t rtems_rtl_trace_mask;
#define RTEMS_RTL_TRACE_UNRESOLVED (1UL << 10)
#define RTEMS_RTL_TRACE_CACHE (1UL << 11)
#define RTEMS_RTL_TRACE_ARCHIVES (1UL << 12)
#define RTEMS_RTL_TRACE_DEPENDENCY (1UL << 13)
#define RTEMS_RTL_TRACE_ALL (0xffffffffUL & ~(RTEMS_RTL_TRACE_CACHE))
#define RTEMS_RTL_TRACE_ARCHIVE_SYMS (1UL << 13)
#define RTEMS_RTL_TRACE_DEPENDENCY (1UL << 14)
#define RTEMS_RTL_TRACE_ALL (0xffffffffUL & ~(RTEMS_RTL_TRACE_CACHE | \
RTEMS_RTL_TRACE_GLOBAL_SYM | \
RTEMS_RTL_TRACE_ARCHIVE_SYMS))
/**
* Call to check if this part is bring traced. If RTEMS_RTL_TRACE is defined to

View File

@@ -53,6 +53,7 @@
#define _RTEMS_RTL_UNRESOLVED_H_
#include <rtems.h>
#include <rtems/chain.h>
#include "rtl-obj-fwd.h"
#ifdef __cplusplus
@@ -79,6 +80,8 @@ typedef enum rtems_rtl_unresolved_rtype
* Unresolved external symbol flags.
*/
#define RTEMS_RTL_UNRESOLV_SYM_SEARCH_ARCHIVE (1 << 0) /**< Search the archive. */
#define RTEMS_RTL_UNRESOLV_SYM_HAS_ERROR (1 << 1) /**< The symbol load
* has an error. */
/**
* Unresolved externals symbols. The symbols are reference counted and separate
@@ -93,7 +96,7 @@ typedef struct rtems_rtl_unresolv_symbol
uint16_t refs; /**< The number of references to this name. */
uint16_t flags; /**< Flags to manage the symbol. */
uint16_t length; /**< The length of this name. */
const char name[10]; /**< The symbol name. */
const char name[]; /**< The symbol name. */
} rtems_rtl_unresolv_symbol;
/**
@@ -117,7 +120,7 @@ typedef struct rtems_rtl_unresolv_rec
rtems_rtl_unresolved_rtype type;
union
{
rtems_rtl_unresolv_symbol name; /**< The symnbol, or */
rtems_rtl_unresolv_symbol name; /**< The symbol, or */
rtems_rtl_unresolv_reloc reloc; /**< the relocation record. */
} rec;
} rtems_rtl_unresolv_rec;
@@ -127,9 +130,9 @@ typedef struct rtems_rtl_unresolv_rec
*/
typedef struct rtems_rtl_unresolv_block
{
rtems_chain_node link; /**< Blocks are chained. */
uint32_t recs; /**< The number of records in the block. */
rtems_rtl_unresolv_rec rec; /**< The records. More follow. */
rtems_chain_node link; /**< Blocks are chained. */
uint32_t recs; /**< The number of records in the block. */
rtems_rtl_unresolv_rec rec[]; /**< The records. More follow. */
} rtems_rtl_unresolv_block;
/**

View File

@@ -137,6 +137,15 @@ rtems_rtl_data* rtems_rtl_data_unprotected (void);
*/
rtems_rtl_symbols* rtems_rtl_global_symbols (void);
/**
* Get the RTL last error string with out locking. This call assumes the RTL is
* locked.
*
* @return const char* The RTL's laste error.
* @retval NULL The RTL data is not initialised.
*/
const char* rtems_rtl_last_error_unprotected (void);
/**
* Get the RTL objects table with out locking. This call assumes the RTL
* is locked.

View File

@@ -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 ();

View File

@@ -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)
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 a duplicate forget it.
*/
if (rtems_rtl_symbol_global_find (name))
continue;
if ((ELF_ST_BIND (symbol.st_info) == STB_GLOBAL) ||
(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))
{
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);
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;
/*
* 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]);
/*
* Caculate the size of sections' name.
*/
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;
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;

View File

@@ -21,6 +21,12 @@
#include <rtems/rtl/rtl-trace.h>
#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",

View File

@@ -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;

View File

@@ -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);
}
uint32_t
rtems_rtl_obj_eh_alignment (const rtems_rtl_obj* obj)
{
return rtems_rtl_obj_section_alignment (obj, RTEMS_RTL_OBJ_SECT_EH);
}
size_t
rtems_rtl_obj_eh_size (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_CONST;
return rtems_rtl_obj_section_size (obj, flags);
}
uint32_t
rtems_rtl_obj_const_alignment (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_CONST;
return rtems_rtl_obj_section_alignment (obj, flags);
}
uint32_t
rtems_rtl_obj_eh_alignment (const rtems_rtl_obj* obj)
{
const uint32_t flags = RTEMS_RTL_OBJ_SECT_LOAD | RTEMS_RTL_OBJ_SECT_EH;
return rtems_rtl_obj_section_alignment (obj, flags);
}
size_t
rtems_rtl_obj_eh_size (const rtems_rtl_obj* obj)
{
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

View File

@@ -128,17 +128,6 @@ typedef struct
bool base; /**< Include the base object file. */
} 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.
*/
@@ -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);
}

View File

@@ -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;
}
/**
* Name management iterator data.
*/
typedef struct
{
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;
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)
{
if ((rec->rec.name.length == nd->length)
&& (strcmp (rec->rec.name.name, nd->name) == 0))
{
++rec->rec.name.refs;
return true;
}
++nd->index;
}
return false;
}
static int
rtems_rtl_unresolved_find_name (rtems_rtl_unresolved* unresolved,
const char* name,
bool update_refcount)
rtems_rtl_unresolved_find_name (const char* name)
{
size_t length = strlen (name) + 1;
int index = 1;
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;
}
rtems_chain_node* node = rtems_chain_first (&unresolved->blocks);
while (!rtems_chain_is_tail (&unresolved->blocks, node))
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)
{
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->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);
}
node = rtems_chain_next (node);
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.
* Is the name present?
*/
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);
}
name_index = rtems_rtl_unresolved_find_name (name);
/*
* No blocks with any spare records, allocate a new block.
*/
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);
/*
* 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))
{
name_block = rtems_rtl_unresolved_block_alloc (unresolved);
if (!name_block)
return false;
}
rec = rtems_rtl_unresolved_rec_first_free (name_block);
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);
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.
*/
if ((block == name_block) && (block->recs >= unresolved->block_recs))
block = rtems_rtl_unresolved_alloc_recs (unresolved, name_recs);
if (block == NULL)
{
block = rtems_rtl_unresolved_block_alloc (unresolved);
if (!block)
return false;
}
/*
* 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);
block->recs += name_recs;
/*
* Find the name index for the name and then reindex the names which
* are moved up because of the insertion.
*/
name_index = rtems_rtl_unresolved_find_index (rec);
if (name_index < 0)
{
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);
@@ -661,13 +723,6 @@ rtems_rtl_unresolved_dump_iterator (rtems_rtl_unresolv_rec* rec,
return false;
}
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)
{
@@ -675,3 +730,10 @@ rtems_rtl_unresolved_dump (void)
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);
}

View File

@@ -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)
{

View File

@@ -576,16 +576,19 @@ dl08-o5.o: dl08/dl-o5.c Makefile
$(AM_V_CC)$(COMPILE) -c -o $@ $<
dl08-o6-123456789-123456789.o: dl08/dl-o6-123456789-123456789.c Makefile
$(AM_V_CC)$(COMPILE) -c -o $@ $<
# echo "#" > etc/rtl-libs.conf
# echo " # blah blah" >> etc/rtl-libs.conf
etc/rtl-libs.conf:
etc/libdl.conf:
mkdir etc; \
echo "/libdl08*.a" >> etc/rtl-libs.conf
echo "#" > etc/libdl.conf
echo " # blah blah" >> etc/libdl.conf
echo "/libdl08*.a" >> etc/libdl.conf
echo "" >> etc/libdl.conf
echo "x" >> etc/libdl.conf
echo "" >> etc/libdl.conf
noinst_LIBRARIES = libdl08_1.a libdl08_2.a
libdl08_1_a_SOURCES = dl08-o2.c dl08-o4.c
libdl08_2_a_SOURCES = dl08-o3.c dl08-o5.c \
dl08-o6-123456789-123456789.c
dl08.tar: etc/rtl-libs.conf dl08-o1.o libdl08_1.a libdl08_2.a
dl08.tar: etc/libdl.conf dl08-o1.o libdl08_1.a libdl08_2.a
@rm -f $@
$(AM_V_GEN)$(PAX) -w -f $@ $+
dl08-tar.c: dl08.tar
@@ -601,7 +604,7 @@ dl08$(EXEEXT): $(dl08_OBJECTS) $(dl08_DEPENDENCIES) dl08-sym.o
$(AM_V_CCLD)$(LINK.c) $(CPU_CFLAGS) $(AM_CFLAGS) $(AM_LDFLAGS) -o $@ $+
CLEANFILES += dl08.pre dl08-sym.o libdl08_1.a libdl08_2.a dl08-o1.o dl08-o2.o \
dl08-o3.o dl08-o4.o dl08-o5.o dl08-o6-123456789-123456789.o \
dl08.tar dl08-tar.h etc/rtl-libs.conf
dl08.tar dl08-tar.h etc/libdl.conf
endif
endif

View File

@@ -15,11 +15,13 @@
RTEMS_RTL_TRACE_UNLOAD | \
RTEMS_RTL_TRACE_SYMBOL | \
RTEMS_RTL_TRACE_RELOC | \
RTEMS_RTL_TRACE_LOAD_SECT | \
RTEMS_RTL_TRACE_ALLOCATOR | \
RTEMS_RTL_TRACE_UNRESOLVED | \
RTEMS_RTL_TRACE_ARCHIVES | \
RTEMS_RTL_TRACE_DEPENDENCY)
#define DL_DEBUG_TRACE DEBUG_TRACE /* RTEMS_RTL_TRACE_ALL */
/* RTEMS_RTL_TRACE_ALL */
#define DL_DEBUG_TRACE DEBUG_TRACE
#define DL_RTL_CMDS 1
#else
#define DL_DEBUG_TRACE 0

View File

@@ -99,7 +99,7 @@ static void dl_check_resolved(void* handle, bool has_unresolved)
handle, unresolved != 0 ? "" : "no ");
}
static void* dl_load_obj(const char* name, bool has_unresolved)
static void* dl_load_obj (const char* name, bool has_unresolved)
{
void* handle;
@@ -184,11 +184,17 @@ int dl_load_test(void)
dl_load_dump ();
/*
* Check for any resolved externals.
*/
printf ("Check is any unresolved externals exist:\n");
dl_check_resolved (RTLD_SELF, false);
printf ("Running rtems_main_o1:\n");
if (dl_call (o[0].handle, "rtems_main_o1"))
return 1;
for (i = 0; i < NUMOF(od); ++i)
for (i = 0; i < NUMOF (od); ++i)
dl_object_close (&o[i]);
return 0;

View File

@@ -7,6 +7,7 @@
*/
#include "dl-load.h"
#include "dl-o4.h"
#include "dl-o5.h"
#include <inttypes.h>