(linenum→info "unix/slp.c:2238")

glibc/2.7/elf/do-lookup.h

    1: /* Look up a symbol in the loaded objects.
    2:    Copyright (C) 1995-2004, 2005, 2006, 2007 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, write to the Free
   17:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   18:    02111-1307 USA.  */
   19: 
   20: 
   21: /* Inner part of the lookup functions.  We return a value > 0 if we
   22:    found the symbol, the value 0 if nothing is found and < 0 if
   23:    something bad happened.  */
   24: static int
   25: __attribute_noinline__
   26: do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
   27:              unsigned long int *old_hash, const ElfW(Sym) *ref,
   28:              struct sym_val *result, struct r_scope_elem *scope, size_t i,
   29:              const struct r_found_version *const version, int flags,
   30:              struct link_map *skip, int type_class)
   31: {
   32:   size_t n = scope->r_nlist;
   33:   /* Make sure we read the value before proceeding.  Otherwise we
   34:      might use r_list pointing to the initial scope and r_nlist being
   35:      the value after a resize.  That is the only path in dl-open.c not
   36:      protected by GSCOPE.  A read barrier here might be to expensive.  */
   37:   __asm volatile ("" : "+r" (n), "+m" (scope->r_list));
   38:   struct link_map **list = scope->r_list;
   39: 
   40:   do
   41:     {
   42:       /* These variables are used in the nested function.  */
   43:       Elf_Symndx symidx;
   44:       int num_versions = 0;
   45:       const ElfW(Sym) *versioned_sym = NULL;
   46: 
   47:       const struct link_map *map = list[i]->l_real;
   48: 
   49:       /* Here come the extra test needed for `_dl_lookup_symbol_skip'.  */
   50:       if (map == skip)
   51:         continue;
   52: 
   53:       /* Don't search the executable when resolving a copy reloc.  */
   54:       if ((type_class & ELF_RTYPE_CLASS_COPY) && map->l_type == lt_executable)
   55:         continue;
   56: 
   57:       /* Do not look into objects which are going to be removed.  */
   58:       if (map->l_removed)
   59:         continue;
   60: 
   61:       /* Print some debugging info if wanted.  */
   62:       if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_SYMBOLS, 0))
   63:         _dl_debug_printf ("symbol=%s;  lookup in file=%s [%lu]\n",
   64:                           undef_name,
   65:                           map->l_name[0] ? map->l_name : rtld_progname,
   66:                           map->l_ns);
   67: 
   68:       /* If the hash table is empty there is nothing to do here.  */
   69:       if (map->l_nbuckets == 0)
   70:         continue;
   71: 
   72:       /* The tables for this map.  */
   73:       const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
   74:       const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
   75: 
   76: 
   77:       /* Nested routine to check whether the symbol matches.  */
   78:       const ElfW(Sym) *
   79:       __attribute_noinline__
   80:       check_match (const ElfW(Sym) *sym)
   81:       {
   82:         assert (ELF_RTYPE_CLASS_PLT == 1);
   83:         if (__builtin_expect ((sym->st_value == 0 /* No value.  */
   84:                                && ELFW(ST_TYPE) (sym->st_info) != STT_TLS)
   85:                               || (type_class & (sym->st_shndx == SHN_UNDEF)),
   86:                               0))
   87:           return NULL;
   88: 
   89:         if (__builtin_expect (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC
   90:                               && ELFW(ST_TYPE) (sym->st_info) != STT_COMMON
   91:                               && ELFW(ST_TYPE) (sym->st_info) != STT_TLS, 0))
   92:           /* Ignore all but STT_NOTYPE, STT_OBJECT, STT_FUNC, and STT_COMMON
   93:              entries (and STT_TLS if TLS is supported) since these
   94:              are no code/data definitions.  */
   95:           return NULL;
   96: 
   97:         if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
   98:           /* Not the symbol we are looking for.  */
   99:           return NULL;
  100: 
  101:         const ElfW(Half) *verstab = map->l_versyms;
  102:         if (version != NULL)
  103:           {
  104:             if (__builtin_expect (verstab == NULL, 0))
  105:               {
  106:                 /* We need a versioned symbol but haven't found any.  If
  107:                    this is the object which is referenced in the verneed
  108:                    entry it is a bug in the library since a symbol must
  109:                    not simply disappear.
  110: 
  111:                    It would also be a bug in the object since it means that
  112:                    the list of required versions is incomplete and so the
  113:                    tests in dl-version.c haven't found a problem.*/
  114:                 assert (version->filename == NULL
  115:                         || ! _dl_name_match_p (version->filename, map));
  116: 
  117:                 /* Otherwise we accept the symbol.  */
  118:               }
  119:             else
  120:               {
  121:                 /* We can match the version information or use the
  122:                    default one if it is not hidden.  */
  123:                 ElfW(Half) ndx = verstab[symidx] & 0x7fff;
  124:                 if ((map->l_versions[ndx].hash != version->hash
  125:                      || strcmp (map->l_versions[ndx].name, version->name))
  126:                     && (version->hidden || map->l_versions[ndx].hash
  127:                         || (verstab[symidx] & 0x8000)))
  128:                   /* It's not the version we want.  */
  129:                   return NULL;
  130:               }
  131:           }
  132:         else
  133:           {
  134:             /* No specific version is selected.  There are two ways we
  135:                can got here:
  136: 
  137:                - a binary which does not include versioning information
  138:                is loaded
  139: 
  140:                - dlsym() instead of dlvsym() is used to get a symbol which
  141:                might exist in more than one form
  142: 
  143:                If the library does not provide symbol version information
  144:                there is no problem at at: we simply use the symbol if it
  145:                is defined.
  146: 
  147:                These two lookups need to be handled differently if the
  148:                library defines versions.  In the case of the old
  149:                unversioned application the oldest (default) version
  150:                should be used.  In case of a dlsym() call the latest and
  151:                public interface should be returned.  */
  152:             if (verstab != NULL)
  153:               {
  154:                 if ((verstab[symidx] & 0x7fff)
  155:                     >= ((flags & DL_LOOKUP_RETURN_NEWEST) ? 2 : 3))
  156:                   {
  157:                     /* Don't accept hidden symbols.  */
  158:                     if ((verstab[symidx] & 0x8000) == 0
  159:                         && num_versions++ == 0)
  160:                       /* No version so far.  */
  161:                       versioned_sym = sym;
  162: 
  163:                     return NULL;
  164:                   }
  165:               }
  166:           }
  167: 
  168:         /* There cannot be another entry for this symbol so stop here.  */
  169:         return sym;
  170:       }
  171: 
  172:       const ElfW(Sym) *sym;
  173:       const ElfW(Addr) *bitmask = map->l_gnu_bitmask;
  174:       if (__builtin_expect (bitmask != NULL, 1))
  175:         {
  176:           ElfW(Addr) bitmask_word
  177:             = bitmask[(new_hash / __ELF_NATIVE_CLASS)
  178:                       & map->l_gnu_bitmask_idxbits];
  179: 
  180:           unsigned int hashbit1 = new_hash & (__ELF_NATIVE_CLASS - 1);
  181:           unsigned int hashbit2 = ((new_hash >> map->l_gnu_shift)
  182:                                    & (__ELF_NATIVE_CLASS - 1));
  183: 
  184:           if (__builtin_expect ((bitmask_word >> hashbit1)
  185:                                 & (bitmask_word >> hashbit2) & 1, 0))
  186:             {
  187:               Elf32_Word bucket = map->l_gnu_buckets[new_hash
  188:                                                      % map->l_nbuckets];
  189:               if (bucket != 0)
  190:                 {
  191:                   const Elf32_Word *hasharr = &map->l_gnu_chain_zero[bucket];
  192: 
  193:                   do
  194:                     if (((*hasharr ^ new_hash) >> 1) == 0)
  195:                       {
  196:                         symidx = hasharr - map->l_gnu_chain_zero;
  197:                         sym = check_match (&symtab[symidx]);
  198:                         if (sym != NULL)
  199:                           goto found_it;
  200:                       }
  201:                   while ((*hasharr++ & 1u) == 0);
  202:                 }
  203:             }
  204:           /* No symbol found.  */
  205:           symidx = SHN_UNDEF;
  206:         }
  207:       else
  208:         {
  209:           if (*old_hash == 0xffffffff)
  210:             *old_hash = _dl_elf_hash (undef_name);
  211: 
  212:           /* Use the old SysV-style hash table.  Search the appropriate
  213:              hash bucket in this object's symbol table for a definition
  214:              for the same symbol name.  */
  215:           for (symidx = map->l_buckets[*old_hash % map->l_nbuckets];
  216:                symidx != STN_UNDEF;
  217:                symidx = map->l_chain[symidx])
  218:             {
  219:               sym = check_match (&symtab[symidx]);
  220:               if (sym != NULL)
  221:                 goto found_it;
  222:             }
  223:         }
  224: 
  225:       /* If we have seen exactly one versioned symbol while we are
  226:          looking for an unversioned symbol and the version is not the
  227:          default version we still accept this symbol since there are
  228:          no possible ambiguities.  */
  229:       sym = num_versions == 1 ? versioned_sym : NULL;
  230: 
  231:       if (sym != NULL)
  232:         {
  233:         found_it:
  234:           switch (ELFW(ST_BIND) (sym->st_info))
  235:             {
  236:             case STB_WEAK:
  237:               /* Weak definition.  Use this value if we don't find another.  */
  238:               if (__builtin_expect (GLRO(dl_dynamic_weak), 0))
  239:                 {
  240:                   if (! result->s)
  241:                     {
  242:                       result->s = sym;
  243:                       result->m = (struct link_map *) map;
  244:                     }
  245:                   break;
  246:                 }
  247:               /* FALLTHROUGH */
  248:             case STB_GLOBAL:
  249:               /* Global definition.  Just what we need.  */
  250:               result->s = sym;
  251:               result->m = (struct link_map *) map;
  252:               return 1;
  253:             default:
  254:               /* Local symbols are ignored.  */
  255:               break;
  256:             }
  257:         }
  258: 
  259:       /* If this current map is the one mentioned in the verneed entry
  260:          and we have not found a weak entry, it is a bug.  */
  261:       if (symidx == STN_UNDEF && version != NULL && version->filename != NULL
  262:           && __builtin_expect (_dl_name_match_p (version->filename, map), 0))
  263:         return -1;
  264:     }
  265:   while (++i < n);
  266: 
  267:   /* We have not found anything until now.  */
  268:   return 0;
  269: }
Syntax (Markdown)