diff --git a/ChangeLog b/ChangeLog index 4931ba52c7..d5078bda3e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,19 @@ 2002-02-04 Ulrich Drepper + * elf/rtld.c (_dl_start): Fill TLS values in link map for rtld. + * include/link.h (struct link_map): Add various members for TLS + information. + * sysdeps/generic/ldsodefs.h (struct rtld_global): Remove + _rtld_tlsoffset, add _dl_initimage_list. + * sysdeps/i386/dl-lookupcfg.h: New file. + * sysdeps/i386/dl-machine.h (elf_machine_rel): Implement missing + TLS relocation. When using TLS we now use RESOLVE_MAP. + (elf_machine_rela): Use RESOLVE_MAP instead of RESOLVE_MAP if TLS + is used. + + * sysdeps/generic/dl-cache.c (_dl_cache_libcmp): Mark as possibly + unused. + * elf/rtld.c (_dl_start_final): Allocate TLS and initialize thread-pointer as soon as possible. * sysdeps/generic/ldsodefs.h: Include . Define first TLS diff --git a/elf/rtld.c b/elf/rtld.c index b7439b2e7b..bdd12b4f81 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -222,10 +222,6 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p, ElfW(Ehdr) *ehdr; ElfW(Phdr) *phdr; size_t cnt; - size_t tlssize = 0; - size_t tlsimagesize = 0; - const void *tlsimage = NULL; - void *tlsblock = NULL; dtv_t initdtv[2]; #endif @@ -261,23 +257,26 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p, for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) if (phdr[cnt].p_type == PT_TLS) { + void *tlsblock; size_t align = MAX (TLS_INIT_TCB_ALIGN, phdr[cnt].p_align); - tlssize = phdr[cnt].p_memsz; - tlsimagesize = phdr[cnt].p_filesz; - tlsimage = (void *) (bootstrap_map_p->l_addr + phdr[cnt].p_offset); + GL(dl_rtld_map).l_tls_blocksize = phdr[cnt].p_memsz; + GL(dl_rtld_map).l_tls_initimage_size = phdr[cnt].p_filesz; + GL(dl_rtld_map).l_tls_initimage = (void *) (bootstrap_map_p->l_addr + + phdr[cnt].p_offset); /* We can now allocate the initial TLS block. This can happen on the stack. We'll get the final memory later when we know all about the various objects loaded at startup time. */ # if TLS_TCB_AT_TP - tlsblock = alloca (roundup (tlssize, TLS_INIT_TCB_ALIGN) + tlsblock = alloca (roundup (GL(dl_rtld_map).l_tls_blocksize, + TLS_INIT_TCB_ALIGN) + TLS_INIT_TCB_SIZE + align); # elif TLS_DTV_AT_TP tlsblock = alloca (roundup (TLS_INIT_TCB_SIZE, phdr[cnt].p_align) - + tlssize + + GL(dl_rtld_map).l_tls_blocksize + align); # else /* In case a model with a different layout for the TCB and DTV @@ -295,24 +294,32 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p, # if TLS_TCB_AT_TP initdtv[1].pointer = tlsblock; # elif TLS_DTV_AT_TP - GL(rtld_tlsoffset) = roundup (TLS_INIT_TCB_SIZE, phdr[cnt].p_align); - initdtv[1].pointer = (char *) tlsblock + GL(rtld_tlsoffset); + GL(dl_rtld_map).l_tls_offset = roundup (TLS_INIT_TCB_SIZE, + phdr[cnt].p_align); + initdtv[1].pointer = (char *) tlsblock + GL(dl_rtld_map).l_tls_offset); # else # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" # endif - memset (__mempcpy (initdtv[1].pointer, tlsimage, tlsimagesize), - '\0', tlssize - tlsimagesize); + memset (__mempcpy (initdtv[1].pointer, GL(dl_rtld_map).l_tls_initimage, + GL(dl_rtld_map).l_tls_initimage_size), + '\0', (GL(dl_rtld_map).l_tls_blocksize + - GL(dl_rtld_map).l_tls_initimage_size)); /* Initialize the thread pointer. */ # if TLS_TCB_AT_TP - GL(rtld_tlsoffset) = roundup (tlssize, TLS_INIT_TCB_ALIGN); - TLS_INIT_TP ((char *) tlsblock + GL(rtld_tlsoffset), initdtv); + GL(dl_rtld_map).l_tls_offset + = roundup (GL(dl_rtld_map).l_tls_blocksize, TLS_INIT_TCB_ALIGN); + TLS_INIT_TP ((char *) tlsblock + GL(dl_rtld_map).l_tls_offset, + initdtv); # elif TLS_DTV_AT_TP - TLS_INIT_TP (tlsblock, intidtv); + TLS_INIT_TP (tlsblock, initdtv); # else # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" # endif + /* So far this is module number one. */ + GL(dl_rtld_map).l_tls_modid = 1; + /* There can only be one PT_TLS entry. */ break; } diff --git a/include/link.h b/include/link.h index 2442350457..5502bbfe61 100644 --- a/include/link.h +++ b/include/link.h @@ -1,6 +1,6 @@ /* Data structure for communication from the run-time dynamic linker for loaded ELF shared objects. - Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc. + Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -21,9 +21,9 @@ #ifndef _LINK_H #define _LINK_H 1 -#include #include #include +#include #include /* We use this macro to refer to ELF types independent of the native wordsize. @@ -254,6 +254,21 @@ struct link_map #endif const ElfW(Sym) *ret; } l_lookup_cache; + + /* Thread-local storage related info. */ + + /* Next module in list of initialization images. */ + struct link_map *l_tls_nextimage; + /* Start of the initialization image. */ + void *l_tls_initimage; + /* Size of the initialization image. */ + size_t l_tls_initimage_size; + /* Size of the TLS block. */ + size_t l_tls_blocksize; + /* For objects present at startup time: offset in the static TLS block. */ + ptrdiff_t l_tls_offset; + /* Index of the module in the dtv array. */ + size_t l_tls_modid; }; struct dl_phdr_info diff --git a/sysdeps/generic/dl-cache.h b/sysdeps/generic/dl-cache.h index ad6b0106d1..d02c1739c1 100644 --- a/sysdeps/generic/dl-cache.h +++ b/sysdeps/generic/dl-cache.h @@ -1,5 +1,5 @@ /* Support for reading /etc/ld.so.cache files written by Linux ldconfig. - Copyright (C) 1999, 2000 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -98,6 +98,7 @@ struct cache_file_new & (~(__alignof__ (struct cache_file_new) - 1))) static int +__attribute__ ((__unused__)) _dl_cache_libcmp (const char *p1, const char *p2) { while (*p1 != '\0') diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 08785a818e..4e4fecf712 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -288,8 +288,10 @@ struct rtld_global #endif #ifdef USE_TLS - /* Offset of the TLS block for ld.so from the thread-pointer. */ - EXTERN size_t _rtld_tlsoffset; + /* Beginning of the list of link maps for objects which contain + thread-local storage sections. This will be traversed to + initialize new TLS blocks. */ + EXTERN struct link_map *_dl_initimage_list; #endif /* Name of the shared object to be profiled (if any). */ diff --git a/sysdeps/i386/dl-lookupcfg.h b/sysdeps/i386/dl-lookupcfg.h new file mode 100644 index 0000000000..8daf7a8a75 --- /dev/null +++ b/sysdeps/i386/dl-lookupcfg.h @@ -0,0 +1,28 @@ +/* Configuration of lookup functions. i386 version. + Copyright (C) 2000, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include + +/* Some platforms need more information from the symbol lookup function + than just the address. For x86 we need it when we support TLS. */ +#ifdef USE_TLS +# define DL_LOOKUP_RETURNS_MAP +#else +# undef DL_LOOKUP_RETURNS_MAP +#endif diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h index f791fa3ffa..3e471805d7 100644 --- a/sysdeps/i386/dl-machine.h +++ b/sysdeps/i386/dl-machine.h @@ -342,20 +342,18 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc, else #endif { -#if defined RTLD_BOOTSTRAP && !defined USE_TLS - Elf32_Addr value; - - assert (r_type == R_386_GLOB_DAT || r_type == R_386_JMP_SLOT); - - value = RESOLVE (&sym, version, r_type); - *reloc_addr = value + sym->st_value; -#else const Elf32_Sym *const refsym = sym; +#if defined USE_TLS && !defined RTLD_BOOTSTRAP + struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type); + Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value; +#else Elf32_Addr value = RESOLVE (&sym, version, r_type); + # ifndef RTLD_BOOTSTRAP - if (sym) + if (sym != NULL) # endif value += sym->st_value; +#endif switch (r_type) { @@ -366,6 +364,7 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc, /* XXX Remove TLS relocations which are not needed. */ +#ifdef USE_TLS case R_386_TLS_DTPMOD32: # ifdef RTLD_BOOTSTRAP /* During startup the dynamic linker is always the module @@ -374,29 +373,36 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc, call. */ *reloc_addr = 1; # else - /* XXX Implement. RESOLVE must return the map from which we - get the module ID. */ - _exit (99); + /* Get the information from the link map returned by the + resolv function. */ + if (sym_map != NULL) + *reloc_addr = sym_map->l_tls_modid; # endif break; case R_386_TLS_DTPOFF32: # ifndef RTLD_BOOTSTRAP /* During relocation all TLS symbols are defined and used. Therefore the offset is already correct. */ - *reloc_addr = sym->st_value; + if (sym != NULL) + *reloc_addr = sym->st_value; # endif break; case R_386_TLS_TPOFF32: /* The offset is positive, backward from the thread pointer. */ # ifdef RTLD_BOOTSTRAP - *reloc_addr = GL(rtld_tlsoffset) - sym->st_value; + *reloc_addr = GL(dl_rtld_map).l_tls_offset - sym->st_value; # else - /* XXX Implement. */ - _exit (98); + /* We know the offset of object the symbol is contained is. + It is a positive value which will be subtracted from the + thread pointer. To get the variable position in the TLS + block we subtract the offset from that of the TLS block. */ + if (sym_map != NULL && sym != NULL) + *reloc_addr = sym_map->l_tls_offset - sym->st_value; # endif break; +#endif /* use TLS */ -# ifndef RTLD_BOOTSTRAP +#ifndef RTLD_BOOTSTRAP case R_386_32: *reloc_addr += value; break; @@ -426,9 +432,8 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc, default: _dl_reloc_bad_type (map, r_type, 0); break; -# endif - } #endif + } } } @@ -438,13 +443,20 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, const Elf32_Sym *sym, const struct r_found_version *version, Elf32_Addr *const reloc_addr) { + const unsigned int r_type = ELF32_R_TYPE (reloc->r_info); + if (ELF32_R_TYPE (reloc->r_info) == R_386_RELATIVE) *reloc_addr = map->l_addr + reloc->r_addend; - else if (ELF32_R_TYPE (reloc->r_info) != R_386_NONE) + else if (r_type != R_386_NONE) { +# ifdef USE_TLS + struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type); + Elf32_Addr value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value; +# else Elf32_Addr value = RESOLVE (&sym, version, ELF32_R_TYPE (reloc->r_info)); - if (sym) + if (sym != NULL) value += sym->st_value; +#endif switch (ELF32_R_TYPE (reloc->r_info)) { @@ -456,10 +468,11 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc, case R_386_PC32: *reloc_addr = (value + reloc->r_addend - (Elf32_Addr) reloc_addr); break; + /* XXX Do we have to handle the TLS relocation here? */ default: /* We add these checks in the version to relocate ld.so only if we are still debugging. */ - _dl_reloc_bad_type (map, ELFW(R_TYPE) (reloc->r_info), 0); + _dl_reloc_bad_type (map, r_type, 0); break; } }