X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;ds=sidebyside;f=src%2Fldso%2Fdynlink.c;h=e0013ec0eecfe698dd717135e79cb55b44214e78;hb=a9e85c0a5c690086c652f3a8ae9a109389f671a3;hp=e1c2ad7d883a4eaa3abc1d1baee7a85095ec18ec;hpb=c82f4a32ec694903a37d3f9e48da52486a470aa2;p=musl diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index e1c2ad7d..e0013ec0 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -1,4 +1,3 @@ -#ifdef __PIC__ #include #include #include @@ -18,6 +17,10 @@ #include #include +static int errflag; + +#ifdef __PIC__ + #include "reloc.h" #if ULONG_MAX == 0xffffffff @@ -47,8 +50,9 @@ struct dso size_t map_len; dev_t dev; ino_t ino; - int global; - int relocated; + char global; + char relocated; + char constructed; struct dso **deps; char *name; char buf[]; @@ -471,6 +475,20 @@ static size_t find_dyn(Phdr *ph, size_t cnt, size_t stride) return 0; } +static void do_init_fini(struct dso *p) +{ + size_t dyn[DYN_CNT] = {0}; + for (; p; p=p->prev) { + if (p->constructed) return; + decode_vec(p->dynv, dyn, DYN_CNT); + if (dyn[0] & (1<base + dyn[DT_FINI])); + if (dyn[0] & (1<base + dyn[DT_INIT]))(); + p->constructed = 1; + } +} + void *__dynlink(int argc, char **argv) { size_t *auxv, aux[AUX_CNT] = {0}; @@ -511,12 +529,16 @@ void *__dynlink(int argc, char **argv) ehdr->e_phnum, ehdr->e_phentsize)); decode_dyn(lib); - /* Assume base address of 0 for the main program. This is not - * valid for PIE code; we will have to search the PHDR to get - * the correct load address in the PIE case (not yet supported). */ + /* Find load address of the main program, via AT_PHDR vs PT_PHDR. */ app->base = 0; + phdr = (void *)aux[AT_PHDR]; + for (i=aux[AT_PHNUM]; i; i--, phdr=(void *)((char *)phdr + aux[AT_PHENT])) { + if (phdr->p_type == PT_PHDR) + app->base = (void *)(aux[AT_PHDR] - phdr->p_vaddr); + } app->name = argv[0]; app->global = 1; + app->constructed = 1; app->dynv = (void *)(app->base + find_dyn( (void *)aux[AT_PHDR], aux[AT_PHNUM], aux[AT_PHENT])); decode_dyn(app); @@ -560,10 +582,13 @@ void *__dynlink(int argc, char **argv) ehdr->e_phentsize, ehdr->e_phnum); /* Load preload/needed libraries, add their symbols to the global - * namespace, and perform all remaining relocations. */ + * namespace, and perform all remaining relocations. The main + * program must be relocated LAST since it may contain copy + * relocations which depend on libraries' relocations. */ if (env_preload) load_preload(env_preload); load_deps(app); make_global(app); + reloc_all(app->next); reloc_all(app); /* Switch to runtime mode: any further failures in the dynamic @@ -571,6 +596,9 @@ void *__dynlink(int argc, char **argv) * error. If the dynamic loader (dlopen) will not be used, free * all memory used by the dynamic linker. */ runtime = 1; + + do_init_fini(tail); + if (!rtld_used) { free_all(head); free(sys_path); @@ -585,9 +613,11 @@ void *dlopen(const char *file, int mode) { struct dso *volatile p, *orig_tail = tail, *next; size_t i; + int cs; if (!file) return head; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); pthread_rwlock_wrlock(&lock); if (setjmp(rtld_fail)) { @@ -603,12 +633,13 @@ void *dlopen(const char *file, int mode) } tail = orig_tail; tail->next = 0; - pthread_rwlock_unlock(&lock); - return 0; - } + p = 0; + } else p = load_library(file); - p = load_library(file); - if (!p) goto end; + if (!p) { + errflag = 1; + goto end; + } /* First load handling */ if (!p->deps) { @@ -630,8 +661,10 @@ void *dlopen(const char *file, int mode) p->global = 1; } + do_init_fini(tail); end: pthread_rwlock_unlock(&lock); + pthread_setcancelstate(cs, 0); return p; } @@ -645,8 +678,11 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra) if (!p) p=head; p=p->next; } - if (p == head || p == RTLD_DEFAULT) - return find_sym(head, s, 0); + if (p == head || p == RTLD_DEFAULT) { + void *res = find_sym(head, s, 0); + if (!res) errflag = 1; + return res; + } h = hash(s); sym = lookup(s, h, p->syms, p->hashtab, p->strings); if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES)) @@ -657,6 +693,7 @@ static void *do_dlsym(struct dso *p, const char *s, void *ra) if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES)) return p->deps[i]->base + sym->st_value; } + errflag = 1; return 0; } @@ -668,9 +705,21 @@ void *__dlsym(void *p, const char *s, void *ra) pthread_rwlock_unlock(&lock); return res; } +#else +void *dlopen(const char *file, int mode) +{ + return 0; +} +void *__dlsym(void *p, const char *s, void *ra) +{ + return 0; +} +#endif char *dlerror() { + if (!errflag) return 0; + errflag = 0; return "unknown error"; } @@ -678,4 +727,3 @@ int dlclose(void *p) { return 0; } -#endif