Module: wine Branch: master Commit: 7b82f507bda6b94f6876256c278d3b3637e95b8c URL: https://gitlab.winehq.org/wine/wine/-/commit/7b82f507bda6b94f6876256c278d3b3...
Author: Brendan Shanks bshanks@codeweavers.com Date: Thu Apr 11 12:24:55 2024 -0700
loader: Use zerofill sections instead of preloader on macOS when building with Xcode 15.3.
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 | 37 +++++++++++++++++++++++++++++++++++-- configure.ac | 11 +++++++++-- loader/main.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 4 deletions(-)
diff --git a/configure b/configure index d4101bf79d0..e77f0893dd8 100755 --- a/configure +++ b/configure @@ -9534,8 +9534,41 @@ fi 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) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-no_huge" >&5 +printf %s "checking whether the compiler supports -Wl,-no_huge... " >&6; } +if test ${ac_cv_cflags__Wl__no_huge+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_wine_try_cflags_saved=$CFLAGS +CFLAGS="$CFLAGS -Wl,-no_huge" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int main(int argc, char **argv) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_cflags__Wl__no_huge=yes +else $as_nop + ac_cv_cflags__Wl__no_huge=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +CFLAGS=$ac_wine_try_cflags_saved +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl__no_huge" >&5 +printf "%s\n" "$ac_cv_cflags__Wl__no_huge" >&6; } +if test "x$ac_cv_cflags__Wl__no_huge" = xyes +then : + 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" +else $as_nop + wine_use_preloader=yes +fi + ;; + *) wine_use_preloader=no ;; esac
if test "$wine_use_preloader" = "yes" diff --git a/configure.ac b/configure.ac index c73562ba58c..e828083fc91 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..b241dbb454d 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(HAVE_WINE_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" );