From 2b0b4ee3592d5074ee6391bda886bdc48d168c5a Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Mon, 30 Mar 2009 08:47:28 +0000 Subject: Implement support for RTLD_NODELETE flag for dlopen() and -z nodelete static linker option. Do it by incrementing reference count on the loaded object and its dependencies. Reviewed by: davidxu, kan --- libexec/rtld-elf/rtld.c | 22 ++++++++++++++++++---- libexec/rtld-elf/rtld.h | 2 ++ 2 files changed, 20 insertions(+), 4 deletions(-) (limited to 'libexec') diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index d98ade7ce25a..07529b3091cf 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -937,6 +937,8 @@ digest_dynamic(Obj_Entry *obj, int early) /* XXX */; if (dynp->d_un.d_val & DF_1_BIND_NOW) obj->bind_now = true; + if (dynp->d_un.d_val & DF_1_NODELETE) + obj->z_nodelete = true; break; default: @@ -1422,15 +1424,21 @@ is_exported(const Elf_Sym *def) static int load_needed_objects(Obj_Entry *first) { - Obj_Entry *obj; + Obj_Entry *obj, *obj1; for (obj = first; obj != NULL; obj = obj->next) { Needed_Entry *needed; for (needed = obj->needed; needed != NULL; needed = needed->next) { - needed->obj = load_object(obj->strtab + needed->name, obj); - if (needed->obj == NULL && !ld_tracing) + obj1 = needed->obj = load_object(obj->strtab + needed->name, obj); + if (obj1 == NULL && !ld_tracing) return -1; + if (obj1 != NULL && obj1->z_nodelete && !obj1->ref_nodel) { + dbg("obj %s nodelete", obj1->path); + init_dag(obj1); + ref_dag(obj1); + obj1->ref_nodel = true; + } } } @@ -1976,12 +1984,13 @@ dlopen(const char *name, int mode) Obj_Entry **old_obj_tail; Obj_Entry *obj; Objlist initlist; - int result, lockstate; + int result, lockstate, nodelete; LD_UTRACE(UTRACE_DLOPEN_START, NULL, NULL, 0, mode, name); ld_tracing = (mode & RTLD_TRACE) == 0 ? NULL : "1"; if (ld_tracing != NULL) environ = (char **)*get_program_var_addr("environ"); + nodelete = mode & RTLD_NODELETE; objlist_init(&initlist); @@ -2029,6 +2038,11 @@ dlopen(const char *name, int mode) if (ld_tracing) goto trace; } + if (obj != NULL && (nodelete || obj->z_nodelete) && !obj->ref_nodel) { + dbg("obj %s nodelete", obj->path); + ref_dag(obj); + obj->z_nodelete = obj->ref_nodel = true; + } } LD_UTRACE(UTRACE_DLOPEN_STOP, obj, NULL, 0, obj ? obj->dl_refcount : 0, diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index f47c21515973..1d7ffb267f10 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -217,6 +217,8 @@ typedef struct Struct_Obj_Entry { bool tls_done : 1; /* Already allocated offset for static TLS */ bool phdr_alloc : 1; /* Phdr is allocated and needs to be freed. */ bool z_origin : 1; /* Process rpath and soname tokens */ + bool z_nodelete : 1; /* Do not unload the object and dependencies */ + bool ref_nodel : 1; /* refcount increased to prevent dlclose */ struct link_map linkmap; /* for GDB and dlinfo() */ Objlist dldags; /* Object belongs to these dlopened DAGs (%) */ -- cgit v1.3