X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Fldso%2Fdynlink.c;h=6ff8850c8eb89d55ac4c16799bc12e5e09ca0d45;hb=61c2cf877ba7518a46d0391f119b3251e5a136b2;hp=057a4cd33e6444cfbb362546b0808f0a3c62e7a0;hpb=5a09a53010046fce204cb5138329f8aace79ab1a;p=musl diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index 057a4cd3..6ff8850c 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -47,8 +47,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 +472,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}; @@ -520,6 +535,7 @@ void *__dynlink(int argc, char **argv) } 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); @@ -577,6 +593,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); @@ -591,9 +610,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)) { @@ -609,8 +630,8 @@ void *dlopen(const char *file, int mode) } tail = orig_tail; tail->next = 0; - pthread_rwlock_unlock(&lock); - return 0; + p = 0; + goto end; } p = load_library(file); @@ -636,8 +657,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; }