Module: wine Branch: master Commit: 7e6a67d8c9f6931ee6b034bcc7db0adc6ba2ab0b URL: https://source.winehq.org/git/wine.git/?a=commit;h=7e6a67d8c9f6931ee6b034bcc...
Author: Alexandre Julliard julliard@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@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 ); +}