X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fldso%2Fdynlink.c;h=1c181339d95a43964502c255c529e3d7449627d5;hb=231b9d1880bf686c0db918cea16c355f2d6598fc;hp=7c1bd890d024384041858ae53d04fdd1c67a9ddc;hpb=08b3c71410e2e4dcbb32d8c6a4fb7c4a8b20ad87;p=musl diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index 7c1bd890..1c181339 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -1,3 +1,4 @@ +#define _GNU_SOURCE #include #include #include @@ -571,7 +572,7 @@ static void free_all(struct dso *p) struct dso *n; while (p) { n = p->next; - if (p->map) free(p); + if (p->map && p!=libc && p!=head) free(p); p = n; } } @@ -584,6 +585,22 @@ static size_t find_dyn(Phdr *ph, size_t cnt, size_t stride) return 0; } +static void find_map_range(Phdr *ph, size_t cnt, size_t stride, struct dso *p) +{ + size_t min_addr = -1, max_addr = 0; + for (; cnt--; ph = (void *)((char *)ph + stride)) { + if (ph->p_type != PT_LOAD) continue; + if (ph->p_vaddr < min_addr) + min_addr = ph->p_vaddr; + if (ph->p_vaddr+ph->p_memsz > max_addr) + max_addr = ph->p_vaddr+ph->p_memsz; + } + min_addr &= -PAGE_SIZE; + max_addr = (max_addr + PAGE_SIZE-1) & -PAGE_SIZE; + p->map = p->base + min_addr; + p->map_len = max_addr - min_addr; +} + static void do_init_fini(struct dso *p) { size_t dyn[DYN_CNT] = {0}; @@ -613,6 +630,7 @@ void *__dynlink(int argc, char **argv) struct dso *const lib = builtin_dsos+1; struct dso *const vdso = builtin_dsos+2; char *env_preload=0; + size_t vdso_base; /* Find aux vector just past environ[] */ for (i=argc+1; argv[i]; i++) @@ -646,6 +664,8 @@ void *__dynlink(int argc, char **argv) lib->name = lib->shortname = "libc.so"; lib->global = 1; ehdr = (void *)lib->base; + find_map_range((void *)(aux[AT_BASE]+ehdr->e_phoff), + ehdr->e_phnum, ehdr->e_phentsize, lib); lib->dynv = (void *)(lib->base + find_dyn( (void *)(aux[AT_BASE]+ehdr->e_phoff), ehdr->e_phnum, ehdr->e_phentsize)); @@ -665,6 +685,8 @@ void *__dynlink(int argc, char **argv) app->name = argv[0]; app->dynv = (void *)(app->base + find_dyn( (void *)aux[AT_PHDR], aux[AT_PHNUM], aux[AT_PHENT])); + find_map_range((void *)aux[AT_PHDR], + aux[AT_PHNUM], aux[AT_PHENT], app); } else { int fd; char *ldname = argv[0]; @@ -701,8 +723,7 @@ void *__dynlink(int argc, char **argv) decode_dyn(app); /* Attach to vdso, if provided by the kernel */ - if (search_vec(auxv, aux, AT_SYSINFO_EHDR)) { - size_t vdso_base = *aux; + if (search_vec(auxv, &vdso_base, AT_SYSINFO_EHDR)) { ehdr = (void *)vdso_base; phdr = (void *)(vdso_base + ehdr->e_phoff); for (i=ehdr->e_phnum; i; i--, phdr=(void *)((char *)phdr + ehdr->e_phentsize)) { @@ -877,7 +898,7 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra) if (p->deps) for (i=0; p->deps[i]; i++) { if (p->deps[i]->ghashtab) { if (!gh) gh = gnu_hash(s); - sym = gnu_lookup(s, h, p->deps[i]); + sym = gnu_lookup(s, gh, p->deps[i]); } else { if (!h) h = sysv_hash(s); sym = sysv_lookup(s, h, p->deps[i]); @@ -891,7 +912,68 @@ failed: return 0; } -void *__dlsym(void *p, const char *s, void *ra) +int __dladdr(void *addr, Dl_info *info) +{ + struct dso *p; + Sym *sym; + uint32_t nsym; + char *strings; + size_t i; + void *best = 0; + char *bestname; + + pthread_rwlock_rdlock(&lock); + for (p=head; p && (unsigned char *)addr-p->map>p->map_len; p=p->next); + pthread_rwlock_unlock(&lock); + + if (!p) return 0; + + sym = p->syms; + strings = p->strings; + if (p->hashtab) { + nsym = p->hashtab[1]; + } else { + uint32_t *buckets; + uint32_t *hashval; + buckets = p->ghashtab + 4 + (p->ghashtab[2]*sizeof(size_t)/4); + sym += p->ghashtab[1]; + for (i = 0; i < p->ghashtab[0]; i++) { + if (buckets[i] > nsym) + nsym = buckets[i]; + } + if (nsym) { + nsym -= p->ghashtab[1]; + hashval = buckets + p->ghashtab[0] + nsym; + do nsym++; + while (!(*hashval++ & 1)); + } + } + + for (; nsym; nsym--, sym++) { + if (sym->st_shndx && sym->st_value + && (1<<(sym->st_info&0xf) & OK_TYPES) + && (1<<(sym->st_info>>4) & OK_BINDS)) { + void *symaddr = p->base + sym->st_value; + if (symaddr > addr || symaddr < best) + continue; + best = symaddr; + bestname = strings + sym->st_name; + if (addr == symaddr) + break; + } + } + + if (!best) return 0; + + info->dli_fname = p->name; + info->dli_fbase = p->base; + info->dli_sname = bestname; + info->dli_saddr = best; + + return 1; +} + +void *__dlsym(void *restrict p, const char *restrict s, void *restrict ra) { void *res; pthread_rwlock_rdlock(&lock); @@ -904,7 +986,11 @@ void *dlopen(const char *file, int mode) { return 0; } -void *__dlsym(void *p, const char *s, void *ra) +void *__dlsym(void *restrict p, const char *restrict s, void *restrict ra) +{ + return 0; +} +int __dladdr (void *addr, Dl_info *info) { return 0; }