Back to index

glibc  2.9
dl-lookup.c
Go to the documentation of this file.
00001 /* Look up a symbol in the loaded objects.
00002    MIPS/Linux version - this is identical to the common version, but
00003    because it is in sysdeps/mips, it gets sysdeps/mips/do-lookup.h.
00004    Using <do-lookup.h> instead of "do-lookup.h" would work too.
00005 
00006    Copyright (C) 1995-2005, 2006, 2007 Free Software Foundation, Inc.
00007    This file is part of the GNU C Library.
00008 
00009    The GNU C Library is free software; you can redistribute it and/or
00010    modify it under the terms of the GNU Lesser General Public
00011    License as published by the Free Software Foundation; either
00012    version 2.1 of the License, or (at your option) any later version.
00013 
00014    The GNU C Library is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017    Lesser General Public License for more details.
00018 
00019    You should have received a copy of the GNU Lesser General Public
00020    License along with the GNU C Library; if not, write to the Free
00021    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00022    02111-1307 USA.  */
00023 
00024 #include <alloca.h>
00025 #include <libintl.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <unistd.h>
00029 #include <ldsodefs.h>
00030 #include <dl-hash.h>
00031 #include <dl-machine.h>
00032 #include <sysdep-cancel.h>
00033 #include <bits/libc-lock.h>
00034 #include <tls.h>
00035 
00036 #include <assert.h>
00037 
00038 #define VERSTAG(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag))
00039 
00040 /* We need this string more than once.  */
00041 static const char undefined_msg[] = "undefined symbol: ";
00042 
00043 
00044 struct sym_val
00045   {
00046     const ElfW(Sym) *s;
00047     struct link_map *m;
00048   };
00049 
00050 
00051 #define make_string(string, rest...) \
00052   ({                                                                 \
00053     const char *all[] = { string, ## rest };                                \
00054     size_t len, cnt;                                                 \
00055     char *result, *cp;                                                      \
00056                                                                      \
00057     len = 1;                                                         \
00058     for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt)              \
00059       len += strlen (all[cnt]);                                             \
00060                                                                      \
00061     cp = result = alloca (len);                                             \
00062     for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt)              \
00063       cp = __stpcpy (cp, all[cnt]);                                         \
00064                                                                      \
00065     result;                                                          \
00066   })
00067 
00068 /* Statistics function.  */
00069 #ifdef SHARED
00070 # define bump_num_relocations() ++GL(dl_num_relocations)
00071 #else
00072 # define bump_num_relocations() ((void) 0)
00073 #endif
00074 
00075 
00076 /* The actual lookup code.  */
00077 #include "do-lookup.h"
00078 
00079 
00080 static uint_fast32_t
00081 dl_new_hash (const char *s)
00082 {
00083   uint_fast32_t h = 5381;
00084   for (unsigned char c = *s; c != '\0'; c = *++s)
00085     h = h * 33 + c;
00086   return h & 0xffffffff;
00087 }
00088 
00089 
00090 /* Add extra dependency on MAP to UNDEF_MAP.  */
00091 static int
00092 internal_function
00093 add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
00094 {
00095   struct link_map *runp;
00096   unsigned int i;
00097   int result = 0;
00098 
00099   /* Avoid self-references and references to objects which cannot be
00100      unloaded anyway.  */
00101   if (undef_map == map)
00102     return 0;
00103 
00104   /* Avoid references to objects which cannot be unloaded anyway.  */
00105   assert (map->l_type == lt_loaded);
00106   if ((map->l_flags_1 & DF_1_NODELETE) != 0)
00107     return 0;
00108 
00109   struct link_map_reldeps *l_reldeps
00110     = atomic_forced_read (undef_map->l_reldeps);
00111 
00112   /* Make sure l_reldeps is read before l_initfini.  */
00113   atomic_read_barrier ();
00114 
00115   /* Determine whether UNDEF_MAP already has a reference to MAP.  First
00116      look in the normal dependencies.  */
00117   struct link_map **l_initfini = atomic_forced_read (undef_map->l_initfini);
00118   if (l_initfini != NULL)
00119     {
00120       for (i = 0; l_initfini[i] != NULL; ++i)
00121        if (l_initfini[i] == map)
00122          return 0;
00123     }
00124 
00125   /* No normal dependency.  See whether we already had to add it
00126      to the special list of dynamic dependencies.  */
00127   unsigned int l_reldepsact = 0;
00128   if (l_reldeps != NULL)
00129     {
00130       struct link_map **list = &l_reldeps->list[0];
00131       l_reldepsact = l_reldeps->act;
00132       for (i = 0; i < l_reldepsact; ++i)
00133        if (list[i] == map)
00134          return 0;
00135     }
00136 
00137   /* Save serial number of the target MAP.  */
00138   unsigned long long serial = map->l_serial;
00139 
00140   /* Make sure nobody can unload the object while we are at it.  */
00141   if (__builtin_expect (flags & DL_LOOKUP_GSCOPE_LOCK, 0))
00142     {
00143       /* We can't just call __rtld_lock_lock_recursive (GL(dl_load_lock))
00144         here, that can result in ABBA deadlock.  */
00145       THREAD_GSCOPE_RESET_FLAG ();
00146       __rtld_lock_lock_recursive (GL(dl_load_lock));
00147       /* While MAP value won't change, after THREAD_GSCOPE_RESET_FLAG ()
00148         it can e.g. point to unallocated memory.  So avoid the optimizer
00149         treating the above read from MAP->l_serial as ensurance it
00150         can safely dereference it.  */
00151       map = atomic_forced_read (map);
00152 
00153       /* From this point on it is unsafe to dereference MAP, until it
00154         has been found in one of the lists.  */
00155 
00156       /* Redo the l_initfini check in case undef_map's l_initfini
00157         changed in the mean time.  */
00158       if (undef_map->l_initfini != l_initfini
00159          && undef_map->l_initfini != NULL)
00160        {
00161          l_initfini = undef_map->l_initfini;
00162          for (i = 0; l_initfini[i] != NULL; ++i)
00163            if (l_initfini[i] == map)
00164              goto out_check;
00165        }
00166 
00167       /* Redo the l_reldeps check if undef_map's l_reldeps changed in
00168         the mean time.  */
00169       if (undef_map->l_reldeps != NULL)
00170        {
00171          if (undef_map->l_reldeps != l_reldeps)
00172            {
00173              struct link_map **list = &undef_map->l_reldeps->list[0];
00174              l_reldepsact = undef_map->l_reldeps->act;
00175              for (i = 0; i < l_reldepsact; ++i)
00176               if (list[i] == map)
00177                 goto out_check;
00178            }
00179          else if (undef_map->l_reldeps->act > l_reldepsact)
00180            {
00181              struct link_map **list
00182               = &undef_map->l_reldeps->list[0];
00183              i = l_reldepsact;
00184              l_reldepsact = undef_map->l_reldeps->act;
00185              for (; i < l_reldepsact; ++i)
00186               if (list[i] == map)
00187                 goto out_check;
00188            }
00189        }
00190     }
00191   else
00192     __rtld_lock_lock_recursive (GL(dl_load_lock));
00193 
00194   /* The object is not yet in the dependency list.  Before we add
00195      it make sure just one more time the object we are about to
00196      reference is still available.  There is a brief period in
00197      which the object could have been removed since we found the
00198      definition.  */
00199   runp = GL(dl_ns)[undef_map->l_ns]._ns_loaded;
00200   while (runp != NULL && runp != map)
00201     runp = runp->l_next;
00202 
00203   if (runp != NULL)
00204     {
00205       /* The object is still available.  */
00206 
00207       /* MAP could have been dlclosed, freed and then some other dlopened
00208         library could have the same link_map pointer.  */
00209       if (map->l_serial != serial)
00210        goto out_check;
00211 
00212       /* Redo the NODELETE check, as when dl_load_lock wasn't held
00213         yet this could have changed.  */
00214       if ((map->l_flags_1 & DF_1_NODELETE) != 0)
00215        goto out;
00216 
00217       /* If the object with the undefined reference cannot be removed ever
00218         just make sure the same is true for the object which contains the
00219         definition.  */
00220       if (undef_map->l_type != lt_loaded
00221          || (undef_map->l_flags_1 & DF_1_NODELETE) != 0)
00222        {
00223          map->l_flags_1 |= DF_1_NODELETE;
00224          goto out;
00225        }
00226 
00227       /* Add the reference now.  */
00228       if (__builtin_expect (l_reldepsact >= undef_map->l_reldepsmax, 0))
00229        {
00230          /* Allocate more memory for the dependency list.  Since this
00231             can never happen during the startup phase we can use
00232             `realloc'.  */
00233          struct link_map_reldeps *newp;
00234          unsigned int max
00235            = undef_map->l_reldepsmax ? undef_map->l_reldepsmax * 2 : 10;
00236 
00237          newp = malloc (sizeof (*newp) + max * sizeof (struct link_map *));
00238          if (newp == NULL)
00239            {
00240              /* If we didn't manage to allocate memory for the list this is
00241                no fatal problem.  We simply make sure the referenced object
00242                cannot be unloaded.  This is semantically the correct
00243                behavior.  */
00244              map->l_flags_1 |= DF_1_NODELETE;
00245              goto out;
00246            }
00247          else
00248            {
00249              if (l_reldepsact)
00250               memcpy (&newp->list[0], &undef_map->l_reldeps->list[0],
00251                      l_reldepsact * sizeof (struct link_map *));
00252              newp->list[l_reldepsact] = map;
00253              newp->act = l_reldepsact + 1;
00254              atomic_write_barrier ();
00255              void *old = undef_map->l_reldeps;
00256              undef_map->l_reldeps = newp;
00257              undef_map->l_reldepsmax = max;
00258              if (old)
00259               _dl_scope_free (old);
00260            }
00261        }
00262       else
00263        {
00264          undef_map->l_reldeps->list[l_reldepsact] = map;
00265          atomic_write_barrier ();
00266          undef_map->l_reldeps->act = l_reldepsact + 1;
00267        }
00268 
00269       /* Display information if we are debugging.  */
00270       if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
00271        _dl_debug_printf ("\
00272 \nfile=%s [%lu];  needed by %s [%lu] (relocation dependency)\n\n",
00273                        map->l_name[0] ? map->l_name : rtld_progname,
00274                        map->l_ns,
00275                        undef_map->l_name[0]
00276                        ? undef_map->l_name : rtld_progname,
00277                        undef_map->l_ns);
00278     }
00279   else
00280     /* Whoa, that was bad luck.  We have to search again.  */
00281     result = -1;
00282 
00283  out:
00284   /* Release the lock.  */
00285   __rtld_lock_unlock_recursive (GL(dl_load_lock));
00286 
00287   if (__builtin_expect (flags & DL_LOOKUP_GSCOPE_LOCK, 0))
00288     THREAD_GSCOPE_SET_FLAG ();
00289 
00290   return result;
00291 
00292  out_check:
00293   if (map->l_serial != serial)
00294     result = -1;
00295   goto out;
00296 }
00297 
00298 static void
00299 internal_function
00300 _dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
00301                   const ElfW(Sym) **ref, struct sym_val *value,
00302                   const struct r_found_version *version, int type_class,
00303                   int protected);
00304 
00305 
00306 /* Search loaded objects' symbol tables for a definition of the symbol
00307    UNDEF_NAME, perhaps with a requested version for the symbol.
00308 
00309    We must never have calls to the audit functions inside this function
00310    or in any function which gets called.  If this would happen the audit
00311    code might create a thread which can throw off all the scope locking.  */
00312 lookup_t
00313 internal_function
00314 _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
00315                    const ElfW(Sym) **ref,
00316                    struct r_scope_elem *symbol_scope[],
00317                    const struct r_found_version *version,
00318                    int type_class, int flags, struct link_map *skip_map)
00319 {
00320   const uint_fast32_t new_hash = dl_new_hash (undef_name);
00321   unsigned long int old_hash = 0xffffffff;
00322   struct sym_val current_value = { NULL, NULL };
00323   struct r_scope_elem **scope = symbol_scope;
00324 
00325   bump_num_relocations ();
00326 
00327   /* No other flag than DL_LOOKUP_ADD_DEPENDENCY or DL_LOOKUP_GSCOPE_LOCK
00328      is allowed if we look up a versioned symbol.  */
00329   assert (version == NULL
00330          || (flags & ~(DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK))
00331             == 0);
00332 
00333   size_t i = 0;
00334   if (__builtin_expect (skip_map != NULL, 0))
00335     /* Search the relevant loaded objects for a definition.  */
00336     while ((*scope)->r_list[i] != skip_map)
00337       ++i;
00338 
00339   /* Search the relevant loaded objects for a definition.  */
00340   for (size_t start = i; *scope != NULL; start = 0, ++scope)
00341     {
00342       int res = do_lookup_x (undef_name, new_hash, &old_hash, *ref,
00343                           &current_value, *scope, start, version, flags,
00344                           skip_map, type_class);
00345       if (res > 0)
00346        break;
00347 
00348       if (__builtin_expect (res, 0) < 0 && skip_map == NULL)
00349        {
00350          /* Oh, oh.  The file named in the relocation entry does not
00351             contain the needed symbol.  This code is never reached
00352             for unversioned lookups.  */
00353          assert (version != NULL);
00354          const char *reference_name = undef_map ? undef_map->l_name : NULL;
00355 
00356          /* XXX We cannot translate the message.  */
00357          _dl_signal_cerror (0, (reference_name[0]
00358                              ? reference_name
00359                              : (rtld_progname ?: "<main program>")),
00360                           N_("relocation error"),
00361                           make_string ("symbol ", undef_name, ", version ",
00362                                      version->name,
00363                                      " not defined in file ",
00364                                      version->filename,
00365                                      " with link time reference",
00366                                      res == -2
00367                                      ? " (no version symbols)" : ""));
00368          *ref = NULL;
00369          return 0;
00370        }
00371     }
00372 
00373   if (__builtin_expect (current_value.s == NULL, 0))
00374     {
00375       if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
00376          && skip_map == NULL)
00377        {
00378          /* We could find no value for a strong reference.  */
00379          const char *reference_name = undef_map ? undef_map->l_name : "";
00380          const char *versionstr = version ? ", version " : "";
00381          const char *versionname = (version && version->name
00382                                  ? version->name : "");
00383 
00384          /* XXX We cannot translate the message.  */
00385          _dl_signal_cerror (0, (reference_name[0]
00386                              ? reference_name
00387                              : (rtld_progname ?: "<main program>")),
00388                           N_("symbol lookup error"),
00389                           make_string (undefined_msg, undef_name,
00390                                      versionstr, versionname));
00391        }
00392       *ref = NULL;
00393       return 0;
00394     }
00395 
00396   int protected = (*ref
00397                  && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED);
00398   if (__builtin_expect (protected != 0, 0))
00399     {
00400       /* It is very tricky.  We need to figure out what value to
00401          return for the protected symbol.  */
00402       if (type_class == ELF_RTYPE_CLASS_PLT)
00403        {
00404          if (current_value.s != NULL && current_value.m != undef_map)
00405            {
00406              current_value.s = *ref;
00407              current_value.m = undef_map;
00408            }
00409        }
00410       else
00411        {
00412          struct sym_val protected_value = { NULL, NULL };
00413 
00414          for (scope = symbol_scope; *scope != NULL; i = 0, ++scope)
00415            if (do_lookup_x (undef_name, new_hash, &old_hash, *ref,
00416                           &protected_value, *scope, i, version, flags,
00417                           skip_map, ELF_RTYPE_CLASS_PLT) != 0)
00418              break;
00419 
00420          if (protected_value.s != NULL && protected_value.m != undef_map)
00421            {
00422              current_value.s = *ref;
00423              current_value.m = undef_map;
00424            }
00425        }
00426     }
00427 
00428   /* We have to check whether this would bind UNDEF_MAP to an object
00429      in the global scope which was dynamically loaded.  In this case
00430      we have to prevent the latter from being unloaded unless the
00431      UNDEF_MAP object is also unloaded.  */
00432   if (__builtin_expect (current_value.m->l_type == lt_loaded, 0)
00433       /* Don't do this for explicit lookups as opposed to implicit
00434         runtime lookups.  */
00435       && (flags & DL_LOOKUP_ADD_DEPENDENCY) != 0
00436       /* Add UNDEF_MAP to the dependencies.  */
00437       && add_dependency (undef_map, current_value.m, flags) < 0)
00438       /* Something went wrong.  Perhaps the object we tried to reference
00439         was just removed.  Try finding another definition.  */
00440       return _dl_lookup_symbol_x (undef_name, undef_map, ref,
00441                               (flags & DL_LOOKUP_GSCOPE_LOCK)
00442                               ? undef_map->l_scope : symbol_scope,
00443                               version, type_class, flags, skip_map);
00444 
00445   /* The object is used.  */
00446   current_value.m->l_used = 1;
00447 
00448   if (__builtin_expect (GLRO(dl_debug_mask)
00449                      & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0))
00450     _dl_debug_bindings (undef_name, undef_map, ref,
00451                      &current_value, version, type_class, protected);
00452 
00453   *ref = current_value.s;
00454   return LOOKUP_VALUE (current_value.m);
00455 }
00456 
00457 
00458 /* Cache the location of MAP's hash table.  */
00459 
00460 void
00461 internal_function
00462 _dl_setup_hash (struct link_map *map)
00463 {
00464   Elf_Symndx *hash;
00465   Elf_Symndx nchain;
00466 
00467   if (__builtin_expect (map->l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
00468                                 + DT_THISPROCNUM + DT_VERSIONTAGNUM
00469                                 + DT_EXTRANUM + DT_VALNUM] != NULL, 1))
00470     {
00471       Elf32_Word *hash32
00472        = (void *) D_PTR (map, l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
00473                                   + DT_THISPROCNUM + DT_VERSIONTAGNUM
00474                                   + DT_EXTRANUM + DT_VALNUM]);
00475       map->l_nbuckets = *hash32++;
00476       Elf32_Word symbias = *hash32++;
00477       Elf32_Word bitmask_nwords = *hash32++;
00478       /* Must be a power of two.  */
00479       assert ((bitmask_nwords & (bitmask_nwords - 1)) == 0);
00480       map->l_gnu_bitmask_idxbits = bitmask_nwords - 1;
00481       map->l_gnu_shift = *hash32++;
00482 
00483       map->l_gnu_bitmask = (ElfW(Addr) *) hash32;
00484       hash32 += __ELF_NATIVE_CLASS / 32 * bitmask_nwords;
00485 
00486       map->l_gnu_buckets = hash32;
00487       hash32 += map->l_nbuckets;
00488       map->l_gnu_chain_zero = hash32 - symbias;
00489       return;
00490     }
00491 
00492   if (!map->l_info[DT_HASH])
00493     return;
00494   hash = (void *) D_PTR (map, l_info[DT_HASH]);
00495 
00496   map->l_nbuckets = *hash++;
00497   nchain = *hash++;
00498   map->l_buckets = hash;
00499   hash += map->l_nbuckets;
00500   map->l_chain = hash;
00501 }
00502 
00503 
00504 static void
00505 internal_function
00506 _dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
00507                   const ElfW(Sym) **ref, struct sym_val *value,
00508                   const struct r_found_version *version, int type_class,
00509                   int protected)
00510 {
00511   const char *reference_name = undef_map->l_name;
00512 
00513   if (GLRO(dl_debug_mask) & DL_DEBUG_BINDINGS)
00514     {
00515       _dl_debug_printf ("binding file %s [%lu] to %s [%lu]: %s symbol `%s'",
00516                      (reference_name[0]
00517                       ? reference_name
00518                       : (rtld_progname ?: "<main program>")),
00519                      undef_map->l_ns,
00520                      value->m->l_name[0] ? value->m->l_name : rtld_progname,
00521                      value->m->l_ns,
00522                      protected ? "protected" : "normal", undef_name);
00523       if (version)
00524        _dl_debug_printf_c (" [%s]\n", version->name);
00525       else
00526        _dl_debug_printf_c ("\n");
00527     }
00528 #ifdef SHARED
00529   if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
00530     {
00531       int conflict = 0;
00532       struct sym_val val = { NULL, NULL };
00533 
00534       if ((GLRO(dl_trace_prelink_map) == NULL
00535           || GLRO(dl_trace_prelink_map) == GL(dl_ns)[LM_ID_BASE]._ns_loaded)
00536          && undef_map != GL(dl_ns)[LM_ID_BASE]._ns_loaded)
00537        {
00538          const uint_fast32_t new_hash = dl_new_hash (undef_name);
00539          unsigned long int old_hash = 0xffffffff;
00540 
00541          do_lookup_x (undef_name, new_hash, &old_hash, *ref, &val,
00542                      undef_map->l_local_scope[0], 0, version, 0, NULL,
00543                      type_class);
00544 
00545          if (val.s != value->s || val.m != value->m)
00546            conflict = 1;
00547        }
00548 
00549       if (value->s
00550          && (__builtin_expect (ELFW(ST_TYPE) (value->s->st_info)
00551                             == STT_TLS, 0)))
00552        type_class = 4;
00553 
00554       if (conflict
00555          || GLRO(dl_trace_prelink_map) == undef_map
00556          || GLRO(dl_trace_prelink_map) == NULL
00557          || type_class == 4)
00558        {
00559          _dl_printf ("%s 0x%0*Zx 0x%0*Zx -> 0x%0*Zx 0x%0*Zx ",
00560                     conflict ? "conflict" : "lookup",
00561                     (int) sizeof (ElfW(Addr)) * 2,
00562                     (size_t) undef_map->l_map_start,
00563                     (int) sizeof (ElfW(Addr)) * 2,
00564                     (size_t) (((ElfW(Addr)) *ref) - undef_map->l_map_start),
00565                     (int) sizeof (ElfW(Addr)) * 2,
00566                     (size_t) (value->s ? value->m->l_map_start : 0),
00567                     (int) sizeof (ElfW(Addr)) * 2,
00568                     (size_t) (value->s ? value->s->st_value : 0));
00569 
00570          if (conflict)
00571            _dl_printf ("x 0x%0*Zx 0x%0*Zx ",
00572                      (int) sizeof (ElfW(Addr)) * 2,
00573                      (size_t) (val.s ? val.m->l_map_start : 0),
00574                      (int) sizeof (ElfW(Addr)) * 2,
00575                      (size_t) (val.s ? val.s->st_value : 0));
00576 
00577          _dl_printf ("/%x %s\n", type_class, undef_name);
00578        }
00579     }
00580 #endif
00581 }