X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fldso%2Fdynlink.c;h=6e79a77e67b90dc2ac3ce4891d38ae4aa8c6d484;hb=a735f53e6ab094bce9b992dd3d3127fdb4ffdcc2;hp=4e6a5c839f097c1463ea60bd1b5691e1705a71de;hpb=84389c64562e2b2ba43225b5b7a9df7d974479b1;p=musl diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index 4e6a5c83..6e79a77e 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -122,6 +122,9 @@ static int dl_strcmp(const char *l, const char *r) } #define strcmp(l,r) dl_strcmp(l,r) +/* Compute load address for a virtual address in a given dso. */ +#define laddr(p, v) (void *)((p)->base + (v)) + static void decode_vec(size_t *v, size_t *a, size_t cnt) { size_t i; @@ -174,35 +177,29 @@ static Sym *sysv_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) +static Sym *gnu_lookup(uint32_t h1, uint32_t *hashtab, struct dso *dso, const char *s) { - 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 i = buckets[h1 % nbuckets]; if (!i) return 0; - hashval = buckets + nbuckets + (i - hashtab[1]); + uint32_t *hashval = buckets + nbuckets + (i - hashtab[1]); for (h1 |= 1; ; i++) { - h2 = *hashval++; - if ((!dso->versym || dso->versym[i] >= 0) - && (h1 == (h2|1)) && !strcmp(s, strings + syms[i].st_name)) - return syms+i; + uint32_t h2 = *hashval++; + if ((h1 == (h2|1)) && (!dso->versym || dso->versym[i] >= 0) + && !strcmp(s, dso->strings + dso->syms[i].st_name)) + return dso->syms+i; if (h2 & 1) break; } return 0; } -static Sym *gnu_lookup_filtered(const char *s, uint32_t h1, struct dso *dso, uint32_t fofs, size_t fmask) +static Sym *gnu_lookup_filtered(uint32_t h1, uint32_t *hashtab, struct dso *dso, const char *s, uint32_t fofs, size_t fmask) { - uint32_t *hashtab = dso->ghashtab; const size_t *bloomwords = (const void *)(hashtab+4); size_t f = bloomwords[fofs & (hashtab[2]-1)]; if (!(f & fmask)) return 0; @@ -210,7 +207,7 @@ static Sym *gnu_lookup_filtered(const char *s, uint32_t h1, struct dso *dso, uin f >>= (h1 >> hashtab[3]) % (8 * sizeof f); if (!(f & 1)) return 0; - return gnu_lookup(s, h1, dso); + return gnu_lookup(h1, hashtab, dso, s); } #define OK_TYPES (1<next) { Sym *sym; if (!dso->global) continue; - if (dso->ghashtab) { + if ((ght = dso->ghashtab)) { if (!ghm) { gh = gnu_hash(s); int maskbits = 8 * sizeof ghm; gho = gh / maskbits; ghm = 1ul << gh % maskbits; } - sym = gnu_lookup_filtered(s, gh, dso, gho, ghm); + sym = gnu_lookup_filtered(gh, ght, dso, s, gho, ghm); } else { if (!h) h = sysv_hash(s); sym = sysv_lookup(s, h, dso); @@ -291,7 +288,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri type = R_TYPE(rel[1]); if (type == REL_NONE) continue; sym_index = R_SYM(rel[1]); - reloc_addr = (void *)(base + rel[0]); + reloc_addr = laddr(dso, rel[0]); if (sym_index) { sym = syms + sym_index; name = strings + sym->st_name; @@ -325,7 +322,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri addend = *reloc_addr; } - sym_val = def.sym ? (size_t)def.dso->base+def.sym->st_value : 0; + sym_val = def.sym ? (size_t)laddr(def.dso, def.sym->st_value) : 0; tls_val = def.sym ? def.sym->st_value : 0; switch(type) { @@ -420,8 +417,8 @@ static void reclaim(struct dso *dso, size_t start, size_t end) start = start + 6*sizeof(size_t)-1 & -4*sizeof(size_t); end = (end & -4*sizeof(size_t)) - 2*sizeof(size_t); if (start>end || end-start < 4*sizeof(size_t)) return; - a = (size_t *)(dso->base + start); - z = (size_t *)(dso->base + end); + a = laddr(dso, start); + z = laddr(dso, end); a[-2] = 1; a[-1] = z[0] = end-start + 2*sizeof(size_t) | 1; z[1] = 1; @@ -693,18 +690,18 @@ static void decode_dyn(struct dso *p) { size_t dyn[DYN_CNT]; decode_vec(p->dynv, dyn, DYN_CNT); - p->syms = (void *)(p->base + dyn[DT_SYMTAB]); - p->strings = (void *)(p->base + dyn[DT_STRTAB]); + p->syms = laddr(p, dyn[DT_SYMTAB]); + p->strings = laddr(p, dyn[DT_STRTAB]); if (dyn[0]&(1<hashtab = (void *)(p->base + dyn[DT_HASH]); + p->hashtab = laddr(p, dyn[DT_HASH]); if (dyn[0]&(1<rpath_orig = (void *)(p->strings + dyn[DT_RPATH]); if (dyn[0]&(1<rpath_orig = (void *)(p->strings + dyn[DT_RUNPATH]); if (search_vec(p->dynv, dyn, DT_GNU_HASH)) - p->ghashtab = (void *)(p->base + *dyn); + p->ghashtab = laddr(p, *dyn); if (search_vec(p->dynv, dyn, DT_VERSYM)) - p->versym = (void *)(p->base + *dyn); + p->versym = laddr(p, *dyn); } static struct dso *load_library(const char *name, struct dso *needed_by) @@ -986,7 +983,7 @@ static void kernel_mapped_dso(struct dso *p) Phdr *ph = p->phdr; for (cnt = p->phnum; cnt--; ph = (void *)((char *)ph + p->phentsize)) { if (ph->p_type == PT_DYNAMIC) { - p->dynv = (void *)(p->base + ph->p_vaddr); + p->dynv = laddr(p, ph->p_vaddr); } else if (ph->p_type == PT_GNU_RELRO) { p->relro_start = ph->p_vaddr & -PAGE_SIZE; p->relro_end = (ph->p_vaddr + ph->p_memsz) & -PAGE_SIZE; @@ -1013,12 +1010,12 @@ static void do_fini() decode_vec(p->dynv, dyn, DYN_CNT); if (dyn[0] & (1<base + dyn[DT_FINI_ARRAY])+n; + size_t *fn = (size_t *)laddr(p, dyn[DT_FINI_ARRAY])+n; while (n--) ((void (*)(void))*--fn)(); } #ifndef NO_LEGACY_INITFINI if ((dyn[0] & (1<base + dyn[DT_FINI]))(); + ((void (*)(void))laddr(p, dyn[DT_FINI]))(); #endif } } @@ -1041,11 +1038,11 @@ static void do_init_fini(struct dso *p) } #ifndef NO_LEGACY_INITFINI if ((dyn[0] & (1<base + dyn[DT_INIT]))(); + ((void (*)(void))laddr(p, dyn[DT_INIT]))(); #endif if (dyn[0] & (1<base + dyn[DT_INIT_ARRAY]); + size_t *fn = laddr(p, dyn[DT_INIT_ARRAY]); while (n--) ((void (*)(void))*fn++)(); } if (!need_locking && libc.threads_minus_1) { @@ -1282,8 +1279,8 @@ _Noreturn void __dls3(size_t *sp) app.tls_align = phdr->p_align; } } - if (app.tls_size) app.tls_image = (char *)app.base + tls_image; - if (interp_off) ldso.name = (char *)app.base + interp_off; + if (app.tls_size) app.tls_image = laddr(&app, tls_image); + if (interp_off) ldso.name = laddr(&app, interp_off); if ((aux[0] & (1UL<e_entry; + aux[AT_ENTRY] = (size_t)laddr(&app, ehdr->e_entry); /* Find the name that would have been used for the dynamic * linker had ldd not taken its place. */ if (ldd_mode) { @@ -1563,7 +1560,7 @@ void *__tls_get_addr(size_t *); static void *do_dlsym(struct dso *p, const char *s, void *ra) { size_t i; - uint32_t h = 0, gh = 0; + uint32_t h = 0, gh = 0, *ght; Sym *sym; if (p == head || p == RTLD_DEFAULT || p == RTLD_NEXT) { if (p == RTLD_DEFAULT) { @@ -1577,13 +1574,13 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra) if (!def.sym) goto failed; if ((def.sym->st_info&0xf) == STT_TLS) return __tls_get_addr((size_t []){def.dso->tls_id, def.sym->st_value}); - return def.dso->base + def.sym->st_value; + return laddr(def.dso, def.sym->st_value); } if (invalid_dso_handle(p)) return 0; - if (p->ghashtab) { + if ((ght = p->ghashtab)) { gh = gnu_hash(s); - sym = gnu_lookup(s, gh, p); + sym = gnu_lookup(gh, ght, p, s); } else { h = sysv_hash(s); sym = sysv_lookup(s, h, p); @@ -1591,11 +1588,11 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra) if (sym && (sym->st_info&0xf) == STT_TLS) return __tls_get_addr((size_t []){p->tls_id, sym->st_value}); if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES)) - return p->base + sym->st_value; + return laddr(p, sym->st_value); if (p->deps) for (i=0; p->deps[i]; i++) { - if (p->deps[i]->ghashtab) { + if ((ght = p->deps[i]->ghashtab)) { if (!gh) gh = gnu_hash(s); - sym = gnu_lookup(s, gh, p->deps[i]); + sym = gnu_lookup(gh, ght, p->deps[i], s); } else { if (!h) h = sysv_hash(s); sym = sysv_lookup(s, h, p->deps[i]); @@ -1603,7 +1600,7 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra) if (sym && (sym->st_info&0xf) == STT_TLS) return __tls_get_addr((size_t []){p->deps[i]->tls_id, sym->st_value}); if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES)) - return p->deps[i]->base + sym->st_value; + return laddr(p->deps[i], sym->st_value); } failed: error("Symbol not found: %s", s); @@ -1651,7 +1648,7 @@ int __dladdr(const void *addr, Dl_info *info) if (sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES) && (1<<(sym->st_info>>4) & OK_BINDS)) { - void *symaddr = p->base + sym->st_value; + void *symaddr = laddr(p, sym->st_value); if (symaddr > addr || symaddr < best) continue; best = symaddr;