Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 30 Mar 2009 08:47:28 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r190543 - in head: include libexec/rtld-elf sys/sys
Message-ID:  <200903300847.n2U8lSGo058512@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Mon Mar 30 08:47:28 2009
New Revision: 190543
URL: http://svn.freebsd.org/changeset/base/190543

Log:
  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

Modified:
  head/include/dlfcn.h
  head/libexec/rtld-elf/rtld.c
  head/libexec/rtld-elf/rtld.h
  head/sys/sys/elf_common.h

Modified: head/include/dlfcn.h
==============================================================================
--- head/include/dlfcn.h	Mon Mar 30 08:44:29 2009	(r190542)
+++ head/include/dlfcn.h	Mon Mar 30 08:47:28 2009	(r190543)
@@ -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().

Modified: head/libexec/rtld-elf/rtld.c
==============================================================================
--- head/libexec/rtld-elf/rtld.c	Mon Mar 30 08:44:29 2009	(r190542)
+++ head/libexec/rtld-elf/rtld.c	Mon Mar 30 08:47:28 2009	(r190543)
@@ -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,

Modified: head/libexec/rtld-elf/rtld.h
==============================================================================
--- head/libexec/rtld-elf/rtld.h	Mon Mar 30 08:44:29 2009	(r190542)
+++ head/libexec/rtld-elf/rtld.h	Mon Mar 30 08:47:28 2009	(r190543)
@@ -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 (%) */

Modified: head/sys/sys/elf_common.h
==============================================================================
--- head/sys/sys/elf_common.h	Mon Mar 30 08:44:29 2009	(r190542)
+++ head/sys/sys/elf_common.h	Mon Mar 30 08:47:28 2009	(r190543)
@@ -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. */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200903300847.n2U8lSGo058512>