Alexandre Julliard : ntdll: Set up virtual memory layout in the Unix library.

Alexandre Julliard julliard at winehq.org
Thu May 14 16:17:45 CDT 2020


Module: wine
Branch: master
Commit: 7e6a67d8c9f6931ee6b034bcc7db0adc6ba2ab0b
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=7e6a67d8c9f6931ee6b034bcc7db0adc6ba2ab0b

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Thu May 14 15:33:36 2020 +0200

ntdll: Set up virtual memory layout in the Unix library.

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/Makefile.in         |   1 +
 dlls/ntdll/unix/loader.c       |   3 +-
 dlls/ntdll/unix/unix_private.h |  28 ++++++
 dlls/ntdll/unix/virtual.c      | 213 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 244 insertions(+), 1 deletion(-)

diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index 813d9a43e2..699c97a1ce 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -52,6 +52,7 @@ C_SRCS = \
 	threadpool.c \
 	time.c \
 	unix/loader.c \
+	unix/virtual.c \
 	version.c \
 	virtual.c \
 	wcstring.c
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index 4008c0a55d..257e74ffca 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -49,7 +49,7 @@
 #include "windef.h"
 #include "winnt.h"
 #include "winternl.h"
-#include "unixlib.h"
+#include "unix_private.h"
 #include "wine/library.h"
 
 extern IMAGE_NT_HEADERS __wine_spec_nt_header;
@@ -514,6 +514,7 @@ void __wine_main( int argc, char *argv[], char *envp[] )
     __wine_main_argc = argc;
     __wine_main_argv = argv;
     __wine_main_environ = envp;
+    virtual_init();
 
     module = load_ntdll();
     fixup_ntdll_imports( &__wine_spec_nt_header, module );
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
new file mode 100644
index 0000000000..071db90218
--- /dev/null
+++ b/dlls/ntdll/unix/unix_private.h
@@ -0,0 +1,28 @@
+/*
+ * Ntdll Unix private interface
+ *
+ * Copyright (C) 2020 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __NTDLL_UNIX_PRIVATE_H
+#define __NTDLL_UNIX_PRIVATE_H
+
+#include "unixlib.h"
+
+extern void virtual_init(void) DECLSPEC_HIDDEN;
+
+#endif /* __NTDLL_UNIX_PRIVATE_H */
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
new file mode 100644
index 0000000000..21201c298c
--- /dev/null
+++ b/dlls/ntdll/unix/virtual.c
@@ -0,0 +1,213 @@
+/*
+ * Unix interface for virtual memory functions
+ *
+ * Copyright (C) 2020 Alexandre Julliard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#if 0
+#pragma makedep unix
+#endif
+
+#include "config.h"
+#include "wine/port.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
+#if defined(__APPLE__)
+# include <mach/mach_init.h>
+# include <mach/mach_vm.h>
+#endif
+
+#include <stdio.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#include "windef.h"
+#include "winnt.h"
+#include "winternl.h"
+#include "unixlib.h"
+#include "wine/library.h"
+
+struct preload_info
+{
+    void  *addr;
+    size_t size;
+};
+
+static const unsigned int granularity_mask = 0xffff;  /* reserved areas have 64k granularity */
+
+extern IMAGE_NT_HEADERS __wine_spec_nt_header;
+
+#ifndef MAP_NORESERVE
+#define MAP_NORESERVE 0
+#endif
+#ifndef MAP_TRYFIXED
+#define MAP_TRYFIXED 0
+#endif
+
+
+static void reserve_area( void *addr, void *end )
+{
+#ifdef __APPLE__
+
+#ifdef __i386__
+    static const mach_vm_address_t max_address = VM_MAX_ADDRESS;
+#else
+    static const mach_vm_address_t max_address = MACH_VM_MAX_ADDRESS;
+#endif
+    mach_vm_address_t address = (mach_vm_address_t)addr;
+    mach_vm_address_t end_address = (mach_vm_address_t)end;
+
+    if (!end_address || max_address < end_address)
+        end_address = max_address;
+
+    while (address < end_address)
+    {
+        mach_vm_address_t hole_address = address;
+        kern_return_t ret;
+        mach_vm_size_t size;
+        vm_region_basic_info_data_64_t info;
+        mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
+        mach_port_t dummy_object_name = MACH_PORT_NULL;
+
+        /* find the mapped region at or above the current address. */
+        ret = mach_vm_region(mach_task_self(), &address, &size, VM_REGION_BASIC_INFO_64,
+                             (vm_region_info_t)&info, &count, &dummy_object_name);
+        if (ret != KERN_SUCCESS)
+        {
+            address = max_address;
+            size = 0;
+        }
+
+        if (end_address < address)
+            address = end_address;
+        if (hole_address < address)
+        {
+            /* found a hole, attempt to reserve it. */
+            size_t hole_size = address - hole_address;
+            mach_vm_address_t alloc_address = hole_address;
+
+            ret = mach_vm_map( mach_task_self(), &alloc_address, hole_size, 0, VM_FLAGS_FIXED,
+                               MEMORY_OBJECT_NULL, 0, 0, PROT_NONE, VM_PROT_ALL, VM_INHERIT_COPY );
+            if (!ret) wine_mmap_add_reserved_area( (void*)hole_address, hole_size );
+            else if (ret == KERN_NO_SPACE)
+            {
+                /* something filled (part of) the hole before we could.
+                   go back and look again. */
+                address = hole_address;
+                continue;
+            }
+        }
+        address += size;
+    }
+#else
+    void *ptr;
+    int flags = MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | MAP_TRYFIXED;
+    size_t size = (char *)end - (char *)addr;
+
+    if (!size) return;
+
+    ptr = mmap( addr, size, PROT_NONE, flags, -1, 0 );
+    if (ptr == addr)
+    {
+        wine_mmap_add_reserved_area( addr, size );
+        return;
+    }
+    if (ptr != (void *)-1) munmap( ptr, size );
+
+    size = (size / 2) & ~granularity_mask;
+    if (size)
+    {
+        reserve_area( addr, (char *)addr + size );
+        reserve_area( (char *)addr + size, end );
+    }
+#endif /* __APPLE__ */
+}
+
+
+static void mmap_init( const struct preload_info *preload_info )
+{
+#ifdef __i386__
+#ifndef __APPLE__
+    char stack;
+    char * const stack_ptr = &stack;
+#endif
+    char *user_space_limit = (char *)0x7ffe0000;
+    int i;
+
+    if (preload_info)
+    {
+        /* check for a reserved area starting at the user space limit */
+        /* to avoid wasting time trying to allocate it again */
+        for (i = 0; preload_info[i].size; i++)
+        {
+            if ((char *)preload_info[i].addr > user_space_limit) break;
+            if ((char *)preload_info[i].addr + preload_info[i].size > user_space_limit)
+            {
+                user_space_limit = (char *)preload_info[i].addr + preload_info[i].size;
+                break;
+            }
+        }
+    }
+    else reserve_area( (void *)0x00010000, (void *)0x40000000 );
+
+
+#ifndef __APPLE__
+    if (stack_ptr >= user_space_limit)
+    {
+        char *end = 0;
+        char *base = stack_ptr - ((unsigned int)stack_ptr & granularity_mask) - (granularity_mask + 1);
+        if (base > user_space_limit) reserve_area( user_space_limit, base );
+        base = stack_ptr - ((unsigned int)stack_ptr & granularity_mask) + (granularity_mask + 1);
+#if defined(linux) || defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__)
+        /* Heuristic: assume the stack is near the end of the address */
+        /* space, this avoids a lot of futile allocation attempts */
+        end = (char *)(((unsigned long)base + 0x0fffffff) & 0xf0000000);
+#endif
+        reserve_area( base, end );
+    }
+    else
+#endif
+        reserve_area( user_space_limit, 0 );
+
+#elif defined(__x86_64__) || defined(__aarch64__)
+
+    if (preload_info) return;
+    /* if we don't have a preloader, try to reserve the space now */
+    reserve_area( (void *)0x000000010000, (void *)0x000068000000 );
+    reserve_area( (void *)0x00007ff00000, (void *)0x00007fff0000 );
+    reserve_area( (void *)0x7ffffe000000, (void *)0x7fffffff0000 );
+
+#endif
+}
+
+void virtual_init(void)
+{
+    const struct preload_info **preload_info = dlsym( RTLD_DEFAULT, "wine_main_preload_info" );
+    int i;
+
+    if (preload_info && *preload_info)
+        for (i = 0; (*preload_info)[i].size; i++)
+            wine_mmap_add_reserved_area( (*preload_info)[i].addr, (*preload_info)[i].size );
+
+    mmap_init( preload_info ? *preload_info : NULL );
+}




More information about the wine-cvs mailing list