Commit cfa0dd9d authored by Brendan Shanks's avatar Brendan Shanks Committed by Alexandre Julliard

loader: On 64-bit macOS, reserve the low 8GB using a zerofill section.

A zerofill section is the only way to reserve address space and prevent system frameworks from using it, including preventing allocations before any preloader code runs: - starting with Ventura, dyld allocates private memory from 0x1000-0x81000. This breaks EXEs that have an image base of 0x10000. - Rosetta allocates memory starting at 0x100000000, which breaks EXEs based there. - starting with Monterey, for proper 10.7 binaries (which include a __program_vars section), libSystem initializes itself before the preloader runs. This fragments the <4GB address space which is needed for Wow64. This will need to be adjusted if any EXEs based at 0x200000000 or higher are found.
parent 09205438
...@@ -9487,7 +9487,7 @@ fi ;; ...@@ -9487,7 +9487,7 @@ fi ;;
if test "$wine_can_build_preloader" = "yes" if test "$wine_can_build_preloader" = "yes"
then then
WINEPRELOADER_LDFLAGS="-nostartfiles -nodefaultlibs -e _start -ldylib1.o -mmacosx-version-min=10.7 -Wl,-no_new_main,-image_base,0x7d400000,-segalign,0x1000,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,loader/wine_info.plist" WINEPRELOADER_LDFLAGS="-nostartfiles -nodefaultlibs -e _start -ldylib1.o -mmacosx-version-min=10.7 -Wl,-no_new_main,-segalign,0x1000,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,loader/wine_info.plist"
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-no_pie" >&5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-no_pie" >&5
printf %s "checking whether the compiler supports -Wl,-no_pie... " >&6; } printf %s "checking whether the compiler supports -Wl,-no_pie... " >&6; }
if test ${ac_cv_cflags__Wl__no_pie+y} if test ${ac_cv_cflags__Wl__no_pie+y}
...@@ -9518,9 +9518,10 @@ then : ...@@ -9518,9 +9518,10 @@ then :
fi fi
case $host_cpu in case $host_cpu in
*i[3456]86*) *i[3456]86*)
WINEPRELOADER_LDFLAGS="-Wl,-image_base,0x7d400000 $WINEPRELOADER_LDFLAGS"
;; ;;
*x86_64*) *x86_64*)
WINEPRELOADER_LDFLAGS="-Wl,-segalign,0x1000,-segaddr,WINE_4GB_RESERVE,0x100000000 $WINEPRELOADER_LDFLAGS" WINEPRELOADER_LDFLAGS="-Wl,-image_base,0x200000000,-segalign,0x1000,-segaddr,WINE_RESERVE,0x1000 $WINEPRELOADER_LDFLAGS"
;; ;;
esac esac
WINELOADER_LDFLAGS="$WINELOADER_LDFLAGS -mmacosx-version-min=10.7" WINELOADER_LDFLAGS="$WINELOADER_LDFLAGS -mmacosx-version-min=10.7"
......
...@@ -685,14 +685,15 @@ case $host_os in ...@@ -685,14 +685,15 @@ case $host_os in
if test "$wine_can_build_preloader" = "yes" if test "$wine_can_build_preloader" = "yes"
then then
WINEPRELOADER_LDFLAGS="-nostartfiles -nodefaultlibs -e _start -ldylib1.o -mmacosx-version-min=10.7 -Wl,-no_new_main,-image_base,0x7d400000,-segalign,0x1000,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,loader/wine_info.plist" WINEPRELOADER_LDFLAGS="-nostartfiles -nodefaultlibs -e _start -ldylib1.o -mmacosx-version-min=10.7 -Wl,-no_new_main,-segalign,0x1000,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,loader/wine_info.plist"
WINE_TRY_CFLAGS([-Wl,-no_pie], WINE_TRY_CFLAGS([-Wl,-no_pie],
[WINEPRELOADER_LDFLAGS="-Wl,-no_pie $WINEPRELOADER_LDFLAGS"]) [WINEPRELOADER_LDFLAGS="-Wl,-no_pie $WINEPRELOADER_LDFLAGS"])
case $host_cpu in case $host_cpu in
*i[[3456]]86*) *i[[3456]]86*)
WINEPRELOADER_LDFLAGS="-Wl,-image_base,0x7d400000 $WINEPRELOADER_LDFLAGS"
;; ;;
*x86_64*) *x86_64*)
WINEPRELOADER_LDFLAGS="-Wl,-segalign,0x1000,-segaddr,WINE_4GB_RESERVE,0x100000000 $WINEPRELOADER_LDFLAGS" WINEPRELOADER_LDFLAGS="-Wl,-image_base,0x200000000,-segalign,0x1000,-segaddr,WINE_RESERVE,0x1000 $WINEPRELOADER_LDFLAGS"
;; ;;
esac esac
dnl If preloader is used, the loader needs to be an LC_UNIXTHREAD binary to avoid AppKit/Core Animation problems. dnl If preloader is used, the loader needs to be an LC_UNIXTHREAD binary to avoid AppKit/Core Animation problems.
......
...@@ -49,18 +49,15 @@ ...@@ -49,18 +49,15 @@
#include "main.h" #include "main.h"
#if defined(__x86_64__) #if defined(__x86_64__)
/* Rosetta on Apple Silicon allocates memory starting at 0x100000000 (the 4GB line) /* Reserve the low 8GB using a zero-fill section, this is the only way to
* before the preloader runs, which prevents any nonrelocatable EXEs with that * prevent system frameworks from using any of it (including allocations
* base address from running. * before any preloader code runs)
*
* This empty linker section forces Rosetta's allocations (currently ~132 MB)
* to start at 0x114000000, and they should end below 0x120000000.
*/ */
__asm__(".zerofill WINE_4GB_RESERVE,WINE_4GB_RESERVE,___wine_4gb_reserve,0x14000000"); __asm__(".zerofill WINE_RESERVE,WINE_RESERVE,___wine_reserve,0x1fffff000");
static const struct wine_preload_info zerofill_sections[] = static const struct wine_preload_info zerofill_sections[] =
{ {
{ (void *)0x000100000000, 0x14000000 }, /* WINE_4GB_RESERVE section */ { (void *)0x000000001000, 0x1fffff000 }, /* WINE_RESERVE section */
{ 0, 0 } /* end of list */ { 0, 0 } /* end of list */
}; };
#else #else
...@@ -92,10 +89,7 @@ static struct wine_preload_info preload_info[] = ...@@ -92,10 +89,7 @@ static struct wine_preload_info preload_info[] =
{ (void *)0x00110000, 0x67ef0000 }, /* low memory area */ { (void *)0x00110000, 0x67ef0000 }, /* low memory area */
{ (void *)0x7f000000, 0x03000000 }, /* top-down allocations + shared user data + virtual heap */ { (void *)0x7f000000, 0x03000000 }, /* top-down allocations + shared user data + virtual heap */
#else /* __i386__ */ #else /* __i386__ */
{ (void *)0x000000010000, 0x00100000 }, /* DOS area */ { (void *)0x000000001000, 0x1fffff000 }, /* WINE_RESERVE section */
{ (void *)0x000000110000, 0x67ef0000 }, /* low memory area */
{ (void *)0x00007f000000, 0x00ff0000 }, /* 32-bit top-down allocations + shared user data */
{ (void *)0x000100000000, 0x14000000 }, /* WINE_4GB_RESERVE section */
{ (void *)0x7ff000000000, 0x01ff0000 }, /* top-down allocations + virtual heap */ { (void *)0x7ff000000000, 0x01ff0000 }, /* top-down allocations + virtual heap */
#endif /* __i386__ */ #endif /* __i386__ */
{ 0, 0 }, /* PE exe range set with WINEPRELOADRESERVE */ { 0, 0 }, /* PE exe range set with WINEPRELOADRESERVE */
...@@ -439,7 +433,7 @@ static int preloader_overlaps_range( const void *start, const void *end ) ...@@ -439,7 +433,7 @@ static int preloader_overlaps_range( const void *start, const void *end )
struct target_segment_command *seg = (struct target_segment_command*)cmd; struct target_segment_command *seg = (struct target_segment_command*)cmd;
const void *seg_start = (const void*)(seg->vmaddr + slide); const void *seg_start = (const void*)(seg->vmaddr + slide);
const void *seg_end = (const char*)seg_start + seg->vmsize; const void *seg_end = (const char*)seg_start + seg->vmsize;
static const char reserved_segname[] = "WINE_4GB_RESERVE"; static const char reserved_segname[] = "WINE_RESERVE";
if (!wld_strncmp( seg->segname, reserved_segname, sizeof(reserved_segname)-1 )) if (!wld_strncmp( seg->segname, reserved_segname, sizeof(reserved_segname)-1 ))
continue; continue;
...@@ -653,7 +647,9 @@ static void set_program_vars( void *stack, void *mod ) ...@@ -653,7 +647,9 @@ static void set_program_vars( void *stack, void *mod )
void *wld_start( void *stack, int *is_unix_thread ) void *wld_start( void *stack, int *is_unix_thread )
{ {
#ifdef __i386__
struct wine_preload_info builtin_dlls = { (void *)0x7a000000, 0x02000000 }; struct wine_preload_info builtin_dlls = { (void *)0x7a000000, 0x02000000 };
#endif
struct wine_preload_info **wine_main_preload_info; struct wine_preload_info **wine_main_preload_info;
char **argv, **p, *reserve = NULL; char **argv, **p, *reserve = NULL;
struct target_mach_header *mh; struct target_mach_header *mh;
...@@ -692,15 +688,19 @@ void *wld_start( void *stack, int *is_unix_thread ) ...@@ -692,15 +688,19 @@ void *wld_start( void *stack, int *is_unix_thread )
} }
} }
#ifdef __i386__
if (!map_region( &builtin_dlls )) if (!map_region( &builtin_dlls ))
builtin_dlls.size = 0; builtin_dlls.size = 0;
#endif
/* load the main binary */ /* load the main binary */
if (!(mod = pdlopen( argv[1], RTLD_NOW ))) if (!(mod = pdlopen( argv[1], RTLD_NOW )))
fatal_error( "%s: could not load binary\n", argv[1] ); fatal_error( "%s: could not load binary\n", argv[1] );
#ifdef __i386__
if (builtin_dlls.size) if (builtin_dlls.size)
wld_munmap( builtin_dlls.addr, builtin_dlls.size ); wld_munmap( builtin_dlls.addr, builtin_dlls.size );
#endif
/* store pointer to the preload info into the appropriate main binary variable */ /* store pointer to the preload info into the appropriate main binary variable */
wine_main_preload_info = pdlsym( mod, "wine_main_preload_info" ); wine_main_preload_info = pdlsym( mod, "wine_main_preload_info" );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment