summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2009-03-30 08:47:28 +0000
committerkib <kib@FreeBSD.org>2009-03-30 08:47:28 +0000
commit566c4f31f122544715745d4e127eaf47249d194b (patch)
tree7fa11a9c6f5eb076d989897ba5ab3e64c0101750
parent96b9a81fd8f883257674bf829243b5ee4b7e74df (diff)
downloadFreeBSD-src-566c4f31f122544715745d4e127eaf47249d194b.zip
FreeBSD-src-566c4f31f122544715745d4e127eaf47249d194b.tar.gz
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
-rw-r--r--include/dlfcn.h1
-rw-r--r--libexec/rtld-elf/rtld.c22
-rw-r--r--libexec/rtld-elf/rtld.h2
-rw-r--r--sys/sys/elf_common.h1
4 files changed, 22 insertions, 4 deletions
diff --git a/include/dlfcn.h b/include/dlfcn.h
index 38f21b2..9fac620 100644
--- a/include/dlfcn.h
+++ b/include/dlfcn.h
@@ -47,6 +47,7 @@
#define RTLD_GLOBAL 0x100 /* Make symbols globally available. */
#define RTLD_LOCAL 0 /* Opposite of RTLD_GLOBAL, and the default. */
#define RTLD_TRACE 0x200 /* Trace loaded objects and exit. */
+#define RTLD_NODELETE 0x01000 /* Do not remove members. */
/*
* Request arguments for dlinfo().
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index d98ade7..07529b3 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 f47c2151..1d7ffb2 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 (%) */
diff --git a/sys/sys/elf_common.h b/sys/sys/elf_common.h
index bf64a3b..42b5cac 100644
--- a/sys/sys/elf_common.h
+++ b/sys/sys/elf_common.h
@@ -469,6 +469,7 @@ typedef struct {
/* Values for DT_FLAGS_1 */
#define DF_1_BIND_NOW 0x00000001 /* Same as DF_BIND_NOW */
#define DF_1_GLOBAL 0x00000002 /* Set the RTLD_GLOBAL for object */
+#define DF_1_NODELETE 0x00000008 /* Set the RTLD_NODELETE for object */
#define DF_1_ORIGIN 0x00000080 /* Process $ORIGIN */
/* Values for n_type. Used in core files. */
OpenPOWER on IntegriCloud