* 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.
This commit is contained in:
Ulrich Drepper 2002-02-05 08:02:04 +00:00
parent 535b764df5
commit 5d6feea8f5
7 changed files with 123 additions and 43 deletions

View File

@ -1,5 +1,19 @@
2002-02-04 Ulrich Drepper <drepper@redhat.com> 2002-02-04 Ulrich Drepper <drepper@redhat.com>
* 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 * elf/rtld.c (_dl_start_final): Allocate TLS and initialize
thread-pointer as soon as possible. thread-pointer as soon as possible.
* sysdeps/generic/ldsodefs.h: Include <tls.h>. Define first TLS * sysdeps/generic/ldsodefs.h: Include <tls.h>. Define first TLS

View File

@ -222,10 +222,6 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
ElfW(Ehdr) *ehdr; ElfW(Ehdr) *ehdr;
ElfW(Phdr) *phdr; ElfW(Phdr) *phdr;
size_t cnt; size_t cnt;
size_t tlssize = 0;
size_t tlsimagesize = 0;
const void *tlsimage = NULL;
void *tlsblock = NULL;
dtv_t initdtv[2]; dtv_t initdtv[2];
#endif #endif
@ -261,23 +257,26 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p,
for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) for (cnt = 0; cnt < ehdr->e_phnum; ++cnt)
if (phdr[cnt].p_type == PT_TLS) if (phdr[cnt].p_type == PT_TLS)
{ {
void *tlsblock;
size_t align = MAX (TLS_INIT_TCB_ALIGN, phdr[cnt].p_align); size_t align = MAX (TLS_INIT_TCB_ALIGN, phdr[cnt].p_align);
tlssize = phdr[cnt].p_memsz; GL(dl_rtld_map).l_tls_blocksize = phdr[cnt].p_memsz;
tlsimagesize = phdr[cnt].p_filesz; GL(dl_rtld_map).l_tls_initimage_size = phdr[cnt].p_filesz;
tlsimage = (void *) (bootstrap_map_p->l_addr + phdr[cnt].p_offset); 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 /* We can now allocate the initial TLS block. This can happen
on the stack. We'll get the final memory later when we on the stack. We'll get the final memory later when we
know all about the various objects loaded at startup know all about the various objects loaded at startup
time. */ time. */
# if TLS_TCB_AT_TP # 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 + TLS_INIT_TCB_SIZE
+ align); + align);
# elif TLS_DTV_AT_TP # elif TLS_DTV_AT_TP
tlsblock = alloca (roundup (TLS_INIT_TCB_SIZE, phdr[cnt].p_align) tlsblock = alloca (roundup (TLS_INIT_TCB_SIZE, phdr[cnt].p_align)
+ tlssize + GL(dl_rtld_map).l_tls_blocksize
+ align); + align);
# else # else
/* In case a model with a different layout for the TCB and DTV /* 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 # if TLS_TCB_AT_TP
initdtv[1].pointer = tlsblock; initdtv[1].pointer = tlsblock;
# elif TLS_DTV_AT_TP # elif TLS_DTV_AT_TP
GL(rtld_tlsoffset) = roundup (TLS_INIT_TCB_SIZE, phdr[cnt].p_align); GL(dl_rtld_map).l_tls_offset = roundup (TLS_INIT_TCB_SIZE,
initdtv[1].pointer = (char *) tlsblock + GL(rtld_tlsoffset); phdr[cnt].p_align);
initdtv[1].pointer = (char *) tlsblock + GL(dl_rtld_map).l_tls_offset);
# else # else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
# endif # endif
memset (__mempcpy (initdtv[1].pointer, tlsimage, tlsimagesize), memset (__mempcpy (initdtv[1].pointer, GL(dl_rtld_map).l_tls_initimage,
'\0', tlssize - tlsimagesize); 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. */ /* Initialize the thread pointer. */
# if TLS_TCB_AT_TP # if TLS_TCB_AT_TP
GL(rtld_tlsoffset) = roundup (tlssize, TLS_INIT_TCB_ALIGN); GL(dl_rtld_map).l_tls_offset
TLS_INIT_TP ((char *) tlsblock + GL(rtld_tlsoffset), initdtv); = 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 # elif TLS_DTV_AT_TP
TLS_INIT_TP (tlsblock, intidtv); TLS_INIT_TP (tlsblock, initdtv);
# else # else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
# endif # endif
/* So far this is module number one. */
GL(dl_rtld_map).l_tls_modid = 1;
/* There can only be one PT_TLS entry. */ /* There can only be one PT_TLS entry. */
break; break;
} }

View File

@ -1,6 +1,6 @@
/* Data structure for communication from the run-time dynamic linker for /* Data structure for communication from the run-time dynamic linker for
loaded ELF shared objects. 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. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
@ -21,9 +21,9 @@
#ifndef _LINK_H #ifndef _LINK_H
#define _LINK_H 1 #define _LINK_H 1
#include <features.h>
#include <elf.h> #include <elf.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <stddef.h>
#include <sys/types.h> #include <sys/types.h>
/* We use this macro to refer to ELF types independent of the native wordsize. /* We use this macro to refer to ELF types independent of the native wordsize.
@ -254,6 +254,21 @@ struct link_map
#endif #endif
const ElfW(Sym) *ret; const ElfW(Sym) *ret;
} l_lookup_cache; } 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 struct dl_phdr_info

View File

@ -1,5 +1,5 @@
/* Support for reading /etc/ld.so.cache files written by Linux ldconfig. /* 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. This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or 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))) & (~(__alignof__ (struct cache_file_new) - 1)))
static int static int
__attribute__ ((__unused__))
_dl_cache_libcmp (const char *p1, const char *p2) _dl_cache_libcmp (const char *p1, const char *p2)
{ {
while (*p1 != '\0') while (*p1 != '\0')

View File

@ -288,8 +288,10 @@ struct rtld_global
#endif #endif
#ifdef USE_TLS #ifdef USE_TLS
/* Offset of the TLS block for ld.so from the thread-pointer. */ /* Beginning of the list of link maps for objects which contain
EXTERN size_t _rtld_tlsoffset; thread-local storage sections. This will be traversed to
initialize new TLS blocks. */
EXTERN struct link_map *_dl_initimage_list;
#endif #endif
/* Name of the shared object to be profiled (if any). */ /* Name of the shared object to be profiled (if any). */

View File

@ -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 <tls.h>
/* 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

View File

@ -342,20 +342,18 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
else else
#endif #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; 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); Elf32_Addr value = RESOLVE (&sym, version, r_type);
# ifndef RTLD_BOOTSTRAP # ifndef RTLD_BOOTSTRAP
if (sym) if (sym != NULL)
# endif # endif
value += sym->st_value; value += sym->st_value;
#endif
switch (r_type) 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. */ /* XXX Remove TLS relocations which are not needed. */
#ifdef USE_TLS
case R_386_TLS_DTPMOD32: case R_386_TLS_DTPMOD32:
# ifdef RTLD_BOOTSTRAP # ifdef RTLD_BOOTSTRAP
/* During startup the dynamic linker is always the module /* 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. */ call. */
*reloc_addr = 1; *reloc_addr = 1;
# else # else
/* XXX Implement. RESOLVE must return the map from which we /* Get the information from the link map returned by the
get the module ID. */ resolv function. */
_exit (99); if (sym_map != NULL)
*reloc_addr = sym_map->l_tls_modid;
# endif # endif
break; break;
case R_386_TLS_DTPOFF32: case R_386_TLS_DTPOFF32:
# ifndef RTLD_BOOTSTRAP # ifndef RTLD_BOOTSTRAP
/* During relocation all TLS symbols are defined and used. /* During relocation all TLS symbols are defined and used.
Therefore the offset is already correct. */ Therefore the offset is already correct. */
*reloc_addr = sym->st_value; if (sym != NULL)
*reloc_addr = sym->st_value;
# endif # endif
break; break;
case R_386_TLS_TPOFF32: case R_386_TLS_TPOFF32:
/* The offset is positive, backward from the thread pointer. */ /* The offset is positive, backward from the thread pointer. */
# ifdef RTLD_BOOTSTRAP # ifdef RTLD_BOOTSTRAP
*reloc_addr = GL(rtld_tlsoffset) - sym->st_value; *reloc_addr = GL(dl_rtld_map).l_tls_offset - sym->st_value;
# else # else
/* XXX Implement. */ /* We know the offset of object the symbol is contained is.
_exit (98); 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 # endif
break; break;
#endif /* use TLS */
# ifndef RTLD_BOOTSTRAP #ifndef RTLD_BOOTSTRAP
case R_386_32: case R_386_32:
*reloc_addr += value; *reloc_addr += value;
break; break;
@ -426,9 +432,8 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
default: default:
_dl_reloc_bad_type (map, r_type, 0); _dl_reloc_bad_type (map, r_type, 0);
break; break;
# endif
}
#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, const Elf32_Sym *sym, const struct r_found_version *version,
Elf32_Addr *const reloc_addr) 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) if (ELF32_R_TYPE (reloc->r_info) == R_386_RELATIVE)
*reloc_addr = map->l_addr + reloc->r_addend; *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)); Elf32_Addr value = RESOLVE (&sym, version, ELF32_R_TYPE (reloc->r_info));
if (sym) if (sym != NULL)
value += sym->st_value; value += sym->st_value;
#endif
switch (ELF32_R_TYPE (reloc->r_info)) 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: case R_386_PC32:
*reloc_addr = (value + reloc->r_addend - (Elf32_Addr) reloc_addr); *reloc_addr = (value + reloc->r_addend - (Elf32_Addr) reloc_addr);
break; break;
/* XXX Do we have to handle the TLS relocation here? */
default: default:
/* We add these checks in the version to relocate ld.so only /* We add these checks in the version to relocate ld.so only
if we are still debugging. */ 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; break;
} }
} }