diff options
author | Joakim Tjernlund <joakim.tjernlund@transmode.se> | 2004-11-10 15:27:26 +0000 |
---|---|---|
committer | Joakim Tjernlund <joakim.tjernlund@transmode.se> | 2004-11-10 15:27:26 +0000 |
commit | 0038f6a2297be2b66a0177bc74b468dddb0a89fa (patch) | |
tree | 2413de564ae1751210c6fd82924636d2b09cebda /ldso/libdl/libdl.c | |
parent | 0657ab0d0b7d9a879091653b2e23f0b46c3ecefa (diff) |
Add RTLD_LOCAL support for dlopened libs. Reported by
Andrew de Quincey, who has been most helpful getting this sorted
out, thanks. Thanks also to Peter Mazinger who did alot of testing.
Removed all traces of dl_parse_copy_information() since it is no longer used.
Diffstat (limited to 'ldso/libdl/libdl.c')
-rw-r--r-- | ldso/libdl/libdl.c | 36 |
1 files changed, 25 insertions, 11 deletions
diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c index 1bb68bdc8..5a4bb0dce 100644 --- a/ldso/libdl/libdl.c +++ b/ldso/libdl/libdl.c @@ -39,7 +39,7 @@ /* When libdl is loaded as a shared library, we need to load in * and use a pile of symbols from ldso... */ -extern char *_dl_find_hash(const char *, struct dyn_elf *, int) +extern char *_dl_find_hash(const char *, struct dyn_elf *, struct elf_resolve *, int) __attribute__ ((__weak__)); extern struct elf_resolve * _dl_load_shared_library(int, struct dyn_elf **, struct elf_resolve *, char *, int) __attribute__ ((__weak__)); @@ -136,7 +136,7 @@ void *dlopen(const char *libname, int flag) struct elf_resolve *tpnt1; void (*dl_brk) (void); int now_flag; - struct init_fini_list *tmp; + struct init_fini_list *tmp, *runp; int nlist, i; struct elf_resolve **init_fini_list; @@ -190,7 +190,7 @@ void *dlopen(const char *libname, int flag) dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf)); _dl_memset(dyn_chain, 0, sizeof(struct dyn_elf)); dyn_chain->dyn = tpnt; - tpnt->rtld_flags |= RTLD_GLOBAL; + tpnt->rtld_flags |= (flag & RTLD_GLOBAL); dyn_chain->next_handle = _dl_handles; _dl_handles = dyn_ptr = dyn_chain; @@ -227,7 +227,7 @@ void *dlopen(const char *libname, int flag) if (!tpnt1) goto oops; } - tpnt1->rtld_flags |= RTLD_GLOBAL; + tpnt1->rtld_flags |= (flag & RTLD_GLOBAL); dyn_ptr->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf)); _dl_memset (dyn_ptr->next, 0, sizeof (struct dyn_elf)); dyn_ptr = dyn_ptr->next; @@ -246,6 +246,15 @@ void *dlopen(const char *libname, int flag) i = 0; for (tcurr = tpnt; tcurr; tcurr = tcurr->next) { init_fini_list[i++] = tcurr; + for(runp = tcurr->init_fini; runp; runp = runp->next){ + if (!(runp->tpnt->rtld_flags & RTLD_GLOBAL)) { + tmp = malloc(sizeof(struct init_fini_list)); + tmp->tpnt = runp->tpnt; + tmp->next = tcurr->rtld_local; + tcurr->rtld_local = tmp; + } + } + } /* Sort the INIT/FINI list in dependency order. */ for (tcurr = tpnt; tcurr; tcurr = tcurr->next) { @@ -275,12 +284,10 @@ void *dlopen(const char *libname, int flag) if(_dl_debug) { fprintf(stderr, "\nINIT/FINI order and dependencies:\n"); for (i=0;i < nlist;i++) { - struct init_fini_list *tmp; - fprintf(stderr, "lib: %s has deps:\n", init_fini_list[i]->libname); - tmp = init_fini_list[i]->init_fini; - for ( ;tmp; tmp = tmp->next) - printf(" %s ", tmp->tpnt->libname); + runp = init_fini_list[i]->init_fini; + for ( ;runp; runp = runp->next) + printf(" %s ", runp->tpnt->libname); printf("\n"); } } @@ -409,7 +416,7 @@ void *dlsym(void *vhandle, const char *name) } } - ret = _dl_find_hash((char*)name, handle, 0); + ret = _dl_find_hash((char*)name, handle, NULL, 0); /* * Nothing found. @@ -422,6 +429,7 @@ void *dlsym(void *vhandle, const char *name) static int do_dlclose(void *vhandle, int need_fini) { struct dyn_elf *rpnt, *rpnt1; + struct init_fini_list *runp, *tmp; ElfW(Phdr) *ppnt; struct elf_resolve *tpnt; int (*dl_elf_fini) (void); @@ -461,7 +469,8 @@ static int do_dlclose(void *vhandle, int need_fini) } } } - free(handle->init_fini.init_fini); + if (handle->dyn->usage_count == 1) + free(handle->init_fini.init_fini); /* OK, this is a valid handle - now close out the file */ for (rpnt = handle; rpnt; rpnt = rpnt->next) { tpnt = rpnt->dyn; @@ -475,6 +484,11 @@ static int do_dlclose(void *vhandle, int need_fini) end = ppnt->p_vaddr + ppnt->p_memsz; } _dl_munmap((void*)tpnt->loadaddr, end); + /* Free elements in RTLD_LOCAL scope list */ + for (runp = tpnt->rtld_local; runp; runp = tmp) { + tmp = runp->next; + free(runp); + } /* Next, remove tpnt from the loaded_module list */ if (_dl_loaded_modules == tpnt) { _dl_loaded_modules = tpnt->next; |