[PATCH] ntdll: Improve portability of call_constructor (and port to FreeBSD)

Gerald Pfeifer gerald at pfeifer.com
Sun Apr 19 03:43:44 CDT 2020


The new function call_constructors in dlls/ntdll/loader.c introduced via

    081c8e1c73bb8d79a060da7816b5c429180b35b7
    Author: Alexandre Julliard <julliard at winehq.org>
    Date:   Thu Apr 16 12:22:24 2020 +0200

    ntdll: Execute .so constructors during module initialization.

breaks the build on FreeBSD and presumably others.  Specifically,

    struct link_map *map;
    :
    if (dlinfo( wm->so_handle, RTLD_DI_LINKMAP, &map ) == -1) return;
    while (map->l_ld->d_tag)
      :

fails to compile:

    loader.c: In function ‘call_constructors’:
    loader.c:1329:21: warning: dereferencing ‘void *’ pointer
     1329 |     while (map->l_ld->d_tag)
          |                     ^~
    loader.c:1329:21: error: request for member ‘d_tag’ in something not a 
                             structure or union

This is due to /usr/include/link.h (via /usr/include/sys/link_elf.h) 
defining link_map.l_ld as a void* as opposed to a more specific type 
like on Linux:

    typedef struct link_map {
        caddr_t         l_addr;           /* Base Address of library */
    #ifdef __mips__
        caddr_t         l_offs;           /* Load Offset of library */
    #endif
        const char      *l_name;          /* Absolute Path to Library */
        const void      *l_ld;            /* Pointer to .dynamic in memory */
        struct link_map *l_next, *l_prev; /* linked list of of mapped libs */
    } Link_map;

Luckily FreeBSD does feature Elf64_Dyn and Elf32_Dyn which do match their
Linux equivalents, so introducing a new variable holding a pointer to one
of those and using implicit type conversions with void* addresses this.

If further platforms require similar adjustments, this should now be a 
question of extending one condition or adding two lines.

Gerald


Signed-off-by: Gerald Pfeifer <gerald at pfeifer.com>
---
 dlls/ntdll/loader.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index c713a5d0a6..e9140145e1 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -1324,17 +1324,25 @@ static void call_constructors( WINE_MODREF *wm )
     void (*init_func)(int, char **, char **) = NULL;
     void (**init_array)(int, char **, char **) = NULL;
     ULONG_PTR i, init_arraysz = 0;
+#if defined (__FreeBSD__) && defined (__LP64__)
+    const Elf64_Dyn *l_ld;
+#elif defined (__FreeBSD__)
+    const Elf32_Dyn *l_ld;
+#else
+    const ElfW(Dyn) *l_ld;
+#endif
 
     if (dlinfo( wm->so_handle, RTLD_DI_LINKMAP, &map ) == -1) return;
-    while (map->l_ld->d_tag)
+    l_ld = map->l_ld;
+    while (l_ld->d_tag)
     {
-        switch (map->l_ld->d_tag)
+        switch (l_ld->d_tag)
         {
-        case 0x60009990: init_array = (void *)((char *)map->l_addr + map->l_ld->d_un.d_val); break;
-        case 0x60009991: init_arraysz = map->l_ld->d_un.d_val; break;
-        case 0x60009992: init_func = (void *)((char *)map->l_addr + map->l_ld->d_un.d_val); break;
+        case 0x60009990: init_array = (void *)((char *)map->l_addr + l_ld->d_un.d_val); break;
+        case 0x60009991: init_arraysz = l_ld->d_un.d_val; break;
+        case 0x60009992: init_func = (void *)((char *)map->l_addr + l_ld->d_un.d_val); break;
         }
-        map->l_ld++;
+        l_ld++;
     }
 
     TRACE( "%s: got init_func %p init_array %p %lu\n", debugstr_us( &wm->ldr.BaseDllName ),
-- 
2.25.0


More information about the wine-devel mailing list