(root)/
glibc-2.38/
elf/
dl-lookup-direct.c
       1  /* Look up a symbol in a single specified object.
       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 <ldsodefs.h>
      20  #include <string.h>
      21  #include <elf_machine_sym_no_match.h>
      22  #include <dl-hash.h>
      23  
      24  /* This function corresponds to do_lookup_x in elf/dl-lookup.c.  The
      25     variant here is simplified because it requires symbol
      26     versioning.  */
      27  static const ElfW(Sym) *
      28  check_match (const struct link_map *const map, const char *const undef_name,
      29               const char *version, uint32_t version_hash,
      30               const Elf_Symndx symidx)
      31  {
      32    const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
      33    const ElfW(Sym) *sym = &symtab[symidx];
      34  
      35    unsigned int stt = ELFW(ST_TYPE) (sym->st_info);
      36    if (__glibc_unlikely ((sym->st_value == 0 /* No value.  */
      37                           && sym->st_shndx != SHN_ABS
      38                           && stt != STT_TLS)
      39                          || elf_machine_sym_no_match (sym)))
      40      return NULL;
      41  
      42    /* Ignore all but STT_NOTYPE, STT_OBJECT, STT_FUNC,
      43       STT_COMMON, STT_TLS, and STT_GNU_IFUNC since these are no
      44       code/data definitions.  */
      45  #define ALLOWED_STT \
      46    ((1 << STT_NOTYPE) | (1 << STT_OBJECT) | (1 << STT_FUNC) \
      47     | (1 << STT_COMMON) | (1 << STT_TLS) | (1 << STT_GNU_IFUNC))
      48    if (__glibc_unlikely (((1 << stt) & ALLOWED_STT) == 0))
      49      return NULL;
      50  
      51    const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
      52  
      53    if (strcmp (strtab + sym->st_name, undef_name) != 0)
      54      /* Not the symbol we are looking for.  */
      55      return NULL;
      56  
      57    ElfW(Half) ndx = map->l_versyms[symidx] & 0x7fff;
      58    if (map->l_versions[ndx].hash != version_hash
      59        || strcmp (map->l_versions[ndx].name, version) != 0)
      60      /* It's not the version we want.  */
      61      return NULL;
      62  
      63    return sym;
      64  }
      65  
      66  
      67  /* This function corresponds to do_lookup_x in elf/dl-lookup.c.  The
      68     variant here is simplified because it does not search object
      69     dependencies.  It is optimized for a successful lookup.  */
      70  const ElfW(Sym) *
      71  _dl_lookup_direct (struct link_map *map,
      72                     const char *undef_name, uint32_t new_hash,
      73                     const char *version, uint32_t version_hash)
      74  {
      75    const ElfW(Addr) *bitmask = map->l_gnu_bitmask;
      76    if (__glibc_likely (bitmask != NULL))
      77      {
      78        Elf32_Word bucket = map->l_gnu_buckets[new_hash % map->l_nbuckets];
      79        if (bucket != 0)
      80          {
      81            const Elf32_Word *hasharr = &map->l_gnu_chain_zero[bucket];
      82  
      83            do
      84              if (((*hasharr ^ new_hash) >> 1) == 0)
      85                {
      86                  Elf_Symndx symidx = ELF_MACHINE_HASH_SYMIDX (map, hasharr);
      87                  const ElfW(Sym) *sym = check_match (map, undef_name,
      88                                                      version, version_hash,
      89                                                      symidx);
      90                  if (sym != NULL)
      91                    return sym;
      92                }
      93            while ((*hasharr++ & 1u) == 0);
      94          }
      95      }
      96    else
      97      {
      98        /* Fallback code for lack of GNU_HASH support.  */
      99        uint32_t old_hash = _dl_elf_hash (undef_name);
     100  
     101        /* Use the old SysV-style hash table.  Search the appropriate
     102           hash bucket in this object's symbol table for a definition
     103           for the same symbol name.  */
     104        for (Elf_Symndx symidx = map->l_buckets[old_hash % map->l_nbuckets];
     105             symidx != STN_UNDEF;
     106             symidx = map->l_chain[symidx])
     107          {
     108            const ElfW(Sym) *sym = check_match (map, undef_name,
     109                                                version, version_hash, symidx);
     110            if (sym != NULL)
     111              return sym;
     112          }
     113      }
     114  
     115    return NULL;
     116  }