summaryrefslogtreecommitdiffstats
path: root/cpukit/libdl
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2018-11-20 14:56:11 +1100
committerChris Johns <chrisj@rtems.org>2018-11-22 12:43:31 +1100
commit03139d5b1cf95d5b2f699e8f56e1f0ba2d7f89e4 (patch)
tree33fd489eac7497cdebe61560bc43e613b3eef0a9 /cpukit/libdl
parentlibdl: Reindex unresolved names after removing used records. (diff)
downloadrtems-03139d5b1cf95d5b2f699e8f56e1f0ba2d7f89e4.tar.bz2
libdl: Add object file dependencies to track references
Tracking references lets us manage when an object file can be unloaded. If an object file has references to it, it cannot be unloaded. Modules that depend on each other cannot be unloaded. Updates #3605
Diffstat (limited to 'cpukit/libdl')
-rw-r--r--cpukit/libdl/rtl-elf.c346
-rw-r--r--cpukit/libdl/rtl-elf.h22
-rw-r--r--cpukit/libdl/rtl-obj.c141
-rw-r--r--cpukit/libdl/rtl-shell.c54
-rw-r--r--cpukit/libdl/rtl-unresolved.c4
-rw-r--r--cpukit/libdl/rtl.c48
6 files changed, 491 insertions, 124 deletions
diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c
index c1821bcfda..762130b9e7 100644
--- a/cpukit/libdl/rtl-elf.c
+++ b/cpukit/libdl/rtl-elf.c
@@ -64,31 +64,40 @@ rtems_rtl_elf_machine_check (Elf_Ehdr* ehdr)
return true;
}
-bool
-rtems_rtl_elf_find_symbol (rtems_rtl_obj* obj,
- const Elf_Sym* sym,
- const char* symname,
- Elf_Word* value)
+static bool
+rtems_rtl_elf_find_symbol (rtems_rtl_obj* obj,
+ const Elf_Sym* sym,
+ const char* symname,
+ rtems_rtl_obj_sym** symbol,
+ Elf_Word* value)
{
rtems_rtl_obj_sect* sect;
- if (ELF_ST_TYPE(sym->st_info) == STT_NOTYPE ||
- sym->st_shndx == SHN_COMMON)
+ /*
+ * If the symbol type is STT_NOTYPE the symbol references a global
+ * symbol. The gobal symbol table is searched to find it and that value
+ * returned. If the symbol is local to the object module the section for the
+ * symbol is located and it's base added to the symbol's value giving an
+ * absolute location.
+ */
+ if (ELF_ST_TYPE(sym->st_info) == STT_NOTYPE || sym->st_shndx == SHN_COMMON)
{
/*
* Search the object file then the global table for the symbol.
*/
- rtems_rtl_obj_sym* symbol = rtems_rtl_symbol_obj_find (obj, symname);
- if (!symbol)
+ *symbol = rtems_rtl_symbol_obj_find (obj, symname);
+ if (!*symbol)
{
rtems_rtl_set_error (EINVAL, "global symbol not found: %s", symname);
return false;
}
- *value = (Elf_Addr) symbol->value;
+ *value = (Elf_Addr) (*symbol)->value;
return true;
}
+ *symbol = NULL;
+
sect = rtems_rtl_obj_find_section_by_index (obj, sym->st_shndx);
if (!sect)
{
@@ -100,11 +109,161 @@ rtems_rtl_elf_find_symbol (rtems_rtl_obj* obj,
return true;
}
+/**
+ * Relocation worker routine.
+ */
+typedef bool (*rtems_rtl_elf_reloc_handler)(rtems_rtl_obj* obj,
+ bool is_rela,
+ void* relbuf,
+ rtems_rtl_obj_sect* targetsect,
+ rtems_rtl_obj_sym* symbol,
+ Elf_Sym* sym,
+ const char* symname,
+ Elf_Word symvalue,
+ bool resolved,
+ void* data);
+
+/**
+ * Relocation parser data.
+ */
+typedef struct
+{
+ size_t dependents; /**< The number of dependent object files. */
+ size_t unresolved; /**< The number of unresolved symbols. */
+} rtems_rtl_elf_reloc_data;
+
+static bool
+rtems_rtl_elf_reloc_parser (rtems_rtl_obj* obj,
+ bool is_rela,
+ void* relbuf,
+ rtems_rtl_obj_sect* targetsect,
+ rtems_rtl_obj_sym* symbol,
+ Elf_Sym* sym,
+ const char* symname,
+ Elf_Word symvalue,
+ bool resolved,
+ void* data)
+{
+ rtems_rtl_elf_reloc_data* rd = (rtems_rtl_elf_reloc_data*) data;
+ /*
+ * 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.
+ */
+ if (!resolved)
+ {
+ ++rd->unresolved;
+ }
+ else if (resolved && symname != NULL)
+ {
+ /*
+ * 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.
+ */
+ rtems_rtl_obj* sobj = rtems_rtl_find_obj_with_symbol (symbol);
+ if (sobj != NULL)
+ {
+ /*
+ * 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;
+}
+
+static bool
+rtems_rtl_elf_reloc_relocator (rtems_rtl_obj* obj,
+ bool is_rela,
+ void* relbuf,
+ rtems_rtl_obj_sect* targetsect,
+ rtems_rtl_obj_sym* symbol,
+ Elf_Sym* sym,
+ const char* symname,
+ Elf_Word symvalue,
+ bool resolved,
+ void* data)
+{
+ const Elf_Rela* rela = (const Elf_Rela*) relbuf;
+ const Elf_Rel* rel = (const Elf_Rel*) relbuf;
+
+ if (!resolved)
+ {
+ uint16_t flags = 0;
+ rtems_rtl_word rel_words[3];
+
+ if (is_rela)
+ {
+ flags = 1;
+ rel_words[REL_R_OFFSET] = rela->r_offset;
+ rel_words[REL_R_INFO] = rela->r_info;
+ rel_words[REL_R_ADDEND] = rela->r_addend;
+ }
+ else
+ {
+ rel_words[REL_R_OFFSET] = rel->r_offset;
+ rel_words[REL_R_INFO] = rel->r_info;
+ rel_words[REL_R_ADDEND] = 0;
+ }
+
+ if (!rtems_rtl_unresolved_add (obj,
+ flags,
+ symname,
+ targetsect->section,
+ rel_words))
+ return false;
+
+ ++obj->unresolved;
+ }
+ else
+ {
+ rtems_rtl_obj* sobj;
+
+ if (is_rela)
+ {
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+ printf ("rtl: rela: 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 (obj, rela, targetsect,
+ symname, sym->st_info, symvalue))
+ return false;
+ }
+ else
+ {
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+ printf ("rtl: rel: 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 (obj, rel, targetsect,
+ symname, sym->st_info, symvalue))
+ return false;
+ }
+
+ sobj = rtems_rtl_find_obj_with_symbol (symbol);
+ if (sobj != NULL)
+ {
+ if (rtems_rtl_obj_add_dependent (obj, sobj))
+ rtems_rtl_obj_inc_reference (sobj);
+ }
+ }
+
+ return true;
+}
+
static bool
-rtems_rtl_elf_relocator (rtems_rtl_obj* obj,
- int fd,
- rtems_rtl_obj_sect* sect,
- void* data)
+rtems_rtl_elf_relocate_worker (rtems_rtl_obj* obj,
+ int fd,
+ rtems_rtl_obj_sect* sect,
+ rtems_rtl_elf_reloc_handler handler,
+ void* data)
{
rtems_rtl_obj_cache* symbols;
rtems_rtl_obj_cache* strings;
@@ -155,15 +314,16 @@ rtems_rtl_elf_relocator (rtems_rtl_obj* obj,
for (reloc = 0; reloc < (sect->size / reloc_size); ++reloc)
{
- uint8_t relbuf[reloc_size];
- const Elf_Rela* rela = (const Elf_Rela*) relbuf;
- const Elf_Rel* rel = (const Elf_Rel*) relbuf;
- Elf_Sym sym;
- const char* symname = NULL;
- off_t off;
- Elf_Word type;
- Elf_Word symvalue = 0;
- bool relocate;
+ uint8_t relbuf[reloc_size];
+ const Elf_Rela* rela = (const Elf_Rela*) relbuf;
+ const Elf_Rel* rel = (const Elf_Rel*) relbuf;
+ rtems_rtl_obj_sym* symbol = NULL;
+ Elf_Sym sym;
+ const char* symname = NULL;
+ off_t off;
+ Elf_Word rel_type;
+ Elf_Word symvalue = 0;
+ bool resolved;
off = obj->ooffset + sect->offset + (reloc * reloc_size);
@@ -203,75 +363,26 @@ rtems_rtl_elf_relocator (rtems_rtl_obj* obj,
/*
* See if the record references an external symbol. If it does find the
* symbol value. If the symbol cannot be found flag the object file as
- * having unresolved externals and store the externals. The load of an
+ * having unresolved externals and store the external. The load of an
* object after this one may provide the unresolved externals.
*/
if (is_rela)
- type = ELF_R_TYPE(rela->r_info);
+ rel_type = ELF_R_TYPE(rela->r_info);
else
- type = ELF_R_TYPE(rel->r_info);
-
- relocate = true;
-
- if (rtems_rtl_elf_rel_resolve_sym (type))
- {
- if (!rtems_rtl_elf_find_symbol (obj, &sym, symname, &symvalue))
- {
- uint16_t flags = 0;
- rtems_rtl_word rel_words[3];
-
- relocate = false;
-
- if (is_rela)
- {
- flags = 1;
- rel_words[REL_R_OFFSET] = rela->r_offset;
- rel_words[REL_R_INFO] = rela->r_info;
- rel_words[REL_R_ADDEND] = rela->r_addend;
- }
- else
- {
- rel_words[REL_R_OFFSET] = rel->r_offset;
- rel_words[REL_R_INFO] = rel->r_info;
- rel_words[REL_R_ADDEND] = 0;
- }
+ rel_type = ELF_R_TYPE(rel->r_info);
- if (!rtems_rtl_unresolved_add (obj,
- flags,
- symname,
- targetsect->section,
- rel_words))
- return false;
+ resolved = true;
- ++obj->unresolved;
- }
- }
+ if (rtems_rtl_elf_rel_resolve_sym (rel_type))
+ resolved = rtems_rtl_elf_find_symbol (obj,
+ &sym, symname,
+ &symbol, &symvalue);
- if (relocate)
- {
- if (is_rela)
- {
- if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
- printf ("rtl: rela: 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 (obj, rela, targetsect,
- symname, sym.st_info, symvalue))
- return false;
- }
- else
- {
- if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
- printf ("rtl: rel: 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 (obj, rel, targetsect,
- symname, sym.st_info, symvalue))
- return false;
- }
- }
+ if (!handler (obj,
+ is_rela, relbuf, targetsect,
+ symbol, &sym, symname, symvalue, resolved,
+ data))
+ return false;
}
/*
@@ -283,6 +394,28 @@ rtems_rtl_elf_relocator (rtems_rtl_obj* obj,
return true;
}
+static bool
+rtems_rtl_elf_relocs_parser (rtems_rtl_obj* obj,
+ int fd,
+ rtems_rtl_obj_sect* sect,
+ void* data)
+{
+ bool r = rtems_rtl_elf_relocate_worker (obj, fd, sect,
+ rtems_rtl_elf_reloc_parser, data);
+ rtems_rtl_obj_update_flags (RTEMS_RTL_OBJ_RELOC_TAG, 0);
+ return r;
+}
+
+static bool
+rtems_rtl_elf_relocs_locator (rtems_rtl_obj* obj,
+ int fd,
+ rtems_rtl_obj_sect* sect,
+ void* data)
+{
+ return rtems_rtl_elf_relocate_worker (obj, fd, sect,
+ rtems_rtl_elf_reloc_relocator, data);
+}
+
bool
rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc* reloc,
rtems_rtl_obj_sym* sym)
@@ -290,8 +423,9 @@ rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc* reloc,
rtems_rtl_obj_sect* sect;
bool is_rela;
Elf_Word symvalue;
+ rtems_rtl_obj* sobj;
- is_rela =reloc->flags & 1;
+ is_rela = reloc->flags & 1;
sect = rtems_rtl_obj_find_section_by_index (reloc->obj, reloc->sect);
if (!sect)
@@ -329,13 +463,20 @@ rtems_rtl_obj_relocate_unresolved (rtems_rtl_unresolv_reloc* reloc,
return false;
}
- if (reloc->obj->unresolved)
+ if (reloc->obj->unresolved > 0)
{
--reloc->obj->unresolved;
- if (!reloc->obj->unresolved)
+ if (reloc->obj->unresolved == 0)
reloc->obj->flags &= ~RTEMS_RTL_OBJ_UNRESOLVED;
}
+ sobj = rtems_rtl_find_obj_with_symbol (sym);
+ if (sobj != NULL)
+ {
+ if (rtems_rtl_obj_add_dependent (reloc->obj, sobj))
+ rtems_rtl_obj_inc_reference (sobj);
+ }
+
return true;
}
@@ -402,6 +543,24 @@ rtems_rtl_elf_common (rtems_rtl_obj* obj,
}
static bool
+rtems_rtl_elf_dependents (rtems_rtl_obj* obj, rtems_rtl_elf_reloc_data* reloc)
+{
+ /*
+ * If there are dependencies and no unresolved externals allocate and size
+ * the dependency table to the number of dependent object files. If there are
+ * unresolved externals the number of dependencies is unknown at this point
+ * in time so use dynamic allocation to allocate the block size number of
+ * entries when the entries are added.
+ */
+ if (reloc->dependents > 0 && reloc->unresolved == 0)
+ {
+ if (!rtems_rtl_obj_alloc_dependents (obj, reloc->dependents))
+ return false;
+ }
+ return true;
+}
+
+static bool
rtems_rtl_elf_symbols (rtems_rtl_obj* obj,
int fd,
rtems_rtl_obj_sect* sect,
@@ -1024,7 +1183,8 @@ rtems_rtl_elf_file_load (rtems_rtl_obj* obj, int fd)
{
rtems_rtl_obj_cache* header;
Elf_Ehdr ehdr;
- rtems_rtl_elf_common_data common = { .size = 0, .alignment = 0 };
+ rtems_rtl_elf_reloc_data relocs = { 0 };
+ rtems_rtl_elf_common_data common = { 0 };
rtems_rtl_obj_caches (&header, NULL, NULL);
@@ -1102,10 +1262,16 @@ rtems_rtl_elf_file_load (rtems_rtl_obj* obj, int fd)
if (!rtems_rtl_obj_load_sections (obj, fd, rtems_rtl_elf_loader, &ehdr))
return false;
+ if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocs_parser, &relocs))
+ return false;
+
+ if (!rtems_rtl_elf_dependents (obj, &relocs))
+ return false;
+
if (!rtems_rtl_obj_load_symbols (obj, fd, rtems_rtl_elf_symbols, &ehdr))
return false;
- if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocator, &ehdr))
+ if (!rtems_rtl_obj_relocate (obj, fd, rtems_rtl_elf_relocs_locator, &ehdr))
return false;
rtems_rtl_obj_synchronize_cache (obj);
diff --git a/cpukit/libdl/rtl-elf.h b/cpukit/libdl/rtl-elf.h
index 5d560a0b34..1f5f82eb89 100644
--- a/cpukit/libdl/rtl-elf.h
+++ b/cpukit/libdl/rtl-elf.h
@@ -123,28 +123,6 @@ bool rtems_rtl_elf_relocate_rela (const rtems_rtl_obj* obj,
const Elf_Word symvalue);
/**
- * Find the symbol. The symbol is passed as an ELF type symbol with the name
- * and the value returned is the absolute address of the symbol.
- *
- * If the symbol type is STT_NOTYPE the symbol references a global symbol. The
- * gobal symbol table is searched to find it and that value returned. If the
- * symbol is local to the object module the section for the symbol is located
- * and it's base added to the symbol's value giving an absolute location.
- *
- * @param obj The object the symbol is being resolved for.
- * @param sym The ELF type symbol.
- * @param symname The sym's name read from the symbol string table.
- * @param value Return the value of the symbol. Only valid if the return value
- * is true.
- * @retval true The symbol resolved.
- * @retval false The symbol could not be result. The RTL error is set.
- */
-bool rtems_rtl_elf_find_symbol (rtems_rtl_obj* obj,
- const Elf_Sym* sym,
- const char* symname,
- Elf_Word* value);
-
-/**
* The ELF format check handler.
*
* @param obj The object being checked.
diff --git a/cpukit/libdl/rtl-obj.c b/cpukit/libdl/rtl-obj.c
index 7109b86fe8..0f58bf9bda 100644
--- a/cpukit/libdl/rtl-obj.c
+++ b/cpukit/libdl/rtl-obj.c
@@ -83,6 +83,7 @@ rtems_rtl_obj_alloc (void)
* Initialise the chains.
*/
rtems_chain_initialize_empty (&obj->sections);
+ rtems_chain_initialize_empty (&obj->dependents);
/*
* No valid format.
*/
@@ -114,6 +115,8 @@ rtems_rtl_obj_free (rtems_rtl_obj* obj)
rtems_chain_extract (&obj->link);
rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base, &obj->eh_base,
&obj->data_base, &obj->bss_base);
+ rtems_rtl_obj_erase_sections (obj);
+ rtems_rtl_obj_erase_dependents (obj);
rtems_rtl_symbol_obj_erase (obj);
rtems_rtl_obj_free_names (obj);
if (obj->sec_num)
@@ -550,6 +553,110 @@ rtems_rtl_obj_find_section_by_mask (const rtems_rtl_obj* obj,
return match.sect;
}
+bool
+rtems_rtl_obj_alloc_dependents (rtems_rtl_obj* obj, size_t dependents)
+{
+ rtems_rtl_obj_depends* depends;
+ size_t size;
+
+ size = sizeof (rtems_rtl_obj_depends) + sizeof (rtems_rtl_obj*) * dependents;
+
+ depends = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT,
+ size,
+ true);
+ if (depends == NULL)
+ {
+ rtems_rtl_set_error (ENOMEM, "no memory for the dependency");
+ }
+ else
+ {
+ depends->dependents = dependents;
+ rtems_chain_append (&obj->dependents, &depends->node);
+ }
+
+ return depends != NULL;
+}
+
+void
+rtems_rtl_obj_erase_dependents (rtems_rtl_obj* obj)
+{
+ rtems_chain_node* node = rtems_chain_first (&obj->dependents);
+ while (!rtems_chain_is_tail (&obj->dependents, node))
+ {
+ rtems_rtl_obj_depends* depends = (rtems_rtl_obj_depends*) node;
+ rtems_chain_node* next_node = rtems_chain_next (node);
+ rtems_chain_extract (node);
+ rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, depends);
+ node = next_node;
+ }
+}
+
+bool
+rtems_rtl_obj_add_dependent (rtems_rtl_obj* obj, rtems_rtl_obj* dependent)
+{
+ rtems_rtl_obj** free_slot;
+ rtems_chain_node* node;
+ if (obj == dependent || dependent == rtems_rtl_baseimage ())
+ return false;
+ free_slot = NULL;
+ node = rtems_chain_first (&obj->dependents);
+ while (!rtems_chain_is_tail (&obj->dependents, node))
+ {
+ rtems_rtl_obj_depends* depends = (rtems_rtl_obj_depends*) node;
+ size_t d;
+ for (d = 0; d < depends->dependents; ++d)
+ {
+ if (free_slot == NULL && depends->depends[d] == NULL)
+ free_slot = &(depends->depends[d]);
+ if (depends->depends[d] == dependent)
+ return false;
+ }
+ node = rtems_chain_next (node);
+ }
+ if (free_slot == NULL)
+ {
+ if (rtems_rtl_obj_alloc_dependents (obj,
+ RTEMS_RTL_DEPENDENCY_BLOCK_SIZE))
+ {
+ rtems_rtl_obj_depends* depends;
+ node = rtems_chain_last (&obj->dependents);
+ depends = (rtems_rtl_obj_depends*) node;
+ free_slot = &(depends->depends[0]);
+ if (*free_slot != NULL)
+ {
+ rtems_rtl_set_error (EINVAL, "new dependency node not empty");
+ free_slot = NULL;
+ }
+ }
+ }
+ if (free_slot != NULL)
+ *free_slot = dependent;
+ return free_slot != NULL;
+}
+
+bool
+rtems_rtl_obj_iterate_dependents (rtems_rtl_obj* obj,
+ rtems_rtl_obj_depends_iterator iterator,
+ void* data)
+{
+ rtems_chain_node* node = rtems_chain_first (&obj->dependents);
+ while (!rtems_chain_is_tail (&obj->dependents, node))
+ {
+ rtems_rtl_obj_depends* depends = (rtems_rtl_obj_depends*) node;
+ size_t d;
+ for (d = 0; d < depends->dependents; ++d)
+ {
+ if (depends->depends[d])
+ {
+ if (iterator (obj, depends->depends[d], data))
+ return true;
+ }
+ }
+ node = rtems_chain_next (node);
+ }
+ return false;
+}
+
size_t
rtems_rtl_obj_text_size (const rtems_rtl_obj* obj)
{
@@ -1220,10 +1327,42 @@ static bool
rtems_rtl_obj_file_unload (rtems_rtl_obj* obj)
{
if (obj->format >= 0 && obj->format < RTEMS_RTL_LOADERS)
- return loaders[obj->format].unload (obj);
+ {
+ rtems_chain_node* node;
+
+ if (!loaders[obj->format].unload (obj))
+ return false;
+
+ node = rtems_chain_first (&obj->dependents);
+ while (!rtems_chain_is_tail (&obj->dependents, node))
+ {
+ rtems_rtl_obj_depends* depends = (rtems_rtl_obj_depends*) node;
+ size_t d;
+ for (d = 0; d < depends->dependents; ++d)
+ {
+ if (depends->depends[d] != NULL)
+ rtems_rtl_obj_dec_reference (depends->depends[d]);
+ }
+ node = rtems_chain_next (node);
+ }
+ }
+
return false;
}
+void
+rtems_rtl_obj_inc_reference (rtems_rtl_obj* obj)
+{
+ ++obj->refs;
+}
+
+void
+rtems_rtl_obj_dec_reference (rtems_rtl_obj* obj)
+{
+ if (obj->refs)
+ --obj->refs;
+}
+
bool
rtems_rtl_obj_load (rtems_rtl_obj* obj)
{
diff --git a/cpukit/libdl/rtl-shell.c b/cpukit/libdl/rtl-shell.c
index 5c144977a0..f3471d8d8e 100644
--- a/cpukit/libdl/rtl-shell.c
+++ b/cpukit/libdl/rtl-shell.c
@@ -117,13 +117,14 @@ rtems_rtl_shell_status (rtems_rtl_data* rtl, int argc, char *argv[])
*/
typedef struct
{
- rtems_rtl_data* rtl; /**< The RTL data. */
- int indent; /**< Spaces to indent. */
- bool oname; /**< Print object names. */
- bool names; /**< Print details of all names. */
- bool memory_map; /**< Print the memory map. */
- bool symbols; /**< Print the global symbols. */
- bool base; /**< Include the base object file. */
+ rtems_rtl_data* rtl; /**< The RTL data. */
+ int indent; /**< Spaces to indent. */
+ bool oname; /**< Print object names. */
+ bool names; /**< Print details of all names. */
+ bool memory_map; /**< Print the memory map. */
+ bool symbols; /**< Print the global symbols. */
+ bool dependencies; /**< Print any dependencies. */
+ bool base; /**< Include the base object file. */
} rtems_rtl_obj_print;
/**
@@ -169,6 +170,29 @@ rtems_rtl_symbols_arg (int argc, char *argv[])
}
/**
+ * Dependenncies printer.
+ */
+typedef struct
+{
+ bool first; /**< Is this the first line printed. */
+ size_t indent; /**< The indent. */
+} rtems_rtl_dep_data;
+
+static bool
+rtems_rtl_dependencies (rtems_rtl_obj* obj,
+ rtems_rtl_obj* dependent,
+ void* data)
+{
+ rtems_rtl_dep_data* dd = (rtems_rtl_dep_data*) data;
+ if (!dd->first)
+ printf ("\n%-*c: ", dd->indent, ' ');
+ else
+ dd->first = false;
+ printf ("%s", dependent->oname);
+ return false;
+}
+
+/**
* Object printer.
*/
static bool
@@ -214,7 +238,9 @@ rtems_rtl_obj_printer (rtems_rtl_obj_print* print, rtems_rtl_obj* obj)
printf ("%-*cbss base : %p (%zi)\n", print->indent, ' ',
obj->bss_base, obj->bss_size);
}
- printf ("%-*cunresolved : %" PRIu32 "\n", print->indent, ' ', obj->unresolved);
+ printf ("%-*cunresolved : %zu\n", print->indent, ' ', obj->unresolved);
+ printf ("%-*cusers : %zu\n", print->indent, ' ', obj->users);
+ printf ("%-*creferences : %zu\n", print->indent, ' ', obj->refs);
printf ("%-*csymbols : %zi\n", print->indent, ' ', obj->global_syms);
printf ("%-*csymbol memory : %zi\n", print->indent, ' ', obj->global_size);
if (print->symbols)
@@ -231,6 +257,16 @@ rtems_rtl_obj_printer (rtems_rtl_obj_print* print, rtems_rtl_obj* obj)
printf ("%-*c%-*s = %p\n", print->indent + 2, ' ',
max_len, obj->global_table[s].name, obj->global_table[s].value);
}
+ if (print->dependencies)
+ {
+ rtems_rtl_dep_data dd = {
+ .first = true,
+ .indent = strlen ("dependencies :") + print->indent
+ };
+ printf ("%-*cdependencies : ", print->indent, ' ');
+ rtems_rtl_obj_iterate_dependents (obj, rtems_rtl_dependencies, &dd);
+ printf ("\n");
+ }
printf ("\n");
return true;
}
@@ -269,6 +305,7 @@ rtems_rtl_shell_list (rtems_rtl_data* rtl, int argc, char *argv[])
print.names = true;
print.memory_map = true;
print.symbols = rtems_rtl_symbols_arg (argc, argv);
+ print.dependencies = true;
print.base = false;
rtems_rtl_chain_iterate (&rtl->objects,
rtems_rtl_obj_print_iterator,
@@ -286,6 +323,7 @@ rtems_rtl_shell_sym (rtems_rtl_data* rtl, int argc, char *argv[])
print.names = false;
print.memory_map = false;
print.symbols = true;
+ print.dependencies = false;
print.base = rtems_rtl_base_arg (argc, argv);
rtems_rtl_chain_iterate (&rtl->objects,
rtems_rtl_obj_print_iterator,
diff --git a/cpukit/libdl/rtl-unresolved.c b/cpukit/libdl/rtl-unresolved.c
index 4c0f6b3bf1..4992c3bb4a 100644
--- a/cpukit/libdl/rtl-unresolved.c
+++ b/cpukit/libdl/rtl-unresolved.c
@@ -171,7 +171,7 @@ rtems_rtl_unresolved_resolve_reloc (rtems_rtl_unresolv_rec* rec,
rtems_rtl_unresolved_reloc_data* rd;
rd = (rtems_rtl_unresolved_reloc_data*) data;
- if (rec->rec.reloc.name == rd->name)
+ if (rec->rec.reloc.name == rd->name && rec->rec.reloc.obj != NULL)
{
if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNRESOLVED))
printf ("rtl: unresolv: resolve reloc: %s\n", rd->name_rec->rec.name.name);
@@ -185,7 +185,7 @@ rtems_rtl_unresolved_resolve_reloc (rtems_rtl_unresolv_rec* rec,
* names with a reference count of 0.
*/
rec->rec.reloc.obj = NULL;
- if (rd->name_rec && rd->name_rec->rec.name.refs)
+ if (rd->name_rec != NULL && rd->name_rec->rec.name.refs > 0)
--rd->name_rec->rec.name.refs;
}
}
diff --git a/cpukit/libdl/rtl.c b/cpukit/libdl/rtl.c
index 628fc771bc..fdf4c1229f 100644
--- a/cpukit/libdl/rtl.c
+++ b/cpukit/libdl/rtl.c
@@ -216,6 +216,11 @@ rtems_rtl_data_init (void)
*/
rtl->base->oname = rtems_rtl_strdup ("rtems-kernel");
+ /*
+ * Lock the base image and flag it as the base image.
+ */
+ rtl->base->flags |= RTEMS_RTL_OBJ_LOCKED | RTEMS_RTL_OBJ_BASE;
+
rtems_chain_append (&rtl->objects, &rtl->base->link);
}
@@ -312,6 +317,21 @@ rtems_rtl_obj_decompress (rtems_rtl_obj_comp** decomp,
}
}
+void
+rtems_rtl_obj_update_flags (uint32_t clear, uint32_t set)
+{
+ rtems_chain_node* node = rtems_chain_first (&rtl->objects);
+ while (!rtems_chain_is_tail (&rtl->objects, node))
+ {
+ rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
+ if (clear != 0)
+ obj->flags &= ~clear;
+ if (set != 0)
+ obj->flags |= set;
+ node = rtems_chain_next (node);
+ }
+}
+
rtems_rtl_data*
rtems_rtl_lock (void)
{
@@ -386,6 +406,21 @@ rtems_rtl_find_obj (const char* name)
}
rtems_rtl_obj*
+rtems_rtl_find_obj_with_symbol (const rtems_rtl_obj_sym* sym)
+{
+ rtems_chain_node* node = rtems_chain_first (&rtl->objects);
+ while (!rtems_chain_is_tail (&rtl->objects, node))
+ {
+ rtems_rtl_obj* obj = (rtems_rtl_obj*) node;
+ if (sym >= obj->global_table &&
+ sym < (obj->global_table + obj->global_syms))
+ return obj;
+ node = rtems_chain_next (node);
+ }
+ return NULL;
+}
+
+rtems_rtl_obj*
rtems_rtl_load_object (const char* name, int mode)
{
rtems_rtl_obj* obj;
@@ -489,6 +524,11 @@ rtems_rtl_unload_object (rtems_rtl_obj* obj)
if (obj->users == 0)
{
+ if (obj->refs != 0)
+ {
+ rtems_rtl_set_error (EBUSY, "object file referenced");
+ return false;
+ }
obj->flags |= RTEMS_RTL_OBJ_LOCKED;
rtems_rtl_unlock ();
rtems_rtl_obj_run_dtors (obj);
@@ -618,5 +658,11 @@ rtems_rtl_base_sym_global_add (const unsigned char* esyms,
rtems_rtl_obj*
rtems_rtl_baseimage (void)
{
- return NULL;
+ rtems_rtl_obj* base = NULL;
+ if (rtems_rtl_lock ())
+ {
+ base = rtl->base;
+ rtems_rtl_unlock ();
+ }
+ return base;
}