From b93b98daf0dd45ac52f99fc4d906e5926cdd5239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Thu, 22 Apr 2010 08:28:10 +0000 Subject: ldso: support RTLD_NODELETE and DF_1_NODELETE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Honor the nodelete flags so we don't delete shared library if it's sticky. This is useful for libpthread if it gets pulled in by a dlopen'ed library. Signed-off-by: Timo Teräs Signed-off-by: Austin Foxley --- ldso/include/dl-elf.h | 20 +++++++++++++------- ldso/ldso/dl-elf.c | 10 ++++++---- ldso/libdl/libdl.c | 5 +++-- 3 files changed, 22 insertions(+), 13 deletions(-) (limited to 'ldso') diff --git a/ldso/include/dl-elf.h b/ldso/include/dl-elf.h index 076678cfc..9c2888f5b 100644 --- a/ldso/include/dl-elf.h +++ b/ldso/include/dl-elf.h @@ -104,13 +104,15 @@ extern void _dl_protect_relro (struct elf_resolve *l); # define DT_GNU_HASH_IDX (DT_RELCONT_IDX + 1) #endif -extern void _dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[], - void *debug_addr, DL_LOADADDR_TYPE load_off); +extern unsigned int _dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[], + void *debug_addr, DL_LOADADDR_TYPE load_off); static __always_inline -void __dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[], - void *debug_addr, DL_LOADADDR_TYPE load_off) +unsigned int __dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[], + void *debug_addr, DL_LOADADDR_TYPE load_off) { + unsigned int rtld_flags = 0; + for (; dpnt->d_tag; dpnt++) { if (dpnt->d_tag < DT_NUM) { dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val; @@ -138,9 +140,12 @@ void __dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[], } else if (dpnt->d_tag < DT_LOPROC) { if (dpnt->d_tag == DT_RELOCCOUNT) dynamic_info[DT_RELCONT_IDX] = dpnt->d_un.d_val; - if (dpnt->d_tag == DT_FLAGS_1 && - (dpnt->d_un.d_val & DF_1_NOW)) - dynamic_info[DT_BIND_NOW] = 1; + if (dpnt->d_tag == DT_FLAGS_1) { + if (dpnt->d_un.d_val & DF_1_NOW) + dynamic_info[DT_BIND_NOW] = 1; + if (dpnt->d_un.d_val & DF_1_NODELETE) + rtld_flags |= RTLD_NODELETE; + } #ifdef __LDSO_GNU_HASH_SUPPORT__ if (dpnt->d_tag == DT_GNU_HASH) dynamic_info[DT_GNU_HASH_IDX] = dpnt->d_un.d_ptr; @@ -167,6 +172,7 @@ void __dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[], ADJUST_DYN_INFO(DT_GNU_HASH_IDX, load_off); #endif #undef ADJUST_DYN_INFO + return rtld_flags; } /* Reloc type classes as returned by elf_machine_type_class(). diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c index 8fb8ffa2d..5562e0784 100644 --- a/ldso/ldso/dl-elf.c +++ b/ldso/ldso/dl-elf.c @@ -337,6 +337,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, unsigned long *lpnt; unsigned long libaddr; unsigned long minvma = 0xffffffff, maxvma = 0; + unsigned int rtld_flags; int i, flags, piclib, infile; ElfW(Addr) relro_addr = 0; size_t relro_size = 0; @@ -700,7 +701,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, dpnt = (ElfW(Dyn) *) dynamic_addr; _dl_memset(dynamic_info, 0, sizeof(dynamic_info)); - _dl_parse_dynamic_info(dpnt, dynamic_info, NULL, lib_loadaddr); + rtld_flags = _dl_parse_dynamic_info(dpnt, dynamic_info, NULL, lib_loadaddr); /* If the TEXTREL is set, this means that we need to make the pages writable before we perform relocations. Do this now. They get set back again later. */ @@ -732,6 +733,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, tpnt->st_ino = st.st_ino; tpnt->ppnt = (ElfW(Phdr) *) DL_RELOC_ADDR(tpnt->loadaddr, epnt->e_phoff); tpnt->n_phent = epnt->e_phnum; + tpnt->rtld_flags |= rtld_flags; #if defined(USE_TLS) && USE_TLS if (tlsppnt) { @@ -991,8 +993,8 @@ char *_dl_strdup(const char *string) return retval; } -void _dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[], - void *debug_addr, DL_LOADADDR_TYPE load_off) +unsigned int _dl_parse_dynamic_info(ElfW(Dyn) *dpnt, unsigned long dynamic_info[], + void *debug_addr, DL_LOADADDR_TYPE load_off) { - __dl_parse_dynamic_info(dpnt, dynamic_info, debug_addr, load_off); + return __dl_parse_dynamic_info(dpnt, dynamic_info, debug_addr, load_off); } diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c index 05a68ddcc..f19a0151e 100644 --- a/ldso/libdl/libdl.c +++ b/ldso/libdl/libdl.c @@ -736,7 +736,7 @@ static int do_dlclose(void *vhandle, int need_fini) _dl_handles = rpnt->next_handle; _dl_if_debug_print("%s: usage count: %d\n", handle->dyn->libname, handle->dyn->usage_count); - if (handle->dyn->usage_count != 1) { + if (handle->dyn->usage_count != 1 || (handle->dyn->rtld_flags & RTLD_NODELETE)) { handle->dyn->usage_count--; free(handle); return 0; @@ -744,7 +744,8 @@ static int do_dlclose(void *vhandle, int need_fini) /* OK, this is a valid handle - now close out the file */ for (j = 0; j < handle->init_fini.nlist; ++j) { tpnt = handle->init_fini.init_fini[j]; - if (--tpnt->usage_count == 0) { + tpnt->usage_count--; + if (tpnt->usage_count == 0 && !(tpnt->rtld_flags & RTLD_NODELETE)) { if ((tpnt->dynamic_info[DT_FINI] || tpnt->dynamic_info[DT_FINI_ARRAY]) && need_fini -- cgit v1.2.3