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; +}
