Currently our runtime linker must locate a shared library via hits, or 
directory search operations prior to identifying the shared library is already 
loaded. This differs from Linux, FreeBSD and Solaris at least, where loaded 
objects are checked for matches first. This difference prevents a useful 
technique from working.

Say you have two shared libs where both of them will not be found by normal 
search means (i.e. located in a directory that is not normally searched). 
libAAA.so is linked to libBBB.so. With other Unix's it is possible to 
dlopen("/full/path/to/libBBB.so") and then dlopen("/full/path/to/libAAA.so"), 
but on OpenBSD this currently fails. It fails because when libAAA.so tries to 
load its dep lib on libBBB.so it can't find it and doesn't realize it is 
already loaded.

On Solaris the above technique works. On FreeBSD and Linux it works if SONAME 
is set on libBBB.so. My current update to OpenJDK 7 requires this technique to 
work.

The following diff adds searching for loaded libs first and support for SONAME 
matching.

Please test on desktops and build machines (ports or base). Report any possible 
issues to me directly.

Index: library.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/library.c,v
retrieving revision 1.58
diff -u -p -r1.58 library.c
--- library.c   2 Oct 2008 20:12:08 -0000       1.58
+++ library.c   4 Oct 2010 17:45:37 -0000
@@ -92,18 +92,6 @@ _dl_tryload_shlib(const char *libname, i
 #define ROUND_PG(x) (((x) + align) & ~(align))
 #define TRUNC_PG(x) ((x) & ~(align))
 
-       object = _dl_lookup_object(libname);
-       if (object) {
-               object->obj_flags |= flags & RTLD_GLOBAL;
-               if (_dl_loading_object == NULL)
-                       _dl_loading_object = object;
-               if (object->load_object != _dl_objects &&
-                   object->load_object != _dl_loading_object) {
-                       _dl_link_grpref(object->load_object, 
_dl_loading_object);
-               }
-               return(object);         /* Already loaded */
-       }
-
        libfile = _dl_open(libname, O_RDONLY);
        if (libfile < 0) {
                _dl_errno = DL_CANT_OPEN;
Index: library_mquery.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/library_mquery.c,v
retrieving revision 1.36
diff -u -p -r1.36 library_mquery.c
--- library_mquery.c    2 Oct 2008 20:12:08 -0000       1.36
+++ library_mquery.c    4 Oct 2010 17:45:37 -0000
@@ -98,18 +98,6 @@ _dl_tryload_shlib(const char *libname, i
 #define ROUND_PG(x) (((x) + align) & ~(align))
 #define TRUNC_PG(x) ((x) & ~(align))
 
-       object = _dl_lookup_object(libname);
-       if (object) {
-               object->obj_flags |= flags & RTLD_GLOBAL;
-               if (_dl_loading_object == NULL)
-                       _dl_loading_object = object;
-               if (object->load_object != _dl_objects &&
-                   object->load_object != _dl_loading_object) {
-                       _dl_link_grpref(object->load_object, 
_dl_loading_object);
-               }
-               return(object);         /* Already loaded */
-       }
-
        libfile = _dl_open(libname, O_RDONLY);
        if (libfile < 0) {
                _dl_errno = DL_CANT_OPEN;
Index: library_subr.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/library_subr.c,v
retrieving revision 1.31
diff -u -p -r1.31 library_subr.c
--- library_subr.c      1 Jul 2010 19:25:44 -0000       1.31
+++ library_subr.c      4 Oct 2010 17:45:37 -0000
@@ -59,11 +59,11 @@ struct dlochld _dlopened_child_list;
  */
 
 int
-_dl_match_file(struct sod *sodp, char *name, int namelen)
+_dl_match_file(struct sod *sodp, const char *name, int namelen)
 {
        int match;
        struct sod lsod;
-       char *lname;
+       const char *lname;
 
        lname = name;
        if (sodp->sod_library) {
@@ -93,6 +93,35 @@ _dl_match_file(struct sod *sodp, char *n
        return match;
 }
 
+/*
+ * _dl_cmp_sod()
+ *
+ * This fucntion compares sod structs. The major must match exactly,
+ * and the minor must be same or larger.
+ *
+ * sodp is updated with the minor if this matches.
+ */
+
+int
+_dl_cmp_sod(struct sod *sodp, const struct sod *lsod)
+{
+       int match;
+
+       match = 1;
+       if ((_dl_strcmp((char *)lsod->sod_name, (char *)sodp->sod_name) == 0) &&
+           (lsod->sod_library == sodp->sod_library) &&
+           ((sodp->sod_major == -1) || (sodp->sod_major == lsod->sod_major)) &&
+           ((sodp->sod_minor == -1) ||
+           (lsod->sod_minor >= sodp->sod_minor))) {
+               match = 0;
+
+               /* return version matched */
+               sodp->sod_major = lsod->sod_major;
+               sodp->sod_minor = lsod->sod_minor;
+       }
+       return match;
+}
+
 char _dl_hint_store[MAXPATHLEN];
 
 char *
@@ -227,8 +256,67 @@ nohints:
        return NULL;
 }
 
+elf_object_t *
+_dl_lookup_object(const char *req_name, struct sod *req_sod)
+{
+       elf_object_t *object = _dl_objects;
+
+       while (object) {
+               char *soname;
+
+               if (_dl_cmp_sod(req_sod, &object->sod) == 0)
+                       return(object);
+
+               soname = (char *)object->Dyn.info[DT_SONAME];
+               if (soname != NULL) {
+                       if (_dl_strcmp(req_name, soname) == 0)
+                               return(object);
+               }
+
+               object = object->next;
+       }
+
+       return(NULL);
+}
+
+elf_object_t *
+_dl_find_loaded_shlib(const char *req_name, struct sod req_sod, int flags)
+{
+       elf_object_t *object;
+
+       object = _dl_lookup_object(req_name, &req_sod);
+
+       /* if not found retry with any minor */
+       if (object == NULL && req_sod.sod_library && req_sod.sod_minor != -1) {
+               short orig_minor = req_sod.sod_minor;
+               req_sod.sod_minor = -1;
+               object = _dl_lookup_object(req_name, &req_sod);
+
+               if (object != NULL && req_sod.sod_minor < orig_minor)
+                       _dl_printf("warning: lib%s.so.%d.%d: "
+                           "minor version >= %d expected, "
+                           "using it anyway\n",
+                           req_sod.sod_name, req_sod.sod_major,
+                           req_sod.sod_minor, orig_minor);
+       }
+
+       if (object) {   /* Already loaded */
+               object->obj_flags |= flags & RTLD_GLOBAL;
+               if (_dl_loading_object == NULL)
+                       _dl_loading_object = object;
+               if (object->load_object != _dl_objects &&
+                   object->load_object != _dl_loading_object) {
+                       _dl_link_grpref(object->load_object, 
_dl_loading_object);
+               }
+       }
+
+       return (object);
+}
+
 /*
  *  Load a shared object. Search order is:
+ *      First check loaded objects for a matching shlib, otherwise:
+ *
  *     If the name contains a '/' use only the path preceding the
  *     library name and do not continue on to other methods if not
  *     found.
@@ -302,6 +390,12 @@ fullpathdone:
        _dl_build_sod(libname, &sod);
        req_sod = sod;
 
+       object = _dl_find_loaded_shlib(libname, req_sod, flags);
+       if (object) {
+               _dl_free((char *)sod.sod_name);
+               return (object);
+       }
+
 again:
        /* No '/' in name. Scan the known places, LD_LIBRARY_PATH first.  */
        if (_dl_libpath != NULL) {
@@ -345,8 +439,14 @@ done:
                            sod.sod_name, sod.sod_major,
                            req_sod.sod_minor, sod.sod_minor);
                object = _dl_tryload_shlib(hint, type, flags);
+               if (object) {
+                       object->sod = req_sod;
+               } else {
+                       _dl_free((char *)sod.sod_name);
+               }
+       } else {
+               _dl_free((char *)sod.sod_name);
        }
-       _dl_free((char *)sod.sod_name);
        return(object);
 }
 
Index: loader.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/loader.c,v
retrieving revision 1.119
diff -u -p -r1.119 loader.c
--- loader.c    1 Jul 2010 19:25:44 -0000       1.119
+++ loader.c    4 Oct 2010 17:45:37 -0000
@@ -58,6 +58,7 @@ void _dl_setup_env(char **);
 void _dl_dtors(void);
 void _dl_boot_bind(const long, long *, Elf_Dyn *);
 void _dl_fixup_user_env(void);
+void _dl_set_sod(const char *, struct sod *);
 
 const char *_dl_progname;
 int  _dl_pagesz;
@@ -78,6 +79,17 @@ struct r_debug *_dl_debug_map;
 void _dl_dopreload(char *paths);
 
 void
+_dl_set_sod(const char *path, struct sod *sod)
+{
+       char *fname = _dl_strrchr(path, '/');
+
+       if (fname != NULL)
+               _dl_build_sod(++fname, sod);
+       else
+               _dl_build_sod(path, sod);
+}
+
+void
 _dl_debug_state(void)
 {
        /* Debugger stub */
@@ -472,6 +484,7 @@ _dl_boot(const char **argv, char **envp,
        exe_obj->load_list = load_list;
        exe_obj->obj_flags |= RTLD_GLOBAL;
        exe_obj->load_size = maxva - minva;
+       _dl_set_sod(exe_obj->load_name, &exe_obj->sod);
 
        n = _dl_malloc(sizeof *n);
        if (n == NULL)
@@ -501,6 +514,7 @@ _dl_boot(const char **argv, char **envp,
        _dl_link_grpsym(dyn_obj, 1);
 
        dyn_obj->status |= STAT_RELOC_DONE;
+       _dl_set_sod(dyn_obj->load_name, &dyn_obj->sod);
 
        /*
         * Everything should be in place now for doing the relocation
Index: resolve.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/resolve.c,v
retrieving revision 1.51
diff -u -p -r1.51 resolve.c
--- resolve.c   11 Aug 2010 01:14:27 -0000      1.51
+++ resolve.c   4 Oct 2010 17:45:37 -0000
@@ -113,7 +113,7 @@ _dl_finalize_object(const char *objname,
        if (object->Dyn.info[DT_RELA])
                object->Dyn.info[DT_RELA] += obase;
        if (object->Dyn.info[DT_SONAME])
-               object->Dyn.info[DT_SONAME] += obase;
+               object->Dyn.info[DT_SONAME] += object->Dyn.info[DT_STRTAB];
        if (object->Dyn.info[DT_RPATH])
                object->Dyn.info[DT_RPATH] += object->Dyn.info[DT_STRTAB];
        if (object->Dyn.info[DT_REL])
@@ -202,6 +202,8 @@ _dl_cleanup_objects()
        while (head != NULL) {
                if (head->load_name)
                        _dl_free(head->load_name);
+               if (head->sod.sod_name)
+                       _dl_free((char *)head->sod.sod_name);
                _dl_tailq_free(TAILQ_FIRST(&head->grpsym_list));
                _dl_tailq_free(TAILQ_FIRST(&head->child_list));
                _dl_tailq_free(TAILQ_FIRST(&head->grpref_list));
@@ -225,20 +227,6 @@ _dl_remove_object(elf_object_t *object)
        free_objects = object;
 }
 
-
-elf_object_t *
-_dl_lookup_object(const char *name)
-{
-       elf_object_t *object;
-
-       object = _dl_objects;
-       while (object) {
-               if (_dl_strcmp(name, object->load_name) == 0)
-                       return(object);
-               object = object->next;
-       }
-       return(0);
-}
 
 int _dl_find_symbol_obj(elf_object_t *object, const char *name,
     unsigned long hash, int flags, const Elf_Sym **ref,
Index: resolve.h
===================================================================
RCS file: /cvs/src/libexec/ld.so/resolve.h,v
retrieving revision 1.61
diff -u -p -r1.61 resolve.h
--- resolve.h   11 Aug 2010 01:14:27 -0000      1.61
+++ resolve.h   4 Oct 2010 17:45:37 -0000
@@ -136,6 +136,7 @@ struct elf_object {
 
        /* object that caused this module to be loaded, used in symbol lookup */
        elf_object_t    *load_object;
+       struct sod      sod;
 
        void *prebind_data;
 
@@ -160,7 +161,6 @@ elf_object_t *_dl_finalize_object(const 
 void   _dl_remove_object(elf_object_t *object);
 void   _dl_cleanup_objects(void);
 
-elf_object_t *_dl_lookup_object(const char *objname);
 elf_object_t *_dl_load_shlib(const char *, elf_object_t *, int, int);
 elf_object_t *_dl_tryload_shlib(const char *libname, int type, int flags);
 
@@ -220,7 +220,7 @@ void _dl_run_all_dtors(void);
 /* Please don't rename; gdb(1) knows about this. */
 Elf_Addr _dl_bind(elf_object_t *object, int index);
 
-int    _dl_match_file(struct sod *sodp, char *name, int namelen);
+int    _dl_match_file(struct sod *sodp, const char *name, int namelen);
 char   *_dl_find_shlib(struct sod *sodp, const char *searchpath, int nohints);
 void   _dl_load_list_free(struct load_list *load_list);

Reply via email to