mirror of git://git.musl-libc.org/musl
work around libraries with versioned symbols in dynamic linker
this commit does not add versioning support; it merely fixes incorrect lookups of symbols in libraries that contain versioned symbols. previously, the version information was completely ignored, and empirically this seems to have resulted in the oldest version being chosen, but I am uncertain if that behavior was even reliable. the new behavior being introduced is to completely ignore symbols which are marked "hidden" (this seems to be the confusing nomenclature for non-current-version) when versioning is present. this should solve all problems related to libraries with symbol versioning as long as all binaries involved are up-to-date (compatible with the latest-version symbols), and it's the needed behavior for dlsym under all circumstances.
This commit is contained in:
parent
e28c2ecae4
commit
72482f9020
|
@ -63,6 +63,7 @@ struct dso {
|
|||
Sym *syms;
|
||||
uint32_t *hashtab;
|
||||
uint32_t *ghashtab;
|
||||
int16_t *versym;
|
||||
char *strings;
|
||||
unsigned char *map;
|
||||
size_t map_len;
|
||||
|
@ -156,7 +157,8 @@ static Sym *sysv_lookup(const char *s, uint32_t h, struct dso *dso)
|
|||
uint32_t *hashtab = dso->hashtab;
|
||||
char *strings = dso->strings;
|
||||
for (i=hashtab[2+h%hashtab[0]]; i; i=hashtab[2+hashtab[0]+i]) {
|
||||
if (!strcmp(s, strings+syms[i].st_name))
|
||||
if ((!dso->versym || dso->versym[i] >= 0)
|
||||
&& (!strcmp(s, strings+syms[i].st_name)))
|
||||
return syms+i;
|
||||
}
|
||||
return 0;
|
||||
|
@ -164,25 +166,24 @@ static Sym *sysv_lookup(const char *s, uint32_t h, struct dso *dso)
|
|||
|
||||
static Sym *gnu_lookup(const char *s, uint32_t h1, struct dso *dso)
|
||||
{
|
||||
Sym *sym;
|
||||
char *strings;
|
||||
Sym *syms = dso->syms;
|
||||
char *strings = dso->strings;
|
||||
uint32_t *hashtab = dso->ghashtab;
|
||||
uint32_t nbuckets = hashtab[0];
|
||||
uint32_t *buckets = hashtab + 4 + hashtab[2]*(sizeof(size_t)/4);
|
||||
uint32_t h2;
|
||||
uint32_t *hashval;
|
||||
uint32_t n = buckets[h1 % nbuckets];
|
||||
uint32_t i = buckets[h1 % nbuckets];
|
||||
|
||||
if (!n) return 0;
|
||||
if (!i) return 0;
|
||||
|
||||
strings = dso->strings;
|
||||
sym = dso->syms + n;
|
||||
hashval = buckets + nbuckets + (n - hashtab[1]);
|
||||
hashval = buckets + nbuckets + (i - hashtab[1]);
|
||||
|
||||
for (h1 |= 1; ; sym++) {
|
||||
for (h1 |= 1; ; i++) {
|
||||
h2 = *hashval++;
|
||||
if ((h1 == (h2|1)) && !strcmp(s, strings + sym->st_name))
|
||||
return sym;
|
||||
if ((!dso->versym || dso->versym[i] >= 0)
|
||||
&& (h1 == (h2|1)) && !strcmp(s, strings + syms[i].st_name))
|
||||
return syms+i;
|
||||
if (h2 & 1) break;
|
||||
}
|
||||
|
||||
|
@ -456,6 +457,8 @@ static void decode_dyn(struct dso *p)
|
|||
p->hashtab = (void *)(p->base + dyn[DT_HASH]);
|
||||
if (search_vec(p->dynv, dyn, DT_GNU_HASH))
|
||||
p->ghashtab = (void *)(p->base + *dyn);
|
||||
if (search_vec(p->dynv, dyn, DT_VERSYM))
|
||||
p->versym = (void *)(p->base + *dyn);
|
||||
}
|
||||
|
||||
static struct dso *load_library(const char *name)
|
||||
|
|
Loading…
Reference in New Issue