|
Packit Service |
da41ad |
/* Look up a symbol in a single specified object.
|
|
Packit Service |
da41ad |
Copyright (C) 1995-2020 Free Software Foundation, Inc.
|
|
Packit Service |
da41ad |
This file is part of the GNU C Library.
|
|
Packit Service |
da41ad |
|
|
Packit Service |
da41ad |
The GNU C Library is free software; you can redistribute it and/or
|
|
Packit Service |
da41ad |
modify it under the terms of the GNU Lesser General Public
|
|
Packit Service |
da41ad |
License as published by the Free Software Foundation; either
|
|
Packit Service |
da41ad |
version 2.1 of the License, or (at your option) any later version.
|
|
Packit Service |
da41ad |
|
|
Packit Service |
da41ad |
The GNU C Library is distributed in the hope that it will be useful,
|
|
Packit Service |
da41ad |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
da41ad |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
da41ad |
Lesser General Public License for more details.
|
|
Packit Service |
da41ad |
|
|
Packit Service |
da41ad |
You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
da41ad |
License along with the GNU C Library; if not, see
|
|
Packit Service |
da41ad |
<https://www.gnu.org/licenses/>. */
|
|
Packit Service |
da41ad |
|
|
Packit Service |
da41ad |
#include <ldsodefs.h>
|
|
Packit Service |
da41ad |
#include <string.h>
|
|
Packit Service |
da41ad |
#include <elf_machine_sym_no_match.h>
|
|
Packit Service |
da41ad |
#include <dl-hash.h>
|
|
Packit Service |
da41ad |
|
|
Packit Service |
da41ad |
/* This function corresponds to do_lookup_x in elf/dl-lookup.c. The
|
|
Packit Service |
da41ad |
variant here is simplified because it requires symbol
|
|
Packit Service |
da41ad |
versioning. */
|
|
Packit Service |
da41ad |
static const ElfW(Sym) *
|
|
Packit Service |
da41ad |
check_match (const struct link_map *const map, const char *const undef_name,
|
|
Packit Service |
da41ad |
const char *version, uint32_t version_hash,
|
|
Packit Service |
da41ad |
const Elf_Symndx symidx)
|
|
Packit Service |
da41ad |
{
|
|
Packit Service |
da41ad |
const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
|
|
Packit Service |
da41ad |
const ElfW(Sym) *sym = &symtab[symidx];
|
|
Packit Service |
da41ad |
|
|
Packit Service |
da41ad |
unsigned int stt = ELFW(ST_TYPE) (sym->st_info);
|
|
Packit Service |
da41ad |
if (__glibc_unlikely ((sym->st_value == 0 /* No value. */
|
|
Packit Service |
da41ad |
&& sym->st_shndx != SHN_ABS
|
|
Packit Service |
da41ad |
&& stt != STT_TLS)
|
|
Packit Service |
da41ad |
|| elf_machine_sym_no_match (sym)))
|
|
Packit Service |
da41ad |
return NULL;
|
|
Packit Service |
da41ad |
|
|
Packit Service |
da41ad |
/* Ignore all but STT_NOTYPE, STT_OBJECT, STT_FUNC,
|
|
Packit Service |
da41ad |
STT_COMMON, STT_TLS, and STT_GNU_IFUNC since these are no
|
|
Packit Service |
da41ad |
code/data definitions. */
|
|
Packit Service |
da41ad |
#define ALLOWED_STT \
|
|
Packit Service |
da41ad |
((1 << STT_NOTYPE) | (1 << STT_OBJECT) | (1 << STT_FUNC) \
|
|
Packit Service |
da41ad |
| (1 << STT_COMMON) | (1 << STT_TLS) | (1 << STT_GNU_IFUNC))
|
|
Packit Service |
da41ad |
if (__glibc_unlikely (((1 << stt) & ALLOWED_STT) == 0))
|
|
Packit Service |
da41ad |
return NULL;
|
|
Packit Service |
da41ad |
|
|
Packit Service |
da41ad |
const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
|
|
Packit Service |
da41ad |
|
|
Packit Service |
da41ad |
if (strcmp (strtab + sym->st_name, undef_name) != 0)
|
|
Packit Service |
da41ad |
/* Not the symbol we are looking for. */
|
|
Packit Service |
da41ad |
return NULL;
|
|
Packit Service |
da41ad |
|
|
Packit Service |
da41ad |
ElfW(Half) ndx = map->l_versyms[symidx] & 0x7fff;
|
|
Packit Service |
da41ad |
if (map->l_versions[ndx].hash != version_hash
|
|
Packit Service |
da41ad |
|| strcmp (map->l_versions[ndx].name, version) != 0)
|
|
Packit Service |
da41ad |
/* It's not the version we want. */
|
|
Packit Service |
da41ad |
return NULL;
|
|
Packit Service |
da41ad |
|
|
Packit Service |
da41ad |
return sym;
|
|
Packit Service |
da41ad |
}
|
|
Packit Service |
da41ad |
|
|
Packit Service |
da41ad |
|
|
Packit Service |
da41ad |
/* This function corresponds to do_lookup_x in elf/dl-lookup.c. The
|
|
Packit Service |
da41ad |
variant here is simplified because it does not search object
|
|
Packit Service |
da41ad |
dependencies. It is optimized for a successful lookup. */
|
|
Packit Service |
da41ad |
const ElfW(Sym) *
|
|
Packit Service |
da41ad |
_dl_lookup_direct (struct link_map *map,
|
|
Packit Service |
da41ad |
const char *undef_name, uint32_t new_hash,
|
|
Packit Service |
da41ad |
const char *version, uint32_t version_hash)
|
|
Packit Service |
da41ad |
{
|
|
Packit Service |
da41ad |
const ElfW(Addr) *bitmask = map->l_gnu_bitmask;
|
|
Packit Service |
da41ad |
if (__glibc_likely (bitmask != NULL))
|
|
Packit Service |
da41ad |
{
|
|
Packit Service |
da41ad |
Elf32_Word bucket = map->l_gnu_buckets[new_hash % map->l_nbuckets];
|
|
Packit Service |
da41ad |
if (bucket != 0)
|
|
Packit Service |
da41ad |
{
|
|
Packit Service |
da41ad |
const Elf32_Word *hasharr = &map->l_gnu_chain_zero[bucket];
|
|
Packit Service |
da41ad |
|
|
Packit Service |
da41ad |
do
|
|
Packit Service |
da41ad |
if (((*hasharr ^ new_hash) >> 1) == 0)
|
|
Packit Service |
da41ad |
{
|
|
Packit Service |
da41ad |
Elf_Symndx symidx = ELF_MACHINE_HASH_SYMIDX (map, hasharr);
|
|
Packit Service |
da41ad |
const ElfW(Sym) *sym = check_match (map, undef_name,
|
|
Packit Service |
da41ad |
version, version_hash,
|
|
Packit Service |
da41ad |
symidx);
|
|
Packit Service |
da41ad |
if (sym != NULL)
|
|
Packit Service |
da41ad |
return sym;
|
|
Packit Service |
da41ad |
}
|
|
Packit Service |
da41ad |
while ((*hasharr++ & 1u) == 0);
|
|
Packit Service |
da41ad |
}
|
|
Packit Service |
da41ad |
}
|
|
Packit Service |
da41ad |
else
|
|
Packit Service |
da41ad |
{
|
|
Packit Service |
da41ad |
/* Fallback code for lack of GNU_HASH support. */
|
|
Packit Service |
da41ad |
uint32_t old_hash = _dl_elf_hash (undef_name);
|
|
Packit Service |
da41ad |
|
|
Packit Service |
da41ad |
/* Use the old SysV-style hash table. Search the appropriate
|
|
Packit Service |
da41ad |
hash bucket in this object's symbol table for a definition
|
|
Packit Service |
da41ad |
for the same symbol name. */
|
|
Packit Service |
da41ad |
for (Elf_Symndx symidx = map->l_buckets[old_hash % map->l_nbuckets];
|
|
Packit Service |
da41ad |
symidx != STN_UNDEF;
|
|
Packit Service |
da41ad |
symidx = map->l_chain[symidx])
|
|
Packit Service |
da41ad |
{
|
|
Packit Service |
da41ad |
const ElfW(Sym) *sym = check_match (map, undef_name,
|
|
Packit Service |
da41ad |
version, version_hash, symidx);
|
|
Packit Service |
da41ad |
if (sym != NULL)
|
|
Packit Service |
da41ad |
return sym;
|
|
Packit Service |
da41ad |
}
|
|
Packit Service |
da41ad |
}
|
|
Packit Service |
da41ad |
|
|
Packit Service |
da41ad |
return NULL;
|
|
Packit Service |
da41ad |
}
|