X-Git-Url: http://nsz.repo.hu/git/?p=musl;a=blobdiff_plain;f=src%2Fldso%2Fdynlink.c;h=d7d6800238fea88d161ebdc2ac0ea8dc0b3cf167;hp=08f9118d34b46a3a230ad9a06086932b0a04665a;hb=2bd05a4fc26c297754f7ee5745a1c3b072a44b7d;hpb=87d13a4c33b8f75afac357f46341847ac92e2978 diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index 08f9118d..d7d68002 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -22,8 +22,6 @@ static char errbuf[128]; #ifdef SHARED -#include "reloc.h" - #if ULONG_MAX == 0xffffffff typedef Elf32_Ehdr Ehdr; typedef Elf32_Phdr Phdr; @@ -55,6 +53,7 @@ struct dso { int refcnt; Sym *syms; uint32_t *hashtab; + uint32_t *ghashtab; char *strings; unsigned char *map; size_t map_len; @@ -68,6 +67,8 @@ struct dso { char buf[]; }; +#include "reloc.h" + void __init_ssp(size_t *); static struct dso *head, *tail, *libc; @@ -76,6 +77,7 @@ static int rtld_used; static int ssp_used; static int runtime; static int ldd_mode; +static int ldso_fail; static jmp_buf rtld_fail; static pthread_rwlock_t lock; static struct debug debug; @@ -94,7 +96,15 @@ static void decode_vec(size_t *v, size_t *a, size_t cnt) } } -static uint32_t hash(const char *s0) +static int search_vec(size_t *v, size_t *r, size_t key) +{ + for (; v[0]!=key; v+=2) + if (!v[0]) return 0; + *r = v[1]; + return 1; +} + +static uint32_t sysv_hash(const char *s0) { const unsigned char *s = (void *)s0; uint_fast32_t h = 0; @@ -105,7 +115,16 @@ static uint32_t hash(const char *s0) return h & 0xfffffff; } -static Sym *lookup(const char *s, uint32_t h, struct dso *dso) +static uint32_t gnu_hash(const char *s0) +{ + const unsigned char *s = (void *)s0; + uint_fast32_t h = 5381; + for (; *s; s++) + h = h*33 + *s; + return h; +} + +static Sym *sysv_lookup(const char *s, uint32_t h, struct dso *dso) { size_t i; Sym *syms = dso->syms; @@ -118,20 +137,61 @@ static Sym *lookup(const char *s, uint32_t h, struct dso *dso) return 0; } +static Sym *gnu_lookup(const char *s, uint32_t h1, struct dso *dso) +{ + Sym *sym; + char *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]; + + if (!n) return 0; + + strings = dso->strings; + sym = dso->syms + n; + hashval = buckets + nbuckets + (n - hashtab[1]); + + for (h1 |= 1; ; sym++) { + h2 = *hashval++; + if ((h1 == (h2|1)) && !strcmp(s, strings + sym->st_name)) + return sym; + if (h2 & 1) break; + } + + return 0; +} + #define OK_TYPES (1<ghashtab) { + gh = gnu_hash(s); + if (gh == 0xf9040207 && !strcmp(s, "dlopen")) rtld_used = 1; + if (gh == 0xf4dc4ae && !strcmp(s, "dlsym")) rtld_used = 1; + if (gh == 0x1f4039c9 && !strcmp(s, "__stack_chk_fail")) ssp_used = 1; + } else { + h = sysv_hash(s); + if (h == 0x6b366be && !strcmp(s, "dlopen")) rtld_used = 1; + if (h == 0x6b3afd && !strcmp(s, "dlsym")) rtld_used = 1; + if (h == 0x595a4cc && !strcmp(s, "__stack_chk_fail")) ssp_used = 1; + } for (; dso; dso=dso->next) { Sym *sym; if (!dso->global) continue; - sym = lookup(s, h, dso); + if (dso->ghashtab) { + if (!gh) gh = gnu_hash(s); + sym = gnu_lookup(s, gh, dso); + } else { + if (!h) h = sysv_hash(s); + sym = sysv_lookup(s, h, dso); + } if (sym && (!need_def || sym->st_shndx) && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES) && (1<<(sym->st_info>>4) & OK_BINDS)) { @@ -171,9 +231,12 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri dso->name, name); if (runtime) longjmp(rtld_fail, 1); dprintf(2, "%s\n", errbuf); - _exit(127); + ldso_fail = 1; + continue; } sym_size = sym->st_size; + } else { + sym_val = sym_size = 0; } do_single_reloc(reloc_addr, type, sym_val, sym_size, base, rel[2]); } @@ -321,8 +384,11 @@ static void decode_dyn(struct dso *p) size_t dyn[DYN_CNT] = {0}; decode_vec(p->dynv, dyn, DYN_CNT); p->syms = (void *)(p->base + dyn[DT_SYMTAB]); - p->hashtab = (void *)(p->base + dyn[DT_HASH]); p->strings = (void *)(p->base + dyn[DT_STRTAB]); + if (dyn[0]&(1<hashtab = (void *)(p->base + dyn[DT_HASH]); + if (search_vec(p->dynv, dyn, DT_GNU_HASH)) + p->ghashtab = (void *)(p->base + *dyn); } static struct dso *load_library(const char *name) @@ -448,7 +514,8 @@ static void load_deps(struct dso *p) p->strings + p->dynv[i+1], p->name); if (runtime) longjmp(rtld_fail, 1); dprintf(2, "%s\n", errbuf); - _exit(127); + ldso_fail = 1; + continue; } if (runtime) { tmp = realloc(*deps, sizeof(*tmp)*(ndeps+2)); @@ -487,6 +554,9 @@ static void reloc_all(struct dso *p) for (; p; p=p->next) { if (p->relocated) continue; decode_vec(p->dynv, dyn, DYN_CNT); +#ifdef NEED_ARCH_RELOCS + do_arch_relocs(p, head); +#endif do_relocs(p, (void *)(p->base+dyn[DT_JMPREL]), dyn[DT_PLTRELSZ], 2+(dyn[DT_PLTREL]==DT_RELA)); do_relocs(p, (void *)(p->base+dyn[DT_REL]), dyn[DT_RELSZ], 2); @@ -677,6 +747,7 @@ void *__dynlink(int argc, char **argv) reloc_all(app->next); reloc_all(app); + if (ldso_fail) _exit(127); if (ldd_mode) _exit(0); /* Switch to runtime mode: any further failures in the dynamic @@ -685,9 +756,11 @@ void *__dynlink(int argc, char **argv) * all memory used by the dynamic linker. */ runtime = 1; +#ifndef DYNAMIC_IS_RO for (i=0; app->dynv[i]; i+=2) if (app->dynv[i]==DT_DEBUG) app->dynv[i+1] = (size_t)&debug; +#endif debug.ver = 1; debug.bp = _dl_debug_state; debug.head = head; @@ -777,7 +850,7 @@ end: static void *do_dlsym(struct dso *p, const char *s, void *ra) { size_t i; - uint32_t h; + uint32_t h = 0, gh = 0; Sym *sym; if (p == RTLD_NEXT) { for (p=head; p && (unsigned char *)ra-p->map>p->map_len; p=p->next); @@ -791,12 +864,23 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra) if (!res) goto failed; return res; } - h = hash(s); - sym = lookup(s, h, p); + if (p->ghashtab) { + gh = gnu_hash(s); + sym = gnu_lookup(s, gh, p); + } else { + h = sysv_hash(s); + sym = sysv_lookup(s, h, p); + } if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES)) return p->base + sym->st_value; if (p->deps) for (i=0; p->deps[i]; i++) { - sym = lookup(s, h, p); + if (p->deps[i]->ghashtab) { + if (!gh) gh = gnu_hash(s); + sym = gnu_lookup(s, h, p->deps[i]); + } else { + if (!h) h = sysv_hash(s); + sym = sysv_lookup(s, h, p->deps[i]); + } if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES)) return p->deps[i]->base + sym->st_value; }