Commit a0ab2a7b authored by Sebastian Lackner's avatar Sebastian Lackner Committed by Alexandre Julliard

loader: Implement preloader for macOS.

parent bd2d7952
......@@ -87,6 +87,7 @@ conf_manext = 5
WINELOADER_PROGRAMS = @WINELOADER_PROGRAMS@
WINELOADER_DEPENDS = @WINELOADER_DEPENDS@
WINELOADER_LDFLAGS = @WINELOADER_LDFLAGS@
WINEPRELOADER_LDFLAGS = @WINEPRELOADER_LDFLAGS@
LIBWINE_SHAREDLIB = @LIBWINE_SHAREDLIB@
LIBWINE_IMPORTLIB = @LIBWINE_IMPORTLIB@
LIBWINE_LDFLAGS = @LIBWINE_LDFLAGS@
......
......@@ -734,6 +734,7 @@ SUBDIRS
READELF
OTOOL
LDD
WINEPRELOADER_LDFLAGS
WINELOADER_LDFLAGS
TOP_INSTALL_DEV
TOP_INSTALL_LIB
......@@ -7756,6 +7757,8 @@ TOP_INSTALL_DEV=""
WINELOADER_LDFLAGS=""
WINEPRELOADER_LDFLAGS=""
LIBEXT="so"
DLLEXT=".so"
IMPLIBEXT="def"
......@@ -8591,7 +8594,35 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
APPKIT_LIBS="-framework AppKit"
WINELOADER_LDFLAGS="-image_base 0x7bf00000 -Wl,-pagezero_size,0x1000,-segaddr,WINE_DOS,0x00001000,-segaddr,WINE_SHAREDHEAP,0x7f000000,-sectcreate,__TEXT,__info_plist,wine_info.plist"
WINELOADER_LDFLAGS="-Wl,-pie,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,wine_info.plist"
WINEPRELOADER_LDFLAGS="-nostartfiles -nodefaultlibs -e _start -ldylib1.o -Wl,-image_base,0x7c400000,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,wine_info.plist"
{ $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 :
$as_echo_n "(cached) " >&6
else
ac_wine_try_cflags_saved=$CFLAGS
CFLAGS="$CFLAGS -Wl,-no_new_main -e _main"
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_new_main__e__main=yes
else
ac_cv_cflags__Wl__no_new_main__e__main=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
CFLAGS=$ac_wine_try_cflags_saved
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl__no_new_main__e__main" >&5
$as_echo "$ac_cv_cflags__Wl__no_new_main__e__main" >&6; }
if test "x$ac_cv_cflags__Wl__no_new_main__e__main" = xyes; then :
WINEPRELOADER_LDFLAGS="-Wl,-no_new_main $WINEPRELOADER_LDFLAGS"
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -Wl,-no_pie" >&5
$as_echo_n "checking whether the compiler supports -Wl,-no_pie... " >&6; }
if ${ac_cv_cflags__Wl__no_pie+:} false; then :
......@@ -8615,8 +8646,9 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags__Wl__no_pie" >&5
$as_echo "$ac_cv_cflags__Wl__no_pie" >&6; }
if test "x$ac_cv_cflags__Wl__no_pie" = xyes; then :
WINELOADER_LDFLAGS="-Wl,-no_pie $WINELOADER_LDFLAGS"
WINEPRELOADER_LDFLAGS="-Wl,-no_pie $WINEPRELOADER_LDFLAGS"
fi
if test "$ac_cv_header_DiskArbitration_DiskArbitration_h" = "yes"
then
DISKARBITRATION_LIBS="-framework DiskArbitration -framework CoreFoundation"
......@@ -8838,6 +8870,7 @@ $as_echo "$ac_cv_cflags__fPIC__Wl___export_dynamic" >&6; }
if test "x$ac_cv_cflags__fPIC__Wl___export_dynamic" = xyes; then :
WINELOADER_LDFLAGS="-Wl,--export-dynamic"
fi
WINEPRELOADER_LDFLAGS="-static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x7c400000"
as_ac_var=`$as_echo "ac_cv_cflags_-fPIC -Wl,--rpath,\\$ORIGIN/../lib" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fPIC -Wl,--rpath,\$ORIGIN/../lib" >&5
$as_echo_n "checking whether the compiler supports -fPIC -Wl,--rpath,\$ORIGIN/../lib... " >&6; }
......@@ -9177,6 +9210,7 @@ $as_echo "$ac_cv_cflags__fPIC__Wl___export_dynamic" >&6; }
if test "x$ac_cv_cflags__fPIC__Wl___export_dynamic" = xyes; then :
WINELOADER_LDFLAGS="-Wl,--export-dynamic"
fi
WINEPRELOADER_LDFLAGS="-static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x7c400000"
as_ac_var=`$as_echo "ac_cv_cflags_-fPIC -Wl,--rpath,\\$ORIGIN/../lib" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports -fPIC -Wl,--rpath,\$ORIGIN/../lib" >&5
......@@ -16478,6 +16512,14 @@ case $host_os in
;;
esac
;;
darwin*|macosx*)
case $host_cpu in
*i[3456789]86*|x86_64*)
test "$wine_binary" = wine || wine_fn_append_file CONFIGURE_TARGETS "loader/wine-preloader"
WINELOADER_PROGRAMS="$WINELOADER_PROGRAMS $wine_binary-preloader"
;;
esac
;;
esac
......
......@@ -707,6 +707,7 @@ AC_SUBST(LDEXECFLAGS,"")
AC_SUBST(TOP_INSTALL_LIB,"")
AC_SUBST(TOP_INSTALL_DEV,"")
AC_SUBST(WINELOADER_LDFLAGS,"")
AC_SUBST(WINEPRELOADER_LDFLAGS,"")
LIBEXT="so"
DLLEXT=".so"
IMPLIBEXT="def"
......@@ -767,9 +768,15 @@ case $host_os in
AC_SUBST(APPLICATIONSERVICES_LIBS,"-framework ApplicationServices")
AC_SUBST(CORESERVICES_LIBS,"-framework CoreServices")
AC_SUBST(APPKIT_LIBS,"-framework AppKit")
WINELOADER_LDFLAGS="-image_base 0x7bf00000 -Wl,-pagezero_size,0x1000,-segaddr,WINE_DOS,0x00001000,-segaddr,WINE_SHAREDHEAP,0x7f000000,-sectcreate,__TEXT,__info_plist,wine_info.plist"
WINELOADER_LDFLAGS="-Wl,-pie,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,wine_info.plist"
WINEPRELOADER_LDFLAGS="-nostartfiles -nodefaultlibs -e _start -ldylib1.o -Wl,-image_base,0x7c400000,-pagezero_size,0x1000,-sectcreate,__TEXT,__info_plist,wine_info.plist"
WINE_TRY_CFLAGS([-Wl,-no_new_main -e _main],
[WINEPRELOADER_LDFLAGS="-Wl,-no_new_main $WINEPRELOADER_LDFLAGS"])
WINE_TRY_CFLAGS([-Wl,-no_pie],
[WINELOADER_LDFLAGS="-Wl,-no_pie $WINELOADER_LDFLAGS"])
[WINEPRELOADER_LDFLAGS="-Wl,-no_pie $WINEPRELOADER_LDFLAGS"])
if test "$ac_cv_header_DiskArbitration_DiskArbitration_h" = "yes"
then
dnl DiskArbitration API is not public on Darwin < 8.0, use it only if header found
......@@ -885,6 +892,7 @@ case $host_os in
enable_wineandroid_drv=${enable_wineandroid_drv:-yes}
WINE_TRY_CFLAGS([-fPIC -Wl,--export-dynamic],
[WINELOADER_LDFLAGS="-Wl,--export-dynamic"])
WINEPRELOADER_LDFLAGS="-static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x7c400000"
WINE_TRY_CFLAGS([-fPIC -Wl,--rpath,\$ORIGIN/../lib],
[LDRPATH_INSTALL="-Wl,--rpath,\\\$\$ORIGIN/\`\$(MAKEDEP) -R \${bindir} \${libdir}\`"
LDRPATH_LOCAL="-Wl,--rpath,\\\$\$ORIGIN/\$(top_builddir)/libs/wine"],
......@@ -932,6 +940,7 @@ case $host_os in
WINE_TRY_CFLAGS([-fPIC -Wl,--export-dynamic],
[WINELOADER_LDFLAGS="-Wl,--export-dynamic"])
WINEPRELOADER_LDFLAGS="-static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x7c400000"
WINE_TRY_CFLAGS([-fPIC -Wl,--rpath,\$ORIGIN/../lib],
[LDRPATH_INSTALL="-Wl,--rpath,\\\$\$ORIGIN/\`\$(MAKEDEP) -R \${bindir} \${libdir}\`"
......@@ -2111,6 +2120,14 @@ case $host_os in
;;
esac
;;
darwin*|macosx*)
case $host_cpu in
*i[[3456789]]86*|x86_64*)
test "$wine_binary" = wine || WINE_IGNORE_FILE("loader/wine-preloader")
WINELOADER_PROGRAMS="$WINELOADER_PROGRAMS $wine_binary-preloader"
;;
esac
;;
esac
dnl **** Check for functions ****
......
......@@ -2417,14 +2417,20 @@ void virtual_release_address_space(void)
if (range.limit > range.base)
{
while (wine_mmap_enum_reserved_areas( free_reserved_memory, &range, 1 )) /* nothing */;
#ifdef __APPLE__
/* On macOS, we still want to free some of low memory, for OpenGL resources */
range.base = (char *)0x40000000;
#else
range.base = NULL;
#endif
}
else
range.base = (char *)0x20000000;
if (range.base)
{
#ifndef __APPLE__ /* dyld doesn't support parts of the WINE_DOS segment being unmapped */
range.base = (char *)0x20000000;
range.limit = (char *)0x7f000000;
while (wine_mmap_enum_reserved_areas( free_reserved_memory, &range, 0 )) /* nothing */;
#endif
}
server_leave_uninterrupted_section( &csVirtual, &sigset );
......
......@@ -573,7 +573,7 @@ void wine_exec_wine_binary( const char *name, char **argv, const char *env_var )
if (!name) name = argv0_name; /* no name means default loader */
#ifdef linux
#if defined(linux) || defined(__APPLE__)
use_preloader = !strendswith( name, "wineserver" );
#else
use_preloader = 0;
......
......@@ -2,6 +2,7 @@ SOURCES = \
l_intl.nls \
main.c \
preloader.c \
preloader_mac.c \
wine.de.UTF-8.man.in \
wine.desktop \
wine.fr.UTF-8.man.in \
......@@ -23,8 +24,8 @@ wine64_OBJS = main.o
wine64_DEPS = $(WINELOADER_DEPENDS)
wine64_LDFLAGS = $(WINELOADER_LDFLAGS) $(LDEXECFLAGS) -lwine $(PTHREAD_LIBS)
wine_preloader_OBJS = preloader.o
wine_preloader_LDFLAGS = -static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x7c400000
wine_preloader_OBJS = preloader.o preloader_mac.o
wine_preloader_LDFLAGS = $(WINEPRELOADER_LDFLAGS)
wine64_preloader_OBJS = preloader.o
wine64_preloader_LDFLAGS = -static -nostartfiles -nodefaultlibs -Wl,-Ttext=0x7c400000
wine64_preloader_OBJS = preloader.o preloader_mac.o
wine64_preloader_LDFLAGS = $(WINEPRELOADER_LDFLAGS)
......@@ -41,44 +41,9 @@
#include "wine/library.h"
#include "main.h"
#ifdef __APPLE__
#ifndef __clang__
__asm__(".zerofill WINE_DOS, WINE_DOS, ___wine_dos, 0x40000000");
__asm__(".zerofill WINE_SHAREDHEAP, WINE_SHAREDHEAP, ___wine_shared_heap, 0x03000000");
extern char __wine_dos[0x40000000], __wine_shared_heap[0x03000000];
#else
__asm__(".zerofill WINE_DOS, WINE_DOS");
__asm__(".zerofill WINE_SHAREDHEAP, WINE_SHAREDHEAP");
static char __wine_dos[0x40000000] __attribute__((section("WINE_DOS, WINE_DOS")));
static char __wine_shared_heap[0x03000000] __attribute__((section("WINE_SHAREDHEAP, WINE_SHAREDHEAP")));
#endif
static const struct wine_preload_info wine_main_preload_info[] =
{
{ __wine_dos, sizeof(__wine_dos) }, /* DOS area + PE exe */
{ __wine_shared_heap, sizeof(__wine_shared_heap) }, /* shared user data + shared heap */
{ 0, 0 } /* end of list */
};
static inline void reserve_area( void *addr, size_t size )
{
wine_anon_mmap( addr, size, PROT_NONE, MAP_FIXED | MAP_NORESERVE );
wine_mmap_add_reserved_area( addr, size );
}
#else /* __APPLE__ */
/* the preloader will set this variable */
const struct wine_preload_info *wine_main_preload_info = NULL;
static inline void reserve_area( void *addr, size_t size )
{
wine_mmap_add_reserved_area( addr, size );
}
#endif /* __APPLE__ */
/***********************************************************************
* check_command_line
*
......@@ -202,6 +167,13 @@ static int pre_exec(void)
return 1; /* we have a preloader on x86-64/arm64 */
}
#elif defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__))
static int pre_exec(void)
{
return 1; /* we have a preloader */
}
#elif (defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__))
static int pre_exec(void)
......@@ -247,12 +219,10 @@ int main( int argc, char *argv[] )
}
}
#ifndef __APPLE__
if (wine_main_preload_info)
#endif
{
for (i = 0; wine_main_preload_info[i].size; i++)
reserve_area( wine_main_preload_info[i].addr, wine_main_preload_info[i].size );
wine_mmap_add_reserved_area( wine_main_preload_info[i].addr, wine_main_preload_info[i].size );
}
wine_init( argc, argv, error, sizeof(error) );
......
......@@ -63,7 +63,6 @@
#include "config.h"
#include "wine/port.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
......@@ -91,15 +90,9 @@
# include <sys/link.h>
#endif
#include "main.h"
#include "preloader.h"
static int wld_vsprintf(char *buffer, const char *fmt, va_list args );
static __attribute__((format(printf,1,2))) void wld_printf(const char *fmt, ... );
static __attribute__((noreturn,format(printf,1,2))) void fatal_error(const char *fmt, ... );
static void preload_reserve( const char *str );
#ifdef __linux__
/* ELF definitions */
#define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) (mapstartpref)
......@@ -545,28 +538,6 @@ SYSCALL_NOERR( wld_getegid, 177 /* SYS_getegid */ );
#error preloader not implemented for this CPU
#endif
/* replacement for libc functions */
static int wld_strcmp( const char *str1, const char *str2 )
{
while (*str1 && (*str1 == *str2)) { str1++; str2++; }
return *str1 - *str2;
}
static int wld_strncmp( const char *str1, const char *str2, size_t len )
{
if (len <= 0) return 0;
while ((--len > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
return *str1 - *str2;
}
static inline void *wld_memset( void *dest, int val, size_t len )
{
char *dst = dest;
while (len--) *dst++ = val;
return dest;
}
#ifdef DUMP_AUX_INFO
/*
* Dump interesting bits of the ELF auxv_t structure that is passed
......@@ -1063,17 +1034,6 @@ static int is_addr_reserved( const void *addr )
return 0;
}
/* remove a range from the preload list */
static void remove_preload_range( int i )
{
while (preload_info[i].size)
{
preload_info[i].addr = preload_info[i+1].addr;
preload_info[i].size = preload_info[i+1].size;
i++;
}
}
/*
* is_in_preload_range
*
......@@ -1155,13 +1115,13 @@ void* wld_start( void **stack )
#endif
/* reserve memory that Wine needs */
if (reserve) preload_reserve( reserve );
if (reserve) preload_reserve( reserve, preload_info, page_mask );
for (i = 0; preload_info[i].size; i++)
{
if ((char *)av >= (char *)preload_info[i].addr &&
(char *)pargc <= (char *)preload_info[i].addr + preload_info[i].size)
{
remove_preload_range( i );
remove_preload_range( i, preload_info );
i--;
}
else if (wld_mmap( preload_info[i].addr, preload_info[i].size, PROT_NONE,
......@@ -1175,7 +1135,7 @@ void* wld_start( void **stack )
)
wld_printf( "preloader: Warning: failed to reserve range %p-%p\n",
preload_info[i].addr, (char *)preload_info[i].addr + preload_info[i].size );
remove_preload_range( i );
remove_preload_range( i, preload_info );
i--;
}
}
......@@ -1243,6 +1203,10 @@ void* wld_start( void **stack )
return (void *)ld_so_map.l_entry;
}
#endif /* __linux__ */
/* replacement for libc functions */
/*
* wld_printf - just the basics
*
......@@ -1250,7 +1214,7 @@ void* wld_start( void **stack )
* %s prints a string
* %p prints a pointer
*/
static int wld_vsprintf(char *buffer, const char *fmt, va_list args )
int wld_vsprintf(char *buffer, const char *fmt, va_list args )
{
static const char hex_chars[16] = "0123456789abcdef";
const char *p = fmt;
......@@ -1297,7 +1261,7 @@ static int wld_vsprintf(char *buffer, const char *fmt, va_list args )
return str - buffer;
}
static void wld_printf(const char *fmt, ... )
void wld_printf(const char *fmt, ... )
{
va_list args;
char buffer[256];
......@@ -1309,7 +1273,7 @@ static void wld_printf(const char *fmt, ... )
wld_write(2, buffer, len);
}
static void fatal_error(const char *fmt, ... )
void fatal_error(const char *fmt, ... )
{
va_list args;
char buffer[256];
......@@ -1327,7 +1291,7 @@ static void fatal_error(const char *fmt, ... )
*
* Reserve a range specified in string format
*/
static void preload_reserve( const char *str )
void preload_reserve( const char *str, struct wine_preload_info *preload_info, size_t page_mask )
{
const char *p;
unsigned long result = 0;
......
/*
* Definitions for Wine preloader
*
* Copyright (C) 2004 Mike McCormack for CodeWeavers
* Copyright (C) 2004 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __WINE_LOADER_PRELOADER_H
#define __WINE_LOADER_PRELOADER_H
#include <stdarg.h>
#include "main.h"
static inline int wld_strcmp( const char *str1, const char *str2 )
{
while (*str1 && (*str1 == *str2)) { str1++; str2++; }
return *str1 - *str2;
}
static inline int wld_strncmp( const char *str1, const char *str2, size_t len )
{
if (len <= 0) return 0;
while ((--len > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
return *str1 - *str2;
}
static inline void *wld_memset( void *dest, int val, size_t len )
{
char *dst = dest;
while (len--) *dst++ = val;
return dest;
}
extern int wld_vsprintf(char *buffer, const char *fmt, va_list args );
extern __attribute__((format(printf,1,2))) void wld_printf(const char *fmt, ... );
extern __attribute__((noreturn,format(printf,1,2))) void fatal_error(const char *fmt, ... );
extern void preload_reserve( const char *str, struct wine_preload_info *preload_info, size_t page_mask );
/* remove a range from the preload list */
static inline void remove_preload_range( int i, struct wine_preload_info *preload_info )
{
while (preload_info[i].size)
{
preload_info[i].addr = preload_info[i+1].addr;
preload_info[i].size = preload_info[i+1].size;
i++;
}
}
#endif /* __WINE_LOADER_PRELOADER_H */
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