From 9d34214affb9f2762d53c4b2a0482decd34a808f Mon Sep 17 00:00:00 2001 From: imp Date: Mon, 18 Jan 2016 21:40:20 +0000 Subject: Restore ABI variants now that ldconfig groks -soft. In addition, as a transition mechanism, if we don't have /usr/libsoft, assume that soft float ABI binaries are the default, so treat them as default binaries. When we've fully transitioned, it will make no sense to do this stat, and it will be removed. --- libexec/rtld-elf/arm/reloc.c | 19 ++++++++++++++----- libexec/rtld-elf/paths.h | 2 +- libexec/rtld-elf/rtld.c | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) (limited to 'libexec') diff --git a/libexec/rtld-elf/arm/reloc.c b/libexec/rtld-elf/arm/reloc.c index 6bdda73..286e493 100644 --- a/libexec/rtld-elf/arm/reloc.c +++ b/libexec/rtld-elf/arm/reloc.c @@ -3,6 +3,7 @@ #include __FBSDID("$FreeBSD$"); #include +#include #include #include @@ -21,6 +22,7 @@ void arm_abi_variant_hook(Elf_Auxinfo **aux_info) { Elf_Word ehdr; + struct stat sb; /* * If we're running an old kernel that doesn't provide any data fail @@ -38,12 +40,19 @@ arm_abi_variant_hook(Elf_Auxinfo **aux_info) return; /* + * If there's no /usr/libsoft, then we don't have a system with both + * hard and soft float. In that case, hope for the best and just + * return. Such systems are required to have all soft or all hard + * float ABI binaries and libraries. This is, at best, a transition + * compatibility hack. Once we're fully hard-float, this should + * be removed. + */ + if (stat("/usr/libsoft", &sb) != 0 || !S_ISDIR(sb.st_mode)) + return; + + /* * This is a soft float ABI binary. We need to use the soft float - * settings. For the moment, the standard library path includes the hard - * float paths as well. When upgrading, we need to execute the wrong - * kind of binary until we've installed the new binaries. We could go - * off whether or not /libsoft exists, but the simplicity of having it - * in the path wins. + * settings. */ ld_elf_hints_default = _PATH_SOFT_ELF_HINTS; ld_path_libmap_conf = _PATH_SOFT_LIBMAP_CONF; diff --git a/libexec/rtld-elf/paths.h b/libexec/rtld-elf/paths.h index abfeb3f..7d9d372 100644 --- a/libexec/rtld-elf/paths.h +++ b/libexec/rtld-elf/paths.h @@ -62,7 +62,7 @@ #define _PATH_SOFT_ELF_HINTS "/var/run/ld-elf-soft.so.hints" #define _PATH_SOFT_LIBMAP_CONF "/etc/libmap-soft.conf" #define _PATH_SOFT_RTLD "/libexec/ld-elf.so.1" -#define SOFT_STANDARD_LIBRARY_PATH "/libsoft:/usr/libsoft:/lib:/usr/lib" +#define SOFT_STANDARD_LIBRARY_PATH "/usr/libsoft" #define LD_SOFT_ "LD_SOFT_" extern char *ld_elf_hints_default; diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index ad5d359..66edc15 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -435,7 +435,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) trust = !issetugid(); -/* md_abi_variant_hook(aux_info); */ + md_abi_variant_hook(aux_info); ld_bind_now = getenv(_LD("BIND_NOW")); /* -- cgit v1.1 From 5f1c6d1039bf8273173d337033d24a394bbbf3ae Mon Sep 17 00:00:00 2001 From: kib Date: Wed, 20 Jan 2016 07:21:33 +0000 Subject: Do not call callbacks for dl_iterate_phdr(3) with the rtld bind and phdr locks locked. This allows to call rtld services from the callback, which is only reasonable for dlopen(path, RTLD_NOLOAD) to test existence of the library in the image, and for dlsym(). The later might still be not quite safe, due to the lazy resolution of filters. To allow dropping the locks around iteration in dl_iterate_phdr(3), we insert markers to track current position between relocks. The global objects list is converted to tailq and all iterators skip markers, globallist_next() and globallist_curr() helpers are added. Reported and tested by: davide Reviewed by: kan Sponsored by: The FreeBSD Foundation MFC after: 3 weeks --- libexec/rtld-elf/aarch64/reloc.c | 4 +- libexec/rtld-elf/amd64/reloc.c | 3 +- libexec/rtld-elf/arm/reloc.c | 4 +- libexec/rtld-elf/debug.c | 3 +- libexec/rtld-elf/i386/reloc.c | 3 +- libexec/rtld-elf/powerpc/reloc.c | 4 +- libexec/rtld-elf/powerpc64/reloc.c | 4 +- libexec/rtld-elf/riscv/reloc.c | 4 +- libexec/rtld-elf/rtld.c | 247 ++++++++++++++++++++++++------------- libexec/rtld-elf/rtld.h | 7 +- libexec/rtld-elf/sparc64/reloc.c | 4 +- 11 files changed, 182 insertions(+), 105 deletions(-) (limited to 'libexec') diff --git a/libexec/rtld-elf/aarch64/reloc.c b/libexec/rtld-elf/aarch64/reloc.c index 7a9ce97..de7ffd5 100644 --- a/libexec/rtld-elf/aarch64/reloc.c +++ b/libexec/rtld-elf/aarch64/reloc.c @@ -99,8 +99,8 @@ do_copy_relocations(Obj_Entry *dstobj) req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); req.flags = SYMLOOK_EARLY; - for (srcobj = dstobj->next; srcobj != NULL; - srcobj = srcobj->next) { + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { res = symlook_obj(&req, srcobj); if (res == 0) { srcsym = req.sym_out; diff --git a/libexec/rtld-elf/amd64/reloc.c b/libexec/rtld-elf/amd64/reloc.c index 9895944..80a3c35 100644 --- a/libexec/rtld-elf/amd64/reloc.c +++ b/libexec/rtld-elf/amd64/reloc.c @@ -85,7 +85,8 @@ do_copy_relocations(Obj_Entry *dstobj) req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); req.flags = SYMLOOK_EARLY; - for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) { + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { res = symlook_obj(&req, srcobj); if (res == 0) { srcsym = req.sym_out; diff --git a/libexec/rtld-elf/arm/reloc.c b/libexec/rtld-elf/arm/reloc.c index 286e493..5e21ca5 100644 --- a/libexec/rtld-elf/arm/reloc.c +++ b/libexec/rtld-elf/arm/reloc.c @@ -101,8 +101,8 @@ do_copy_relocations(Obj_Entry *dstobj) ELF_R_SYM(rel->r_info)); req.flags = SYMLOOK_EARLY; - for (srcobj = dstobj->next; srcobj != NULL; - srcobj = srcobj->next) { + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { res = symlook_obj(&req, srcobj); if (res == 0) { srcsym = req.sym_out; diff --git a/libexec/rtld-elf/debug.c b/libexec/rtld-elf/debug.c index 8f8311c..3c37b7f 100644 --- a/libexec/rtld-elf/debug.c +++ b/libexec/rtld-elf/debug.c @@ -62,7 +62,8 @@ dump_relocations (Obj_Entry *obj0) { Obj_Entry *obj; - for (obj = obj0; obj != NULL; obj = obj->next) { + for (obj = globallist_curr(obj0); obj != NULL; + obj = globallist_next(obj)) { dump_obj_relocations(obj); } } diff --git a/libexec/rtld-elf/i386/reloc.c b/libexec/rtld-elf/i386/reloc.c index 55b6537..2d6021c 100644 --- a/libexec/rtld-elf/i386/reloc.c +++ b/libexec/rtld-elf/i386/reloc.c @@ -86,7 +86,8 @@ do_copy_relocations(Obj_Entry *dstobj) req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rel->r_info)); req.flags = SYMLOOK_EARLY; - for (srcobj = dstobj->next; srcobj != NULL; srcobj = srcobj->next) { + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { res = symlook_obj(&req, srcobj); if (res == 0) { srcsym = req.sym_out; diff --git a/libexec/rtld-elf/powerpc/reloc.c b/libexec/rtld-elf/powerpc/reloc.c index 1fe9676..89a0089 100644 --- a/libexec/rtld-elf/powerpc/reloc.c +++ b/libexec/rtld-elf/powerpc/reloc.c @@ -94,8 +94,8 @@ do_copy_relocations(Obj_Entry *dstobj) req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); req.flags = SYMLOOK_EARLY; - for (srcobj = dstobj->next; srcobj != NULL; - srcobj = srcobj->next) { + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { res = symlook_obj(&req, srcobj); if (res == 0) { srcsym = req.sym_out; diff --git a/libexec/rtld-elf/powerpc64/reloc.c b/libexec/rtld-elf/powerpc64/reloc.c index c428d6b..5cef3f8 100644 --- a/libexec/rtld-elf/powerpc64/reloc.c +++ b/libexec/rtld-elf/powerpc64/reloc.c @@ -90,8 +90,8 @@ do_copy_relocations(Obj_Entry *dstobj) req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); req.flags = SYMLOOK_EARLY; - for (srcobj = dstobj->next; srcobj != NULL; - srcobj = srcobj->next) { + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { res = symlook_obj(&req, srcobj); if (res == 0) { srcsym = req.sym_out; diff --git a/libexec/rtld-elf/riscv/reloc.c b/libexec/rtld-elf/riscv/reloc.c index c43800a..92c4276 100644 --- a/libexec/rtld-elf/riscv/reloc.c +++ b/libexec/rtld-elf/riscv/reloc.c @@ -120,8 +120,8 @@ do_copy_relocations(Obj_Entry *dstobj) req.ventry = fetch_ventry(dstobj, ELF_R_SYM(rela->r_info)); req.flags = SYMLOOK_EARLY; - for (srcobj = dstobj->next; srcobj != NULL; - srcobj = srcobj->next) { + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { res = symlook_obj(&req, srcobj); if (res == 0) { srcsym = req.sym_out; diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 66edc15..06690ff 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -90,7 +90,7 @@ static void init_dag(Obj_Entry *); static void init_pagesizes(Elf_Auxinfo **aux_info); static void init_rtld(caddr_t, Elf_Auxinfo **); static void initlist_add_neededs(Needed_Entry *, Objlist *); -static void initlist_add_objects(Obj_Entry *, Obj_Entry **, Objlist *); +static void initlist_add_objects(Obj_Entry *, Obj_Entry *, Objlist *); static void linkmap_add(Obj_Entry *); static void linkmap_delete(Obj_Entry *); static void load_filtees(Obj_Entry *, int flags, RtldLockState *); @@ -180,12 +180,11 @@ static char *ld_preload; /* Environment variable for libraries to static char *ld_elf_hints_path; /* Environment variable for alternative hints path */ static char *ld_tracing; /* Called from ldd to print libs */ static char *ld_utrace; /* Use utrace() to log events. */ -static Obj_Entry *obj_list; /* Head of linked list of shared objects */ -static Obj_Entry **obj_tail; /* Link field of last object in list */ +static struct obj_entry_q obj_list; /* Queue of all loaded objects */ static Obj_Entry *obj_main; /* The main program shared object */ static Obj_Entry obj_rtld; /* The dynamic linker shared object */ static unsigned int obj_count; /* Number of objects in obj_list */ -static unsigned int obj_loads; /* Number of objects in obj_list */ +static unsigned int obj_loads; /* Number of loads of objects (gen count) */ static Objlist list_global = /* Objects dlopened with RTLD_GLOBAL */ STAILQ_HEAD_INITIALIZER(list_global); @@ -370,7 +369,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) const char *argv0; Objlist_Entry *entry; Obj_Entry *obj; - Obj_Entry **preload_tail; + Obj_Entry *preload_tail; Obj_Entry *last_interposer; Objlist initlist; RtldLockState lockstate; @@ -569,8 +568,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) linkmap_add(&obj_rtld); /* Link the main program into the list of objects. */ - *obj_tail = obj_main; - obj_tail = &obj_main->next; + TAILQ_INSERT_HEAD(&obj_list, obj_main, next); obj_count++; obj_loads++; @@ -585,7 +583,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) dbg("loading LD_PRELOAD libraries"); if (load_preload_objects() == -1) rtld_die(); - preload_tail = obj_tail; + preload_tail = globallist_curr(TAILQ_LAST(&obj_list, obj_entry_q)); dbg("loading needed objects"); if (load_needed_objects(obj_main, 0) == -1) @@ -593,7 +591,9 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) /* Make a list of all objects loaded at startup. */ last_interposer = obj_main; - for (obj = obj_list; obj != NULL; obj = obj->next) { + TAILQ_FOREACH(obj, &obj_list, next) { + if (obj->marker) + continue; if (obj->z_interpose && obj != obj_main) { objlist_put_after(&list_main, last_interposer, obj); last_interposer = obj; @@ -651,7 +651,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) * might be the subject for relocations. */ dbg("initializing initial thread local storage"); - allocate_initial_tls(obj_list); + allocate_initial_tls(globallist_curr(TAILQ_FIRST(&obj_list))); dbg("initializing key program variables"); set_program_var("__progname", argv[0] != NULL ? basename(argv[0]) : ""); @@ -660,7 +660,8 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) /* Make a list of init functions to call. */ objlist_init(&initlist); - initlist_add_objects(obj_list, preload_tail, &initlist); + initlist_add_objects(globallist_curr(TAILQ_FIRST(&obj_list)), + preload_tail, &initlist); r_debug_state(NULL, &obj_main->linkmap); /* say hello to gdb! */ @@ -690,7 +691,9 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) _r_debug_postinit(&obj_main->linkmap); objlist_clear(&initlist); dbg("loading filtees"); - for (obj = obj_list->next; obj != NULL; obj = obj->next) { + TAILQ_FOREACH(obj, &obj_list, next) { + if (obj->marker) + continue; if (ld_loadfltr || obj->z_loadfltr) load_filtees(obj, 0, &lockstate); } @@ -1410,9 +1413,10 @@ dlcheck(void *handle) { Obj_Entry *obj; - for (obj = obj_list; obj != NULL; obj = obj->next) + TAILQ_FOREACH(obj, &obj_list, next) { if (obj == (Obj_Entry *) handle) break; + } if (obj == NULL || obj->refcount == 0 || obj->dl_refcount == 0) { _rtld_error("Invalid shared object handle %p", handle); @@ -1823,6 +1827,32 @@ init_dag(Obj_Entry *root) root->dag_inited = true; } +Obj_Entry * +globallist_curr(const Obj_Entry *obj) +{ + + for (;;) { + if (obj == NULL) + return (NULL); + if (!obj->marker) + return (__DECONST(Obj_Entry *, obj)); + obj = TAILQ_PREV(obj, obj_entry_q, next); + } +} + +Obj_Entry * +globallist_next(const Obj_Entry *obj) +{ + + for (;;) { + obj = TAILQ_NEXT(obj, next); + if (obj == NULL) + return (NULL); + if (!obj->marker) + return (__DECONST(Obj_Entry *, obj)); + } +} + static void process_z(Obj_Entry *root) { @@ -1905,7 +1935,7 @@ init_rtld(caddr_t mapbase, Elf_Auxinfo **aux_info) } /* Initialize the object list. */ - obj_tail = &obj_list; + TAILQ_INIT(&obj_list); /* Now that non-local variables can be accesses, copy out obj_rtld. */ memcpy(&obj_rtld, &objtmp, sizeof(obj_rtld)); @@ -1986,7 +2016,7 @@ initlist_add_neededs(Needed_Entry *needed, Objlist *list) /* Process the current needed object. */ if (needed->obj != NULL) - initlist_add_objects(needed->obj, &needed->obj->next, list); + initlist_add_objects(needed->obj, globallist_next(needed->obj), list); } /* @@ -1999,16 +2029,18 @@ initlist_add_neededs(Needed_Entry *needed, Objlist *list) * held when this function is called. */ static void -initlist_add_objects(Obj_Entry *obj, Obj_Entry **tail, Objlist *list) +initlist_add_objects(Obj_Entry *obj, Obj_Entry *tail, Objlist *list) { + Obj_Entry *nobj; if (obj->init_scanned || obj->init_done) return; obj->init_scanned = true; /* Recursively process the successor objects. */ - if (&obj->next != tail) - initlist_add_objects(obj->next, tail, list); + nobj = globallist_next(obj); + if (nobj != NULL && nobj != tail) + initlist_add_objects(nobj, tail, list); /* Recursively process the needed objects. */ if (obj->needed != NULL) @@ -2111,7 +2143,10 @@ load_needed_objects(Obj_Entry *first, int flags) { Obj_Entry *obj; - for (obj = first; obj != NULL; obj = obj->next) { + obj = first; + TAILQ_FOREACH_FROM(obj, &obj_list, next) { + if (obj->marker) + continue; if (process_needed(obj, obj->needed, flags) == -1) return (-1); } @@ -2173,7 +2208,9 @@ load_object(const char *name, int fd_u, const Obj_Entry *refobj, int flags) fd = -1; if (name != NULL) { - for (obj = obj_list->next; obj != NULL; obj = obj->next) { + TAILQ_FOREACH(obj, &obj_list, next) { + if (obj->marker) + continue; if (object_match_name(obj, name)) return (obj); } @@ -2218,9 +2255,12 @@ load_object(const char *name, int fd_u, const Obj_Entry *refobj, int flags) free(path); return NULL; } - for (obj = obj_list->next; obj != NULL; obj = obj->next) + TAILQ_FOREACH(obj, &obj_list, next) { + if (obj->marker) + continue; if (obj->ino == sb.st_ino && obj->dev == sb.st_dev) break; + } if (obj != NULL && name != NULL) { object_add_name(obj, name); free(path); @@ -2288,8 +2328,7 @@ do_load_object(int fd, const char *name, char *path, struct stat *sbp, } obj->dlopened = (flags & RTLD_LO_DLOPEN) != 0; - *obj_tail = obj; - obj_tail = &obj->next; + TAILQ_INSERT_TAIL(&obj_list, obj, next); obj_count++; obj_loads++; linkmap_add(obj); /* for GDB & dlinfo() */ @@ -2310,7 +2349,9 @@ obj_from_addr(const void *addr) { Obj_Entry *obj; - for (obj = obj_list; obj != NULL; obj = obj->next) { + TAILQ_FOREACH(obj, &obj_list, next) { + if (obj->marker) + continue; if (addr < (void *) obj->mapbase) continue; if (addr < (void *) (obj->mapbase + obj->mapsize)) @@ -2436,8 +2477,11 @@ objlist_call_init(Objlist *list, RtldLockState *lockstate) * possibly initialized earlier if any of vectors called below * cause the change by using dlopen. */ - for (obj = obj_list; obj != NULL; obj = obj->next) + TAILQ_FOREACH(obj, &obj_list, next) { + if (obj->marker) + continue; obj->init_scanned = false; + } /* * Preserve the current error message since an init function might @@ -2681,7 +2725,11 @@ relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj, Obj_Entry *obj; int error; - for (error = 0, obj = first; obj != NULL; obj = obj->next) { + error = 0; + obj = first; + TAILQ_FOREACH_FROM(obj, &obj_list, next) { + if (obj->marker) + continue; error = relocate_object(obj, bind_now, rtldobj, flags, lockstate); if (error == -1) @@ -2719,7 +2767,10 @@ resolve_objects_ifunc(Obj_Entry *first, bool bind_now, int flags, { Obj_Entry *obj; - for (obj = first; obj != NULL; obj = obj->next) { + obj = first; + TAILQ_FOREACH_FROM(obj, &obj_list, next) { + if (obj->marker) + continue; if (resolve_object_ifunc(obj, bind_now, flags, lockstate) == -1) return (-1); } @@ -3033,7 +3084,7 @@ static Obj_Entry * dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags, int mode, RtldLockState *lockstate) { - Obj_Entry **old_obj_tail; + Obj_Entry *old_obj_tail; Obj_Entry *obj; Objlist initlist; RtldLockState mlockstate; @@ -3047,7 +3098,7 @@ dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags, } GDB_STATE(RT_ADD,NULL); - old_obj_tail = obj_tail; + old_obj_tail = globallist_curr(TAILQ_LAST(&obj_list, obj_entry_q)); obj = NULL; if (name == NULL && fd == -1) { obj = obj_main; @@ -3060,8 +3111,9 @@ dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags, obj->dl_refcount++; if (mode & RTLD_GLOBAL && objlist_find(&list_global, obj) == NULL) objlist_push_tail(&list_global, obj); - if (*old_obj_tail != NULL) { /* We loaded something new. */ - assert(*old_obj_tail == obj); + if (globallist_next(old_obj_tail) != NULL) { + /* We loaded something new. */ + assert(globallist_next(old_obj_tail) == obj); result = load_needed_objects(obj, lo_flags & (RTLD_LO_DLOPEN | RTLD_LO_EARLY)); init_dag(obj); @@ -3088,7 +3140,7 @@ dlopen_object(const char *name, int fd, Obj_Entry *refobj, int lo_flags, */ } else { /* Make list of init functions to call. */ - initlist_add_objects(obj, &obj->next, &initlist); + initlist_add_objects(obj, globallist_next(obj), &initlist); } /* * Process all no_delete or global objects here, given @@ -3194,8 +3246,10 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, } else if (handle == RTLD_NEXT || /* Objects after caller's */ handle == RTLD_SELF) { /* ... caller included */ if (handle == RTLD_NEXT) - obj = obj->next; - for (; obj != NULL; obj = obj->next) { + obj = globallist_next(obj); + TAILQ_FOREACH_FROM(obj, &obj_list, next) { + if (obj->marker) + continue; res = symlook_obj(&req, obj); if (res == 0) { if (def == NULL || @@ -3464,31 +3518,43 @@ rtld_fill_dl_phdr_info(const Obj_Entry *obj, struct dl_phdr_info *phdr_info) int dl_iterate_phdr(__dl_iterate_hdr_callback callback, void *param) { - struct dl_phdr_info phdr_info; - const Obj_Entry *obj; - RtldLockState bind_lockstate, phdr_lockstate; - int error; - - wlock_acquire(rtld_phdr_lock, &phdr_lockstate); - rlock_acquire(rtld_bind_lock, &bind_lockstate); - - error = 0; - - for (obj = obj_list; obj != NULL; obj = obj->next) { - rtld_fill_dl_phdr_info(obj, &phdr_info); - if ((error = callback(&phdr_info, sizeof phdr_info, param)) != 0) - break; + struct dl_phdr_info phdr_info; + Obj_Entry *obj, marker; + RtldLockState bind_lockstate, phdr_lockstate; + int error; - } - if (error == 0) { - rtld_fill_dl_phdr_info(&obj_rtld, &phdr_info); - error = callback(&phdr_info, sizeof(phdr_info), param); - } + bzero(&marker, sizeof(marker)); + marker.marker = true; + error = 0; - lock_release(rtld_bind_lock, &bind_lockstate); - lock_release(rtld_phdr_lock, &phdr_lockstate); + wlock_acquire(rtld_phdr_lock, &phdr_lockstate); + rlock_acquire(rtld_bind_lock, &bind_lockstate); + for (obj = globallist_curr(TAILQ_FIRST(&obj_list)); obj != NULL;) { + TAILQ_INSERT_AFTER(&obj_list, obj, &marker, next); + rtld_fill_dl_phdr_info(obj, &phdr_info); + lock_release(rtld_bind_lock, &bind_lockstate); + lock_release(rtld_phdr_lock, &phdr_lockstate); + + error = callback(&phdr_info, sizeof phdr_info, param); + + wlock_acquire(rtld_phdr_lock, &phdr_lockstate); + rlock_acquire(rtld_bind_lock, &bind_lockstate); + obj = globallist_next(&marker); + TAILQ_REMOVE(&obj_list, &marker, next); + if (error != 0) { + lock_release(rtld_bind_lock, &bind_lockstate); + lock_release(rtld_phdr_lock, &phdr_lockstate); + return (error); + } + } - return (error); + if (error == 0) { + rtld_fill_dl_phdr_info(&obj_rtld, &phdr_info); + lock_release(rtld_bind_lock, &bind_lockstate); + lock_release(rtld_phdr_lock, &phdr_lockstate); + error = callback(&phdr_info, sizeof(phdr_info), param); + } + return (error); } static void * @@ -4208,11 +4274,13 @@ trace_loaded_objects(Obj_Entry *obj) list_containers = getenv(_LD("TRACE_LOADED_OBJECTS_ALL")); - for (; obj; obj = obj->next) { + TAILQ_FOREACH_FROM(obj, &obj_list, next) { Needed_Entry *needed; char *name, *path; bool is_lib; + if (obj->marker) + continue; if (list_containers && obj->needed != NULL) rtld_printf("%s:\n", obj->path); for (needed = obj->needed; needed; needed = needed->next) { @@ -4295,34 +4363,30 @@ trace_loaded_objects(Obj_Entry *obj) static void unload_object(Obj_Entry *root) { - Obj_Entry *obj; - Obj_Entry **linkp; + Obj_Entry *obj, *obj1; - assert(root->refcount == 0); + assert(root->refcount == 0); - /* - * Pass over the DAG removing unreferenced objects from - * appropriate lists. - */ - unlink_object(root); - - /* Unmap all objects that are no longer referenced. */ - linkp = &obj_list->next; - while ((obj = *linkp) != NULL) { - if (obj->refcount == 0) { - LD_UTRACE(UTRACE_UNLOAD_OBJECT, obj, obj->mapbase, obj->mapsize, 0, - obj->path); - dbg("unloading \"%s\"", obj->path); - unload_filtees(root); - munmap(obj->mapbase, obj->mapsize); - linkmap_delete(obj); - *linkp = obj->next; - obj_count--; - obj_free(obj); - } else - linkp = &obj->next; - } - obj_tail = linkp; + /* + * Pass over the DAG removing unreferenced objects from + * appropriate lists. + */ + unlink_object(root); + + /* Unmap all objects that are no longer referenced. */ + TAILQ_FOREACH_SAFE(obj, &obj_list, next, obj1) { + if (obj->marker || obj->refcount != 0) + continue; + LD_UTRACE(UTRACE_UNLOAD_OBJECT, obj, obj->mapbase, + obj->mapsize, 0, obj->path); + dbg("unloading \"%s\"", obj->path); + unload_filtees(root); + munmap(obj->mapbase, obj->mapsize); + linkmap_delete(obj); + TAILQ_REMOVE(&obj_list, obj, next); + obj_count--; + obj_free(obj); + } } static void @@ -4455,7 +4519,8 @@ allocate_tls(Obj_Entry *objs, void *oldtcb, size_t tcbsize, size_t tcbalign) dtv[0] = tls_dtv_generation; dtv[1] = tls_max_index; - for (obj = objs; obj; obj = obj->next) { + for (obj = globallist_curr(objs); obj != NULL; + obj = globallist_next(obj)) { if (obj->tlsoffset > 0) { addr = (Elf_Addr)tls + obj->tlsoffset; if (obj->tlsinitsize > 0) @@ -4554,15 +4619,16 @@ allocate_tls(Obj_Entry *objs, void *oldtls, size_t tcbsize, size_t tcbalign) */ free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr)); } else { - for (obj = objs; obj; obj = obj->next) { - if (obj->tlsoffset) { + obj = objs; + TAILQ_FOREACH_FROM(obj, &obj_list, next) { + if (obj->marker || obj->tlsoffset == 0) + continue; addr = segbase - obj->tlsoffset; memset((void*) (addr + obj->tlsinitsize), 0, obj->tlssize - obj->tlsinitsize); if (obj->tlsinit) memcpy((void*) addr, obj->tlsinit, obj->tlsinitsize); dtv[obj->tlsindex + 1] = addr; - } } } @@ -4611,7 +4677,9 @@ allocate_module_tls(int index) Obj_Entry* obj; char* p; - for (obj = obj_list; obj; obj = obj->next) { + TAILQ_FOREACH(obj, &obj_list, next) { + if (obj->marker) + continue; if (obj->tlsindex == index) break; } @@ -4690,7 +4758,8 @@ _rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign) RtldLockState lockstate; wlock_acquire(rtld_bind_lock, &lockstate); - ret = allocate_tls(obj_list, oldtls, tcbsize, tcbalign); + ret = allocate_tls(globallist_curr(TAILQ_FIRST(&obj_list)), oldtls, + tcbsize, tcbalign); lock_release(rtld_bind_lock, &lockstate); return (ret); } diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index 72a632e..5fbfb27 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -139,7 +139,7 @@ typedef struct Struct_Obj_Entry { Elf_Size magic; /* Magic number (sanity check) */ Elf_Size version; /* Version number of struct format */ - struct Struct_Obj_Entry *next; + TAILQ_ENTRY(Struct_Obj_Entry) next; char *path; /* Pathname of underlying file (%) */ char *origin_path; /* Directory path of origin file */ int refcount; @@ -264,6 +264,7 @@ typedef struct Struct_Obj_Entry { bool valid_hash_sysv : 1; /* A valid System V hash hash tag is available */ bool valid_hash_gnu : 1; /* A valid GNU hash tag is available */ bool dlopened : 1; /* dlopen()-ed (vs. load statically) */ + bool marker : 1; /* marker on the global obj list */ struct link_map linkmap; /* For GDB and dlinfo() */ Objlist dldags; /* Object belongs to these dlopened DAGs (%) */ @@ -276,6 +277,8 @@ typedef struct Struct_Obj_Entry { #define RTLD_MAGIC 0xd550b87a #define RTLD_VERSION 1 +TAILQ_HEAD(obj_entry_q, Struct_Obj_Entry); + #define RTLD_STATIC_TLS_EXTRA 128 /* Flags to be passed into symlook_ family of functions. */ @@ -367,6 +370,8 @@ const Elf_Sym *find_symdef(unsigned long, const Obj_Entry *, void init_pltgot(Obj_Entry *); void lockdflt_init(void); void digest_notes(Obj_Entry *, Elf_Addr, Elf_Addr); +Obj_Entry *globallist_curr(const Obj_Entry *obj); +Obj_Entry *globallist_next(const Obj_Entry *obj); void obj_free(Obj_Entry *); Obj_Entry *obj_new(void); void _rtld_bind_start(void); diff --git a/libexec/rtld-elf/sparc64/reloc.c b/libexec/rtld-elf/sparc64/reloc.c index 738a847..242fb8e 100644 --- a/libexec/rtld-elf/sparc64/reloc.c +++ b/libexec/rtld-elf/sparc64/reloc.c @@ -266,8 +266,8 @@ do_copy_relocations(Obj_Entry *dstobj) ELF_R_SYM(rela->r_info)); req.flags = SYMLOOK_EARLY; - for (srcobj = dstobj->next; srcobj != NULL; - srcobj = srcobj->next) { + for (srcobj = globallist_next(dstobj); srcobj != NULL; + srcobj = globallist_next(srcobj)) { res = symlook_obj(&req, srcobj); if (res == 0) { srcsym = req.sym_out; -- cgit v1.1