diff options
author | Ulrich Drepper <drepper@redhat.com> | 2002-02-05 00:57:29 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2002-02-05 00:57:29 +0000 |
commit | 535b764df5ca722066c2db615190e6a70688c6a6 (patch) | |
tree | 06f6ba9853ac4e8f698fc1e3b0b4cb80ffd06bae /elf/rtld.c | |
parent | 67ddea92542c12f2099a89dbc58a045a65bb7771 (diff) | |
download | glibc-535b764df5ca722066c2db615190e6a70688c6a6.zip glibc-535b764df5ca722066c2db615190e6a70688c6a6.tar.gz glibc-535b764df5ca722066c2db615190e6a70688c6a6.tar.bz2 |
Update.
* elf/rtld.c (_dl_start_final): Allocate TLS and initialize
thread-pointer as soon as possible.
* sysdeps/generic/ldsodefs.h: Include <tls.h>. Define first TLS
elements in rtld_global.
* sysdeps/generic/tls.h: New file.
* elf/Makefile (distribute): Add tls.h.
* sysdeps/i386/dl-machine.h (elf_machine_rel): Add support for TLS
relocations. Not complete yet.
* resolv/resolv.h: Allow user to define __need_res_state and only
define __res_start structure then.
* include/resolv.h: Only declare functions if _RESOLV_H_ is defined.
Diffstat (limited to 'elf/rtld.c')
-rw-r--r-- | elf/rtld.c | 75 |
1 files changed, 75 insertions, 0 deletions
@@ -218,6 +218,16 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p, which use `alloca'. */ ElfW(Addr) *start_addr = alloca (sizeof (ElfW(Addr))); extern char _begin[], _end[]; +#ifdef USE_TLS + 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 if (HP_TIMING_AVAIL) { @@ -244,11 +254,76 @@ _dl_start_final (void *arg, struct link_map *bootstrap_map_p, HP_TIMING_NOW (GL(dl_cpuclock_offset)); #endif +#if USE_TLS + /* Get the dynamic linkers program header. */ + ehdr = (ElfW(Ehdr) *) bootstrap_map_p->l_addr; + phdr = (ElfW(Phdr) *) (bootstrap_map_p->l_addr + ehdr->e_phoff); + for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) + if (phdr[cnt].p_type == PT_TLS) + { + 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); + + /* 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) + + TLS_INIT_TCB_SIZE + + align); +# elif TLS_DTV_AT_TP + tlsblock = alloca (roundup (TLS_INIT_TCB_SIZE, phdr[cnt].p_align) + + tlssize + + align); +# else + /* In case a model with a different layout for the TCB and DTV + is defined add another #elif here and in the following #ifs. */ +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + /* Align the TLS block. */ + tlsblock = (void *) (((uintptr_t) tlsblock + align - 1) + & ~(align - 1)); + + /* Initialize the dtv. */ + initdtv[0].counter = 1; + + /* Initialize the TLS block. */ +# 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); +# 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); + + /* 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); +# elif TLS_DTV_AT_TP + TLS_INIT_TP (tlsblock, intidtv); +# else +# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" +# endif + + /* There can only be one PT_TLS entry. */ + break; + } +#endif /* use TLS */ + /* Call the OS-dependent function to set up life so we can do things like file access. It will call `dl_main' (below) to do all the real work of the dynamic linker, and then unwind our frame and run the user entry point on the same stack we entered on. */ *start_addr = _dl_sysdep_start (arg, &dl_main); + #ifndef HP_TIMING_NONAVAIL if (HP_TIMING_AVAIL) { |