From 4408603e27d028c5c735cf5d9d8160807ce1d591 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Wed, 9 Jan 2019 22:14:11 +1100 Subject: libdl: Fix the support for constructors and desctructors. - Fix the handling of pending objects. - Add a constructor flags in objects to track then being called. Closes #2921 --- cpukit/libdl/rtl-elf.c | 21 ++++++++++ cpukit/libdl/rtl-mdreloc-arm.c | 12 +++--- cpukit/libdl/rtl-unresolved.c | 4 +- cpukit/libdl/rtl.c | 93 +++++++++++++++++++++++++++--------------- 4 files changed, 91 insertions(+), 39 deletions(-) (limited to 'cpukit/libdl') diff --git a/cpukit/libdl/rtl-elf.c b/cpukit/libdl/rtl-elf.c index caa37e6bab..63242acaae 100644 --- a/cpukit/libdl/rtl-elf.c +++ b/cpukit/libdl/rtl-elf.c @@ -993,6 +993,24 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr) flags = RTEMS_RTL_OBJ_SECT_STR; break; + case SHT_INIT_ARRAY: + /* + * Constructors are text and need to be loaded. + */ + flags = (RTEMS_RTL_OBJ_SECT_CTOR | + RTEMS_RTL_OBJ_SECT_TEXT | + RTEMS_RTL_OBJ_SECT_LOAD); + break; + + case SHT_FINI_ARRAY: + /* + * Destructors are text and need to be loaded. + */ + flags = (RTEMS_RTL_OBJ_SECT_DTOR | + RTEMS_RTL_OBJ_SECT_TEXT | + RTEMS_RTL_OBJ_SECT_LOAD); + break; + default: /* * See if there are architecture specific flags? @@ -1019,6 +1037,9 @@ rtems_rtl_elf_parse_sections (rtems_rtl_obj* obj, int fd, Elf_Ehdr* ehdr) if ((shdr.sh_flags & SHF_LINK_ORDER) != 0) flags |= RTEMS_RTL_OBJ_SECT_LINK; + /* + * Some architexctures support 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, diff --git a/cpukit/libdl/rtl-mdreloc-arm.c b/cpukit/libdl/rtl-mdreloc-arm.c index 96e14fc676..ef00701d32 100644 --- a/cpukit/libdl/rtl-mdreloc-arm.c +++ b/cpukit/libdl/rtl-mdreloc-arm.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -193,6 +194,7 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj* obj, case R_TYPE(ABS32): /* word32 (S + A) | T */ case R_TYPE(GLOB_DAT): /* word32 (S + A) | T */ case R_TYPE(PREL31): /* word32 (S + A) | T - P */ + case R_TYPE(TARGET1): /* Equivalent to ABS32 */ case R_TYPE(TARGET2): /* Equivalent to REL32 */ if (__predict_true(RELOC_ALIGNED_P(where))) { tmp = *where + symvalue; @@ -249,8 +251,8 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj* obj, break; case R_TYPE(THM_JUMP24): - /* same to THM_CALL; insn b.w */ - case R_TYPE(THM_CALL): + /* same as THM_PC22; insn b.w */ + case R_TYPE(THM_PC22): upper_insn = *(uint16_t *)where; lower_insn = *((uint16_t *)where + 1); sign = (upper_insn & (1 << 10)) >> 10; @@ -322,7 +324,7 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj* obj, tmp = tmp - (Elf_Addr)where; if (((Elf_Sword)tmp > 0x7ffffe) || ((Elf_Sword)tmp < -0x800000)) { - rtems_rtl_set_error (EINVAL, "%s: Overflow %ld " + rtems_rtl_set_error (EINVAL, "%s: Overflow %" PRIu32 " " "THM_JUMP19 relocations", sect->name, (uint32_t) ELF_R_TYPE(rel->r_info)); return false; @@ -342,12 +344,12 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj* obj, break; default: - printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, " + printf ("rtl: reloc unknown: sym = %" PRIu32 ", type = %" PRIu32 ", offset = %p, " "contents = %p\n", ELF_R_SYM(rel->r_info), (uint32_t) ELF_R_TYPE(rel->r_info), (void *)rel->r_offset, (void *)*where); rtems_rtl_set_error (EINVAL, - "%s: Unsupported relocation type %ld " + "%s: Unsupported relocation type %" PRIu32 " " "in non-PLT relocations", sect->name, (uint32_t) ELF_R_TYPE(rel->r_info)); return false; diff --git a/cpukit/libdl/rtl-unresolved.c b/cpukit/libdl/rtl-unresolved.c index 4e81c3c64e..7e2d920594 100644 --- a/cpukit/libdl/rtl-unresolved.c +++ b/cpukit/libdl/rtl-unresolved.c @@ -181,7 +181,8 @@ rtems_rtl_unresolved_resolve_reloc (rtems_rtl_unresolv_rec* rec, 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); + printf ("rtl: unresolv: resolve reloc: %s\n", + rd->name_rec->rec.name.name); rtems_rtl_obj_relocate_unresolved (&rec->rec.reloc, rd->sym); @@ -193,6 +194,7 @@ rtems_rtl_unresolved_resolve_reloc (rtems_rtl_unresolv_rec* rec, 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); } diff --git a/cpukit/libdl/rtl.c b/cpukit/libdl/rtl.c index f331cbbf02..a3664c7e34 100644 --- a/cpukit/libdl/rtl.c +++ b/cpukit/libdl/rtl.c @@ -512,6 +512,8 @@ rtems_rtl_load_object (const char* name, int mode) return NULL; } + rtems_chain_append (&rtl->pending, &obj->link); + /* * Find the file in the file system using the search path. The fname field * will point to a valid file name if found. @@ -523,8 +525,6 @@ rtems_rtl_load_object (const char* name, int mode) return NULL; } - rtems_chain_append (&rtl->pending, &obj->link); - if (!rtems_rtl_obj_load (obj)) { rtems_chain_extract (&obj->link); @@ -533,6 +533,16 @@ rtems_rtl_load_object (const char* name, int mode) return NULL; } + /* + * If there are unresolved externals remove from the pending queue and place + * on the objects list until the symbols are resolved. + */ + if (obj->unresolved != 0) + { + rtems_chain_extract (&obj->link); + rtems_chain_append (&rtl->objects, &obj->link); + } + rtems_rtl_obj_caches_flush (); } @@ -572,34 +582,34 @@ rtems_rtl_load (const char* name, int mode) node = rtems_chain_first (&rtl->pending); while (!rtems_chain_is_tail (&rtl->pending, node)) { - rtems_rtl_obj* obj = (rtems_rtl_obj*) node; + rtems_rtl_obj* pobj = (rtems_rtl_obj*) node; /* * Move to the next pending object file and place this object file on the * RTL's objects list. */ - node = rtems_chain_next (&obj->link); - rtems_chain_extract (&obj->link); - rtems_chain_append (&rtl->objects, &obj->link); + node = rtems_chain_next (&pobj->link); + rtems_chain_extract (&pobj->link); + rtems_chain_append (&rtl->objects, &pobj->link); /* * Make sure the object file and cache is synchronized. */ - rtems_rtl_obj_synchronize_cache (obj); + rtems_rtl_obj_synchronize_cache (pobj); /* - * Run any local constructors if this is the first user because the - * object file will have just been loaded. Unlock the linker to avoid any - * dead locks if the object file needs to load files or update the symbol - * table. We also do not want a constructor to unload this object file. + * Run any local constructors if they have not been run. Unlock the linker + * to avoid any dead locks if the object file needs to load files or + * update the symbol table. We also do not want a constructor to unload + * this object file. */ - if (obj->users == 1) + if ((pobj->flags & RTEMS_RTL_OBJ_CTOR_RUN) == 0) { - obj->flags |= RTEMS_RTL_OBJ_LOCKED; + pobj->flags |= RTEMS_RTL_OBJ_LOCKED | RTEMS_RTL_OBJ_CTOR_RUN; rtems_rtl_unlock (); - rtems_rtl_obj_run_ctors (obj); + rtems_rtl_obj_run_ctors (pobj); rtems_rtl_lock (); - obj->flags &= ~RTEMS_RTL_OBJ_LOCKED; + pobj->flags &= ~RTEMS_RTL_OBJ_LOCKED; } } } @@ -623,7 +633,7 @@ rtems_rtl_unload_object (rtems_rtl_obj* obj) } /* - * Move the object file from the objects list to the pending list if unloaded. + * The object file cannot be unloaded if it is referenced. */ if (rtems_rtl_obj_get_reference (obj) > 0) { @@ -649,30 +659,43 @@ rtems_rtl_unload (rtems_rtl_obj* obj) { rtems_chain_control unloading; rtems_chain_node* node; + bool orphaned_found = true; + int loop = 0; /* - * Remove the orphaned object files from the objects list. This makes the - * list private and any changes in any desctructors will effect the run. + * Remove the orphaned object files from the objects list. The unloading is + * private so any changes in any desctructors will not effect the list as it + * is being iterated over. + * + * To avoid maintaining a complex tree loop while oprhans are still be found. */ + rtems_chain_initialize_empty (&unloading); - node = rtems_chain_first (&rtl->objects); - while (!rtems_chain_is_tail (&rtl->objects, node)) + while (orphaned_found) { - rtems_chain_node* next_node = rtems_chain_next (node); - rtems_rtl_obj* uobj = (rtems_rtl_obj*) node; - if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD)) - printf ("rtl: unload object: %s: %s\n", - rtems_rtl_obj_oname (obj), - rtems_rtl_obj_orphaned (uobj) ? "orphaned" : "inuse"); - if (rtems_rtl_obj_orphaned (uobj)) + orphaned_found = false; + ++loop; + node = rtems_chain_first (&rtl->objects); + while (!rtems_chain_is_tail (&rtl->objects, node)) { - rtems_rtl_obj_remove_dependencies (uobj); - rtems_chain_extract (&uobj->link); - rtems_chain_append (&unloading, &uobj->link); - uobj->flags |= RTEMS_RTL_OBJ_LOCKED; + rtems_chain_node* next_node = rtems_chain_next (node); + rtems_rtl_obj* uobj = (rtems_rtl_obj*) node; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD)) + printf ("rtl: unload object: %3i: %9s: %s\n", + loop, + rtems_rtl_obj_orphaned (uobj) ? "orphaned" : "inuse", + rtems_rtl_obj_oname (uobj)); + if (rtems_rtl_obj_orphaned (uobj)) + { + orphaned_found = true; + rtems_rtl_obj_remove_dependencies (uobj); + rtems_chain_extract (&uobj->link); + rtems_chain_append (&unloading, &uobj->link); + uobj->flags |= RTEMS_RTL_OBJ_LOCKED; + } + node = next_node; } - node = next_node; } /* @@ -684,7 +707,11 @@ rtems_rtl_unload (rtems_rtl_obj* obj) while (!rtems_chain_is_tail (&unloading, node)) { rtems_rtl_obj* uobj = (rtems_rtl_obj*) node; - rtems_rtl_obj_run_dtors (uobj); + if ((uobj->flags & RTEMS_RTL_OBJ_CTOR_RUN) != 0) + { + rtems_rtl_obj_run_dtors (uobj); + uobj->flags &= ~RTEMS_RTL_OBJ_CTOR_RUN; + } node = rtems_chain_next (node); } -- cgit v1.2.3