From: Brendan Shanks bshanks@codeweavers.com
Xcode 15.3 adds a new linker flag ('-no_huge') which allows the loader to use zero-fill sections to reserve the areas currently being reserved by the preloader.
This means the preloader is no longer needed (a good thing, since it's heavily dependent on private APIs).
The preloader will still be used when Xcode <15.3 is being used, or when building for i386 (32-bit for 10.14 and earlier). --- configure.ac | 11 +++++++++-- loader/main.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac index 1ed6bf059ea..ccd0932a37e 100644 --- a/configure.ac +++ b/configure.ac @@ -640,8 +640,15 @@ case $host_os in WINELOADER_LDFLAGS="-Wl,-segalign,0x1000,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,loader/wine_info.plist"
case $HOST_ARCH in - i386|x86_64) wine_use_preloader=yes ;; - *) wine_use_preloader=no ;; + i386) wine_use_preloader=yes ;; + x86_64) + dnl If the -no_huge linker option is present (added in Xcode 15.3), use zerofill sections instead of the preloader + WINE_TRY_CFLAGS([-Wl,-no_huge], + [wine_use_preloader=no + WINELOADER_LDFLAGS="$WINELOADER_LDFLAGS -Wl,-no_pie,-image_base,0x200000000,-no_huge,-no_fixup_chains,-segalign,0x1000,-segaddr,WINE_RESERVE,0x1000,-segaddr,WINE_TOP_DOWN,0x7ff000000000"], + [wine_use_preloader=yes]) + ;; + *) wine_use_preloader=no ;; esac
if test "$wine_use_preloader" = "yes" diff --git a/loader/main.c b/loader/main.c index c258e025183..8778916623f 100644 --- a/loader/main.c +++ b/loader/main.c @@ -25,6 +25,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> @@ -38,9 +39,51 @@
extern char **environ;
+#if defined(__APPLE__) && defined(__x86_64__) && !defined(USE_PRELOADER) + +/* Not using the preloader on x86_64: + * Reserve the same areas as the preloader does, but using zero-fill sections + * (the only way to prevent system frameworks from using them, including allocations + * before main() runs). + */ +__asm__(".zerofill WINE_RESERVE,WINE_RESERVE"); +static char __wine_reserve[0x1fffff000] __attribute__((section("WINE_RESERVE, WINE_RESERVE"))); + +__asm__(".zerofill WINE_TOP_DOWN,WINE_TOP_DOWN"); +static char __wine_top_down[0x001ff0000] __attribute__((section("WINE_TOP_DOWN, WINE_TOP_DOWN"))); + +static const struct wine_preload_info preload_info[] = +{ + { __wine_reserve, sizeof(__wine_reserve) }, /* 0x1000 - 0x200000000: low 8GB */ + { __wine_top_down, sizeof(__wine_top_down) }, /* 0x7ff000000000 - 0x7ff001ff0000: top-down allocations + virtual heap */ + { 0, 0 } /* end of list */ +}; + +const __attribute((visibility("default"))) struct wine_preload_info *wine_main_preload_info = preload_info; + +static void init_reserved_areas(void) +{ + int i; + + for (i = 0; wine_main_preload_info[i].size != 0; i++) + { + /* Match how the preloader maps reserved areas: */ + mmap(wine_main_preload_info[i].addr, wine_main_preload_info[i].size, PROT_NONE, + MAP_FIXED | MAP_NORESERVE | MAP_PRIVATE | MAP_ANON, -1, 0); + } +} + +#else + /* the preloader will set this variable */ const __attribute((visibility("default"))) struct wine_preload_info *wine_main_preload_info = NULL;
+static void init_reserved_areas(void) +{ +} + +#endif + /* canonicalize path and return its directory name */ static char *realpath_dirname( const char *name ) { @@ -177,6 +220,8 @@ int main( int argc, char *argv[] ) { void *handle;
+ init_reserved_areas(); + if ((handle = load_ntdll( argv[0] ))) { void (*init_func)(int, char **, char **) = dlsym( handle, "__wine_main" );