X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ldso%2Fdynlink.c;h=3741c30d3da49b047925a15d4f0b7026ce6ceb92;hb=f0b235c138d26caafeda44475818508f1911e78e;hp=178fe27eb2f657b4c9b92f4bb9002f90621622d6;hpb=cb525397bb053ea49cf160965477a17b17286eb3;p=musl diff --git a/ldso/dynlink.c b/ldso/dynlink.c index 178fe27e..3741c30d 100644 --- a/ldso/dynlink.c +++ b/ldso/dynlink.c @@ -129,6 +129,7 @@ static size_t static_tls_cnt; static pthread_mutex_t init_fini_lock = { ._m_type = PTHREAD_MUTEX_RECURSIVE }; static struct fdpic_loadmap *app_loadmap; static struct fdpic_dummy_loadmap app_dummy_loadmap; +static struct dso *const nodeps_dummy; struct debug *_dl_debug_addr = &debug; @@ -258,18 +259,12 @@ static Sym *gnu_lookup_filtered(uint32_t h1, uint32_t *hashtab, struct dso *dso, static struct symdef find_sym(struct dso *dso, const char *s, int need_def) { - uint32_t h = 0, gh, gho, *ght; - size_t ghm = 0; + uint32_t h = 0, gh = gnu_hash(s), gho = gh / (8*sizeof(size_t)), *ght; + size_t ghm = 1ul << gh % (8*sizeof(size_t)); struct symdef def = {0}; for (; dso; dso=dso->syms_next) { Sym *sym; 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(gh, ght, dso, s, gho, ghm); } else { if (!h) h = sysv_hash(s); @@ -730,7 +725,6 @@ done_mapping: dso->base = base; dso->dynv = laddr(dso, dyn); if (dso->tls.size) dso->tls.image = laddr(dso, tls_image); - if (!runtime) reclaim_gaps(dso); free(allocated_buf); return map; noexec: @@ -813,7 +807,16 @@ static int fixup_rpath(struct dso *p, char *buf, size_t buf_size) origin = p->name; } t = strrchr(origin, '/'); - l = t ? t-origin : 0; + if (t) { + l = t-origin; + } else { + /* Normally p->name will always be an absolute or relative + * pathname containing at least one '/' character, but in the + * case where ldso was invoked as a command to execute a + * program in the working directory, app.name may not. Fix. */ + origin = "."; + l = 1; + } p->rpath = malloc(strlen(p->rpath_orig) + n*l + 1); if (!p->rpath) return -1; @@ -1049,6 +1052,10 @@ static struct dso *load_library(const char *name, struct dso *needed_by) unmap_library(&temp_dso); return load_library("libc.so", needed_by); } + /* Past this point, if we haven't reached runtime yet, ldso has + * committed either to use the mapped library or to abort execution. + * Unmapping is not possible, so we can safely reclaim gaps. */ + if (!runtime) reclaim_gaps(&temp_dso); /* Allocate storage for the new DSO. When there is TLS, this * storage must include a reservation for all pre-existing @@ -1131,6 +1138,7 @@ static void load_deps(struct dso *p) } } } + if (!*deps) *deps = (struct dso **)&nodeps_dummy; } static void load_preload(char *s) @@ -1441,6 +1449,7 @@ _Noreturn void __dls3(size_t *sp) size_t aux[AUX_CNT], *auxv; size_t i; char *env_preload=0; + char *replace_argv0=0; size_t vdso_base; int argc = *sp; char **argv = (void *)(sp+1); @@ -1525,6 +1534,10 @@ _Noreturn void __dls3(size_t *sp) if (opt[7]=='=') env_preload = opt+8; else if (opt[7]) *argv = 0; else if (*argv) env_preload = *argv++; + } else if (!memcmp(opt, "argv0", 5)) { + if (opt[5]=='=') replace_argv0 = opt+6; + else if (opt[5]) *argv = 0; + else if (*argv) replace_argv0 = *argv++; } else { argv[0] = 0; } @@ -1544,13 +1557,11 @@ _Noreturn void __dls3(size_t *sp) dprintf(2, "%s: cannot load %s: %s\n", ldname, argv[0], strerror(errno)); _exit(1); } - runtime = 1; Ehdr *ehdr = (void *)map_library(fd, &app); if (!ehdr) { dprintf(2, "%s: %s: Not a valid dynamic program\n", ldname, argv[0]); _exit(1); } - runtime = 0; close(fd); ldso.name = ldname; app.name = argv[0]; @@ -1681,6 +1692,8 @@ _Noreturn void __dls3(size_t *sp) debug.state = 0; _dl_debug_state(); + if (replace_argv0) argv[0] = replace_argv0; + errno = 0; CRTJMP((void *)aux[AT_ENTRY], argv-1); @@ -1748,7 +1761,8 @@ void *dlopen(const char *file, int mode) free(p->funcdescs); if (p->rpath != p->rpath_orig) free(p->rpath); - free(p->deps); + if (p->deps != &nodeps_dummy) + free(p->deps); unmap_library(p); free(p); } @@ -1774,19 +1788,24 @@ void *dlopen(const char *file, int mode) } /* First load handling */ - if (!p->relocated) { + int first_load = !p->deps; + if (first_load) { load_deps(p); - if ((mode & RTLD_LAZY)) { + if (!p->relocated && (mode & RTLD_LAZY)) { prepare_lazy(p); - if (p->deps) for (i=0; p->deps[i]; i++) + for (i=0; p->deps[i]; i++) if (!p->deps[i]->relocated) prepare_lazy(p->deps[i]); } + } + if (first_load || (mode & RTLD_GLOBAL)) { /* Make new symbols global, at least temporarily, so we can do * relocations. If not RTLD_GLOBAL, this is reverted below. */ add_syms(p); - if (p->deps) for (i=0; p->deps[i]; i++) + for (i=0; p->deps[i]; i++) add_syms(p->deps[i]); + } + if (first_load) { reloc_all(p); } @@ -1884,7 +1903,7 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra) return p->funcdescs + (sym - p->syms); if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES)) return laddr(p, sym->st_value); - if (p->deps) for (i=0; p->deps[i]; i++) { + for (i=0; p->deps[i]; i++) { if ((ght = p->deps[i]->ghashtab)) { if (!gh) gh = gnu_hash(s); sym = gnu_lookup(gh, ght, p->deps[i], s); @@ -1951,7 +1970,7 @@ int dladdr(const void *addr, Dl_info *info) best = p->funcdescs + (bestsym - p->syms); info->dli_fname = p->name; - info->dli_fbase = p->base; + info->dli_fbase = p->map; info->dli_sname = strings + bestsym->st_name; info->dli_saddr = best;