[PATCH] ntdll: get struct link_map fully working on all FreeBSD versions

Damjan Jovanovic damjan.jov at gmail.com
Sun Nov 15 01:52:13 CST 2020


autoheader and autoconf need to be run.

Signed-off-by: Damjan Jovanovic <damjan.jov at gmail.com>
---
 configure.ac             |  3 +++
 dlls/ntdll/unix/loader.c | 25 +++++++++++++++++++++++--
 2 files changed, 26 insertions(+), 2 deletions(-)
-------------- next part --------------
diff --git a/configure.ac b/configure.ac
index 666219f5f36..455dc07b0e3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2219,6 +2219,9 @@ CFLAGS="$ac_save_CFLAGS"
 dnl Check for -ldl
 AC_SEARCH_LIBS(dlopen, dl)
 WINE_CHECK_LIB_FUNCS(dladdr dlinfo,[$DL_LIBS])
+AC_CHECK_MEMBERS([struct link_map.l_base],,,
+[#include <elf.h>
+#include <link.h>])
 
 dnl Check for -lpoll for Mac OS X/Darwin
 if test "$ac_cv_func_poll" = no
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index c2b6ea603e3..43ddc6f166b 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -1412,9 +1412,30 @@ found:
         caddr_t relocbase = (caddr_t)map->l_addr;
 
 #ifdef __FreeBSD__
-        /* On older FreeBSD versions, l_addr was the absolute load address, now it's the relocation offset. */
+        /* l_addr changed meaning from absolute load address (which is now l_base)
+         * to relocation offset, but also got moved within the struct, breaking
+         * the ABI via struct layout change:
+         *
+         *  OLD header:                  NEW header:
+         *  typedef struct link_map {    typedef struct link_map {
+         *      caddr_t l_addr;              caddr_t l_base;
+         *      ...                          ...
+         *      ...                          caddr_t l_addr;
+         *  };                           };
+         *
+         *  OLD ld-elf.so:               NEW ld-elf.so:
+         *  ...                          exports _rtld_version_laddr_offset
+         *
+         * Since the header change and rtld change aren't coupled, we have to
+         * worry about the interaction between link.h version at compile time,
+         * and ld-elf.so version at runtime...
+         */
+#ifdef HAVE_STRUCT_LINK_MAP_L_BASE
         if (!dlsym(RTLD_DEFAULT, "_rtld_version_laddr_offset"))
-            if (!get_relocbase(map->l_addr, &relocbase)) return;
+            if (!get_relocbase(map->l_base, &relocbase)) return;
+#else
+        if (!get_relocbase(map->l_addr, &relocbase)) return;
+#endif
 #endif
         switch (dyn->d_tag)
         {


More information about the wine-devel mailing list