(root)/
glibc-2.38/
elf/
dl-sym.c
       1  /* Look up a symbol in a shared object loaded by `dlopen'.
       2     Copyright (C) 1999-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 <assert.h>
      20  #include <stddef.h>
      21  #include <setjmp.h>
      22  #include <stdlib.h>
      23  #include <libintl.h>
      24  
      25  #include <dlfcn.h>
      26  #include <ldsodefs.h>
      27  #include <dl-hash.h>
      28  #include <sysdep-cancel.h>
      29  #include <dl-tls.h>
      30  #include <dl-irel.h>
      31  #include <dl-sym-post.h>
      32  
      33  
      34  #ifdef SHARED
      35  /* Systems which do not have tls_index also probably have to define
      36     DONT_USE_TLS_INDEX.  */
      37  
      38  # ifndef __TLS_GET_ADDR
      39  #  define __TLS_GET_ADDR __tls_get_addr
      40  # endif
      41  
      42  /* Return the symbol address given the map of the module it is in and
      43     the symbol record.  This is used in dl-sym.c.  */
      44  static void *
      45  _dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref)
      46  {
      47  # ifndef DONT_USE_TLS_INDEX
      48    tls_index tmp =
      49      {
      50        .ti_module = map->l_tls_modid,
      51        .ti_offset = ref->st_value
      52      };
      53  
      54    return __TLS_GET_ADDR (&tmp);
      55  # else
      56    return __TLS_GET_ADDR (map->l_tls_modid, ref->st_value);
      57  # endif
      58  }
      59  #endif
      60  
      61  
      62  struct call_dl_lookup_args
      63  {
      64    /* Arguments to do_dlsym.  */
      65    struct link_map *map;
      66    const char *name;
      67    struct r_found_version *vers;
      68    int flags;
      69  
      70    /* Return values of do_dlsym.  */
      71    lookup_t loadbase;
      72    const ElfW(Sym) **refp;
      73  };
      74  
      75  static void
      76  call_dl_lookup (void *ptr)
      77  {
      78    struct call_dl_lookup_args *args = (struct call_dl_lookup_args *) ptr;
      79    args->map = GLRO(dl_lookup_symbol_x) (args->name, args->map, args->refp,
      80  					args->map->l_scope, args->vers, 0,
      81  					args->flags, NULL);
      82  }
      83  
      84  static void *
      85  do_sym (void *handle, const char *name, void *who,
      86  	struct r_found_version *vers, int flags)
      87  {
      88    const ElfW(Sym) *ref = NULL;
      89    lookup_t result;
      90    ElfW(Addr) caller = (ElfW(Addr)) who;
      91  
      92    /* Link map of the caller if needed.  */
      93    struct link_map *match = NULL;
      94  
      95    if (handle == RTLD_DEFAULT)
      96      {
      97        match = _dl_sym_find_caller_link_map (caller);
      98  
      99        /* Search the global scope.  We have the simple case where
     100  	 we look up in the scope of an object which was part of
     101  	 the initial binary.  And then the more complex part
     102  	 where the object is dynamically loaded and the scope
     103  	 array can change.  */
     104        if (RTLD_SINGLE_THREAD_P)
     105  	result = GLRO(dl_lookup_symbol_x) (name, match, &ref,
     106  					   match->l_scope, vers, 0,
     107  					   flags | DL_LOOKUP_ADD_DEPENDENCY,
     108  					   NULL);
     109        else
     110  	{
     111  	  struct call_dl_lookup_args args;
     112  	  args.name = name;
     113  	  args.map = match;
     114  	  args.vers = vers;
     115  	  args.flags
     116  	    = flags | DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK;
     117  	  args.refp = &ref;
     118  
     119  	  THREAD_GSCOPE_SET_FLAG ();
     120  	  struct dl_exception exception;
     121  	  int err = _dl_catch_exception (&exception, call_dl_lookup, &args);
     122  	  THREAD_GSCOPE_RESET_FLAG ();
     123  	  if (__glibc_unlikely (exception.errstring != NULL))
     124  	    _dl_signal_exception (err, &exception, NULL);
     125  
     126  	  result = args.map;
     127  	}
     128      }
     129    else if (handle == RTLD_NEXT)
     130      {
     131        match = _dl_sym_find_caller_link_map (caller);
     132  
     133        if (__glibc_unlikely (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded))
     134  	{
     135  	  if (match == NULL
     136  	      || caller < match->l_map_start
     137  	      || caller >= match->l_map_end)
     138  	    _dl_signal_error (0, NULL, NULL, N_("\
     139  RTLD_NEXT used in code not dynamically loaded"));
     140  	}
     141  
     142        struct link_map *l = match;
     143        while (l->l_loader != NULL)
     144  	l = l->l_loader;
     145  
     146        result = GLRO(dl_lookup_symbol_x) (name, match, &ref, l->l_local_scope,
     147  					 vers, 0, flags, match);
     148      }
     149    else
     150      {
     151        /* Search the scope of the given object.  */
     152        struct link_map *map = handle;
     153        result = GLRO(dl_lookup_symbol_x) (name, map, &ref, map->l_local_scope,
     154  					 vers, 0, flags, NULL);
     155      }
     156  
     157    if (ref != NULL)
     158      {
     159        void *value;
     160  
     161  #ifdef SHARED
     162        if (ELFW(ST_TYPE) (ref->st_info) == STT_TLS)
     163  	/* The found symbol is a thread-local storage variable.
     164  	   Return the address for to the current thread.  */
     165  	value = _dl_tls_symaddr (result, ref);
     166        else
     167  #endif
     168  	value = DL_SYMBOL_ADDRESS (result, ref);
     169  
     170        return _dl_sym_post (result, ref, value, caller, match);
     171      }
     172  
     173    return NULL;
     174  }
     175  
     176  
     177  void *
     178  _dl_vsym (void *handle, const char *name, const char *version, void *who)
     179  {
     180    struct r_found_version vers;
     181  
     182    /* Compute hash value to the version string.  */
     183    vers.name = version;
     184    vers.hidden = 1;
     185    vers.hash = _dl_elf_hash (version);
     186    /* We don't have a specific file where the symbol can be found.  */
     187    vers.filename = NULL;
     188  
     189    return do_sym (handle, name, who, &vers, 0);
     190  }
     191  
     192  void *
     193  _dl_sym (void *handle, const char *name, void *who)
     194  {
     195    return do_sym (handle, name, who, NULL, DL_LOOKUP_RETURN_NEWEST);
     196  }