diff options
Diffstat (limited to 'ldso')
-rw-r--r-- | ldso/include/dl-elf.h | 20 | ||||
-rw-r--r-- | ldso/include/ldso.h | 2 | ||||
-rw-r--r-- | ldso/include/ldsodefs.h | 10 | ||||
-rw-r--r-- | ldso/ldso/Makefile.in | 6 | ||||
-rw-r--r-- | ldso/ldso/arm/aeabi_read_tp.S | 1 | ||||
-rw-r--r-- | ldso/ldso/dl-elf.c | 18 | ||||
-rw-r--r-- | ldso/ldso/dl-tls.c | 5 | ||||
-rw-r--r-- | ldso/ldso/i386/elfinterp.c | 10 | ||||
-rw-r--r-- | ldso/ldso/ldso.c | 26 | ||||
-rw-r--r-- | ldso/ldso/x86_64/dl-sysdep.h | 8 | ||||
-rw-r--r-- | ldso/ldso/x86_64/elfinterp.c | 28 | ||||
-rw-r--r-- | ldso/libdl/Makefile.in | 2 | ||||
-rw-r--r-- | ldso/libdl/libdl.c | 5 |
13 files changed, 91 insertions, 50 deletions
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/include/ldso.h b/ldso/include/ldso.h index e5669057c..53bb5be9e 100644 --- a/ldso/include/ldso.h +++ b/ldso/include/ldso.h @@ -72,7 +72,7 @@ extern char *_dl_ldsopath; /* Where the shared lib loader was found extern const char *_dl_progname; /* The name of the executable being run */ extern size_t _dl_pagesize; /* Store the page size for use later */ -#ifdef USE_TLS +#if defined(USE_TLS) && USE_TLS extern void _dl_add_to_slotinfo (struct link_map *l); extern void ** __attribute__ ((const)) _dl_initial_error_catch_tsd (void); #endif diff --git a/ldso/include/ldsodefs.h b/ldso/include/ldsodefs.h index 432c7b848..0c15254c1 100644 --- a/ldso/include/ldsodefs.h +++ b/ldso/include/ldsodefs.h @@ -116,12 +116,12 @@ EXTERN void **(*_dl_error_catch_tsd) (void) __attribute__ ((const)); /* Number of additional slots in the dtv allocated. */ # define DTV_SURPLUS (14) - /* Initial dtv of the main thread, not allocated with normal malloc. */ - EXTERN void *_dl_initial_dtv; - /* Generation counter for the dtv. */ - EXTERN size_t _dl_tls_generation; +/* Initial dtv of the main thread, not allocated with normal malloc. */ +EXTERN void *_dl_initial_dtv; +/* Generation counter for the dtv. */ +EXTERN size_t _dl_tls_generation; - EXTERN void (*_dl_init_static_tls) (struct link_map *); +EXTERN void (*_dl_init_static_tls) (struct link_map *); /* We have the auxiliary vector. */ #define HAVE_AUX_VECTOR diff --git a/ldso/ldso/Makefile.in b/ldso/ldso/Makefile.in index 724563155..e71ae1563 100644 --- a/ldso/ldso/Makefile.in +++ b/ldso/ldso/Makefile.in @@ -62,9 +62,9 @@ ldso-y := $($(UCLIBC_LDSO_NAME)_OBJS:.o=.oS) lib-so-y += $(ldso) objclean-y += CLEAN_ldso/ldso -$(ldso): $(ldso:.$(MAJOR_VERSION)=) -$(ldso:.$(MAJOR_VERSION)=): $($(UCLIBC_LDSO_NAME)_OUT)/$(UCLIBC_LDSO_NAME)_so.a - $(call link.so,$(ldso_FULL_NAME),$(MAJOR_VERSION)) +$(ldso): $(ldso:.$(ABI_VERSION)=) +$(ldso:.$(ABI_VERSION)=): $($(UCLIBC_LDSO_NAME)_OUT)/$(UCLIBC_LDSO_NAME)_so.a + $(call link.so,$(ldso_FULL_NAME),$(ABI_VERSION)) $($(UCLIBC_LDSO_NAME)_OUT)/$(UCLIBC_LDSO_NAME)_so.a: $(ldso-y) $(Q)$(RM) $@ diff --git a/ldso/ldso/arm/aeabi_read_tp.S b/ldso/ldso/arm/aeabi_read_tp.S index e906d07ce..564f59331 100644 --- a/ldso/ldso/arm/aeabi_read_tp.S +++ b/ldso/ldso/arm/aeabi_read_tp.S @@ -38,7 +38,6 @@ #ifdef __UCLIBC_HAS_THREADS_NATIVE__ #include <sysdep.h> -#include <tls.h> /* GCC will emit calls to this routine under -mtp=soft. Linux has an equivalent helper function (which clobbers fewer registers than diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c index 6b64f3e04..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,13 +733,14 @@ 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) { _dl_debug_early("Found TLS header for %s\n", libname); -#if NO_TLS_OFFSET != 0 +# if NO_TLS_OFFSET != 0 tpnt->l_tls_offset = NO_TLS_OFFSET; -#endif +# endif tpnt->l_tls_blocksize = tlsppnt->p_memsz; tpnt->l_tls_align = tlsppnt->p_align; if (tlsppnt->p_align == 0) @@ -755,10 +757,14 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure, /* We know the load address, so add it to the offset. */ if (tpnt->l_tls_initimage != NULL) { +# ifdef __SUPPORT_LD_DEBUG_EARLY__ unsigned int tmp = (unsigned int) tpnt->l_tls_initimage; tpnt->l_tls_initimage = (char *) tlsppnt->p_vaddr + tpnt->loadaddr; _dl_debug_early("Relocated TLS initial image from %x to %x (size = %x)\n", tmp, tpnt->l_tls_initimage, tpnt->l_tls_initimage_size); tmp = 0; +# else + tpnt->l_tls_initimage = (char *) tlsppnt->p_vaddr + tpnt->loadaddr; +# endif } } #endif @@ -987,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/ldso/dl-tls.c b/ldso/ldso/dl-tls.c index 52b7aa534..d2808f968 100644 --- a/ldso/ldso/dl-tls.c +++ b/ldso/ldso/dl-tls.c @@ -842,7 +842,10 @@ __tls_get_addr (GET_ADDR_ARGS) void *p; if (__builtin_expect (dtv[0].counter != _dl_tls_generation, 0)) - the_map = _dl_update_slotinfo (GET_ADDR_MODULE); + { + the_map = _dl_update_slotinfo (GET_ADDR_MODULE); + dtv = THREAD_DTV (); + } p = dtv[GET_ADDR_MODULE].pointer.val; diff --git a/ldso/ldso/i386/elfinterp.c b/ldso/ldso/i386/elfinterp.c index a01c1d020..1e3a2b248 100644 --- a/ldso/ldso/i386/elfinterp.c +++ b/ldso/ldso/i386/elfinterp.c @@ -175,7 +175,9 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, symbol_addr = 0; symname = strtab + symtab[symtab_index].st_name; - if (symtab_index) { + if (symtab_index && + (ELF32_ST_VISIBILITY(symtab[symtab_index].st_other) + != STV_PROTECTED)) { symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt, elf_machine_type_class(reloc_type), &tls_tpnt); @@ -188,7 +190,11 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, && ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) return 1; } else { - symbol_addr = symtab[symtab_index].st_value; + if (symtab_index) + symbol_addr = DL_FIND_HASH_VALUE(tpnt, elf_machine_type_class(reloc_type), + &symtab[symtab_index]); + else + symbol_addr = symtab[symtab_index].st_value; tls_tpnt = tpnt; } diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c index a8224e2c7..ea4ad0f1c 100644 --- a/ldso/ldso/ldso.c +++ b/ldso/ldso/ldso.c @@ -382,19 +382,6 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr, _dl_init_static_tls = &_dl_nothread_init_static_tls; #endif -#ifdef __UCLIBC_HAS_SSP__ - /* Set up the stack checker's canary. */ - stack_chk_guard = _dl_setup_stack_chk_guard (); -# ifdef THREAD_SET_STACK_GUARD - THREAD_SET_STACK_GUARD (stack_chk_guard); -# ifdef __UCLIBC_HAS_SSP_COMPAT__ - __guard = stack_chk_guard; -# endif -# else - __stack_chk_guard = stack_chk_guard; -# endif -#endif - /* At this point we are now free to examine the user application, * and figure out which libraries are supposed to be called. Until * we have this list, we will not be completely ready for dynamic @@ -952,6 +939,19 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr, tcbp = init_tls (); } #endif +#ifdef __UCLIBC_HAS_SSP__ + /* Set up the stack checker's canary. */ + stack_chk_guard = _dl_setup_stack_chk_guard (); +# ifdef THREAD_SET_STACK_GUARD + THREAD_SET_STACK_GUARD (stack_chk_guard); +# ifdef __UCLIBC_HAS_SSP_COMPAT__ + __guard = stack_chk_guard; +# endif +# else + __stack_chk_guard = stack_chk_guard; +# endif +#endif + _dl_debug_early("Beginning relocation fixups\n"); diff --git a/ldso/ldso/x86_64/dl-sysdep.h b/ldso/ldso/x86_64/dl-sysdep.h index 0eed657e8..ae3542aed 100644 --- a/ldso/ldso/x86_64/dl-sysdep.h +++ b/ldso/ldso/x86_64/dl-sysdep.h @@ -46,8 +46,12 @@ extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_ent define the value. ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one of the main executable's symbols, as for a COPY reloc. */ -#define elf_machine_type_class(type) \ - ((((type) == R_X86_64_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT) \ +#define elf_machine_type_class(type) \ + ((((type) == R_X86_64_JUMP_SLOT \ + || (type) == R_X86_64_DTPMOD64 \ + || (type) == R_X86_64_DTPOFF64 \ + || (type) == R_X86_64_TPOFF64) \ + * ELF_RTYPE_CLASS_PLT) \ | (((type) == R_X86_64_COPY) * ELF_RTYPE_CLASS_COPY)) /* Return the link-time address of _DYNAMIC. Conveniently, this is the diff --git a/ldso/ldso/x86_64/elfinterp.c b/ldso/ldso/x86_64/elfinterp.c index 92ac5acbc..54528d382 100644 --- a/ldso/ldso/x86_64/elfinterp.c +++ b/ldso/ldso/x86_64/elfinterp.c @@ -157,6 +157,7 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, int reloc_type; int symtab_index; char *symname; + struct elf_resolve *tls_tpnt = 0; ElfW(Sym) *sym; ElfW(Addr) *reloc_addr; ElfW(Addr) symbol_addr; @@ -173,18 +174,26 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, if (symtab_index) { symbol_addr = (ElfW(Addr))_dl_find_hash(symname, scope, tpnt, - elf_machine_type_class(reloc_type), NULL); + elf_machine_type_class(reloc_type), &tls_tpnt); /* * We want to allow undefined references to weak symbols - this * might have been intentional. We should not be linking local * symbols here, so all bases should be covered. */ - if (unlikely(!symbol_addr && ELF_ST_BIND(sym->st_info) != STB_WEAK)) { - _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname); - _dl_exit(1); + if (unlikely(!symbol_addr && (ELF_ST_TYPE(sym->st_info) != STT_TLS) + && (ELF_ST_BIND(sym->st_info) != STB_WEAK))) { + /* This may be non-fatal if called from dlopen. */ + return 1; } + } else { + /* Relocs against STN_UNDEF are usually treated as using a + * symbol value of zero, and using the module containing the + * reloc itself. */ + symbol_addr = sym->st_value; + tls_tpnt = tpnt; } + #if defined (__SUPPORT_LD_DEBUG__) old_val = *reloc_addr; #endif @@ -212,13 +221,20 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, break; */ case R_X86_64_DTPMOD64: - *reloc_addr = 1; + *reloc_addr = tls_tpnt->l_tls_modid; break; case R_X86_64_DTPOFF64: + /* During relocation all TLS symbols are defined and used. + * Therefore the offset is already correct. */ *reloc_addr = sym->st_value + rpnt->r_addend; break; case R_X86_64_TPOFF64: - *reloc_addr = sym->st_value + rpnt->r_addend - symbol_addr; + /* The offset is negative, forward from the thread pointer. + * We know the offset of the object the symbol is contained in. + * It is a negative value which will be added to the + * thread pointer. */ + CHECK_STATIC_TLS ((struct link_map *) tls_tpnt); + *reloc_addr = sym->st_value - tls_tpnt->l_tls_offset + rpnt->r_addend; break; case R_X86_64_32: *(unsigned int *) reloc_addr = symbol_addr + rpnt->r_addend; diff --git a/ldso/libdl/Makefile.in b/ldso/libdl/Makefile.in index 64a320e1c..39db7a876 100644 --- a/ldso/libdl/Makefile.in +++ b/ldso/libdl/Makefile.in @@ -44,7 +44,7 @@ lib-so-y += $(top_builddir)lib/libdl.so objclean-y += CLEAN_ldso/libdl $(top_builddir)lib/libdl.so: $(libdl_OUT)/libdl_so.a $(libc.depend) - $(call link.so,$(libdl_FULL_NAME),$(MAJOR_VERSION)) + $(call link.so,$(libdl_FULL_NAME),$(ABI_VERSION)) $(libdl_OUT)/libdl_so.a: $(libdl-so-y) $(Q)$(RM) $@ 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 |