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. */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to