Back to index

glibc  2.9
do-lookup.h
Go to the documentation of this file.
00001 /* Look up a symbol in the loaded objects.
00002    Copyright (C) 1995-2004, 2005, 2006, 2007 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 
00021 /* Inner part of the lookup functions.  We return a value > 0 if we
00022    found the symbol, the value 0 if nothing is found and < 0 if
00023    something bad happened.  */
00024 static int
00025 __attribute_noinline__
00026 do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
00027             unsigned long int *old_hash, const ElfW(Sym) *ref,
00028             struct sym_val *result, struct r_scope_elem *scope, size_t i,
00029             const struct r_found_version *const version, int flags,
00030             struct link_map *skip, int type_class)
00031 {
00032   size_t n = scope->r_nlist;
00033   /* Make sure we read the value before proceeding.  Otherwise we
00034      might use r_list pointing to the initial scope and r_nlist being
00035      the value after a resize.  That is the only path in dl-open.c not
00036      protected by GSCOPE.  A read barrier here might be to expensive.  */
00037   __asm volatile ("" : "+r" (n), "+m" (scope->r_list));
00038   struct link_map **list = scope->r_list;
00039 
00040   do
00041     {
00042       /* These variables are used in the nested function.  */
00043       Elf_Symndx symidx;
00044       int num_versions = 0;
00045       const ElfW(Sym) *versioned_sym = NULL;
00046 
00047       const struct link_map *map = list[i]->l_real;
00048 
00049       /* Here come the extra test needed for `_dl_lookup_symbol_skip'.  */
00050       if (map == skip)
00051        continue;
00052 
00053       /* Don't search the executable when resolving a copy reloc.  */
00054       if ((type_class & ELF_RTYPE_CLASS_COPY) && map->l_type == lt_executable)
00055        continue;
00056 
00057       /* Do not look into objects which are going to be removed.  */
00058       if (map->l_removed)
00059        continue;
00060 
00061       /* Print some debugging info if wanted.  */
00062       if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_SYMBOLS, 0))
00063        _dl_debug_printf ("symbol=%s;  lookup in file=%s [%lu]\n",
00064                        undef_name,
00065                        map->l_name[0] ? map->l_name : rtld_progname,
00066                        map->l_ns);
00067 
00068       /* If the hash table is empty there is nothing to do here.  */
00069       if (map->l_nbuckets == 0)
00070        continue;
00071 
00072       /* The tables for this map.  */
00073       const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
00074       const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
00075 
00076 
00077       /* Nested routine to check whether the symbol matches.  */
00078       const ElfW(Sym) *
00079       __attribute_noinline__
00080       check_match (const ElfW(Sym) *sym)
00081       {
00082        assert (ELF_RTYPE_CLASS_PLT == 1);
00083        if (__builtin_expect ((sym->st_value == 0 /* No value.  */
00084                             && ELFW(ST_TYPE) (sym->st_info) != STT_TLS)
00085                            || (type_class & (sym->st_shndx == SHN_UNDEF)),
00086                            0))
00087          return NULL;
00088 
00089        if (__builtin_expect (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC
00090                            && ELFW(ST_TYPE) (sym->st_info) != STT_COMMON
00091                            && ELFW(ST_TYPE) (sym->st_info) != STT_TLS, 0))
00092          /* Ignore all but STT_NOTYPE, STT_OBJECT, STT_FUNC, and STT_COMMON
00093             entries (and STT_TLS if TLS is supported) since these
00094             are no code/data definitions.  */
00095          return NULL;
00096 
00097        if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
00098          /* Not the symbol we are looking for.  */
00099          return NULL;
00100 
00101        const ElfW(Half) *verstab = map->l_versyms;
00102        if (version != NULL)
00103          {
00104            if (__builtin_expect (verstab == NULL, 0))
00105              {
00106               /* We need a versioned symbol but haven't found any.  If
00107                  this is the object which is referenced in the verneed
00108                  entry it is a bug in the library since a symbol must
00109                  not simply disappear.
00110 
00111                  It would also be a bug in the object since it means that
00112                  the list of required versions is incomplete and so the
00113                  tests in dl-version.c haven't found a problem.*/
00114               assert (version->filename == NULL
00115                      || ! _dl_name_match_p (version->filename, map));
00116 
00117               /* Otherwise we accept the symbol.  */
00118              }
00119            else
00120              {
00121               /* We can match the version information or use the
00122                  default one if it is not hidden.  */
00123               ElfW(Half) ndx = verstab[symidx] & 0x7fff;
00124               if ((map->l_versions[ndx].hash != version->hash
00125                    || strcmp (map->l_versions[ndx].name, version->name))
00126                   && (version->hidden || map->l_versions[ndx].hash
00127                      || (verstab[symidx] & 0x8000)))
00128                 /* It's not the version we want.  */
00129                 return NULL;
00130              }
00131          }
00132        else
00133          {
00134            /* No specific version is selected.  There are two ways we
00135               can got here:
00136 
00137               - a binary which does not include versioning information
00138               is loaded
00139 
00140               - dlsym() instead of dlvsym() is used to get a symbol which
00141               might exist in more than one form
00142 
00143               If the library does not provide symbol version information
00144               there is no problem at at: we simply use the symbol if it
00145               is defined.
00146 
00147               These two lookups need to be handled differently if the
00148               library defines versions.  In the case of the old
00149               unversioned application the oldest (default) version
00150               should be used.  In case of a dlsym() call the latest and
00151               public interface should be returned.  */
00152            if (verstab != NULL)
00153              {
00154               if ((verstab[symidx] & 0x7fff)
00155                   >= ((flags & DL_LOOKUP_RETURN_NEWEST) ? 2 : 3))
00156                 {
00157                   /* Don't accept hidden symbols.  */
00158                   if ((verstab[symidx] & 0x8000) == 0
00159                      && num_versions++ == 0)
00160                     /* No version so far.  */
00161                     versioned_sym = sym;
00162 
00163                   return NULL;
00164                 }
00165              }
00166          }
00167 
00168        /* There cannot be another entry for this symbol so stop here.  */
00169        return sym;
00170       }
00171 
00172       const ElfW(Sym) *sym;
00173       const ElfW(Addr) *bitmask = map->l_gnu_bitmask;
00174       if (__builtin_expect (bitmask != NULL, 1))
00175        {
00176          ElfW(Addr) bitmask_word
00177            = bitmask[(new_hash / __ELF_NATIVE_CLASS)
00178                     & map->l_gnu_bitmask_idxbits];
00179 
00180          unsigned int hashbit1 = new_hash & (__ELF_NATIVE_CLASS - 1);
00181          unsigned int hashbit2 = ((new_hash >> map->l_gnu_shift)
00182                                & (__ELF_NATIVE_CLASS - 1));
00183 
00184          if (__builtin_expect ((bitmask_word >> hashbit1)
00185                             & (bitmask_word >> hashbit2) & 1, 0))
00186            {
00187              Elf32_Word bucket = map->l_gnu_buckets[new_hash
00188                                                % map->l_nbuckets];
00189              if (bucket != 0)
00190               {
00191                 const Elf32_Word *hasharr = &map->l_gnu_chain_zero[bucket];
00192 
00193                 do
00194                   if (((*hasharr ^ new_hash) >> 1) == 0)
00195                     {
00196                      symidx = hasharr - map->l_gnu_chain_zero;
00197                      sym = check_match (&symtab[symidx]);
00198                      if (sym != NULL)
00199                        goto found_it;
00200                     }
00201                 while ((*hasharr++ & 1u) == 0);
00202               }
00203            }
00204          /* No symbol found.  */
00205          symidx = SHN_UNDEF;
00206        }
00207       else
00208        {
00209          if (*old_hash == 0xffffffff)
00210            *old_hash = _dl_elf_hash (undef_name);
00211 
00212          /* Use the old SysV-style hash table.  Search the appropriate
00213             hash bucket in this object's symbol table for a definition
00214             for the same symbol name.  */
00215          for (symidx = map->l_buckets[*old_hash % map->l_nbuckets];
00216               symidx != STN_UNDEF;
00217               symidx = map->l_chain[symidx])
00218            {
00219              sym = check_match (&symtab[symidx]);
00220              if (sym != NULL)
00221               goto found_it;
00222            }
00223        }
00224 
00225       /* If we have seen exactly one versioned symbol while we are
00226         looking for an unversioned symbol and the version is not the
00227         default version we still accept this symbol since there are
00228         no possible ambiguities.  */
00229       sym = num_versions == 1 ? versioned_sym : NULL;
00230 
00231       if (sym != NULL)
00232        {
00233        found_it:
00234          switch (ELFW(ST_BIND) (sym->st_info))
00235            {
00236            case STB_WEAK:
00237              /* Weak definition.  Use this value if we don't find another.  */
00238              if (__builtin_expect (GLRO(dl_dynamic_weak), 0))
00239               {
00240                 if (! result->s)
00241                   {
00242                     result->s = sym;
00243                     result->m = (struct link_map *) map;
00244                   }
00245                 break;
00246               }
00247              /* FALLTHROUGH */
00248            case STB_GLOBAL:
00249              /* Global definition.  Just what we need.  */
00250              result->s = sym;
00251              result->m = (struct link_map *) map;
00252              return 1;
00253            default:
00254              /* Local symbols are ignored.  */
00255              break;
00256            }
00257        }
00258 
00259       /* If this current map is the one mentioned in the verneed entry
00260         and we have not found a weak entry, it is a bug.  */
00261       if (symidx == STN_UNDEF && version != NULL && version->filename != NULL
00262          && __builtin_expect (_dl_name_match_p (version->filename, map), 0))
00263        return -1;
00264     }
00265   while (++i < n);
00266 
00267   /* We have not found anything until now.  */
00268   return 0;
00269 }