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).
This commit is contained in:
Brendan Shanks 2024-04-11 12:24:55 -07:00 committed by Alexandre Julliard
parent 5da03c7a60
commit 7b82f507bd
3 changed files with 89 additions and 4 deletions

37
configure vendored
View file

@ -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"

View file

@ -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"

View file

@ -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" );