Reuben Thomas wrote:
> > The patch looks nearly fine. A few small nits, though:
> 
> Thanks for the rapid review; I attach a revised patch.

Thanks. I am adding it, with
  - fixed indentation in relocatable.c,
  - moving the added block of _GL_* definitions up,
  - systematic m4 quoting even of single words in m4 code,
  - and a GNU-style ChangeLog entry.

Then I notice that
  - m4/libdl.m4 is missing from modules/relocatable-lib-lgpl,
  - Testing with
    ./configure --enable-relocatable CFLAGS="-DPIC -DINSTALLDIR=\\\"/tmp\\\" 
-DENABLE_COSTLY_RELOCATABLE"
    on AIX, I get a compilation error:

../../gllib/relocatable.c: In function 'find_shared_library_fullname':
../../gllib/relocatable.c:465:3: error: unknown type name 'Dl_info'; did you 
mean 'fh_ino'?
   Dl_info info;
   ^~~~~~~
   fh_ino
../../gllib/relocatable.c:466:13: warning: implicit declaration of function 
'dladdr' [-Wimplicit-function-declaration]
   int ret = dladdr (find_shared_library_fullname, &info);
             ^~~~~~
../../gllib/relocatable.c:467:23: error: request for member 'dli_fname' in 
something not a structure or union
   if (ret != 0 && info.dli_fname != NULL)
                       ^
../../gllib/relocatable.c:468:43: error: request for member 'dli_fname' in 
something not a structure or union
     shared_library_fullname = strdup (info.dli_fname);
                                           ^
gmake[3]: *** [Makefile:2276: relocatable.o] Error 1

    This is because AIX has <dlfcn.h> but does not have dladdr().

The next question is: How costly is this dladdr() call? Would it therefore
make sense to enable ENABLE_COSTLY_RELOCATABLE by default on more platforms?

Bruno

>From a7d3b961679194c60c9e2a24d57505abf411ae60 Mon Sep 17 00:00:00 2001
From: Reuben Thomas <[email protected]>
Date: Mon, 8 Dec 2025 18:59:01 +0000
Subject: [PATCH 1/2] relocatable-lib: Find shared library filename via dladdr.

* lib/relocatable.c (_GL_USE_PROCFS, _GL_USE_WIN32, _GL_USE_DLADDR):
New macros.
(find_shared_library_fullname): Use dladdr if _GL_USE_DLADDR is defined.
(get_shared_library_fullname): Use _GL_USE_WIN32.
* m4/libdl.m4 (gl_LIBDL): Update comment.
* modules/relocatable-lib (Files): Add m4/libdl.m4.
(configure.ac): Invoke gl_LIBDL. Define _GL_DLADDR_IN_LIBC.
* modules/relocatable-lib-lgpl (configure.ac): Likewise.
---
 ChangeLog                    | 12 ++++++++++++
 lib/relocatable.c            | 38 ++++++++++++++++++++++++++----------
 m4/libdl.m4                  |  2 +-
 modules/relocatable-lib      |  5 +++++
 modules/relocatable-lib-lgpl |  4 ++++
 5 files changed, 50 insertions(+), 11 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index ab93efe052..cf3ddd6df8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2025-12-09  Reuben Thomas  <[email protected]>
+
+	relocatable-lib: Find shared library filename via dladdr.
+	* lib/relocatable.c (_GL_USE_PROCFS, _GL_USE_WIN32, _GL_USE_DLADDR):
+	New macros.
+	(find_shared_library_fullname): Use dladdr if _GL_USE_DLADDR is defined.
+	(get_shared_library_fullname): Use _GL_USE_WIN32.
+	* m4/libdl.m4 (gl_LIBDL): Update comment.
+	* modules/relocatable-lib (Files): Add m4/libdl.m4.
+	(configure.ac): Invoke gl_LIBDL. Define _GL_DLADDR_IN_LIBC.
+	* modules/relocatable-lib-lgpl (configure.ac): Likewise.
+
 2025-12-07  Bruno Haible  <[email protected]>
 
 	argp: Replace some 'continue;' statements with if/else.
diff --git a/lib/relocatable.c b/lib/relocatable.c
index 15b3bc442d..a3d741aff2 100644
--- a/lib/relocatable.c
+++ b/lib/relocatable.c
@@ -65,6 +65,21 @@
 # include <libintl.h>
 #endif
 
+/* We have special code for two types of system: non-Cygwin Windows, and
+   Linux where dladdr is in a separate library (uClibc and glibc < 2.34).
+   Need glibc >= 2, for getline().
+
+   Otherwise, use dladdr.
+*/
+#if defined __linux__ && (defined __UCLIBC__ || ((__GLIBC__ >= 2) && (__GLIBC_MINOR__ < 34)))
+# define _GL_USE_PROCFS 1
+#elif (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__
+# define _GL_USE_WIN32 1
+#elif _GL_DLADDR_IN_LIBC
+# define _GL_USE_DLADDR 1
+# include <dlfcn.h>
+#endif
+
 #if defined _WIN32 && !defined __CYGWIN__
 /* Don't assume that UNICODE is not defined.  */
 # undef GetModuleFileName
@@ -318,10 +333,9 @@ static char *shared_library_fullname;
 
 #if defined _WIN32 && !defined __CYGWIN__
 /* Native Windows only.
-   On Cygwin, it is better to use the Cygwin provided /proc interface, than
-   to use native Windows API and cygwin_conv_to_posix_path, because it
-   supports longer file names
-   (see <https://cygwin.com/ml/cygwin/2011-01/msg00410.html>).  */
+   On Cygwin, it is better to use dladdr, than to use native Windows
+   API and cygwin_conv_to_posix_path, because it supports longer file
+   names (see <https://cygwin.com/ml/cygwin/2011-01/msg00410.html>).  */
 
 /* Determine the full pathname of the shared library when it is loaded.
 
@@ -402,12 +416,10 @@ _DLL_InitTerm (unsigned long hModule, unsigned long ulFlag)
 static void
 find_shared_library_fullname ()
 {
-#if (defined __linux__ && (__GLIBC__ >= 2 || defined __UCLIBC__)) || defined __CYGWIN__
+#if _GL_USE_PROCFS
   /* Linux has /proc/self/maps. glibc 2 and uClibc have the getline()
      function.
-     Cygwin >= 1.5 has /proc/self/maps and the getline() function too.
-     But it is costly: ca. 0.3 ms on Linux, 3 ms on Cygwin 1.5, and 5 ms on
-     Cygwin 1.7.  */
+     But it is costly: ca. 0.3 ms.  */
   FILE *fp;
 
   /* Open the current process' maps file.  It describes one VMA per line.  */
@@ -449,6 +461,11 @@ find_shared_library_fullname ()
         }
       fclose (fp);
     }
+#elif _GL_USE_DLADDR
+  Dl_info info;
+  int ret = dladdr (find_shared_library_fullname, &info);
+  if (ret != 0 && info.dli_fname != NULL)
+    shared_library_fullname = strdup (info.dli_fname);
 #endif
 }
 
@@ -456,11 +473,12 @@ find_shared_library_fullname ()
 
 /* Return the full pathname of the current shared library.
    Return NULL if unknown.
-   Guaranteed to work only on Linux, EMX, Cygwin, and native Windows.  */
+   Guaranteed to work only on Linux, EMX, Cygwin, native Windows, and
+   systems with dladdr in libc.  */
 static char *
 get_shared_library_fullname ()
 {
-#if !(defined _WIN32 && !defined __CYGWIN__) && !defined __EMX__
+#if !_GL_USE_WIN32
   static bool tried_find_shared_library_fullname;
   if (!tried_find_shared_library_fullname)
     {
diff --git a/m4/libdl.m4 b/m4/libdl.m4
index 4b4357b7f8..839b053af5 100644
--- a/m4/libdl.m4
+++ b/m4/libdl.m4
@@ -15,7 +15,7 @@ AC_DEFUN([gl_LIBDL]
   dnl dlopen, dlsym are
   dnl - in libc on glibc >= 2.34, musl libc, macOS, FreeBSD, NetBSD, OpenBSD,
   dnl   AIX, Solaris, Cygwin, Haiku,
-  dnl - in a separate libdl on glibc < 2.34, Android.
+  dnl - in a separate libdl on glibc < 2.34, Android, uClibc.
   AC_CACHE_CHECK([for library needed for dlopen and dlsym],
     [gl_cv_lib_dl],
     [AC_LINK_IFELSE(
diff --git a/modules/relocatable-lib b/modules/relocatable-lib
index 0d59464fe6..d2f513861b 100644
--- a/modules/relocatable-lib
+++ b/modules/relocatable-lib
@@ -7,6 +7,7 @@ doc/relocatable.texi
 lib/relocatable.h
 lib/relocatable.c
 lib/relocatable.valgrind
+m4/libdl.m4
 m4/relocatable-lib.m4
 m4/build-to-host.m4
 
@@ -19,6 +20,10 @@ gl_RELOCATABLE_LIBRARY
 if test $RELOCATABLE = yes; then
   AC_LIBOBJ([relocatable])
 fi
+gl_LIBDL
+if test -z "$LIBDL"; then
+  AC_DEFINE([_GL_DLADDR_IN_LIBC], [1], [Define to 1 if dladdr is in libc.])
+fi
 
 Makefile.am:
 
diff --git a/modules/relocatable-lib-lgpl b/modules/relocatable-lib-lgpl
index b8ecb51ef8..4fe84cea85 100644
--- a/modules/relocatable-lib-lgpl
+++ b/modules/relocatable-lib-lgpl
@@ -18,6 +18,10 @@ gl_RELOCATABLE_LIBRARY
 if test $RELOCATABLE = yes; then
   AC_LIBOBJ([relocatable])
 fi
+gl_LIBDL
+if test -z "$LIBDL"; then
+  AC_DEFINE([_GL_DLADDR_IN_LIBC], [1], [Define to 1 if dladdr is in libc.])
+fi
 
 Makefile.am:
 DEFS += -DNO_XMALLOC
-- 
2.52.0

From 34951d0cb0fbfcc86fa8e37bc9ff5a2e03662f60 Mon Sep 17 00:00:00 2001
From: Bruno Haible <[email protected]>
Date: Tue, 9 Dec 2025 14:58:00 +0100
Subject: [PATCH 2/2] relocatable-lib: Fix and simplify previous commit.

* m4/relocatable-lib.m4 (gl_RELOCATABLE_LIBRARY_BODY): Invoke gl_LIBDL.
Define HAVE_DLADDR_IN_LIBC.
* modules/relocatable-lib (configure.ac): Revert last change.
* modules/relocatable-lib-lgpl (Files): Add m4/libdl.m4.
(configure.ac): Revert last change.
* lib/relocatable.c (_GL_USE_PROCFS, _GL_USE_WIN32, _GL_USE_DLADDR):
Remove macros.
(ENABLE_COSTLY_RELOCATABLE): Update comments.
(find_shared_library_fullname): Use dladdr as first alternative. Test
HAVE_DLADDR_IN_LIBC instead of _GL_USE_PROCFS. Define as macro.
(get_shared_library_fullname): Update comments. Test
find_shared_library_fullname instead of _GL_USE_WIN32.
---
 ChangeLog                    | 16 ++++++++++
 lib/relocatable.c            | 57 +++++++++++++++++-------------------
 m4/libdl.m4                  |  4 +--
 m4/relocatable-lib.m4        | 10 ++++++-
 modules/relocatable-lib      |  6 +---
 modules/relocatable-lib-lgpl |  5 +---
 6 files changed, 56 insertions(+), 42 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index cf3ddd6df8..e745af71cd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2025-12-09  Bruno Haible  <[email protected]>
+
+	relocatable-lib: Fix and simplify previous commit.
+	* m4/relocatable-lib.m4 (gl_RELOCATABLE_LIBRARY_BODY): Invoke gl_LIBDL.
+	Define HAVE_DLADDR_IN_LIBC.
+	* modules/relocatable-lib (configure.ac): Revert last change.
+	* modules/relocatable-lib-lgpl (Files): Add m4/libdl.m4.
+	(configure.ac): Revert last change.
+	* lib/relocatable.c (_GL_USE_PROCFS, _GL_USE_WIN32, _GL_USE_DLADDR):
+	Remove macros.
+	(ENABLE_COSTLY_RELOCATABLE): Update comments.
+	(find_shared_library_fullname): Use dladdr as first alternative. Test
+	HAVE_DLADDR_IN_LIBC instead of _GL_USE_PROCFS. Define as macro.
+	(get_shared_library_fullname): Update comments. Test
+	find_shared_library_fullname instead of _GL_USE_WIN32.
+
 2025-12-09  Reuben Thomas  <[email protected]>
 
 	relocatable-lib: Find shared library filename via dladdr.
diff --git a/lib/relocatable.c b/lib/relocatable.c
index a3d741aff2..5eb7e8b716 100644
--- a/lib/relocatable.c
+++ b/lib/relocatable.c
@@ -55,6 +55,10 @@
 # define strncmp strnicmp
 #endif
 
+#if HAVE_DLADDR_IN_LIBC
+# include <dlfcn.h>
+#endif
+
 #if DEPENDS_ON_LIBCHARSET
 # include <libcharset.h>
 #endif
@@ -65,21 +69,6 @@
 # include <libintl.h>
 #endif
 
-/* We have special code for two types of system: non-Cygwin Windows, and
-   Linux where dladdr is in a separate library (uClibc and glibc < 2.34).
-   Need glibc >= 2, for getline().
-
-   Otherwise, use dladdr.
-*/
-#if defined __linux__ && (defined __UCLIBC__ || ((__GLIBC__ >= 2) && (__GLIBC_MINOR__ < 34)))
-# define _GL_USE_PROCFS 1
-#elif (defined _WIN32 && !defined __CYGWIN__) || defined __EMX__
-# define _GL_USE_WIN32 1
-#elif _GL_DLADDR_IN_LIBC
-# define _GL_USE_DLADDR 1
-# include <dlfcn.h>
-#endif
-
 #if defined _WIN32 && !defined __CYGWIN__
 /* Don't assume that UNICODE is not defined.  */
 # undef GetModuleFileName
@@ -116,9 +105,8 @@
 
 /* Whether to enable the more costly support for relocatable libraries.
    It allows libraries to be have been installed with a different original
-   prefix than the program.  But it is quite costly, especially on Cygwin
-   platforms, see below.  Therefore we enable it by default only on native
-   Windows platforms.  */
+   prefix than the program.  But it is quite costly, see below.  Therefore
+   we enable it by default only on native Windows platforms.  */
 #ifndef ENABLE_COSTLY_RELOCATABLE
 # if defined _WIN32 && !defined __CYGWIN__
 #  define ENABLE_COSTLY_RELOCATABLE 1
@@ -333,9 +321,10 @@ static char *shared_library_fullname;
 
 #if defined _WIN32 && !defined __CYGWIN__
 /* Native Windows only.
-   On Cygwin, it is better to use dladdr, than to use native Windows
-   API and cygwin_conv_to_posix_path, because it supports longer file
-   names (see <https://cygwin.com/ml/cygwin/2011-01/msg00410.html>).  */
+   On Cygwin, it is better to use either dladdr() or the Cygwin provided /proc
+   interface, than to use native Windows API and cygwin_conv_to_posix_path,
+   because it supports longer file names
+   (see <https://cygwin.com/ml/cygwin/2011-01/msg00410.html>).  */
 
 /* Determine the full pathname of the shared library when it is loaded.
 
@@ -416,7 +405,17 @@ _DLL_InitTerm (unsigned long hModule, unsigned long ulFlag)
 static void
 find_shared_library_fullname ()
 {
-#if _GL_USE_PROCFS
+#if HAVE_DLADDR_IN_LIBC
+  /* glibc >= 2.34, musl, macOS, FreeBSD, NetBSD, OpenBSD, Solaris, Cygwin, Minix */
+  /* We can use dladdr() without introducing extra link dependencies.  */
+  Dl_info info;
+  /* It is OK to use a 'static' function ??? that does not appear in the
+     dynamic symbol table of any ELF object ??? as argument of dladdr() here,
+     because we don't access the fields info.dli_sname and info.dli_saddr.  */
+  int ret = dladdr (find_shared_library_fullname, &info);
+  if (ret != 0 && info.dli_fname != NULL)
+    shared_library_fullname = strdup (info.dli_fname);
+#elif (defined __linux__ && (__GLIBC__ >= 2 || defined __UCLIBC__)) || defined __CYGWIN__
   /* Linux has /proc/self/maps. glibc 2 and uClibc have the getline()
      function.
      But it is costly: ca. 0.3 ms.  */
@@ -461,24 +460,22 @@ find_shared_library_fullname ()
         }
       fclose (fp);
     }
-#elif _GL_USE_DLADDR
-  Dl_info info;
-  int ret = dladdr (find_shared_library_fullname, &info);
-  if (ret != 0 && info.dli_fname != NULL)
-    shared_library_fullname = strdup (info.dli_fname);
 #endif
 }
 
+# define find_shared_library_fullname find_shared_library_fullname
+
 #endif /* Native Windows / EMX / Unix */
 
 /* Return the full pathname of the current shared library.
    Return NULL if unknown.
-   Guaranteed to work only on Linux, EMX, Cygwin, native Windows, and
-   systems with dladdr in libc.  */
+   Guaranteed to work only on
+     glibc >= 2.34, Linux, macOS, FreeBSD, NetBSD, OpenBSD, Solaris, Cygwin,
+     Minix, native Windows, EMX. */
 static char *
 get_shared_library_fullname ()
 {
-#if !_GL_USE_WIN32
+#if defined find_shared_library_fullname
   static bool tried_find_shared_library_fullname;
   if (!tried_find_shared_library_fullname)
     {
diff --git a/m4/libdl.m4 b/m4/libdl.m4
index 839b053af5..6c87f727bc 100644
--- a/m4/libdl.m4
+++ b/m4/libdl.m4
@@ -1,5 +1,5 @@
 # libdl.m4
-# serial 2
+# serial 3
 dnl Copyright (C) 2024-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -15,7 +15,7 @@ AC_DEFUN([gl_LIBDL]
   dnl dlopen, dlsym are
   dnl - in libc on glibc >= 2.34, musl libc, macOS, FreeBSD, NetBSD, OpenBSD,
   dnl   AIX, Solaris, Cygwin, Haiku,
-  dnl - in a separate libdl on glibc < 2.34, Android, uClibc.
+  dnl - in a separate libdl on glibc < 2.34, uClibc, Android.
   AC_CACHE_CHECK([for library needed for dlopen and dlsym],
     [gl_cv_lib_dl],
     [AC_LINK_IFELSE(
diff --git a/m4/relocatable-lib.m4 b/m4/relocatable-lib.m4
index 5efed5218d..222fb68494 100644
--- a/m4/relocatable-lib.m4
+++ b/m4/relocatable-lib.m4
@@ -1,5 +1,5 @@
 # relocatable-lib.m4
-# serial 8
+# serial 9
 dnl Copyright (C) 2003, 2005-2007, 2009-2025 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -31,6 +31,14 @@ AC_DEFUN([gl_RELOCATABLE_LIBRARY_BODY]
       [Define to 1 if the package shall run at any location in the file
        system.])
   fi
+  dnl Determine whether dladdr() exists in libc.
+  gl_LIBDL
+  if test -z "$LIBDL"; then
+    AC_CHECK_FUNC([dladdr],
+      [AC_DEFINE([HAVE_DLADDR_IN_LIBC], [1],
+         [Define to 1 if dladdr exists and is defined in libc.])
+      ])
+  fi
 ])
 
 dnl Support for relocatable packages for which it is a nop.
diff --git a/modules/relocatable-lib b/modules/relocatable-lib
index d2f513861b..64be8dbf49 100644
--- a/modules/relocatable-lib
+++ b/modules/relocatable-lib
@@ -7,8 +7,8 @@ doc/relocatable.texi
 lib/relocatable.h
 lib/relocatable.c
 lib/relocatable.valgrind
-m4/libdl.m4
 m4/relocatable-lib.m4
+m4/libdl.m4
 m4/build-to-host.m4
 
 Depends-on:
@@ -20,10 +20,6 @@ gl_RELOCATABLE_LIBRARY
 if test $RELOCATABLE = yes; then
   AC_LIBOBJ([relocatable])
 fi
-gl_LIBDL
-if test -z "$LIBDL"; then
-  AC_DEFINE([_GL_DLADDR_IN_LIBC], [1], [Define to 1 if dladdr is in libc.])
-fi
 
 Makefile.am:
 
diff --git a/modules/relocatable-lib-lgpl b/modules/relocatable-lib-lgpl
index 4fe84cea85..c0cdafade2 100644
--- a/modules/relocatable-lib-lgpl
+++ b/modules/relocatable-lib-lgpl
@@ -8,6 +8,7 @@ lib/relocatable.h
 lib/relocatable.c
 lib/relocatable.valgrind
 m4/relocatable-lib.m4
+m4/libdl.m4
 m4/build-to-host.m4
 
 Depends-on:
@@ -18,10 +19,6 @@ gl_RELOCATABLE_LIBRARY
 if test $RELOCATABLE = yes; then
   AC_LIBOBJ([relocatable])
 fi
-gl_LIBDL
-if test -z "$LIBDL"; then
-  AC_DEFINE([_GL_DLADDR_IN_LIBC], [1], [Define to 1 if dladdr is in libc.])
-fi
 
 Makefile.am:
 DEFS += -DNO_XMALLOC
-- 
2.52.0

Reply via email to