Back to home page

Wine source

 
 

    


File indexing completed on 2023-07-21 22:40:33

a0ab2a7b0 Seba*0001 /*
                0002  * Preloader for macOS
                0003  *
                0004  * Copyright (C) 1995,96,97,98,99,2000,2001,2002 Free Software Foundation, Inc.
                0005  * Copyright (C) 2004 Mike McCormack for CodeWeavers
                0006  * Copyright (C) 2004 Alexandre Julliard
                0007  * Copyright (C) 2017 Michael Müller
                0008  * Copyright (C) 2017 Sebastian Lackner
                0009  *
                0010  * This library is free software; you can redistribute it and/or
                0011  * modify it under the terms of the GNU Lesser General Public
                0012  * License as published by the Free Software Foundation; either
                0013  * version 2.1 of the License, or (at your option) any later version.
                0014  *
                0015  * This library is distributed in the hope that it will be useful,
                0016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                0017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                0018  * Lesser General Public License for more details.
                0019  *
                0020  * You should have received a copy of the GNU Lesser General Public
                0021  * License along with this library; if not, write to the Free Software
                0022  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
                0023  */
                0024 
                0025 #ifdef __APPLE__
                0026 
                0027 #include "config.h"
                0028 
df8c5a37e Alex*0029 #include <stdarg.h>
a0ab2a7b0 Seba*0030 #include <stdio.h>
                0031 #include <stdlib.h>
                0032 #include <string.h>
                0033 #include <sys/types.h>
28d7d5ba9 Alex*0034 #include <sys/stat.h>
a0ab2a7b0 Seba*0035 #include <fcntl.h>
e3001b6a7 Alex*0036 #include <sys/mman.h>
a0ab2a7b0 Seba*0037 #ifdef HAVE_SYS_SYSCALL_H
                0038 # include <sys/syscall.h>
                0039 #endif
28d7d5ba9 Alex*0040 #include <unistd.h>
                0041 #include <dlfcn.h>
a0ab2a7b0 Seba*0042 #ifdef HAVE_MACH_O_LOADER_H
                0043 #include <mach/thread_status.h>
                0044 #include <mach-o/loader.h>
cc24255da Ken *0045 #include <mach-o/ldsyms.h>
a0ab2a7b0 Seba*0046 #endif
                0047 
d5a372abb Alex*0048 #include "wine/asm.h"
df8c5a37e Alex*0049 #include "main.h"
a0ab2a7b0 Seba*0050 
93941d6ec Bren*0051 #if defined(__x86_64__)
cfa0dd9dd Bren*0052 /* Reserve the low 8GB using a zero-fill section, this is the only way to
                0053  * prevent system frameworks from using any of it (including allocations
                0054  * before any preloader code runs)
307f5d00f Bren*0055  */
cfa0dd9dd Bren*0056 __asm__(".zerofill WINE_RESERVE,WINE_RESERVE,___wine_reserve,0x1fffff000");
93941d6ec Bren*0057 
                0058 static const struct wine_preload_info zerofill_sections[] =
                0059 {
cfa0dd9dd Bren*0060     { (void *)0x000000001000, 0x1fffff000 }, /* WINE_RESERVE section */
93941d6ec Bren*0061     { 0, 0 }                                 /* end of list */
                0062 };
                0063 #else
                0064 static const struct wine_preload_info zerofill_sections[] =
                0065 {
                0066     { 0, 0 }                                 /* end of list */
                0067 };
307f5d00f Bren*0068 #endif
                0069 
a0ab2a7b0 Seba*0070 #ifndef LC_MAIN
                0071 #define LC_MAIN 0x80000028
                0072 struct entry_point_command
                0073 {
                0074     uint32_t cmd;
                0075     uint32_t cmdsize;
                0076     uint64_t entryoff;
                0077     uint64_t stacksize;
                0078 };
                0079 #endif
                0080 
                0081 static struct wine_preload_info preload_info[] =
                0082 {
                0083     /* On macOS, we allocate the low 64k area in two steps because PAGEZERO
                0084      * might not always be available. */
                0085 #ifdef __i386__
                0086     { (void *)0x00000000, 0x00001000 },  /* first page */
                0087     { (void *)0x00001000, 0x0000f000 },  /* low 64k */
                0088     { (void *)0x00010000, 0x00100000 },  /* DOS area */
                0089     { (void *)0x00110000, 0x67ef0000 },  /* low memory area */
6b0836e3f Tim *0090     { (void *)0x7f000000, 0x03000000 },  /* top-down allocations + shared user data + virtual heap */
a0ab2a7b0 Seba*0091 #else  /* __i386__ */
cfa0dd9dd Bren*0092     { (void *)0x000000001000, 0x1fffff000 }, /* WINE_RESERVE section */
c10207e2a Bren*0093     { (void *)0x7ff000000000, 0x01ff0000 },  /* top-down allocations + virtual heap */
a0ab2a7b0 Seba*0094 #endif /* __i386__ */
                0095     { 0, 0 },                            /* PE exe range set with WINEPRELOADRESERVE */
                0096     { 0, 0 }                             /* end of list */
                0097 };
                0098 
                0099 /*
                0100  * These functions are only called when file is compiled with -fstack-protector.
                0101  * They are normally provided by libc's startup files, but since we
                0102  * build the preloader with "-nostartfiles -nodefaultlibs", we have to
                0103  * provide our own versions, otherwise the linker fails.
                0104  */
                0105 void *__stack_chk_guard = 0;
                0106 void __stack_chk_fail_local(void) { return; }
                0107 void __stack_chk_fail(void) { return; }
                0108 
4e6dbf3b9 Bren*0109 /* Binaries targeting 10.6 and 10.7 contain the __program_vars section, and
                0110  * dyld4 (starting in Monterey) does not like it to be missing:
                0111  * - running vmmap on a Wine process prints this warning:
                0112  *   "Process exists but has not fully started -- dyld has initialized but libSystem has not"
                0113  * - because libSystem is not initialized, dlerror() always returns NULL (causing GStreamer
                0114  *   to crash on init).
                0115  * - starting with macOS Sonoma, Wine crashes on launch if libSystem is not initialized.
                0116  *
                0117  * Adding __program_vars fixes those issues, and also allows more of the vars to
                0118  * be set correctly by the preloader for the loaded binary.
                0119  *
                0120  * See also:
                0121  * <https://github.com/apple-oss-distributions/Csu/blob/Csu-88/crt.c#L42>
                0122  * <https://github.com/apple-oss-distributions/dyld/blob/dyld-1042.1/common/MachOAnalyzer.cpp#L2185>
                0123  */
                0124 int           NXArgc = 0;
                0125 const char**  NXArgv = NULL;
                0126 const char**  environ = NULL;
                0127 const char*   __progname = NULL;
                0128 
                0129 extern void* __dso_handle;
                0130 struct ProgramVars
                0131 {
                0132     void*           mh;
                0133     int*            NXArgcPtr;
                0134     const char***   NXArgvPtr;
                0135     const char***   environPtr;
                0136     const char**    __prognamePtr;
                0137 };
                0138 __attribute__((used))  static struct ProgramVars pvars
                0139 __attribute__ ((section ("__DATA,__program_vars")))  = { &__dso_handle, &NXArgc, &NXArgv, &environ, &__progname };
                0140 
                0141 
4ec770a13 Bren*0142 /*
                0143  * When 'start' is called, stack frame looks like:
                0144  *
                0145  *         :
                0146  *  | STRING AREA |
                0147  *  +-------------+
                0148  *  |      0      |
                0149  *  +-------------+
                0150  *  |  exec_path  | extra "apple" parameters start after NULL terminating env array
                0151  *  +-------------+
                0152  *  |      0      |
                0153  *  +-------------+
                0154  *  |    env[n]   |
                0155  *  +-------------+
                0156  *         :
                0157  *         :
                0158  *  +-------------+
                0159  *  |    env[0]   |
                0160  *  +-------------+
                0161  *  |      0      |
                0162  *  +-------------+
                0163  *  | arg[argc-1] |
                0164  *  +-------------+
                0165  *         :
                0166  *         :
                0167  *  +-------------+
                0168  *  |    arg[0]   |
                0169  *  +-------------+
                0170  *  |     argc    | argc is always 4 bytes long, even in 64-bit architectures
                0171  *  +-------------+ <- sp
                0172  *
                0173  *  Where arg[i] and env[i] point into the STRING AREA
                0174  *
                0175  *  See also:
                0176  *  macOS C runtime 'start':
                0177  *  <https://github.com/apple-oss-distributions/Csu/blob/Csu-88/start.s>
                0178  *
                0179  *  macOS dyld '__dyld_start' (pre-dyld4):
                0180  *  <https://github.com/apple-oss-distributions/dyld/blob/dyld-852.2/src/dyldStartup.s>
                0181  */
                0182 
a0ab2a7b0 Seba*0183 #ifdef __i386__
                0184 
                0185 static const size_t page_mask = 0xfff;
                0186 #define target_mach_header      mach_header
cc24255da Ken *0187 #define target_segment_command  segment_command
                0188 #define TARGET_LC_SEGMENT       LC_SEGMENT
a0ab2a7b0 Seba*0189 #define target_thread_state_t   i386_thread_state_t
                0190 #ifdef __DARWIN_UNIX03
                0191 #define target_thread_ip(x)     (x)->__eip
                0192 #else
                0193 #define target_thread_ip(x)     (x)->eip
                0194 #endif
                0195 
                0196 #define SYSCALL_FUNC( name, nr ) \
                0197     __ASM_GLOBAL_FUNC( name, \
                0198                        "\tmovl $" #nr ",%eax\n" \
                0199                        "\tint $0x80\n" \
                0200                        "\tjnb 1f\n" \
                0201                        "\tmovl $-1,%eax\n" \
                0202                        "1:\tret\n" )
                0203 
                0204 #define SYSCALL_NOERR( name, nr ) \
                0205     __ASM_GLOBAL_FUNC( name, \
                0206                        "\tmovl $" #nr ",%eax\n" \
                0207                        "\tint $0x80\n" \
                0208                        "\tret\n" )
                0209 
                0210 __ASM_GLOBAL_FUNC( start,
                0211                    __ASM_CFI("\t.cfi_undefined %eip\n")
                0212                    /* The first 16 bytes are used as a function signature on i386 */
4ec770a13 Bren*0213                    "\t.byte 0x6a,0x00\n"            /* pushl $0: push a zero for debugger end of frames marker */
                0214                    "\t.byte 0x89,0xe5\n"            /* movl %esp,%ebp: pointer to base of kernel frame */
                0215                    "\t.byte 0x83,0xe4,0xf0\n"       /* andl $-16,%esp: force SSE alignment */
                0216                    "\t.byte 0x83,0xec,0x10\n"       /* subl $16,%esp: room for new argc, argv, & envp, SSE aligned */
                0217                    "\t.byte 0x8b,0x5d,0x04\n"       /* movl 4(%ebp),%ebx: pickup argc in %ebx */
                0218                    "\t.byte 0x89,0x5c,0x24,0x00\n"  /* movl %ebx,0(%esp): argc to reserved stack word */
                0219 
                0220                    /* call wld_start(stack, &is_unix_thread) */
a0ab2a7b0 Seba*0221                    "\tleal 4(%ebp),%eax\n"
                0222                    "\tmovl %eax,0(%esp)\n"          /* stack */
                0223                    "\tleal 8(%esp),%eax\n"
                0224                    "\tmovl %eax,4(%esp)\n"          /* &is_unix_thread */
                0225                    "\tmovl $0,(%eax)\n"
                0226                    "\tcall _wld_start\n"
                0227 
588e55542 Bren*0228                    /* jmp based on is_unix_thread */
                0229                    "\tcmpl $0,8(%esp)\n"
                0230                    "\tjne 2f\n"
                0231 
                0232                    "\tmovl 4(%ebp),%edi\n"          /* %edi = argc */
                0233                    "\tleal 8(%ebp),%esi\n"          /* %esi = argv */
4ec770a13 Bren*0234                    "\tleal 4(%esi,%edi,4),%edx\n"   /* %edx = env */
                0235                    "\tmovl %edx,%ecx\n"
a0ab2a7b0 Seba*0236                    "1:\tmovl (%ecx),%ebx\n"
                0237                    "\tadd $4,%ecx\n"
4ec770a13 Bren*0238                    "\torl %ebx,%ebx\n"              /* look for the NULL ending the env[] array */
                0239                    "\tjnz 1b\n"                     /* %ecx = apple data */
a0ab2a7b0 Seba*0240 
                0241                    /* LC_MAIN */
                0242                    "\tmovl %edi,0(%esp)\n"          /* argc */
                0243                    "\tmovl %esi,4(%esp)\n"          /* argv */
                0244                    "\tmovl %edx,8(%esp)\n"          /* env */
                0245                    "\tmovl %ecx,12(%esp)\n"         /* apple data */
4ec770a13 Bren*0246                    "\tcall *%eax\n"                 /* call main(argc,argv,env,apple) */
                0247                    "\tmovl %eax,(%esp)\n"           /* pass result from main() to exit() */
                0248                    "\tcall _wld_exit\n"             /* need to use call to keep stack aligned */
a0ab2a7b0 Seba*0249                    "\thlt\n"
                0250 
                0251                    /* LC_UNIXTHREAD */
588e55542 Bren*0252                    "\t2:movl %ebp,%esp\n"           /* restore the unaligned stack pointer */
                0253                    "\taddl $4,%esp\n"               /* remove the debugger end frame marker */
4ec770a13 Bren*0254                    "\tmovl $0,%ebp\n"               /* restore ebp back to zero */
                0255                    "\tjmpl *%eax\n" )               /* jump to the entry point */
a0ab2a7b0 Seba*0256 
                0257 #elif defined(__x86_64__)
                0258 
                0259 static const size_t page_mask = 0xfff;
                0260 #define target_mach_header      mach_header_64
cc24255da Ken *0261 #define target_segment_command  segment_command_64
                0262 #define TARGET_LC_SEGMENT       LC_SEGMENT_64
a0ab2a7b0 Seba*0263 #define target_thread_state_t   x86_thread_state64_t
                0264 #ifdef __DARWIN_UNIX03
                0265 #define target_thread_ip(x)     (x)->__rip
                0266 #else
                0267 #define target_thread_ip(x)     (x)->rip
                0268 #endif
                0269 
                0270 #define SYSCALL_FUNC( name, nr ) \
                0271     __ASM_GLOBAL_FUNC( name, \
                0272                        "\tmovq %rcx, %r10\n" \
                0273                        "\tmovq $(" #nr "|0x2000000),%rax\n" \
                0274                        "\tsyscall\n" \
                0275                        "\tjnb 1f\n" \
                0276                        "\tmovq $-1,%rax\n" \
                0277                        "1:\tret\n" )
                0278 
                0279 #define SYSCALL_NOERR( name, nr ) \
                0280     __ASM_GLOBAL_FUNC( name, \
                0281                        "\tmovq %rcx, %r10\n" \
                0282                        "\tmovq $(" #nr "|0x2000000),%rax\n" \
                0283                        "\tsyscall\n" \
                0284                        "\tret\n" )
                0285 
                0286 __ASM_GLOBAL_FUNC( start,
                0287                    __ASM_CFI("\t.cfi_undefined %rip\n")
4ec770a13 Bren*0288                    "\tpushq $0\n"                   /* push a zero for debugger end of frames marker */
                0289                    "\tmovq %rsp,%rbp\n"             /* pointer to base of kernel frame */
                0290                    "\tandq $-16,%rsp\n"             /* force SSE alignment */
                0291                    "\tsubq $16,%rsp\n"              /* room for local variables */
a0ab2a7b0 Seba*0292 
4ec770a13 Bren*0293                    /* call wld_start(stack, &is_unix_thread) */
a0ab2a7b0 Seba*0294                    "\tleaq 8(%rbp),%rdi\n"          /* stack */
                0295                    "\tmovq %rsp,%rsi\n"             /* &is_unix_thread */
                0296                    "\tmovq $0,(%rsi)\n"
                0297                    "\tcall _wld_start\n"
                0298 
588e55542 Bren*0299                    /* jmp based on is_unix_thread */
                0300                    "\tcmpl $0,0(%rsp)\n"
                0301                    "\tjne 2f\n"
                0302 
                0303                    /* LC_MAIN */
                0304                    "\tmovq 8(%rbp),%rdi\n"          /* %rdi = argc */
                0305                    "\tleaq 16(%rbp),%rsi\n"         /* %rsi = argv */
4ec770a13 Bren*0306                    "\tleaq 8(%rsi,%rdi,8),%rdx\n"   /* %rdx = env */
                0307                    "\tmovq %rdx,%rcx\n"
a0ab2a7b0 Seba*0308                    "1:\tmovq (%rcx),%r8\n"
                0309                    "\taddq $8,%rcx\n"
4ec770a13 Bren*0310                    "\torq %r8,%r8\n"                /* look for the NULL ending the env[] array */
                0311                    "\tjnz 1b\n"                     /* %rcx = apple data */
a0ab2a7b0 Seba*0312 
4ec770a13 Bren*0313                    "\taddq $16,%rsp\n"              /* remove local variables */
                0314                    "\tcall *%rax\n"                 /* call main(argc,argv,env,apple) */
                0315                    "\tmovq %rax,%rdi\n"             /* pass result from main() to exit() */
                0316                    "\tcall _wld_exit\n"             /* need to use call to keep stack aligned */
a0ab2a7b0 Seba*0317                    "\thlt\n"
                0318 
                0319                    /* LC_UNIXTHREAD */
588e55542 Bren*0320                    "\t2:movq %rbp,%rsp\n"           /* restore the unaligned stack pointer */
                0321                    "\taddq $8,%rsp\n"               /* remove the debugger end frame marker */
4ec770a13 Bren*0322                    "\tmovq $0,%rbp\n"               /* restore ebp back to zero */
                0323                    "\tjmpq *%rax\n" )               /* jump to the entry point */
a0ab2a7b0 Seba*0324 
                0325 #else
                0326 #error preloader not implemented for this CPU
                0327 #endif
                0328 
                0329 void wld_exit( int code ) __attribute__((noreturn));
                0330 SYSCALL_NOERR( wld_exit, 1 /* SYS_exit */ );
                0331 
                0332 ssize_t wld_write( int fd, const void *buffer, size_t len );
                0333 SYSCALL_FUNC( wld_write, 4 /* SYS_write */ );
                0334 
                0335 void *wld_mmap( void *start, size_t len, int prot, int flags, int fd, off_t offset );
                0336 SYSCALL_FUNC( wld_mmap, 197 /* SYS_mmap */ );
                0337 
                0338 void *wld_munmap( void *start, size_t len );
                0339 SYSCALL_FUNC( wld_munmap, 73 /* SYS_munmap */ );
                0340 
                0341 static intptr_t (*p_dyld_get_image_slide)( const struct target_mach_header* mh );
                0342 
                0343 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
                0344 MAKE_FUNCPTR(dlopen);
                0345 MAKE_FUNCPTR(dlsym);
                0346 MAKE_FUNCPTR(dladdr);
                0347 #undef MAKE_FUNCPTR
                0348 
                0349 extern int _dyld_func_lookup( const char *dyld_func_name, void **address );
                0350 
df8c5a37e Alex*0351 /* replacement for libc functions */
                0352 
588e55542 Bren*0353 void * memmove( void *dst, const void *src, size_t len )
                0354 {
                0355     char *d = dst;
                0356     const char *s = src;
                0357     if (d < s)
                0358         while (len--)
                0359             *d++ = *s++;
                0360     else
                0361     {
                0362         const char *lasts = s + (len-1);
                0363         char *lastd = d + (len-1);
                0364         while (len--)
                0365             *lastd-- = *lasts--;
                0366     }
                0367     return dst;
                0368 }
                0369 
df8c5a37e Alex*0370 static int wld_strncmp( const char *str1, const char *str2, size_t len )
                0371 {
                0372     if (len <= 0) return 0;
                0373     while ((--len > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
                0374     return *str1 - *str2;
                0375 }
                0376 
                0377 /*
                0378  * wld_printf - just the basics
                0379  *
                0380  *  %x prints a hex number
                0381  *  %s prints a string
                0382  *  %p prints a pointer
                0383  */
                0384 static int wld_vsprintf(char *buffer, const char *fmt, va_list args )
                0385 {
                0386     static const char hex_chars[16] = "0123456789abcdef";
                0387     const char *p = fmt;
                0388     char *str = buffer;
                0389     int i;
                0390 
                0391     while( *p )
                0392     {
                0393         if( *p == '%' )
                0394         {
                0395             p++;
                0396             if( *p == 'x' )
                0397             {
                0398                 unsigned int x = va_arg( args, unsigned int );
                0399                 for (i = 2*sizeof(x) - 1; i >= 0; i--)
                0400                     *str++ = hex_chars[(x>>(i*4))&0xf];
                0401             }
                0402             else if (p[0] == 'l' && p[1] == 'x')
                0403             {
                0404                 unsigned long x = va_arg( args, unsigned long );
                0405                 for (i = 2*sizeof(x) - 1; i >= 0; i--)
                0406                     *str++ = hex_chars[(x>>(i*4))&0xf];
                0407                 p++;
                0408             }
                0409             else if( *p == 'p' )
                0410             {
                0411                 unsigned long x = (unsigned long)va_arg( args, void * );
                0412                 for (i = 2*sizeof(x) - 1; i >= 0; i--)
                0413                     *str++ = hex_chars[(x>>(i*4))&0xf];
                0414             }
                0415             else if( *p == 's' )
                0416             {
                0417                 char *s = va_arg( args, char * );
                0418                 while(*s)
                0419                     *str++ = *s++;
                0420             }
                0421             else if( *p == 0 )
                0422                 break;
                0423             p++;
                0424         }
                0425         *str++ = *p++;
                0426     }
                0427     *str = 0;
                0428     return str - buffer;
                0429 }
                0430 
                0431 static __attribute__((format(printf,1,2))) void wld_printf(const char *fmt, ... )
                0432 {
                0433     va_list args;
                0434     char buffer[256];
                0435     int len;
                0436 
                0437     va_start( args, fmt );
                0438     len = wld_vsprintf(buffer, fmt, args );
                0439     va_end( args );
                0440     wld_write(2, buffer, len);
                0441 }
                0442 
                0443 static __attribute__((noreturn,format(printf,1,2))) void fatal_error(const char *fmt, ... )
                0444 {
                0445     va_list args;
                0446     char buffer[256];
                0447     int len;
                0448 
                0449     va_start( args, fmt );
                0450     len = wld_vsprintf(buffer, fmt, args );
                0451     va_end( args );
                0452     wld_write(2, buffer, len);
                0453     wld_exit(1);
                0454 }
                0455 
cc24255da Ken *0456 static int preloader_overlaps_range( const void *start, const void *end )
                0457 {
                0458     intptr_t slide = p_dyld_get_image_slide(&_mh_execute_header);
                0459     struct load_command *cmd = (struct load_command*)(&_mh_execute_header + 1);
                0460     int i;
                0461 
                0462     for (i = 0; i < _mh_execute_header.ncmds; ++i)
                0463     {
                0464         if (cmd->cmd == TARGET_LC_SEGMENT)
                0465         {
                0466             struct target_segment_command *seg = (struct target_segment_command*)cmd;
                0467             const void *seg_start = (const void*)(seg->vmaddr + slide);
                0468             const void *seg_end = (const char*)seg_start + seg->vmsize;
cfa0dd9dd Bren*0469             static const char reserved_segname[] = "WINE_RESERVE";
307f5d00f Bren*0470 
                0471             if (!wld_strncmp( seg->segname, reserved_segname, sizeof(reserved_segname)-1 ))
                0472                 continue;
cc24255da Ken *0473 
                0474             if (end > seg_start && start <= seg_end)
                0475             {
                0476                 char segname[sizeof(seg->segname) + 1];
                0477                 memcpy(segname, seg->segname, sizeof(seg->segname));
                0478                 segname[sizeof(segname) - 1] = 0;
                0479                 wld_printf( "WINEPRELOADRESERVE range %p-%p overlaps preloader %s segment %p-%p\n",
                0480                              start, end, segname, seg_start, seg_end );
                0481                 return 1;
                0482             }
                0483         }
                0484         cmd = (struct load_command*)((char*)cmd + cmd->cmdsize);
                0485     }
                0486 
                0487     return 0;
                0488 }
                0489 
df8c5a37e Alex*0490 /*
                0491  *  preload_reserve
                0492  *
                0493  * Reserve a range specified in string format
                0494  */
                0495 static void preload_reserve( const char *str )
                0496 {
                0497     const char *p;
                0498     unsigned long result = 0;
                0499     void *start = NULL, *end = NULL;
                0500     int i, first = 1;
                0501 
                0502     for (p = str; *p; p++)
                0503     {
                0504         if (*p >= '0' && *p <= '9') result = result * 16 + *p - '0';
                0505         else if (*p >= 'a' && *p <= 'f') result = result * 16 + *p - 'a' + 10;
                0506         else if (*p >= 'A' && *p <= 'F') result = result * 16 + *p - 'A' + 10;
                0507         else if (*p == '-')
                0508         {
                0509             if (!first) goto error;
                0510             start = (void *)(result & ~page_mask);
                0511             result = 0;
                0512             first = 0;
                0513         }
                0514         else goto error;
                0515     }
                0516     if (!first) end = (void *)((result + page_mask) & ~page_mask);
                0517     else if (result) goto error;  /* single value '0' is allowed */
                0518 
                0519     /* sanity checks */
cc24255da Ken *0520     if (end <= start || preloader_overlaps_range(start, end))
                0521         start = end = NULL;
df8c5a37e Alex*0522 
                0523     /* check for overlap with low memory areas */
                0524     for (i = 0; preload_info[i].size; i++)
                0525     {
                0526         if ((char *)preload_info[i].addr > (char *)0x00110000) break;
                0527         if ((char *)end <= (char *)preload_info[i].addr + preload_info[i].size)
                0528         {
                0529             start = end = NULL;
                0530             break;
                0531         }
                0532         if ((char *)start < (char *)preload_info[i].addr + preload_info[i].size)
                0533             start = (char *)preload_info[i].addr + preload_info[i].size;
                0534     }
                0535 
                0536     while (preload_info[i].size) i++;
                0537     preload_info[i].addr = start;
                0538     preload_info[i].size = (char *)end - (char *)start;
                0539     return;
                0540 
                0541 error:
                0542     fatal_error( "invalid WINEPRELOADRESERVE value '%s'\n", str );
                0543 }
                0544 
                0545 /* remove a range from the preload list */
                0546 static void remove_preload_range( int i )
                0547 {
                0548     while (preload_info[i].size)
                0549     {
                0550         preload_info[i].addr = preload_info[i+1].addr;
                0551         preload_info[i].size = preload_info[i+1].size;
                0552         i++;
                0553     }
                0554 }
                0555 
a0ab2a7b0 Seba*0556 static void *get_entry_point( struct target_mach_header *mh, intptr_t slide, int *unix_thread )
                0557 {
                0558     struct entry_point_command *entry;
                0559     target_thread_state_t *state;
                0560     struct load_command *cmd;
                0561     int i;
                0562 
                0563     /* try LC_MAIN first */
                0564     cmd = (struct load_command *)(mh + 1);
                0565     for (i = 0; i < mh->ncmds; i++)
                0566     {
                0567         if (cmd->cmd == LC_MAIN)
                0568         {
                0569             *unix_thread = FALSE;
                0570             entry = (struct entry_point_command *)cmd;
                0571             return (char *)mh + entry->entryoff;
                0572         }
                0573         cmd = (struct load_command *)((char *)cmd + cmd->cmdsize);
                0574     }
                0575 
                0576     /* then try LC_UNIXTHREAD */
                0577     cmd = (struct load_command *)(mh + 1);
                0578     for (i = 0; i < mh->ncmds; i++)
                0579     {
                0580         if (cmd->cmd == LC_UNIXTHREAD)
                0581         {
                0582             *unix_thread = TRUE;
                0583             state = (target_thread_state_t *)((char *)cmd + 16);
                0584             return (void *)(target_thread_ip(state) + slide);
                0585         }
                0586         cmd = (struct load_command *)((char *)cmd + cmd->cmdsize);
                0587     }
                0588 
                0589     return NULL;
                0590 };
                0591 
93941d6ec Bren*0592 static int is_zerofill( struct wine_preload_info *info )
a0ab2a7b0 Seba*0593 {
                0594     int i;
                0595 
93941d6ec Bren*0596     for (i = 0; zerofill_sections[i].size; i++)
a0ab2a7b0 Seba*0597     {
93941d6ec Bren*0598         if ((zerofill_sections[i].addr == info->addr) &&
                0599             (zerofill_sections[i].size == info->size))
                0600             return 1;
a0ab2a7b0 Seba*0601     }
93941d6ec Bren*0602     return 0;
a0ab2a7b0 Seba*0603 }
                0604 
                0605 static int map_region( struct wine_preload_info *info )
                0606 {
                0607     int flags = MAP_PRIVATE | MAP_ANON;
                0608     void *ret;
                0609 
93941d6ec Bren*0610     if (!info->addr || is_zerofill( info )) flags |= MAP_FIXED;
a0ab2a7b0 Seba*0611 
93941d6ec Bren*0612     ret = wld_mmap( info->addr, info->size, PROT_NONE, flags, -1, 0 );
                0613     if (ret == info->addr) return 1;
                0614     if (ret != (void *)-1) wld_munmap( ret, info->size );
a0ab2a7b0 Seba*0615 
                0616     /* don't warn for zero page */
                0617     if (info->addr >= (void *)0x1000)
                0618         wld_printf( "preloader: Warning: failed to reserve range %p-%p\n",
                0619                     info->addr, (char *)info->addr + info->size );
                0620     return 0;
                0621 }
                0622 
                0623 static inline void get_dyld_func( const char *name, void **func )
                0624 {
                0625     _dyld_func_lookup( name, func );
                0626     if (!*func) fatal_error( "Failed to get function pointer for %s\n", name );
                0627 }
                0628 
                0629 #define LOAD_POSIX_DYLD_FUNC(f) get_dyld_func( "__dyld_" #f, (void **)&p##f )
                0630 #define LOAD_MACHO_DYLD_FUNC(f) get_dyld_func( "_" #f, (void **)&p##f )
                0631 
588e55542 Bren*0632 static void fixup_stack( void *stack )
                0633 {
                0634     int *pargc;
36bb7175c Bren*0635     char **argv, **env_new;
                0636     static char dummyvar[] = "WINEPRELOADERDUMMYVAR=1";
588e55542 Bren*0637 
                0638     pargc = stack;
                0639     argv = (char **)pargc + 1;
                0640 
36bb7175c Bren*0641     /* decrement argc, and "remove" argv[0] */
588e55542 Bren*0642     *pargc = *pargc - 1;
36bb7175c Bren*0643     memmove( &argv[0], &argv[1], (*pargc + 1) * sizeof(char *) );
                0644 
                0645     env_new = &argv[*pargc-1] + 2;
                0646     /* In the launched binary on some OSes, _NSGetEnviron() returns
                0647      * the original 'environ' pointer, so env_new[0] would be ignored.
                0648      * Put a dummy variable in env_new[0], so nothing is lost in this case.
                0649      */
                0650     env_new[0] = dummyvar;
588e55542 Bren*0651 }
                0652 
f99eef684 Bren*0653 static void set_program_vars( void *stack, void *mod )
                0654 {
                0655     int *pargc;
4e6dbf3b9 Bren*0656     const char **argv, **env;
f99eef684 Bren*0657     int *wine_NXArgc = pdlsym( mod, "NXArgc" );
4e6dbf3b9 Bren*0658     const char ***wine_NXArgv = pdlsym( mod, "NXArgv" );
                0659     const char ***wine_environ = pdlsym( mod, "environ" );
f99eef684 Bren*0660 
                0661     pargc = stack;
4e6dbf3b9 Bren*0662     argv = (const char **)pargc + 1;
f99eef684 Bren*0663     env = &argv[*pargc-1] + 2;
                0664 
4e6dbf3b9 Bren*0665     /* set vars in the loaded binary */
f99eef684 Bren*0666     if (wine_NXArgc)
                0667         *wine_NXArgc = *pargc;
                0668     else
                0669         wld_printf( "preloader: Warning: failed to set NXArgc\n" );
                0670 
                0671     if (wine_NXArgv)
                0672         *wine_NXArgv = argv;
                0673     else
                0674         wld_printf( "preloader: Warning: failed to set NXArgv\n" );
                0675 
                0676     if (wine_environ)
                0677         *wine_environ = env;
                0678     else
                0679         wld_printf( "preloader: Warning: failed to set environ\n" );
4e6dbf3b9 Bren*0680 
                0681     /* set vars in the __program_vars section */
                0682     NXArgc = *pargc;
                0683     NXArgv = argv;
                0684     environ = env;
f99eef684 Bren*0685 }
                0686 
a0ab2a7b0 Seba*0687 void *wld_start( void *stack, int *is_unix_thread )
                0688 {
cfa0dd9dd Bren*0689 #ifdef __i386__
a0ab2a7b0 Seba*0690     struct wine_preload_info builtin_dlls = { (void *)0x7a000000, 0x02000000 };
cfa0dd9dd Bren*0691 #endif
a0ab2a7b0 Seba*0692     struct wine_preload_info **wine_main_preload_info;
                0693     char **argv, **p, *reserve = NULL;
                0694     struct target_mach_header *mh;
                0695     void *mod, *entry;
                0696     int *pargc, i;
                0697     Dl_info info;
                0698 
                0699     pargc = stack;
                0700     argv = (char **)pargc + 1;
                0701     if (*pargc < 2) fatal_error( "Usage: %s wine_binary [args]\n", argv[0] );
                0702 
                0703     /* skip over the parameters */
                0704     p = argv + *pargc + 1;
                0705 
                0706     /* skip over the environment */
                0707     while (*p)
                0708     {
                0709         static const char res[] = "WINEPRELOADRESERVE=";
                0710         if (!wld_strncmp( *p, res, sizeof(res)-1 )) reserve = *p + sizeof(res) - 1;
                0711         p++;
                0712     }
                0713 
cc24255da Ken *0714     LOAD_POSIX_DYLD_FUNC( dlopen );
                0715     LOAD_POSIX_DYLD_FUNC( dlsym );
                0716     LOAD_POSIX_DYLD_FUNC( dladdr );
                0717     LOAD_MACHO_DYLD_FUNC( _dyld_get_image_slide );
                0718 
a0ab2a7b0 Seba*0719     /* reserve memory that Wine needs */
df8c5a37e Alex*0720     if (reserve) preload_reserve( reserve );
a0ab2a7b0 Seba*0721     for (i = 0; preload_info[i].size; i++)
                0722     {
                0723         if (!map_region( &preload_info[i] ))
                0724         {
df8c5a37e Alex*0725             remove_preload_range( i );
a0ab2a7b0 Seba*0726             i--;
                0727         }
                0728     }
                0729 
cfa0dd9dd Bren*0730 #ifdef __i386__
a0ab2a7b0 Seba*0731     if (!map_region( &builtin_dlls ))
                0732         builtin_dlls.size = 0;
cfa0dd9dd Bren*0733 #endif
a0ab2a7b0 Seba*0734 
                0735     /* load the main binary */
                0736     if (!(mod = pdlopen( argv[1], RTLD_NOW )))
                0737         fatal_error( "%s: could not load binary\n", argv[1] );
                0738 
cfa0dd9dd Bren*0739 #ifdef __i386__
a0ab2a7b0 Seba*0740     if (builtin_dlls.size)
                0741         wld_munmap( builtin_dlls.addr, builtin_dlls.size );
cfa0dd9dd Bren*0742 #endif
a0ab2a7b0 Seba*0743 
                0744     /* store pointer to the preload info into the appropriate main binary variable */
                0745     wine_main_preload_info = pdlsym( mod, "wine_main_preload_info" );
                0746     if (wine_main_preload_info) *wine_main_preload_info = preload_info;
                0747     else wld_printf( "wine_main_preload_info not found\n" );
                0748 
                0749     if (!pdladdr( wine_main_preload_info, &info ) || !(mh = info.dli_fbase))
                0750         fatal_error( "%s: could not find mach header\n", argv[1] );
                0751     if (!(entry = get_entry_point( mh, p_dyld_get_image_slide(mh), is_unix_thread )))
                0752         fatal_error( "%s: could not find entry point\n", argv[1] );
                0753 
588e55542 Bren*0754     /* decrement argc and "remove" argv[0] */
                0755     fixup_stack(stack);
                0756 
f99eef684 Bren*0757     /* Set NXArgc, NXArgv, and environ in the new binary.
                0758      * On different configurations these were either NULL/0 or still had their
                0759      * values from this preloader's launch.
                0760      *
                0761      * In particular, environ was not being updated, resulting in environ[0] being lost.
                0762      * And for LC_UNIXTHREAD binaries on Monterey and later, environ was just NULL.
9ab93415f Bren*0763      */
f99eef684 Bren*0764     set_program_vars( stack, mod );
9ab93415f Bren*0765 
a0ab2a7b0 Seba*0766     return entry;
                0767 }
                0768 
                0769 #endif /* __APPLE__ */