Back to index

glibc  2.9
tlsdesc.c
Go to the documentation of this file.
00001 /* Manage TLS descriptors.  x86_64 version.
00002    Copyright (C) 2005, 2008 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <link.h>
00021 #include <ldsodefs.h>
00022 #include <elf/dynamic-link.h>
00023 #include <tls.h>
00024 #include <dl-tlsdesc.h>
00025 #include <tlsdeschtab.h>
00026 
00027 /* The following 2 functions take a caller argument, that contains the
00028    address expected to be in the TLS descriptor.  If it's changed, we
00029    want to return immediately.  */
00030 
00031 /* This function is used to lazily resolve TLS_DESC RELA relocations.
00032    The argument location is used to hold a pointer to the relocation.  */
00033 
00034 void
00035 attribute_hidden
00036 _dl_tlsdesc_resolve_rela_fixup (struct tlsdesc volatile *td,
00037                             struct link_map *l)
00038 {
00039   const ElfW(Rela) *reloc = td->arg;
00040 
00041   if (_dl_tlsdesc_resolve_early_return_p
00042       (td, (void*)(D_PTR (l, l_info[ADDRIDX (DT_TLSDESC_PLT)]) + l->l_addr)))
00043     return;
00044 
00045   /* The code below was borrowed from _dl_fixup().  */
00046   const ElfW(Sym) *const symtab
00047     = (const void *) D_PTR (l, l_info[DT_SYMTAB]);
00048   const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
00049   const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
00050   lookup_t result;
00051 
00052    /* Look up the target symbol.  If the normal lookup rules are not
00053       used don't look in the global scope.  */
00054   if (ELFW(ST_BIND) (sym->st_info) != STB_LOCAL
00055       && __builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
00056     {
00057       const struct r_found_version *version = NULL;
00058 
00059       if (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
00060        {
00061          const ElfW(Half) *vernum =
00062            (const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
00063          ElfW(Half) ndx = vernum[ELFW(R_SYM) (reloc->r_info)] & 0x7fff;
00064          version = &l->l_versions[ndx];
00065          if (version->hash == 0)
00066            version = NULL;
00067        }
00068 
00069       result = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
00070                                 l->l_scope, version, ELF_RTYPE_CLASS_PLT,
00071                                 DL_LOOKUP_ADD_DEPENDENCY, NULL);
00072     }
00073   else
00074     {
00075       /* We already found the symbol.  The module (and therefore its load
00076         address) is also known.  */
00077       result = l;
00078     }
00079 
00080   if (! sym)
00081     {
00082       td->arg = (void*)reloc->r_addend;
00083       td->entry = _dl_tlsdesc_undefweak;
00084     }
00085   else
00086     {
00087 #  ifndef SHARED
00088       CHECK_STATIC_TLS (l, result);
00089 #  else
00090       if (!TRY_STATIC_TLS (l, result))
00091        {
00092          td->arg = _dl_make_tlsdesc_dynamic (result, sym->st_value
00093                                          + reloc->r_addend);
00094          td->entry = _dl_tlsdesc_dynamic;
00095        }
00096       else
00097 #  endif
00098        {
00099          td->arg = (void*)(sym->st_value - result->l_tls_offset
00100                          + reloc->r_addend);
00101          td->entry = _dl_tlsdesc_return;
00102        }
00103     }
00104 
00105   _dl_tlsdesc_wake_up_held_fixups ();
00106 }
00107 
00108 /* This function is used to avoid busy waiting for other threads to
00109    complete the lazy relocation.  Once another thread wins the race to
00110    relocate a TLS descriptor, it sets the descriptor up such that this
00111    function is called to wait until the resolver releases the
00112    lock.  */
00113 
00114 void
00115 attribute_hidden
00116 _dl_tlsdesc_resolve_hold_fixup (struct tlsdesc volatile *td,
00117                             void *caller)
00118 {
00119   /* Maybe we're lucky and can return early.  */
00120   if (caller != td->entry)
00121     return;
00122 
00123   /* Locking here will stop execution until the running resolver runs
00124      _dl_tlsdesc_wake_up_held_fixups(), releasing the lock.
00125 
00126      FIXME: We'd be better off waiting on a condition variable, such
00127      that we didn't have to hold the lock throughout the relocation
00128      processing.  */
00129   __rtld_lock_lock_recursive (GL(dl_load_lock));
00130   __rtld_lock_unlock_recursive (GL(dl_load_lock));
00131 }
00132 
00133 /* Unmap the dynamic object, but also release its TLS descriptor table
00134    if there is one.  */
00135 
00136 void
00137 internal_function
00138 _dl_unmap (struct link_map *map)
00139 {
00140   __munmap ((void *) (map)->l_map_start,
00141            (map)->l_map_end - (map)->l_map_start);
00142 
00143 #if SHARED
00144   /* _dl_unmap is only called for dlopen()ed libraries, for which
00145      calling free() is safe, or before we've completed the initial
00146      relocation, in which case calling free() is probably pointless,
00147      but still safe.  */
00148   if (map->l_mach.tlsdesc_table)
00149     htab_delete (map->l_mach.tlsdesc_table);
00150 #endif
00151 }