Brendan Shanks : loader: On Mac, reserve an area starting at 4GB to force Rosetta's allocations higher.

Alexandre Julliard julliard at winehq.org
Mon Jun 7 15:02:07 CDT 2021


Module: wine
Branch: stable
Commit: f1a7cae5cb46a84e2b57ffdd0b7096f5a7ba26dd
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=f1a7cae5cb46a84e2b57ffdd0b7096f5a7ba26dd

Author: Brendan Shanks <bshanks at codeweavers.com>
Date:   Thu Jan 28 14:52:46 2021 -0800

loader: On Mac, reserve an area starting at 4GB to force Rosetta's allocations higher.

On Apple Silicon, Rosetta allocates memory starting at 0x100000000
(the 4GB line) before the preloader runs.
The .NET 3.5 installer and DirectX Jun2010 redistributable both contain
non-relocatable EXEs with that base address, which fail to run.

The workaround is to create an empty linker section at that address,
which is mapped by the kernel before Rosetta runs and forces Rosetta's
allocations higher in memory.
The linker section runs from 0x100000000-0x114000000.
Rosetta's allocations are ~132MB, and should end below 0x120000000.

This is not an exact science: a non-relocatable EXE with base address
between 0x114000000-0x120000000 will fail to run. If one is discovered,
the section size will need to be changed.

Signed-off-by: Brendan Shanks <bshanks at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
(cherry picked from commit 307f5d00f17d71fe0030acb6ba9f28c3c9d76615)
Signed-off-by: Michael Stefaniuc <mstefani at winehq.org>

---

 configure              |  2 +-
 configure.ac           |  2 +-
 loader/preloader_mac.c | 16 ++++++++++++++++
 3 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/configure b/configure
index 6a0f0ad92c2..53556675b21 100755
--- a/configure
+++ b/configure
@@ -8722,7 +8722,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
     WINELOADER_LDFLAGS="-Wl,-pie,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,loader/wine_info.plist"
 
     wine_can_build_preloader=yes
-    WINEPRELOADER_LDFLAGS="-nostartfiles -nodefaultlibs -e _start -ldylib1.o -Wl,-image_base,0x7d400000,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,loader/wine_info.plist"
+    WINEPRELOADER_LDFLAGS="-nostartfiles -nodefaultlibs -e _start -ldylib1.o -Wl,-image_base,0x7d400000,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,loader/wine_info.plist,-segaddr,WINE_4GB_RESERVE,0x100000000"
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-no_new_main -e _main" >&5
 $as_echo_n "checking whether the compiler supports -Wl,-no_new_main -e _main... " >&6; }
 if ${ac_cv_cflags__Wl__no_new_main__e__main+:} false; then :
diff --git a/configure.ac b/configure.ac
index 2c4bd667e8f..6eedc151e83 100644
--- a/configure.ac
+++ b/configure.ac
@@ -745,7 +745,7 @@ case $host_os in
     WINELOADER_LDFLAGS="-Wl,-pie,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,loader/wine_info.plist"
 
     wine_can_build_preloader=yes
-    WINEPRELOADER_LDFLAGS="-nostartfiles -nodefaultlibs -e _start -ldylib1.o -Wl,-image_base,0x7d400000,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,loader/wine_info.plist"
+    WINEPRELOADER_LDFLAGS="-nostartfiles -nodefaultlibs -e _start -ldylib1.o -Wl,-image_base,0x7d400000,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,loader/wine_info.plist,-segaddr,WINE_4GB_RESERVE,0x100000000"
     WINE_TRY_CFLAGS([-Wl,-no_new_main -e _main],
                     [WINEPRELOADER_LDFLAGS="-Wl,-no_new_main $WINEPRELOADER_LDFLAGS"
                      WINE_TRY_CFLAGS([-Wl,-no_new_main -e _main -nostartfiles -nodefaultlibs],,
diff --git a/loader/preloader_mac.c b/loader/preloader_mac.c
index d86675538bb..fc07b7da0ed 100644
--- a/loader/preloader_mac.c
+++ b/loader/preloader_mac.c
@@ -54,6 +54,17 @@
 #include "wine/asm.h"
 #include "main.h"
 
+/* Rosetta on Apple Silicon allocates memory starting at 0x100000000 (the 4GB line)
+ * before the preloader runs, which prevents any nonrelocatable EXEs with that
+ * base address from running.
+ *
+ * This empty linker section forces Rosetta's allocations (currently ~132 MB)
+ * to start at 0x114000000, and they should end below 0x120000000.
+ */
+#if defined(__x86_64__)
+__asm__(".zerofill WINE_4GB_RESERVE,WINE_4GB_RESERVE,___wine_4gb_reserve,0x14000000");
+#endif
+
 #ifndef LC_MAIN
 #define LC_MAIN 0x80000028
 struct entry_point_command
@@ -79,6 +90,7 @@ static struct wine_preload_info preload_info[] =
     { (void *)0x000000010000, 0x00100000 },  /* DOS area */
     { (void *)0x000000110000, 0x67ef0000 },  /* low memory area */
     { (void *)0x00007ff00000, 0x000f0000 },  /* shared user data */
+    { (void *)0x000100000000, 0x14000000 },  /* WINE_4GB_RESERVE section */
     { (void *)0x7ffd00000000, 0x01ff0000 },  /* top-down allocations + virtual heap */
 #endif /* __i386__ */
     { 0, 0 },                            /* PE exe range set with WINEPRELOADRESERVE */
@@ -395,6 +407,10 @@ static int preloader_overlaps_range( const void *start, const void *end )
             struct target_segment_command *seg = (struct target_segment_command*)cmd;
             const void *seg_start = (const void*)(seg->vmaddr + slide);
             const void *seg_end = (const char*)seg_start + seg->vmsize;
+            static const char reserved_segname[] = "WINE_4GB_RESERVE";
+
+            if (!wld_strncmp( seg->segname, reserved_segname, sizeof(reserved_segname)-1 ))
+                continue;
 
             if (end > seg_start && start <= seg_end)
             {




More information about the wine-cvs mailing list