svn commit: r235396 - in stable/9/libexec/rtld-elf: . amd64 arm
i386 ia64 powerpc powerpc64 sparc64
Konstantin Belousov
kib at FreeBSD.org
Sun May 13 12:50:43 UTC 2012
Author: kib
Date: Sun May 13 12:50:42 2012
New Revision: 235396
URL: http://svn.freebsd.org/changeset/base/235396
Log:
MFC r234840:
Split the symlook_obj1 into a loop iterating over the ELF object symbol
hash elements, and a helper matched_symbol() which match the given hash
entry and request, performing needed type and version checks.
MFC r234841:
Add GNU hash support for rtld.
MFC r235054:
Work around a situation where symlook_obj() could be called for the
object for which digest_dynamic1() was not done yet. Just return
EINVAL and do not try to dereference NULL buckets hash array.
Modified:
stable/9/libexec/rtld-elf/amd64/reloc.c
stable/9/libexec/rtld-elf/arm/reloc.c
stable/9/libexec/rtld-elf/i386/reloc.c
stable/9/libexec/rtld-elf/ia64/reloc.c
stable/9/libexec/rtld-elf/powerpc/reloc.c
stable/9/libexec/rtld-elf/powerpc64/reloc.c
stable/9/libexec/rtld-elf/rtld.c
stable/9/libexec/rtld-elf/rtld.h
stable/9/libexec/rtld-elf/sparc64/reloc.c
Directory Properties:
stable/9/libexec/rtld-elf/ (props changed)
Modified: stable/9/libexec/rtld-elf/amd64/reloc.c
==============================================================================
--- stable/9/libexec/rtld-elf/amd64/reloc.c Sun May 13 11:34:05 2012 (r235395)
+++ stable/9/libexec/rtld-elf/amd64/reloc.c Sun May 13 12:50:42 2012 (r235396)
@@ -132,7 +132,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry
* limited amounts of stack available so we cannot use alloca().
*/
if (obj != obj_rtld) {
- cache = calloc(obj->nchains, sizeof(SymCache));
+ cache = calloc(obj->dynsymcount, sizeof(SymCache));
/* No need to check for NULL here */
} else
cache = NULL;
Modified: stable/9/libexec/rtld-elf/arm/reloc.c
==============================================================================
--- stable/9/libexec/rtld-elf/arm/reloc.c Sun May 13 11:34:05 2012 (r235395)
+++ stable/9/libexec/rtld-elf/arm/reloc.c Sun May 13 12:50:42 2012 (r235396)
@@ -268,7 +268,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry
* The dynamic loader may be called from a thread, we have
* limited amounts of stack available so we cannot use alloca().
*/
- cache = calloc(obj->nchains, sizeof(SymCache));
+ cache = calloc(obj->dynsymcount, sizeof(SymCache));
/* No need to check for NULL here */
rellim = (const Elf_Rel *)((caddr_t)obj->rel + obj->relsize);
Modified: stable/9/libexec/rtld-elf/i386/reloc.c
==============================================================================
--- stable/9/libexec/rtld-elf/i386/reloc.c Sun May 13 11:34:05 2012 (r235395)
+++ stable/9/libexec/rtld-elf/i386/reloc.c Sun May 13 12:50:42 2012 (r235396)
@@ -133,7 +133,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry
* limited amounts of stack available so we cannot use alloca().
*/
if (obj != obj_rtld) {
- cache = calloc(obj->nchains, sizeof(SymCache));
+ cache = calloc(obj->dynsymcount, sizeof(SymCache));
/* No need to check for NULL here */
} else
cache = NULL;
Modified: stable/9/libexec/rtld-elf/ia64/reloc.c
==============================================================================
--- stable/9/libexec/rtld-elf/ia64/reloc.c Sun May 13 11:34:05 2012 (r235395)
+++ stable/9/libexec/rtld-elf/ia64/reloc.c Sun May 13 12:50:42 2012 (r235396)
@@ -104,7 +104,7 @@ alloc_fptrs(Obj_Entry *obj, bool mapped)
struct fptr **fptrs;
size_t fbytes;
- fbytes = obj->nchains * sizeof(struct fptr *);
+ fbytes = obj->dynsymcount * sizeof(struct fptr *);
/*
* Avoid malloc, if requested. Happens when relocating
@@ -138,7 +138,7 @@ free_fptrs(Obj_Entry *obj, bool mapped)
if (fptrs == NULL)
return;
- fbytes = obj->nchains * sizeof(struct fptr *);
+ fbytes = obj->dynsymcount * sizeof(struct fptr *);
if (mapped)
munmap(fptrs, fbytes);
else
@@ -348,7 +348,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry
const Elf_Rela *relalim;
const Elf_Rela *rela;
SymCache *cache;
- int bytes = obj->nchains * sizeof(SymCache);
+ int bytes = obj->dynsymcount * sizeof(SymCache);
int r = -1;
/*
Modified: stable/9/libexec/rtld-elf/powerpc/reloc.c
==============================================================================
--- stable/9/libexec/rtld-elf/powerpc/reloc.c Sun May 13 11:34:05 2012 (r235395)
+++ stable/9/libexec/rtld-elf/powerpc/reloc.c Sun May 13 12:50:42 2012 (r235396)
@@ -299,7 +299,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry
* limited amounts of stack available so we cannot use alloca().
*/
if (obj != obj_rtld) {
- cache = calloc(obj->nchains, sizeof(SymCache));
+ cache = calloc(obj->dynsymcount, sizeof(SymCache));
/* No need to check for NULL here */
} else
cache = NULL;
Modified: stable/9/libexec/rtld-elf/powerpc64/reloc.c
==============================================================================
--- stable/9/libexec/rtld-elf/powerpc64/reloc.c Sun May 13 11:34:05 2012 (r235395)
+++ stable/9/libexec/rtld-elf/powerpc64/reloc.c Sun May 13 12:50:42 2012 (r235396)
@@ -287,7 +287,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry
const Elf_Rela *relalim;
const Elf_Rela *rela;
SymCache *cache;
- int bytes = obj->nchains * sizeof(SymCache);
+ int bytes = obj->dynsymcount * sizeof(SymCache);
int r = -1;
/*
Modified: stable/9/libexec/rtld-elf/rtld.c
==============================================================================
--- stable/9/libexec/rtld-elf/rtld.c Sun May 13 11:34:05 2012 (r235395)
+++ stable/9/libexec/rtld-elf/rtld.c Sun May 13 12:50:42 2012 (r235396)
@@ -1,7 +1,8 @@
/*-
* Copyright 1996, 1997, 1998, 1999, 2000 John D. Polstra.
* Copyright 2003 Alexander Kabaev <kan at FreeBSD.ORG>.
- * Copyright 2009, 2010, 2011 Konstantin Belousov <kib at FreeBSD.ORG>.
+ * Copyright 2009-2012 Konstantin Belousov <kib at FreeBSD.ORG>.
+ * Copyright 2012 John Marino <draco at marino.st>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -132,7 +133,8 @@ static int symlook_global(SymLook *, Don
static void symlook_init_from_req(SymLook *, const SymLook *);
static int symlook_list(SymLook *, const Objlist *, DoneList *);
static int symlook_needed(SymLook *, const Needed_Entry *, DoneList *);
-static int symlook_obj1(SymLook *, const Obj_Entry *);
+static int symlook_obj1_sysv(SymLook *, const Obj_Entry *);
+static int symlook_obj1_gnu(SymLook *, const Obj_Entry *);
static void trace_loaded_objects(Obj_Entry *);
static void unlink_object(Obj_Entry *);
static void unload_object(Obj_Entry *);
@@ -149,6 +151,9 @@ static int object_match_name(const Obj_
static void ld_utrace_log(int, void *, void *, size_t, int, const char *);
static void rtld_fill_dl_phdr_info(const Obj_Entry *obj,
struct dl_phdr_info *phdr_info);
+static uint32_t gnu_hash(const char *);
+static bool matched_symbol(SymLook *, const Obj_Entry *, Sym_Match_Result *,
+ const unsigned long);
void r_debug_state(struct r_debug *, struct link_map *) __noinline;
@@ -485,6 +490,9 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_
}
digest_dynamic(obj_main, 0);
+ dbg("%s valid_hash_sysv %d valid_hash_gnu %d dynsymcount %d",
+ obj_main->path, obj_main->valid_hash_sysv, obj_main->valid_hash_gnu,
+ obj_main->dynsymcount);
linkmap_add(obj_main);
linkmap_add(&obj_rtld);
@@ -822,6 +830,11 @@ digest_dynamic1(Obj_Entry *obj, int earl
Needed_Entry **needed_tail = &obj->needed;
Needed_Entry **needed_filtees_tail = &obj->needed_filtees;
Needed_Entry **needed_aux_filtees_tail = &obj->needed_aux_filtees;
+ const Elf_Hashelt *hashtab;
+ const Elf32_Word *hashval;
+ Elf32_Word bkt, nmaskwords;
+ int bloom_size32;
+ bool nmw_power2;
int plttype = DT_REL;
*dyn_rpath = NULL;
@@ -911,12 +924,35 @@ digest_dynamic1(Obj_Entry *obj, int earl
case DT_HASH:
{
- const Elf_Hashelt *hashtab = (const Elf_Hashelt *)
- (obj->relocbase + dynp->d_un.d_ptr);
+ hashtab = (const Elf_Hashelt *)(obj->relocbase +
+ dynp->d_un.d_ptr);
obj->nbuckets = hashtab[0];
obj->nchains = hashtab[1];
obj->buckets = hashtab + 2;
obj->chains = obj->buckets + obj->nbuckets;
+ obj->valid_hash_sysv = obj->nbuckets > 0 && obj->nchains > 0 &&
+ obj->buckets != NULL;
+ }
+ break;
+
+ case DT_GNU_HASH:
+ {
+ hashtab = (const Elf_Hashelt *)(obj->relocbase +
+ dynp->d_un.d_ptr);
+ obj->nbuckets_gnu = hashtab[0];
+ obj->symndx_gnu = hashtab[1];
+ nmaskwords = hashtab[2];
+ bloom_size32 = (__ELF_WORD_SIZE / 32) * nmaskwords;
+ /* Number of bitmask words is required to be power of 2 */
+ nmw_power2 = ((nmaskwords & (nmaskwords - 1)) == 0);
+ obj->maskwords_bm_gnu = nmaskwords - 1;
+ obj->shift2_gnu = hashtab[3];
+ obj->bloom_gnu = (Elf_Addr *) (hashtab + 4);
+ obj->buckets_gnu = hashtab + 4 + bloom_size32;
+ obj->chain_zero_gnu = obj->buckets_gnu + obj->nbuckets_gnu -
+ obj->symndx_gnu;
+ obj->valid_hash_gnu = nmw_power2 && obj->nbuckets_gnu > 0 &&
+ obj->buckets_gnu != NULL;
}
break;
@@ -1093,6 +1129,22 @@ digest_dynamic1(Obj_Entry *obj, int earl
obj->pltrelasize = obj->pltrelsize;
obj->pltrelsize = 0;
}
+
+ /* Determine size of dynsym table (equal to nchains of sysv hash) */
+ if (obj->valid_hash_sysv)
+ obj->dynsymcount = obj->nchains;
+ else if (obj->valid_hash_gnu) {
+ obj->dynsymcount = 0;
+ for (bkt = 0; bkt < obj->nbuckets_gnu; bkt++) {
+ if (obj->buckets_gnu[bkt] == 0)
+ continue;
+ hashval = &obj->chain_zero_gnu[obj->buckets_gnu[bkt]];
+ do
+ obj->dynsymcount++;
+ while ((*hashval++ & 1u) == 0);
+ }
+ obj->dynsymcount += obj->symndx_gnu;
+ }
}
static void
@@ -1309,6 +1361,22 @@ elf_hash(const char *name)
}
/*
+ * The GNU hash function is the Daniel J. Bernstein hash clipped to 32 bits
+ * unsigned in case it's implemented with a wider type.
+ */
+static uint32_t
+gnu_hash(const char *s)
+{
+ uint32_t h;
+ unsigned char c;
+
+ h = 5381;
+ for (c = *s; c != '\0'; c = *++s)
+ h = h * 33 + c;
+ return (h & 0xffffffff);
+}
+
+/*
* Find the library with the given name, and return its full pathname.
* The returned string is dynamically allocated. Generates an error
* message and returns NULL if the library cannot be found.
@@ -1384,7 +1452,7 @@ find_symdef(unsigned long symnum, const
* If we have already found this symbol, get the information from
* the cache.
*/
- if (symnum >= refobj->nchains)
+ if (symnum >= refobj->dynsymcount)
return NULL; /* Bad object */
if (cache != NULL && cache[symnum].sym != NULL) {
*defobj_out = cache[symnum].obj;
@@ -1882,6 +1950,8 @@ do_load_object(int fd, const char *name,
object_add_name(obj, name);
obj->path = path;
digest_dynamic(obj, 0);
+ dbg("%s valid_hash_sysv %d valid_hash_gnu %d dynsymcount %d", obj->path,
+ obj->valid_hash_sysv, obj->valid_hash_gnu, obj->dynsymcount);
if (obj->z_noopen && (flags & (RTLD_LO_DLOPEN | RTLD_LO_TRACE)) ==
RTLD_LO_DLOPEN) {
dbg("refusing to load non-loadable \"%s\"", obj->path);
@@ -2165,8 +2235,8 @@ relocate_objects(Obj_Entry *first, bool
if (obj != rtldobj)
dbg("relocating \"%s\"", obj->path);
- if (obj->nbuckets == 0 || obj->nchains == 0 || obj->buckets == NULL ||
- obj->symtab == NULL || obj->strtab == NULL) {
+ if (obj->symtab == NULL || obj->strtab == NULL ||
+ !(obj->valid_hash_sysv || obj->valid_hash_gnu)) {
_rtld_error("%s: Shared object has no run-time symbol table",
obj->path);
return -1;
@@ -2838,7 +2908,7 @@ dladdr(const void *addr, Dl_info *info)
* Walk the symbol list looking for the symbol whose address is
* closest to the address sent in.
*/
- for (symoffset = 0; symoffset < obj->nchains; symoffset++) {
+ for (symoffset = 0; symoffset < obj->dynsymcount; symoffset++) {
def = obj->symtab + symoffset;
/*
@@ -3409,7 +3479,17 @@ symlook_obj(SymLook *req, const Obj_Entr
SymLook req1;
int flags, res, mres;
- mres = symlook_obj1(req, obj);
+ /*
+ * If there is at least one valid hash at this point, we prefer to
+ * use the faster GNU version if available.
+ */
+ if (obj->valid_hash_gnu)
+ mres = symlook_obj1_gnu(req, obj);
+ else if (obj->valid_hash_sysv)
+ mres = symlook_obj1_sysv(req, obj);
+ else
+ return (EINVAL);
+
if (mres == 0) {
if (obj->needed_filtees != NULL) {
flags = (req->flags & SYMLOOK_EARLY) ? RTLD_LO_EARLY : 0;
@@ -3439,28 +3519,15 @@ symlook_obj(SymLook *req, const Obj_Entr
return (mres);
}
-static int
-symlook_obj1(SymLook *req, const Obj_Entry *obj)
+/* Symbol match routine common to both hash functions */
+static bool
+matched_symbol(SymLook *req, const Obj_Entry *obj, Sym_Match_Result *result,
+ const unsigned long symnum)
{
- unsigned long symnum;
- const Elf_Sym *vsymp;
- Elf_Versym verndx;
- int vcount;
-
- if (obj->buckets == NULL)
- return (ESRCH);
-
- vsymp = NULL;
- vcount = 0;
- symnum = obj->buckets[req->hash % obj->nbuckets];
-
- for (; symnum != STN_UNDEF; symnum = obj->chains[symnum]) {
+ Elf_Versym verndx;
const Elf_Sym *symp;
const char *strp;
- if (symnum >= obj->nchains)
- return (ESRCH); /* Bad object */
-
symp = obj->symtab + symnum;
strp = obj->strtab + symp->st_name;
@@ -3468,103 +3535,183 @@ symlook_obj1(SymLook *req, const Obj_Ent
case STT_FUNC:
case STT_NOTYPE:
case STT_OBJECT:
+ case STT_COMMON:
case STT_GNU_IFUNC:
- if (symp->st_value == 0)
- continue;
+ if (symp->st_value == 0)
+ return (false);
/* fallthrough */
case STT_TLS:
- if (symp->st_shndx != SHN_UNDEF)
- break;
+ if (symp->st_shndx != SHN_UNDEF)
+ break;
#ifndef __mips__
- else if (((req->flags & SYMLOOK_IN_PLT) == 0) &&
- (ELF_ST_TYPE(symp->st_info) == STT_FUNC))
- break;
+ else if (((req->flags & SYMLOOK_IN_PLT) == 0) &&
+ (ELF_ST_TYPE(symp->st_info) == STT_FUNC))
+ break;
/* fallthrough */
#endif
default:
- continue;
+ return (false);
}
if (req->name[0] != strp[0] || strcmp(req->name, strp) != 0)
- continue;
+ return (false);
if (req->ventry == NULL) {
- if (obj->versyms != NULL) {
- verndx = VER_NDX(obj->versyms[symnum]);
- if (verndx > obj->vernum) {
- _rtld_error("%s: symbol %s references wrong version %d",
- obj->path, obj->strtab + symnum, verndx);
- continue;
- }
- /*
- * If we are not called from dlsym (i.e. this is a normal
- * relocation from unversioned binary), accept the symbol
- * immediately if it happens to have first version after
- * this shared object became versioned. Otherwise, if
- * symbol is versioned and not hidden, remember it. If it
- * is the only symbol with this name exported by the
- * shared object, it will be returned as a match at the
- * end of the function. If symbol is global (verndx < 2)
- * accept it unconditionally.
- */
- if ((req->flags & SYMLOOK_DLSYM) == 0 &&
- verndx == VER_NDX_GIVEN) {
- req->sym_out = symp;
- req->defobj_out = obj;
- return (0);
+ if (obj->versyms != NULL) {
+ verndx = VER_NDX(obj->versyms[symnum]);
+ if (verndx > obj->vernum) {
+ _rtld_error(
+ "%s: symbol %s references wrong version %d",
+ obj->path, obj->strtab + symnum, verndx);
+ return (false);
+ }
+ /*
+ * If we are not called from dlsym (i.e. this
+ * is a normal relocation from unversioned
+ * binary), accept the symbol immediately if
+ * it happens to have first version after this
+ * shared object became versioned. Otherwise,
+ * if symbol is versioned and not hidden,
+ * remember it. If it is the only symbol with
+ * this name exported by the shared object, it
+ * will be returned as a match by the calling
+ * function. If symbol is global (verndx < 2)
+ * accept it unconditionally.
+ */
+ if ((req->flags & SYMLOOK_DLSYM) == 0 &&
+ verndx == VER_NDX_GIVEN) {
+ result->sym_out = symp;
+ return (true);
+ }
+ else if (verndx >= VER_NDX_GIVEN) {
+ if ((obj->versyms[symnum] & VER_NDX_HIDDEN)
+ == 0) {
+ if (result->vsymp == NULL)
+ result->vsymp = symp;
+ result->vcount++;
+ }
+ return (false);
+ }
}
- else if (verndx >= VER_NDX_GIVEN) {
- if ((obj->versyms[symnum] & VER_NDX_HIDDEN) == 0) {
- if (vsymp == NULL)
- vsymp = symp;
- vcount ++;
- }
- continue;
- }
- }
- req->sym_out = symp;
- req->defobj_out = obj;
- return (0);
- } else {
- if (obj->versyms == NULL) {
+ result->sym_out = symp;
+ return (true);
+ }
+ if (obj->versyms == NULL) {
if (object_match_name(obj, req->ventry->name)) {
- _rtld_error("%s: object %s should provide version %s for "
- "symbol %s", obj_rtld.path, obj->path,
- req->ventry->name, obj->strtab + symnum);
- continue;
+ _rtld_error("%s: object %s should provide version %s "
+ "for symbol %s", obj_rtld.path, obj->path,
+ req->ventry->name, obj->strtab + symnum);
+ return (false);
}
- } else {
+ } else {
verndx = VER_NDX(obj->versyms[symnum]);
if (verndx > obj->vernum) {
- _rtld_error("%s: symbol %s references wrong version %d",
- obj->path, obj->strtab + symnum, verndx);
- continue;
+ _rtld_error("%s: symbol %s references wrong version %d",
+ obj->path, obj->strtab + symnum, verndx);
+ return (false);
}
if (obj->vertab[verndx].hash != req->ventry->hash ||
strcmp(obj->vertab[verndx].name, req->ventry->name)) {
- /*
- * Version does not match. Look if this is a global symbol
- * and if it is not hidden. If global symbol (verndx < 2)
- * is available, use it. Do not return symbol if we are
- * called by dlvsym, because dlvsym looks for a specific
- * version and default one is not what dlvsym wants.
- */
- if ((req->flags & SYMLOOK_DLSYM) ||
- (obj->versyms[symnum] & VER_NDX_HIDDEN) ||
- (verndx >= VER_NDX_GIVEN))
- continue;
+ /*
+ * Version does not match. Look if this is a
+ * global symbol and if it is not hidden. If
+ * global symbol (verndx < 2) is available,
+ * use it. Do not return symbol if we are
+ * called by dlvsym, because dlvsym looks for
+ * a specific version and default one is not
+ * what dlvsym wants.
+ */
+ if ((req->flags & SYMLOOK_DLSYM) ||
+ (verndx >= VER_NDX_GIVEN) ||
+ (obj->versyms[symnum] & VER_NDX_HIDDEN))
+ return (false);
}
- }
- req->sym_out = symp;
- req->defobj_out = obj;
- return (0);
}
- }
- if (vcount == 1) {
- req->sym_out = vsymp;
- req->defobj_out = obj;
- return (0);
- }
- return (ESRCH);
+ result->sym_out = symp;
+ return (true);
+}
+
+/*
+ * Search for symbol using SysV hash function.
+ * obj->buckets is known not to be NULL at this point; the test for this was
+ * performed with the obj->valid_hash_sysv assignment.
+ */
+static int
+symlook_obj1_sysv(SymLook *req, const Obj_Entry *obj)
+{
+ unsigned long symnum;
+ Sym_Match_Result matchres;
+
+ matchres.sym_out = NULL;
+ matchres.vsymp = NULL;
+ matchres.vcount = 0;
+
+ for (symnum = obj->buckets[req->hash % obj->nbuckets];
+ symnum != STN_UNDEF; symnum = obj->chains[symnum]) {
+ if (symnum >= obj->nchains)
+ return (ESRCH); /* Bad object */
+
+ if (matched_symbol(req, obj, &matchres, symnum)) {
+ req->sym_out = matchres.sym_out;
+ req->defobj_out = obj;
+ return (0);
+ }
+ }
+ if (matchres.vcount == 1) {
+ req->sym_out = matchres.vsymp;
+ req->defobj_out = obj;
+ return (0);
+ }
+ return (ESRCH);
+}
+
+/* Search for symbol using GNU hash function */
+static int
+symlook_obj1_gnu(SymLook *req, const Obj_Entry *obj)
+{
+ Elf_Addr bloom_word;
+ const Elf32_Word *hashval;
+ Elf32_Word bucket;
+ Sym_Match_Result matchres;
+ unsigned int h1, h2;
+ unsigned long symnum;
+
+ matchres.sym_out = NULL;
+ matchres.vsymp = NULL;
+ matchres.vcount = 0;
+
+ /* Pick right bitmask word from Bloom filter array */
+ bloom_word = obj->bloom_gnu[(req->hash_gnu / __ELF_WORD_SIZE) &
+ obj->maskwords_bm_gnu];
+
+ /* Calculate modulus word size of gnu hash and its derivative */
+ h1 = req->hash_gnu & (__ELF_WORD_SIZE - 1);
+ h2 = ((req->hash_gnu >> obj->shift2_gnu) & (__ELF_WORD_SIZE - 1));
+
+ /* Filter out the "definitely not in set" queries */
+ if (((bloom_word >> h1) & (bloom_word >> h2) & 1) == 0)
+ return (ESRCH);
+
+ /* Locate hash chain and corresponding value element*/
+ bucket = obj->buckets_gnu[req->hash_gnu % obj->nbuckets_gnu];
+ if (bucket == 0)
+ return (ESRCH);
+ hashval = &obj->chain_zero_gnu[bucket];
+ do {
+ if (((*hashval ^ req->hash_gnu) >> 1) == 0) {
+ symnum = hashval - obj->chain_zero_gnu;
+ if (matched_symbol(req, obj, &matchres, symnum)) {
+ req->sym_out = matchres.sym_out;
+ req->defobj_out = obj;
+ return (0);
+ }
+ }
+ } while ((*hashval++ & 1) == 0);
+ if (matchres.vcount == 1) {
+ req->sym_out = matchres.vsymp;
+ req->defobj_out = obj;
+ return (0);
+ }
+ return (ESRCH);
}
static void
@@ -4353,6 +4500,7 @@ symlook_init(SymLook *dst, const char *n
bzero(dst, sizeof(*dst));
dst->name = name;
dst->hash = elf_hash(name);
+ dst->hash_gnu = gnu_hash(name);
}
static void
@@ -4361,6 +4509,7 @@ symlook_init_from_req(SymLook *dst, cons
dst->name = src->name;
dst->hash = src->hash;
+ dst->hash_gnu = src->hash_gnu;
dst->ventry = src->ventry;
dst->flags = src->flags;
dst->defobj_out = NULL;
Modified: stable/9/libexec/rtld-elf/rtld.h
==============================================================================
--- stable/9/libexec/rtld-elf/rtld.h Sun May 13 11:34:05 2012 (r235395)
+++ stable/9/libexec/rtld-elf/rtld.h Sun May 13 12:50:42 2012 (r235396)
@@ -126,6 +126,12 @@ typedef struct Struct_Ver_Entry {
const char *file;
} Ver_Entry;
+typedef struct Struct_Sym_Match_Result {
+ const Elf_Sym *sym_out;
+ const Elf_Sym *vsymp;
+ int vcount;
+} Sym_Match_Result;
+
#define VER_INFO_HIDDEN 0x01
/*
@@ -204,7 +210,16 @@ typedef struct Struct_Obj_Entry {
const Elf_Hashelt *buckets; /* Hash table buckets array */
unsigned long nbuckets; /* Number of buckets */
const Elf_Hashelt *chains; /* Hash table chain array */
- unsigned long nchains; /* Number of chains */
+ unsigned long nchains; /* Number of entries in chain array */
+
+ Elf32_Word nbuckets_gnu; /* Number of GNU hash buckets*/
+ Elf32_Word symndx_gnu; /* 1st accessible symbol on dynsym table */
+ Elf32_Word maskwords_bm_gnu; /* Bloom filter words - 1 (bitmask) */
+ Elf32_Word shift2_gnu; /* Bloom filter shift count */
+ Elf32_Word dynsymcount; /* Total entries in dynsym table */
+ Elf_Addr *bloom_gnu; /* Bloom filter used by GNU hash func */
+ const Elf_Hashelt *buckets_gnu; /* GNU hash table bucket array */
+ const Elf_Hashelt *chain_zero_gnu; /* GNU hash table value array (Zeroed) */
char *rpath; /* Search path specified in object */
Needed_Entry *needed; /* Shared objects needed by this one (%) */
@@ -251,6 +266,8 @@ typedef struct Struct_Obj_Entry {
bool irelative : 1; /* Object has R_MACHDEP_IRELATIVE relocs */
bool gnu_ifunc : 1; /* Object has references to STT_GNU_IFUNC */
bool crt_no_init : 1; /* Object' crt does not call _init/_fini */
+ bool valid_hash_sysv : 1; /* A valid System V hash hash tag is available */
+ bool valid_hash_gnu : 1; /* A valid GNU hash tag is available */
struct link_map linkmap; /* For GDB and dlinfo() */
Objlist dldags; /* Object belongs to these dlopened DAGs (%) */
@@ -310,6 +327,7 @@ struct Struct_RtldLockState {
typedef struct Struct_SymLook {
const char *name;
unsigned long hash;
+ uint32_t hash_gnu;
const Ver_Entry *ventry;
int flags;
const Obj_Entry *defobj_out;
Modified: stable/9/libexec/rtld-elf/sparc64/reloc.c
==============================================================================
--- stable/9/libexec/rtld-elf/sparc64/reloc.c Sun May 13 11:34:05 2012 (r235395)
+++ stable/9/libexec/rtld-elf/sparc64/reloc.c Sun May 13 12:50:42 2012 (r235396)
@@ -305,7 +305,7 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry
* limited amounts of stack available so we cannot use alloca().
*/
if (obj != obj_rtld) {
- cache = calloc(obj->nchains, sizeof(SymCache));
+ cache = calloc(obj->dynsymcount, sizeof(SymCache));
/* No need to check for NULL here */
} else
cache = NULL;
More information about the svn-src-stable-9
mailing list