(root)/
glibc-2.38/
elf/
dl-lookup.c
       1  /* Look up a symbol in the loaded objects.
       2     Copyright (C) 1995-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <alloca.h>
      20  #include <libintl.h>
      21  #include <stdlib.h>
      22  #include <string.h>
      23  #include <unistd.h>
      24  #include <ldsodefs.h>
      25  #include <dl-hash.h>
      26  #include <dl-machine.h>
      27  #include <dl-new-hash.h>
      28  #include <dl-protected.h>
      29  #include <sysdep-cancel.h>
      30  #include <libc-lock.h>
      31  #include <tls.h>
      32  #include <atomic.h>
      33  #include <elf_machine_sym_no_match.h>
      34  
      35  #include <assert.h>
      36  
      37  #define VERSTAG(tag)	(DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag))
      38  
      39  struct sym_val
      40    {
      41      const ElfW(Sym) *s;
      42      struct link_map *m;
      43    };
      44  
      45  
      46  /* Statistics function.  */
      47  #ifdef SHARED
      48  # define bump_num_relocations() ++GL(dl_num_relocations)
      49  #else
      50  # define bump_num_relocations() ((void) 0)
      51  #endif
      52  
      53  /* Utility function for do_lookup_x. The caller is called with undef_name,
      54     ref, version, flags and type_class, and those are passed as the first
      55     five arguments. The caller then computes sym, symidx, strtab, and map
      56     and passes them as the next four arguments. Lastly the caller passes in
      57     versioned_sym and num_versions which are modified by check_match during
      58     the checking process.  */
      59  static const ElfW(Sym) *
      60  check_match (const char *const undef_name,
      61  	     const ElfW(Sym) *const ref,
      62  	     const struct r_found_version *const version,
      63  	     const int flags,
      64  	     const int type_class,
      65  	     const ElfW(Sym) *const sym,
      66  	     const Elf_Symndx symidx,
      67  	     const char *const strtab,
      68  	     const struct link_map *const map,
      69  	     const ElfW(Sym) **const versioned_sym,
      70  	     int *const num_versions)
      71  {
      72    unsigned int stt = ELFW(ST_TYPE) (sym->st_info);
      73    assert (ELF_RTYPE_CLASS_PLT == 1);
      74    if (__glibc_unlikely ((sym->st_value == 0 /* No value.  */
      75  			 && sym->st_shndx != SHN_ABS
      76  			 && stt != STT_TLS)
      77  			|| elf_machine_sym_no_match (sym)
      78  			|| (type_class & (sym->st_shndx == SHN_UNDEF))))
      79      return NULL;
      80  
      81    /* Ignore all but STT_NOTYPE, STT_OBJECT, STT_FUNC,
      82       STT_COMMON, STT_TLS, and STT_GNU_IFUNC since these are no
      83       code/data definitions.  */
      84  #define ALLOWED_STT \
      85    ((1 << STT_NOTYPE) | (1 << STT_OBJECT) | (1 << STT_FUNC) \
      86     | (1 << STT_COMMON) | (1 << STT_TLS) | (1 << STT_GNU_IFUNC))
      87    if (__glibc_unlikely (((1 << stt) & ALLOWED_STT) == 0))
      88      return NULL;
      89  
      90    if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
      91      /* Not the symbol we are looking for.  */
      92      return NULL;
      93  
      94    const ElfW(Half) *verstab = map->l_versyms;
      95    if (version != NULL)
      96      {
      97        if (__glibc_unlikely (verstab == NULL))
      98  	{
      99  	  /* We need a versioned symbol but haven't found any.  If
     100  	     this is the object which is referenced in the verneed
     101  	     entry it is a bug in the library since a symbol must
     102  	     not simply disappear.
     103  
     104  	     It would also be a bug in the object since it means that
     105  	     the list of required versions is incomplete and so the
     106  	     tests in dl-version.c haven't found a problem.*/
     107  	  assert (version->filename == NULL
     108  		  || ! _dl_name_match_p (version->filename, map));
     109  
     110  	  /* Otherwise we accept the symbol.  */
     111  	}
     112        else
     113  	{
     114  	  /* We can match the version information or use the
     115  	     default one if it is not hidden.  */
     116  	  ElfW(Half) ndx = verstab[symidx] & 0x7fff;
     117  	  if ((map->l_versions[ndx].hash != version->hash
     118  	       || strcmp (map->l_versions[ndx].name, version->name))
     119  	      && (version->hidden || map->l_versions[ndx].hash
     120  		  || (verstab[symidx] & 0x8000)))
     121  	    /* It's not the version we want.  */
     122  	    return NULL;
     123  	}
     124      }
     125    else
     126      {
     127        /* No specific version is selected.  There are two ways we
     128  	 can got here:
     129  
     130  	 - a binary which does not include versioning information
     131  	 is loaded
     132  
     133  	 - dlsym() instead of dlvsym() is used to get a symbol which
     134  	 might exist in more than one form
     135  
     136  	 If the library does not provide symbol version information
     137  	 there is no problem at all: we simply use the symbol if it
     138  	 is defined.
     139  
     140  	 These two lookups need to be handled differently if the
     141  	 library defines versions.  In the case of the old
     142  	 unversioned application the oldest (default) version
     143  	 should be used.  In case of a dlsym() call the latest and
     144  	 public interface should be returned.  */
     145        if (verstab != NULL)
     146  	{
     147  	  if ((verstab[symidx] & 0x7fff)
     148  	      >= ((flags & DL_LOOKUP_RETURN_NEWEST) ? 2 : 3))
     149  	    {
     150  	      /* Don't accept hidden symbols.  */
     151  	      if ((verstab[symidx] & 0x8000) == 0
     152  		  && (*num_versions)++ == 0)
     153  		/* No version so far.  */
     154  		*versioned_sym = sym;
     155  
     156  	      return NULL;
     157  	    }
     158  	}
     159      }
     160  
     161    /* There cannot be another entry for this symbol so stop here.  */
     162    return sym;
     163  }
     164  
     165  /* Utility function for do_lookup_unique.  Add a symbol to TABLE.  */
     166  static void
     167  enter_unique_sym (struct unique_sym *table, size_t size,
     168                    unsigned int hash, const char *name,
     169                    const ElfW(Sym) *sym, const struct link_map *map)
     170  {
     171    size_t idx = hash % size;
     172    size_t hash2 = 1 + hash % (size - 2);
     173    while (table[idx].name != NULL)
     174      {
     175        idx += hash2;
     176        if (idx >= size)
     177          idx -= size;
     178      }
     179  
     180    table[idx].hashval = hash;
     181    table[idx].name = name;
     182    table[idx].sym = sym;
     183    table[idx].map = map;
     184  }
     185  
     186  /* Mark MAP as NODELETE according to the lookup mode in FLAGS.  During
     187     initial relocation, NODELETE state is pending only.  */
     188  static void
     189  mark_nodelete (struct link_map *map, int flags)
     190  {
     191    if (flags & DL_LOOKUP_FOR_RELOCATE)
     192      map->l_nodelete_pending = true;
     193    else
     194      map->l_nodelete_active = true;
     195  }
     196  
     197  /* Return true if MAP is marked as NODELETE according to the lookup
     198     mode in FLAGS> */
     199  static bool
     200  is_nodelete (struct link_map *map, int flags)
     201  {
     202    /* Non-pending NODELETE always counts.  Pending NODELETE only counts
     203       during initial relocation processing.  */
     204    return map->l_nodelete_active
     205      || ((flags & DL_LOOKUP_FOR_RELOCATE) && map->l_nodelete_pending);
     206  }
     207  
     208  /* Utility function for do_lookup_x. Lookup an STB_GNU_UNIQUE symbol
     209     in the unique symbol table, creating a new entry if necessary.
     210     Return the matching symbol in RESULT.  */
     211  static void
     212  do_lookup_unique (const char *undef_name, unsigned int new_hash,
     213  		  struct link_map *map, struct sym_val *result,
     214  		  int type_class, const ElfW(Sym) *sym, const char *strtab,
     215  		  const ElfW(Sym) *ref, const struct link_map *undef_map,
     216  		  int flags)
     217  {
     218    /* We have to determine whether we already found a symbol with this
     219       name before.  If not then we have to add it to the search table.
     220       If we already found a definition we have to use it.  */
     221  
     222    struct unique_sym_table *tab
     223      = &GL(dl_ns)[map->l_ns]._ns_unique_sym_table;
     224  
     225    __rtld_lock_lock_recursive (tab->lock);
     226  
     227    struct unique_sym *entries = tab->entries;
     228    size_t size = tab->size;
     229    if (entries != NULL)
     230      {
     231        size_t idx = new_hash % size;
     232        size_t hash2 = 1 + new_hash % (size - 2);
     233        while (1)
     234  	{
     235  	  if (entries[idx].hashval == new_hash
     236  	      && strcmp (entries[idx].name, undef_name) == 0)
     237  	    {
     238  	      if ((type_class & ELF_RTYPE_CLASS_COPY) != 0)
     239  		{
     240  		  /* We possibly have to initialize the central
     241  		     copy from the copy addressed through the
     242  		     relocation.  */
     243  		  result->s = sym;
     244  		  result->m = map;
     245  		}
     246  	      else
     247  		{
     248  		  result->s = entries[idx].sym;
     249  		  result->m = (struct link_map *) entries[idx].map;
     250  		}
     251  	      __rtld_lock_unlock_recursive (tab->lock);
     252  	      return;
     253  	    }
     254  
     255  	  if (entries[idx].name == NULL)
     256  	    break;
     257  
     258  	  idx += hash2;
     259  	  if (idx >= size)
     260  	    idx -= size;
     261  	}
     262  
     263        if (size * 3 <= tab->n_elements * 4)
     264  	{
     265  	  /* Expand the table.  */
     266  #ifdef RTLD_CHECK_FOREIGN_CALL
     267  	  /* This must not happen during runtime relocations.  */
     268  	  assert (!RTLD_CHECK_FOREIGN_CALL);
     269  #endif
     270  	  size_t newsize = _dl_higher_prime_number (size + 1);
     271  	  struct unique_sym *newentries
     272  	    = calloc (sizeof (struct unique_sym), newsize);
     273  	  if (newentries == NULL)
     274  	    {
     275  	    nomem:
     276  	      __rtld_lock_unlock_recursive (tab->lock);
     277  	      _dl_fatal_printf ("out of memory\n");
     278  	    }
     279  
     280  	  for (idx = 0; idx < size; ++idx)
     281  	    if (entries[idx].name != NULL)
     282  	      enter_unique_sym (newentries, newsize, entries[idx].hashval,
     283                                  entries[idx].name, entries[idx].sym,
     284                                  entries[idx].map);
     285  
     286  	  tab->free (entries);
     287  	  tab->size = newsize;
     288  	  size = newsize;
     289  	  entries = tab->entries = newentries;
     290  	  tab->free = __rtld_free;
     291  	}
     292      }
     293    else
     294      {
     295  #ifdef RTLD_CHECK_FOREIGN_CALL
     296        /* This must not happen during runtime relocations.  */
     297        assert (!RTLD_CHECK_FOREIGN_CALL);
     298  #endif
     299  
     300  #define INITIAL_NUNIQUE_SYM_TABLE 31
     301        size = INITIAL_NUNIQUE_SYM_TABLE;
     302        entries = calloc (sizeof (struct unique_sym), size);
     303        if (entries == NULL)
     304  	goto nomem;
     305  
     306        tab->entries = entries;
     307        tab->size = size;
     308        tab->free = __rtld_free;
     309      }
     310  
     311    if ((type_class & ELF_RTYPE_CLASS_COPY) != 0)
     312      enter_unique_sym (entries, size, new_hash, strtab + sym->st_name, ref,
     313  	   undef_map);
     314    else
     315      {
     316        enter_unique_sym (entries, size,
     317                          new_hash, strtab + sym->st_name, sym, map);
     318  
     319        if (map->l_type == lt_loaded && !is_nodelete (map, flags))
     320  	{
     321  	  /* Make sure we don't unload this object by
     322  	     setting the appropriate flag.  */
     323  	  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS))
     324  	    _dl_debug_printf ("\
     325  marking %s [%lu] as NODELETE due to unique symbol\n",
     326  			      map->l_name, map->l_ns);
     327  	  mark_nodelete (map, flags);
     328  	}
     329      }
     330    ++tab->n_elements;
     331  
     332    __rtld_lock_unlock_recursive (tab->lock);
     333  
     334    result->s = sym;
     335    result->m = (struct link_map *) map;
     336  }
     337  
     338  /* Inner part of the lookup functions.  We return a value > 0 if we
     339     found the symbol, the value 0 if nothing is found and < 0 if
     340     something bad happened.  */
     341  static int
     342  __attribute_noinline__
     343  do_lookup_x (const char *undef_name, unsigned int new_hash,
     344  	     unsigned long int *old_hash, const ElfW(Sym) *ref,
     345  	     struct sym_val *result, struct r_scope_elem *scope, size_t i,
     346  	     const struct r_found_version *const version, int flags,
     347  	     struct link_map *skip, int type_class, struct link_map *undef_map)
     348  {
     349    size_t n = scope->r_nlist;
     350    /* Make sure we read the value before proceeding.  Otherwise we
     351       might use r_list pointing to the initial scope and r_nlist being
     352       the value after a resize.  That is the only path in dl-open.c not
     353       protected by GSCOPE.  A read barrier here might be to expensive.  */
     354    __asm volatile ("" : "+r" (n), "+m" (scope->r_list));
     355    struct link_map **list = scope->r_list;
     356  
     357    do
     358      {
     359        const struct link_map *map = list[i]->l_real;
     360  
     361        /* Here come the extra test needed for `_dl_lookup_symbol_skip'.  */
     362        if (map == skip)
     363  	continue;
     364  
     365        /* Don't search the executable when resolving a copy reloc.  */
     366        if ((type_class & ELF_RTYPE_CLASS_COPY) && map->l_type == lt_executable)
     367  	continue;
     368  
     369        /* Do not look into objects which are going to be removed,
     370  	 except when the referencing object itself is being removed.
     371  
     372  	 The second part covers the situation when an object lazily
     373  	 binds to another object while running its destructor, but the
     374  	 destructor of the other object has already run, so that
     375  	 dlclose has set l_removed.  It may not always be obvious how
     376  	 to avoid such a scenario to programmers creating DSOs,
     377  	 particularly if C++ vague linkage is involved and triggers
     378  	 symbol interposition.
     379  
     380  	 Accepting these to-be-removed objects makes the lazy and
     381  	 BIND_NOW cases more similar.  (With BIND_NOW, the symbol is
     382  	 resolved early, before the destructor call, so the issue does
     383  	 not arise.).  Behavior matches the constructor scenario: the
     384  	 implementation allows binding to symbols of objects whose
     385  	 constructors have not run.  In fact, not doing this would be
     386  	 mostly incompatible with symbol interposition.  */
     387        if (map->l_removed && !(undef_map != NULL && undef_map->l_removed))
     388  	continue;
     389  
     390        /* Print some debugging info if wanted.  */
     391        if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SYMBOLS))
     392  	_dl_debug_printf ("symbol=%s;  lookup in file=%s [%lu]\n",
     393  			  undef_name, DSO_FILENAME (map->l_name),
     394  			  map->l_ns);
     395  
     396        /* If the hash table is empty there is nothing to do here.  */
     397        if (map->l_nbuckets == 0)
     398  	continue;
     399  
     400        Elf_Symndx symidx;
     401        int num_versions = 0;
     402        const ElfW(Sym) *versioned_sym = NULL;
     403  
     404        /* The tables for this map.  */
     405        const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
     406        const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
     407  
     408        const ElfW(Sym) *sym;
     409        const ElfW(Addr) *bitmask = map->l_gnu_bitmask;
     410        if (__glibc_likely (bitmask != NULL))
     411  	{
     412  	  ElfW(Addr) bitmask_word
     413  	    = bitmask[(new_hash / __ELF_NATIVE_CLASS)
     414  		      & map->l_gnu_bitmask_idxbits];
     415  
     416  	  unsigned int hashbit1 = new_hash & (__ELF_NATIVE_CLASS - 1);
     417  	  unsigned int hashbit2 = ((new_hash >> map->l_gnu_shift)
     418  				   & (__ELF_NATIVE_CLASS - 1));
     419  
     420  	  if (__glibc_unlikely ((bitmask_word >> hashbit1)
     421  				& (bitmask_word >> hashbit2) & 1))
     422  	    {
     423  	      Elf32_Word bucket = map->l_gnu_buckets[new_hash
     424  						     % map->l_nbuckets];
     425  	      if (bucket != 0)
     426  		{
     427  		  const Elf32_Word *hasharr = &map->l_gnu_chain_zero[bucket];
     428  
     429  		  do
     430  		    if (((*hasharr ^ new_hash) >> 1) == 0)
     431  		      {
     432  			symidx = ELF_MACHINE_HASH_SYMIDX (map, hasharr);
     433  			sym = check_match (undef_name, ref, version, flags,
     434  					   type_class, &symtab[symidx], symidx,
     435  					   strtab, map, &versioned_sym,
     436  					   &num_versions);
     437  			if (sym != NULL)
     438  			  goto found_it;
     439  		      }
     440  		  while ((*hasharr++ & 1u) == 0);
     441  		}
     442  	    }
     443  	  /* No symbol found.  */
     444  	  symidx = SHN_UNDEF;
     445  	}
     446        else
     447  	{
     448  	  if (*old_hash == 0xffffffff)
     449  	    *old_hash = _dl_elf_hash (undef_name);
     450  
     451  	  /* Use the old SysV-style hash table.  Search the appropriate
     452  	     hash bucket in this object's symbol table for a definition
     453  	     for the same symbol name.  */
     454  	  for (symidx = map->l_buckets[*old_hash % map->l_nbuckets];
     455  	       symidx != STN_UNDEF;
     456  	       symidx = map->l_chain[symidx])
     457  	    {
     458  	      sym = check_match (undef_name, ref, version, flags,
     459  				 type_class, &symtab[symidx], symidx,
     460  				 strtab, map, &versioned_sym,
     461  				 &num_versions);
     462  	      if (sym != NULL)
     463  		goto found_it;
     464  	    }
     465  	}
     466  
     467        /* If we have seen exactly one versioned symbol while we are
     468  	 looking for an unversioned symbol and the version is not the
     469  	 default version we still accept this symbol since there are
     470  	 no possible ambiguities.  */
     471        sym = num_versions == 1 ? versioned_sym : NULL;
     472  
     473        if (sym != NULL)
     474  	{
     475  	found_it:
     476  	  /* Hidden and internal symbols are local, ignore them.  */
     477  	  if (__glibc_unlikely (dl_symbol_visibility_binds_local_p (sym)))
     478  	    goto skip;
     479  
     480  	  if (ELFW(ST_VISIBILITY) (sym->st_other) == STV_PROTECTED)
     481  	    _dl_check_protected_symbol (undef_name, undef_map, ref, map,
     482  					type_class);
     483  
     484  	  switch (ELFW(ST_BIND) (sym->st_info))
     485  	    {
     486  	    case STB_WEAK:
     487  	      /* Weak definition.  Use this value if we don't find another.  */
     488  	      if (__glibc_unlikely (GLRO(dl_dynamic_weak)))
     489  		{
     490  		  if (! result->s)
     491  		    {
     492  		      result->s = sym;
     493  		      result->m = (struct link_map *) map;
     494  		    }
     495  		  break;
     496  		}
     497  	      /* FALLTHROUGH */
     498  	    case STB_GLOBAL:
     499  	      /* Global definition.  Just what we need.  */
     500  	      result->s = sym;
     501  	      result->m = (struct link_map *) map;
     502  	      return 1;
     503  
     504  	    case STB_GNU_UNIQUE:;
     505  	      do_lookup_unique (undef_name, new_hash, (struct link_map *) map,
     506  				result, type_class, sym, strtab, ref,
     507  				undef_map, flags);
     508  	      return 1;
     509  
     510  	    default:
     511  	      /* Local symbols are ignored.  */
     512  	      break;
     513  	    }
     514  	}
     515  
     516  skip:
     517        ;
     518      }
     519    while (++i < n);
     520  
     521    /* We have not found anything until now.  */
     522    return 0;
     523  }
     524  
     525  
     526  /* Add extra dependency on MAP to UNDEF_MAP.  */
     527  static int
     528  add_dependency (struct link_map *undef_map, struct link_map *map, int flags)
     529  {
     530    struct link_map *runp;
     531    unsigned int i;
     532    int result = 0;
     533  
     534    /* Avoid self-references and references to objects which cannot be
     535       unloaded anyway.  */
     536    if (undef_map == map)
     537      return 0;
     538  
     539    /* Avoid references to objects which cannot be unloaded anyway.  We
     540       do not need to record dependencies if this object goes away
     541       during dlopen failure, either.  IFUNC resolvers with relocation
     542       dependencies may pick an dependency which can be dlclose'd, but
     543       such IFUNC resolvers are undefined anyway.  */
     544    assert (map->l_type == lt_loaded);
     545    if (is_nodelete (map, flags))
     546      return 0;
     547  
     548    struct link_map_reldeps *l_reldeps
     549      = atomic_forced_read (undef_map->l_reldeps);
     550  
     551    /* Make sure l_reldeps is read before l_initfini.  */
     552    atomic_read_barrier ();
     553  
     554    /* Determine whether UNDEF_MAP already has a reference to MAP.  First
     555       look in the normal dependencies.  */
     556    struct link_map **l_initfini = atomic_forced_read (undef_map->l_initfini);
     557    if (l_initfini != NULL)
     558      {
     559        for (i = 0; l_initfini[i] != NULL; ++i)
     560  	if (l_initfini[i] == map)
     561  	  return 0;
     562      }
     563  
     564    /* No normal dependency.  See whether we already had to add it
     565       to the special list of dynamic dependencies.  */
     566    unsigned int l_reldepsact = 0;
     567    if (l_reldeps != NULL)
     568      {
     569        struct link_map **list = &l_reldeps->list[0];
     570        l_reldepsact = l_reldeps->act;
     571        for (i = 0; i < l_reldepsact; ++i)
     572  	if (list[i] == map)
     573  	  return 0;
     574      }
     575  
     576    /* Save serial number of the target MAP.  */
     577    unsigned long long serial = map->l_serial;
     578  
     579    /* Make sure nobody can unload the object while we are at it.  */
     580    if (__glibc_unlikely (flags & DL_LOOKUP_GSCOPE_LOCK))
     581      {
     582        /* We can't just call __rtld_lock_lock_recursive (GL(dl_load_lock))
     583  	 here, that can result in ABBA deadlock.  */
     584        THREAD_GSCOPE_RESET_FLAG ();
     585        __rtld_lock_lock_recursive (GL(dl_load_lock));
     586        /* While MAP value won't change, after THREAD_GSCOPE_RESET_FLAG ()
     587  	 it can e.g. point to unallocated memory.  So avoid the optimizer
     588  	 treating the above read from MAP->l_serial as ensurance it
     589  	 can safely dereference it.  */
     590        map = atomic_forced_read (map);
     591  
     592        /* From this point on it is unsafe to dereference MAP, until it
     593  	 has been found in one of the lists.  */
     594  
     595        /* Redo the l_initfini check in case undef_map's l_initfini
     596  	 changed in the mean time.  */
     597        if (undef_map->l_initfini != l_initfini
     598  	  && undef_map->l_initfini != NULL)
     599  	{
     600  	  l_initfini = undef_map->l_initfini;
     601  	  for (i = 0; l_initfini[i] != NULL; ++i)
     602  	    if (l_initfini[i] == map)
     603  	      goto out_check;
     604  	}
     605  
     606        /* Redo the l_reldeps check if undef_map's l_reldeps changed in
     607  	 the mean time.  */
     608        if (undef_map->l_reldeps != NULL)
     609  	{
     610  	  if (undef_map->l_reldeps != l_reldeps)
     611  	    {
     612  	      struct link_map **list = &undef_map->l_reldeps->list[0];
     613  	      l_reldepsact = undef_map->l_reldeps->act;
     614  	      for (i = 0; i < l_reldepsact; ++i)
     615  		if (list[i] == map)
     616  		  goto out_check;
     617  	    }
     618  	  else if (undef_map->l_reldeps->act > l_reldepsact)
     619  	    {
     620  	      struct link_map **list
     621  		= &undef_map->l_reldeps->list[0];
     622  	      i = l_reldepsact;
     623  	      l_reldepsact = undef_map->l_reldeps->act;
     624  	      for (; i < l_reldepsact; ++i)
     625  		if (list[i] == map)
     626  		  goto out_check;
     627  	    }
     628  	}
     629      }
     630    else
     631      __rtld_lock_lock_recursive (GL(dl_load_lock));
     632  
     633    /* The object is not yet in the dependency list.  Before we add
     634       it make sure just one more time the object we are about to
     635       reference is still available.  There is a brief period in
     636       which the object could have been removed since we found the
     637       definition.  */
     638    runp = GL(dl_ns)[undef_map->l_ns]._ns_loaded;
     639    while (runp != NULL && runp != map)
     640      runp = runp->l_next;
     641  
     642    if (runp != NULL)
     643      {
     644        /* The object is still available.  */
     645  
     646        /* MAP could have been dlclosed, freed and then some other dlopened
     647  	 library could have the same link_map pointer.  */
     648        if (map->l_serial != serial)
     649  	goto out_check;
     650  
     651        /* Redo the NODELETE check, as when dl_load_lock wasn't held
     652  	 yet this could have changed.  */
     653        if (is_nodelete (map, flags))
     654  	goto out;
     655  
     656        /* If the object with the undefined reference cannot be removed ever
     657  	 just make sure the same is true for the object which contains the
     658  	 definition.  */
     659        if (undef_map->l_type != lt_loaded || is_nodelete (map, flags))
     660  	{
     661  	  if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS)
     662  	      && !is_nodelete (map, flags))
     663  	    {
     664  	      if (undef_map->l_name[0] == '\0')
     665  		_dl_debug_printf ("\
     666  marking %s [%lu] as NODELETE due to reference from main program\n",
     667  				  map->l_name, map->l_ns);
     668  	      else
     669  		_dl_debug_printf ("\
     670  marking %s [%lu] as NODELETE due to reference from %s [%lu]\n",
     671  				  map->l_name, map->l_ns,
     672  				  undef_map->l_name, undef_map->l_ns);
     673  	    }
     674  	  mark_nodelete (map, flags);
     675  	  goto out;
     676  	}
     677  
     678        /* Add the reference now.  */
     679        if (__glibc_unlikely (l_reldepsact >= undef_map->l_reldepsmax))
     680  	{
     681  	  /* Allocate more memory for the dependency list.  Since this
     682  	     can never happen during the startup phase we can use
     683  	     `realloc'.  */
     684  	  struct link_map_reldeps *newp;
     685  	  unsigned int max
     686  	    = undef_map->l_reldepsmax ? undef_map->l_reldepsmax * 2 : 10;
     687  
     688  #ifdef RTLD_PREPARE_FOREIGN_CALL
     689  	  RTLD_PREPARE_FOREIGN_CALL;
     690  #endif
     691  
     692  	  newp = malloc (sizeof (*newp) + max * sizeof (struct link_map *));
     693  	  if (newp == NULL)
     694  	    {
     695  	      /* If we didn't manage to allocate memory for the list this is
     696  		 no fatal problem.  We simply make sure the referenced object
     697  		 cannot be unloaded.  This is semantically the correct
     698  		 behavior.  */
     699  	      if (__glibc_unlikely (GLRO (dl_debug_mask) & DL_DEBUG_BINDINGS)
     700  		  && !is_nodelete (map, flags))
     701  		_dl_debug_printf ("\
     702  marking %s [%lu] as NODELETE due to memory allocation failure\n",
     703  				  map->l_name, map->l_ns);
     704  	      /* In case of non-lazy binding, we could actually report
     705  		 the memory allocation error, but for now, we use the
     706  		 conservative approximation as well.  */
     707  	      mark_nodelete (map, flags);
     708  	      goto out;
     709  	    }
     710  	  else
     711  	    {
     712  	      if (l_reldepsact)
     713  		memcpy (&newp->list[0], &undef_map->l_reldeps->list[0],
     714  			l_reldepsact * sizeof (struct link_map *));
     715  	      newp->list[l_reldepsact] = map;
     716  	      newp->act = l_reldepsact + 1;
     717  	      atomic_write_barrier ();
     718  	      void *old = undef_map->l_reldeps;
     719  	      undef_map->l_reldeps = newp;
     720  	      undef_map->l_reldepsmax = max;
     721  	      if (old)
     722  		_dl_scope_free (old);
     723  	    }
     724  	}
     725        else
     726  	{
     727  	  undef_map->l_reldeps->list[l_reldepsact] = map;
     728  	  atomic_write_barrier ();
     729  	  undef_map->l_reldeps->act = l_reldepsact + 1;
     730  	}
     731  
     732        /* Display information if we are debugging.  */
     733        if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
     734  	_dl_debug_printf ("\
     735  \nfile=%s [%lu];  needed by %s [%lu] (relocation dependency)\n\n",
     736  			  DSO_FILENAME (map->l_name),
     737  			  map->l_ns,
     738  			  DSO_FILENAME (undef_map->l_name),
     739  			  undef_map->l_ns);
     740      }
     741    else
     742      /* Whoa, that was bad luck.  We have to search again.  */
     743      result = -1;
     744  
     745   out:
     746    /* Release the lock.  */
     747    __rtld_lock_unlock_recursive (GL(dl_load_lock));
     748  
     749    if (__glibc_unlikely (flags & DL_LOOKUP_GSCOPE_LOCK))
     750      THREAD_GSCOPE_SET_FLAG ();
     751  
     752    return result;
     753  
     754   out_check:
     755    if (map->l_serial != serial)
     756      result = -1;
     757    goto out;
     758  }
     759  
     760  
     761  /* Search loaded objects' symbol tables for a definition of the symbol
     762     UNDEF_NAME, perhaps with a requested version for the symbol.
     763  
     764     We must never have calls to the audit functions inside this function
     765     or in any function which gets called.  If this would happen the audit
     766     code might create a thread which can throw off all the scope locking.  */
     767  lookup_t
     768  _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
     769  		     const ElfW(Sym) **ref,
     770  		     struct r_scope_elem *symbol_scope[],
     771  		     const struct r_found_version *version,
     772  		     int type_class, int flags, struct link_map *skip_map)
     773  {
     774    const unsigned int new_hash = _dl_new_hash (undef_name);
     775    unsigned long int old_hash = 0xffffffff;
     776    struct sym_val current_value = { NULL, NULL };
     777    struct r_scope_elem **scope = symbol_scope;
     778  
     779    bump_num_relocations ();
     780  
     781    /* DL_LOOKUP_RETURN_NEWEST does not make sense for versioned
     782       lookups.  */
     783    assert (version == NULL || !(flags & DL_LOOKUP_RETURN_NEWEST));
     784  
     785    size_t i = 0;
     786    if (__glibc_unlikely (skip_map != NULL))
     787      /* Search the relevant loaded objects for a definition.  */
     788      while ((*scope)->r_list[i] != skip_map)
     789        ++i;
     790  
     791    /* Search the relevant loaded objects for a definition.  */
     792    for (size_t start = i; *scope != NULL; start = 0, ++scope)
     793      if (do_lookup_x (undef_name, new_hash, &old_hash, *ref,
     794  		     &current_value, *scope, start, version, flags,
     795  		     skip_map, type_class, undef_map) != 0)
     796        break;
     797  
     798    if (__glibc_unlikely (current_value.s == NULL))
     799      {
     800        if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
     801  	  && !(GLRO(dl_debug_mask) & DL_DEBUG_UNUSED))
     802  	{
     803  	  /* We could find no value for a strong reference.  */
     804  	  const char *reference_name = undef_map ? undef_map->l_name : "";
     805  	  const char *versionstr = version ? ", version " : "";
     806  	  const char *versionname = (version && version->name
     807  				     ? version->name : "");
     808  	  struct dl_exception exception;
     809  	  /* XXX We cannot translate the message.  */
     810  	  _dl_exception_create_format
     811  	    (&exception, DSO_FILENAME (reference_name),
     812  	     "undefined symbol: %s%s%s",
     813  	     undef_name, versionstr, versionname);
     814  	  _dl_signal_cexception (0, &exception, N_("symbol lookup error"));
     815  	  _dl_exception_free (&exception);
     816  	}
     817        *ref = NULL;
     818        return 0;
     819      }
     820  
     821    int protected = (*ref
     822  		   && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED);
     823    if (__glibc_unlikely (protected != 0))
     824      {
     825        /* It is very tricky.  We need to figure out what value to
     826  	 return for the protected symbol.  */
     827        if (type_class == ELF_RTYPE_CLASS_PLT)
     828  	{
     829  	  if (current_value.s != NULL && current_value.m != undef_map)
     830  	    {
     831  	      current_value.s = *ref;
     832  	      current_value.m = undef_map;
     833  	    }
     834  	}
     835        else
     836  	{
     837  	  struct sym_val protected_value = { NULL, NULL };
     838  
     839  	  for (scope = symbol_scope; *scope != NULL; i = 0, ++scope)
     840  	    if (do_lookup_x (undef_name, new_hash, &old_hash, *ref,
     841  			     &protected_value, *scope, i, version, flags,
     842  			     skip_map, ELF_RTYPE_CLASS_PLT, NULL) != 0)
     843  	      break;
     844  
     845  	  if (protected_value.s != NULL && protected_value.m != undef_map)
     846  	    {
     847  	      current_value.s = *ref;
     848  	      current_value.m = undef_map;
     849  	    }
     850  	}
     851      }
     852  
     853    /* We have to check whether this would bind UNDEF_MAP to an object
     854       in the global scope which was dynamically loaded.  In this case
     855       we have to prevent the latter from being unloaded unless the
     856       UNDEF_MAP object is also unloaded.  */
     857    if (__glibc_unlikely (current_value.m->l_type == lt_loaded)
     858        /* Don't do this for explicit lookups as opposed to implicit
     859  	 runtime lookups.  */
     860        && (flags & DL_LOOKUP_ADD_DEPENDENCY) != 0
     861        /* Add UNDEF_MAP to the dependencies.  */
     862        && add_dependency (undef_map, current_value.m, flags) < 0)
     863        /* Something went wrong.  Perhaps the object we tried to reference
     864  	 was just removed.  Try finding another definition.  */
     865        return _dl_lookup_symbol_x (undef_name, undef_map, ref,
     866  				  (flags & DL_LOOKUP_GSCOPE_LOCK)
     867  				  ? undef_map->l_scope : symbol_scope,
     868  				  version, type_class, flags, skip_map);
     869  
     870    /* The object is used.  */
     871    if (__glibc_unlikely (current_value.m->l_used == 0))
     872      current_value.m->l_used = 1;
     873  
     874   if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_BINDINGS))
     875     {
     876        const char *reference_name = undef_map->l_name;
     877  
     878        _dl_debug_printf ("binding file %s [%lu] to %s [%lu]: %s symbol `%s'",
     879  			DSO_FILENAME (reference_name),
     880  			undef_map->l_ns,
     881  			DSO_FILENAME (current_value.m->l_name),
     882  			current_value.m->l_ns,
     883  			protected ? "protected" : "normal", undef_name);
     884        if (version)
     885  	_dl_debug_printf_c (" [%s]\n", version->name);
     886        else
     887  	_dl_debug_printf_c ("\n");
     888     }
     889  
     890  
     891    *ref = current_value.s;
     892    return LOOKUP_VALUE (current_value.m);
     893  }