mirror of
https://gitlab.winehq.org/wine/wine.git
synced 2024-11-19 17:06:04 -07:00
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.
This commit is contained in:
parent
0920543876
commit
cfa0dd9dd9
Notes:
Alexandre Julliard
2023-07-19 01:59:56 +02:00
Approved-by: Alexandre Julliard (@julliard) Merge-Request: https://gitlab.winehq.org/wine/wine/-/merge_requests/3349
3 changed files with 19 additions and 17 deletions
5
configure
vendored
5
configure
vendored
|
@ -9487,7 +9487,7 @@ fi ;;
|
|||
|
||||
if test "$wine_can_build_preloader" = "yes"
|
||||
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 "checking whether the compiler supports -Wl,-no_pie... " >&6; }
|
||||
if test ${ac_cv_cflags__Wl__no_pie+y}
|
||||
|
@ -9518,9 +9518,10 @@ then :
|
|||
fi
|
||||
case $host_cpu in
|
||||
*i[3456]86*)
|
||||
WINEPRELOADER_LDFLAGS="-Wl,-image_base,0x7d400000 $WINEPRELOADER_LDFLAGS"
|
||||
;;
|
||||
*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
|
||||
WINELOADER_LDFLAGS="$WINELOADER_LDFLAGS -mmacosx-version-min=10.7"
|
||||
|
|
|
@ -685,14 +685,15 @@ case $host_os in
|
|||
|
||||
if test "$wine_can_build_preloader" = "yes"
|
||||
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],
|
||||
[WINEPRELOADER_LDFLAGS="-Wl,-no_pie $WINEPRELOADER_LDFLAGS"])
|
||||
case $host_cpu in
|
||||
*i[[3456]]86*)
|
||||
WINEPRELOADER_LDFLAGS="-Wl,-image_base,0x7d400000 $WINEPRELOADER_LDFLAGS"
|
||||
;;
|
||||
*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
|
||||
dnl If preloader is used, the loader needs to be an LC_UNIXTHREAD binary to avoid AppKit/Core Animation problems.
|
||||
|
|
|
@ -49,18 +49,15 @@
|
|||
#include "main.h"
|
||||
|
||||
#if defined(__x86_64__)
|
||||
/* 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.
|
||||
/* Reserve the low 8GB using a zero-fill section, this is the only way to
|
||||
* prevent system frameworks from using any of it (including allocations
|
||||
* before any preloader code runs)
|
||||
*/
|
||||
__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[] =
|
||||
{
|
||||
{ (void *)0x000100000000, 0x14000000 }, /* WINE_4GB_RESERVE section */
|
||||
{ (void *)0x000000001000, 0x1fffff000 }, /* WINE_RESERVE section */
|
||||
{ 0, 0 } /* end of list */
|
||||
};
|
||||
#else
|
||||
|
@ -92,10 +89,7 @@ static struct wine_preload_info preload_info[] =
|
|||
{ (void *)0x00110000, 0x67ef0000 }, /* low memory area */
|
||||
{ (void *)0x7f000000, 0x03000000 }, /* top-down allocations + shared user data + virtual heap */
|
||||
#else /* __i386__ */
|
||||
{ (void *)0x000000010000, 0x00100000 }, /* DOS area */
|
||||
{ (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 *)0x000000001000, 0x1fffff000 }, /* WINE_RESERVE section */
|
||||
{ (void *)0x7ff000000000, 0x01ff0000 }, /* top-down allocations + virtual heap */
|
||||
#endif /* __i386__ */
|
||||
{ 0, 0 }, /* PE exe range set with WINEPRELOADRESERVE */
|
||||
|
@ -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;
|
||||
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";
|
||||
static const char reserved_segname[] = "WINE_RESERVE";
|
||||
|
||||
if (!wld_strncmp( seg->segname, reserved_segname, sizeof(reserved_segname)-1 ))
|
||||
continue;
|
||||
|
@ -653,7 +647,9 @@ static void set_program_vars( void *stack, void *mod )
|
|||
|
||||
void *wld_start( void *stack, int *is_unix_thread )
|
||||
{
|
||||
#ifdef __i386__
|
||||
struct wine_preload_info builtin_dlls = { (void *)0x7a000000, 0x02000000 };
|
||||
#endif
|
||||
struct wine_preload_info **wine_main_preload_info;
|
||||
char **argv, **p, *reserve = NULL;
|
||||
struct target_mach_header *mh;
|
||||
|
@ -692,15 +688,19 @@ void *wld_start( void *stack, int *is_unix_thread )
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef __i386__
|
||||
if (!map_region( &builtin_dlls ))
|
||||
builtin_dlls.size = 0;
|
||||
#endif
|
||||
|
||||
/* load the main binary */
|
||||
if (!(mod = pdlopen( argv[1], RTLD_NOW )))
|
||||
fatal_error( "%s: could not load binary\n", argv[1] );
|
||||
|
||||
#ifdef __i386__
|
||||
if (builtin_dlls.size)
|
||||
wld_munmap( builtin_dlls.addr, builtin_dlls.size );
|
||||
#endif
|
||||
|
||||
/* store pointer to the preload info into the appropriate main binary variable */
|
||||
wine_main_preload_info = pdlsym( mod, "wine_main_preload_info" );
|
||||
|
|
Loading…
Reference in a new issue