Moving from ports@.

Quick intro:

A library (gstreamer1) uses functions from another library (libsoup)
which exists in two incompatible versions (libsoup-2.4.so.XX and
libsoup-3.0.so.XX).

Other software calling gstreamer might use one or other of these two
libsoups for its own purposes, so gstreamer has been written to work
with either version of libsoup, but it needs to know which it should
use.

the text below from my ports@ mail follows on:

> gstreamer is supposed to detect a libsoup which is already loaded into the
> address space (by using dlopen() with RTLD_NOLOAD to test this) and adapts
> itself to use the appropriate libsoup API+ABI. It does this specifically
> to avoid this type of conflict. Only if it can't find a copy of libsoup2
> or libsoup3 already loaded does it use its own preference order (libsoup3
> by default) and dlopen()s it (via g_module_open) itself.
> 
> (see gst_soup_load_library() in ext/soup/gstsouploader.c from
> gstreamer1/plugins-good).
> 
> But we don't have RTLD_NOLOAD so this trick doesn't work...

... gstreamer code for this is at
https://gitlab.freedesktop.org/gstreamer/gstreamer/-/blob/main/subprojects/gst-plugins-good/ext/soup/gstsouploader.c#L146

Brad pointed me at a diff from guenther@ adding RTLD_NOLOAD (and
RTLD_NODELETE, written before semarie's version of RTLD_NODELETE):
https://marc.info/?l=openbsd-tech&m=162068525021512&w=2

With this applied and gstreamer1-plugins-good rebuilt, the code in
gst_soup_load_library works as expected.

I've included the rebased diff below and added a simple regress test
that I wrote, loosely based on the rtld_nodelete test plus what
gstreamer1 is doing.

Looking around some other ports (it's difficult to do a proper search
because it shows up in rust's translated version of dlfcn.h for various
OS which ends up vendored into various trees) I see some optional use
in a few ports e.g. asterisk ("Check to see if the given resource is
loaded") and vlc (I think this is trying to load a linux v4l2 library
only if not already loaded but allow it to fail gracefully).

Is this something we want?


Index: include/dlfcn.h
===================================================================
RCS file: /cvs/src/include/dlfcn.h,v
retrieving revision 1.15
diff -u -p -r1.15 dlfcn.h
--- include/dlfcn.h     2 Jun 2021 07:29:03 -0000       1.15
+++ include/dlfcn.h     11 Aug 2022 09:04:59 -0000
@@ -43,6 +43,7 @@
 #define RTLD_LOCAL     0x000
 #define RTLD_TRACE     0x200
 #define RTLD_NODELETE  0x400
+#define RTLD_NOLOAD    0x800
 
 /*
  * Special handle arguments for dlsym().
Index: libexec/ld.so/dlfcn.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/dlfcn.c,v
retrieving revision 1.110
diff -u -p -r1.110 dlfcn.c
--- libexec/ld.so/dlfcn.c       8 Jan 2022 17:28:49 -0000       1.110
+++ libexec/ld.so/dlfcn.c       11 Aug 2022 09:04:59 -0000
@@ -45,6 +45,15 @@ static int _dl_real_close(void *handle);
 static lock_cb *_dl_thread_fnc = NULL;
 static elf_object_t *obj_from_addr(const void *addr);
 
+#define OK_FLAGS       (0 \
+       | RTLD_TRACE    \
+       | RTLD_LAZY     \
+       | RTLD_NOW      \
+       | RTLD_GLOBAL   \
+       | RTLD_NODELETE \
+       | RTLD_NOLOAD   \
+       )
+
 void *
 dlopen(const char *libname, int flags)
 {
@@ -53,7 +62,7 @@ dlopen(const char *libname, int flags)
        int failed = 0;
        int obj_flags;
 
-       if (flags & ~(RTLD_TRACE|RTLD_LAZY|RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE)) 
{
+       if (flags & ~OK_FLAGS) {
                _dl_errno = DL_INVALID_MODE;
                return NULL;
        }
@@ -78,7 +87,9 @@ dlopen(const char *libname, int flags)
        _dl_loading_object = NULL;
 
        obj_flags = (flags & RTLD_NOW ? DF_1_NOW : 0)
-           | (flags & RTLD_GLOBAL ? DF_1_GLOBAL : 0);
+           | (flags & RTLD_GLOBAL ? DF_1_GLOBAL : 0)
+           | (flags & RTLD_NOLOAD ? DF_1_NOOPEN : 0)
+           ;
        object = _dl_load_shlib(libname, _dl_objects, OBJTYPE_DLO, obj_flags);
        if (object == 0) {
                DL_DEB(("dlopen: failed to open %s\n", libname));
Index: libexec/ld.so/library.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/library.c,v
retrieving revision 1.86
diff -u -p -r1.86 library.c
--- libexec/ld.so/library.c     8 Jan 2022 06:49:41 -0000       1.86
+++ libexec/ld.so/library.c     11 Aug 2022 09:04:59 -0000
@@ -129,17 +129,15 @@ _dl_tryload_shlib(const char *libname, i
        for (object = _dl_objects; object != NULL; object = object->next) {
                if (object->dev == sb.st_dev &&
                    object->inode == sb.st_ino) {
-                       object->obj_flags |= flags & DF_1_GLOBAL;
                        _dl_close(libfile);
-                       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);
-                       }
+                       _dl_handle_already_loaded(object, flags);
                        return(object);
                }
+       }
+       if (flags & DF_1_NOOPEN) {
+               _dl_close(libfile);
+               return NULL;
+
        }
 
        _dl_read(libfile, hbuf, sizeof(hbuf));
Index: libexec/ld.so/library_mquery.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/library_mquery.c,v
retrieving revision 1.66
diff -u -p -r1.66 library_mquery.c
--- libexec/ld.so/library_mquery.c      8 Jan 2022 06:49:41 -0000       1.66
+++ libexec/ld.so/library_mquery.c      11 Aug 2022 09:04:59 -0000
@@ -134,17 +134,14 @@ _dl_tryload_shlib(const char *libname, i
        for (object = _dl_objects; object != NULL; object = object->next) {
                if (object->dev == sb.st_dev &&
                    object->inode == sb.st_ino) {
-                       object->obj_flags |= flags & DF_1_GLOBAL;
                        _dl_close(libfile);
-                       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);
-                       }
+                       _dl_handle_already_loaded(object, flags);
                        return(object);
                }
+       }
+       if (flags & DF_1_NOOPEN) {
+               _dl_close(libfile);
+               return NULL;
        }
 
        _dl_read(libfile, hbuf, sizeof(hbuf));
Index: libexec/ld.so/library_subr.c
===================================================================
RCS file: /cvs/src/libexec/ld.so/library_subr.c,v
retrieving revision 1.51
diff -u -p -r1.51 library_subr.c
--- libexec/ld.so/library_subr.c        8 Jan 2022 06:49:41 -0000       1.51
+++ libexec/ld.so/library_subr.c        11 Aug 2022 09:04:59 -0000
@@ -241,6 +241,18 @@ _dl_lookup_object(const char *req_name, 
        return(NULL);
 }
 
+void
+_dl_handle_already_loaded(elf_object_t *object, int flags)
+{
+       object->obj_flags |= flags & DF_1_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);
+       }
+}
+
 static elf_object_t *
 _dl_find_loaded_shlib(const char *req_name, struct sod req_sod, int flags)
 {
@@ -262,15 +274,8 @@ _dl_find_loaded_shlib(const char *req_na
                            req_sod.sod_minor, orig_minor);
        }
 
-       if (object) {   /* Already loaded */
-               object->obj_flags |= flags & DF_1_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);
-               }
-       }
+       if (object)
+               _dl_handle_already_loaded(object, flags);
 
        return (object);
 }
Index: libexec/ld.so/resolve.h
===================================================================
RCS file: /cvs/src/libexec/ld.so/resolve.h,v
retrieving revision 1.100
diff -u -p -r1.100 resolve.h
--- libexec/ld.so/resolve.h     28 Jan 2022 05:01:28 -0000      1.100
+++ libexec/ld.so/resolve.h     11 Aug 2022 09:04:59 -0000
@@ -255,6 +255,7 @@ elf_object_t *_dl_finalize_object(const 
 void   _dl_remove_object(elf_object_t *object);
 void   _dl_cleanup_objects(void);
 
+void _dl_handle_already_loaded(elf_object_t *_object, int _flags);
 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);
 
Index: regress/libexec/ld.so/Makefile
===================================================================
RCS file: /cvs/src/regress/libexec/ld.so/Makefile,v
retrieving revision 1.18
diff -u -p -r1.18 Makefile
--- regress/libexec/ld.so/Makefile      2 Jun 2021 07:32:34 -0000       1.18
+++ regress/libexec/ld.so/Makefile      11 Aug 2022 09:38:48 -0000
@@ -4,7 +4,7 @@ SUBDIR+= elf hidden weak dlsym dlopen dl
 SUBDIR+= constructor 
 SUBDIR+= link-order edgecases initfirst
 SUBDIR+= df_1_noopen randomdata subst dependencies
-SUBDIR+= init-env nodelete
+SUBDIR+= init-env nodelete noload
 
 install:
 
Index: regress/libexec/ld.so/noload/Makefile
===================================================================
RCS file: regress/libexec/ld.so/noload/Makefile
diff -N regress/libexec/ld.so/noload/Makefile
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ regress/libexec/ld.so/noload/Makefile       11 Aug 2022 09:38:48 -0000
@@ -0,0 +1,5 @@
+# $OpenBSD$
+
+SUBDIR +=      liba libb test1
+
+.include <bsd.subdir.mk>
Index: regress/libexec/ld.so/noload/liba/Makefile
===================================================================
RCS file: regress/libexec/ld.so/noload/liba/Makefile
diff -N regress/libexec/ld.so/noload/liba/Makefile
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ regress/libexec/ld.so/noload/liba/Makefile  11 Aug 2022 09:38:48 -0000
@@ -0,0 +1,9 @@
+# $OpenBSD$
+
+LIB =  a
+SRCS = liba.c
+
+regress: all
+
+.include <bsd.lib.mk>
+
Index: regress/libexec/ld.so/noload/liba/liba.c
===================================================================
RCS file: regress/libexec/ld.so/noload/liba/liba.c
diff -N regress/libexec/ld.so/noload/liba/liba.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ regress/libexec/ld.so/noload/liba/liba.c    11 Aug 2022 09:38:48 -0000
@@ -0,0 +1,4 @@
+void
+functiona(void)
+{
+}
Index: regress/libexec/ld.so/noload/liba/shlib_version
===================================================================
RCS file: regress/libexec/ld.so/noload/liba/shlib_version
diff -N regress/libexec/ld.so/noload/liba/shlib_version
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ regress/libexec/ld.so/noload/liba/shlib_version     11 Aug 2022 09:38:48 
-0000
@@ -0,0 +1,2 @@
+major=0
+minor=0
Index: regress/libexec/ld.so/noload/libb/Makefile
===================================================================
RCS file: regress/libexec/ld.so/noload/libb/Makefile
diff -N regress/libexec/ld.so/noload/libb/Makefile
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ regress/libexec/ld.so/noload/libb/Makefile  11 Aug 2022 09:38:48 -0000
@@ -0,0 +1,9 @@
+# $OpenBSD$
+
+LIB =  b
+SRCS = libb.c
+
+regress: all
+
+.include <bsd.lib.mk>
+
Index: regress/libexec/ld.so/noload/libb/libb.c
===================================================================
RCS file: regress/libexec/ld.so/noload/libb/libb.c
diff -N regress/libexec/ld.so/noload/libb/libb.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ regress/libexec/ld.so/noload/libb/libb.c    11 Aug 2022 09:38:48 -0000
@@ -0,0 +1,4 @@
+void
+functionb(void)
+{
+}
Index: regress/libexec/ld.so/noload/libb/shlib_version
===================================================================
RCS file: regress/libexec/ld.so/noload/libb/shlib_version
diff -N regress/libexec/ld.so/noload/libb/shlib_version
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ regress/libexec/ld.so/noload/libb/shlib_version     11 Aug 2022 09:38:48 
-0000
@@ -0,0 +1,2 @@
+major=0
+minor=0
Index: regress/libexec/ld.so/noload/test1/Makefile
===================================================================
RCS file: regress/libexec/ld.so/noload/test1/Makefile
diff -N regress/libexec/ld.so/noload/test1/Makefile
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ regress/libexec/ld.so/noload/test1/Makefile 11 Aug 2022 09:38:48 -0000
@@ -0,0 +1,32 @@
+# $OpenBSD$
+
+.include <bsd.obj.mk>
+
+PROG = test1
+
+LIBADIR !=     if test -d ${.CURDIR}/../liba/${__objdir}; then \
+                       echo "${.CURDIR}/../liba/${__objdir}";  \
+               else                                            \
+                       echo "${.CURDIR}/../liba";              \
+               fi
+
+LIBBDIR !=     if test -d ${.CURDIR}/../libb/${__objdir}; then \
+                       echo "${.CURDIR}/../libb/${__objdir}";  \
+               else                                            \
+                       echo "${.CURDIR}/../libb";              \
+               fi
+
+LIBANAME =     ${LIBADIR}/liba.so.0.0
+LIBBNAME =     ${LIBBDIR}/libb.so.0.0
+
+CFLAGS +=      -DLIBANAME=\"${LIBANAME}\" \
+               -DLIBBNAME=\"${LIBBNAME}\"
+
+REGRESS_TARGETS += run-regress
+
+run-regress: ${PROG}
+       if ${PROG} | grep found; then echo failed; exit 1; fi
+       LD_PRELOAD=${LIBANAME} ${PROG} | grep ${LIBANAME}.found
+       LD_PRELOAD=${LIBBNAME} ${PROG} | grep ${LIBBNAME}.found
+
+.include <bsd.regress.mk>
Index: regress/libexec/ld.so/noload/test1/test1.c
===================================================================
RCS file: regress/libexec/ld.so/noload/test1/test1.c
diff -N regress/libexec/ld.so/noload/test1/test1.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ regress/libexec/ld.so/noload/test1/test1.c  11 Aug 2022 09:38:48 -0000
@@ -0,0 +1,26 @@
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef LIBANAME
+#error "LIBANAME undefined"
+#endif
+
+#ifndef LIBBNAME
+#error "LIBBNAME undefined"
+#endif
+
+int
+main(int argc, char *argv[])
+{
+       void *handle;
+
+       printf("opening\n");
+       if ((handle = dlopen(LIBANAME, RTLD_NOW|RTLD_NOLOAD)))
+               printf("%s found\n", LIBANAME);
+       else if ((handle = dlopen(LIBBNAME, RTLD_NOW|RTLD_NOLOAD)))
+               printf("%s found\n", LIBBNAME);
+
+       return 0;
+}

Reply via email to