preloader_mac.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. /*
  2. * Preloader for macOS
  3. *
  4. * Copyright (C) 1995,96,97,98,99,2000,2001,2002 Free Software Foundation, Inc.
  5. * Copyright (C) 2004 Mike McCormack for CodeWeavers
  6. * Copyright (C) 2004 Alexandre Julliard
  7. * Copyright (C) 2017 Michael Müller
  8. * Copyright (C) 2017 Sebastian Lackner
  9. *
  10. * This library is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public
  12. * License as published by the Free Software Foundation; either
  13. * version 2.1 of the License, or (at your option) any later version.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with this library; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #ifdef __APPLE__
  25. #include "config.h"
  26. #include <stdarg.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32. #include <fcntl.h>
  33. #include <sys/mman.h>
  34. #ifdef HAVE_SYS_SYSCALL_H
  35. # include <sys/syscall.h>
  36. #endif
  37. #include <unistd.h>
  38. #include <dlfcn.h>
  39. #ifdef HAVE_MACH_O_LOADER_H
  40. #include <mach/thread_status.h>
  41. #include <mach-o/loader.h>
  42. #include <mach-o/ldsyms.h>
  43. #endif
  44. #include "wine/asm.h"
  45. #include "main.h"
  46. #if defined(__x86_64__)
  47. /* Reserve the low 8GB using a zero-fill section, this is the only way to
  48. * prevent system frameworks from using any of it (including allocations
  49. * before any preloader code runs)
  50. */
  51. __asm__(".zerofill WINE_RESERVE,WINE_RESERVE,___wine_reserve,0x1fffff000");
  52. static const struct wine_preload_info zerofill_sections[] =
  53. {
  54. { (void *)0x000000001000, 0x1fffff000 }, /* WINE_RESERVE section */
  55. { 0, 0 } /* end of list */
  56. };
  57. #else
  58. static const struct wine_preload_info zerofill_sections[] =
  59. {
  60. { 0, 0 } /* end of list */
  61. };
  62. #endif
  63. #ifndef LC_MAIN
  64. #define LC_MAIN 0x80000028
  65. struct entry_point_command
  66. {
  67. uint32_t cmd;
  68. uint32_t cmdsize;
  69. uint64_t entryoff;
  70. uint64_t stacksize;
  71. };
  72. #endif
  73. static struct wine_preload_info preload_info[] =
  74. {
  75. /* On macOS, we allocate the low 64k area in two steps because PAGEZERO
  76. * might not always be available. */
  77. #ifdef __i386__
  78. { (void *)0x00000000, 0x00001000 }, /* first page */
  79. { (void *)0x00001000, 0x0000f000 }, /* low 64k */
  80. { (void *)0x00010000, 0x00100000 }, /* DOS area */
  81. { (void *)0x00110000, 0x67ef0000 }, /* low memory area */
  82. { (void *)0x7f000000, 0x03000000 }, /* top-down allocations + shared user data + virtual heap */
  83. #else /* __i386__ */
  84. { (void *)0x000000001000, 0x1fffff000 }, /* WINE_RESERVE section */
  85. { (void *)0x7ff000000000, 0x01ff0000 }, /* top-down allocations + virtual heap */
  86. #endif /* __i386__ */
  87. { 0, 0 }, /* PE exe range set with WINEPRELOADRESERVE */
  88. { 0, 0 } /* end of list */
  89. };
  90. /*
  91. * These functions are only called when file is compiled with -fstack-protector.
  92. * They are normally provided by libc's startup files, but since we
  93. * build the preloader with "-nostartfiles -nodefaultlibs", we have to
  94. * provide our own versions, otherwise the linker fails.
  95. */
  96. void *__stack_chk_guard = 0;
  97. void __stack_chk_fail_local(void) { return; }
  98. void __stack_chk_fail(void) { return; }
  99. /* Binaries targeting 10.6 and 10.7 contain the __program_vars section, and
  100. * dyld4 (starting in Monterey) does not like it to be missing:
  101. * - running vmmap on a Wine process prints this warning:
  102. * "Process exists but has not fully started -- dyld has initialized but libSystem has not"
  103. * - because libSystem is not initialized, dlerror() always returns NULL (causing GStreamer
  104. * to crash on init).
  105. * - starting with macOS Sonoma, Wine crashes on launch if libSystem is not initialized.
  106. *
  107. * Adding __program_vars fixes those issues, and also allows more of the vars to
  108. * be set correctly by the preloader for the loaded binary.
  109. *
  110. * See also:
  111. * <https://github.com/apple-oss-distributions/Csu/blob/Csu-88/crt.c#L42>
  112. * <https://github.com/apple-oss-distributions/dyld/blob/dyld-1042.1/common/MachOAnalyzer.cpp#L2185>
  113. */
  114. int NXArgc = 0;
  115. const char** NXArgv = NULL;
  116. const char** environ = NULL;
  117. const char* __progname = NULL;
  118. extern void* __dso_handle;
  119. struct ProgramVars
  120. {
  121. void* mh;
  122. int* NXArgcPtr;
  123. const char*** NXArgvPtr;
  124. const char*** environPtr;
  125. const char** __prognamePtr;
  126. };
  127. __attribute__((used)) static struct ProgramVars pvars
  128. __attribute__ ((section ("__DATA,__program_vars"))) = { &__dso_handle, &NXArgc, &NXArgv, &environ, &__progname };
  129. /*
  130. * When 'start' is called, stack frame looks like:
  131. *
  132. * :
  133. * | STRING AREA |
  134. * +-------------+
  135. * | 0 |
  136. * +-------------+
  137. * | exec_path | extra "apple" parameters start after NULL terminating env array
  138. * +-------------+
  139. * | 0 |
  140. * +-------------+
  141. * | env[n] |
  142. * +-------------+
  143. * :
  144. * :
  145. * +-------------+
  146. * | env[0] |
  147. * +-------------+
  148. * | 0 |
  149. * +-------------+
  150. * | arg[argc-1] |
  151. * +-------------+
  152. * :
  153. * :
  154. * +-------------+
  155. * | arg[0] |
  156. * +-------------+
  157. * | argc | argc is always 4 bytes long, even in 64-bit architectures
  158. * +-------------+ <- sp
  159. *
  160. * Where arg[i] and env[i] point into the STRING AREA
  161. *
  162. * See also:
  163. * macOS C runtime 'start':
  164. * <https://github.com/apple-oss-distributions/Csu/blob/Csu-88/start.s>
  165. *
  166. * macOS dyld '__dyld_start' (pre-dyld4):
  167. * <https://github.com/apple-oss-distributions/dyld/blob/dyld-852.2/src/dyldStartup.s>
  168. */
  169. #ifdef __i386__
  170. static const size_t page_mask = 0xfff;
  171. #define target_mach_header mach_header
  172. #define target_segment_command segment_command
  173. #define TARGET_LC_SEGMENT LC_SEGMENT
  174. #define target_thread_state_t i386_thread_state_t
  175. #ifdef __DARWIN_UNIX03
  176. #define target_thread_ip(x) (x)->__eip
  177. #else
  178. #define target_thread_ip(x) (x)->eip
  179. #endif
  180. #define SYSCALL_FUNC( name, nr ) \
  181. __ASM_GLOBAL_FUNC( name, \
  182. "\tmovl $" #nr ",%eax\n" \
  183. "\tint $0x80\n" \
  184. "\tjnb 1f\n" \
  185. "\tmovl $-1,%eax\n" \
  186. "1:\tret\n" )
  187. #define SYSCALL_NOERR( name, nr ) \
  188. __ASM_GLOBAL_FUNC( name, \
  189. "\tmovl $" #nr ",%eax\n" \
  190. "\tint $0x80\n" \
  191. "\tret\n" )
  192. __ASM_GLOBAL_FUNC( start,
  193. __ASM_CFI("\t.cfi_undefined %eip\n")
  194. /* The first 16 bytes are used as a function signature on i386 */
  195. "\t.byte 0x6a,0x00\n" /* pushl $0: push a zero for debugger end of frames marker */
  196. "\t.byte 0x89,0xe5\n" /* movl %esp,%ebp: pointer to base of kernel frame */
  197. "\t.byte 0x83,0xe4,0xf0\n" /* andl $-16,%esp: force SSE alignment */
  198. "\t.byte 0x83,0xec,0x10\n" /* subl $16,%esp: room for new argc, argv, & envp, SSE aligned */
  199. "\t.byte 0x8b,0x5d,0x04\n" /* movl 4(%ebp),%ebx: pickup argc in %ebx */
  200. "\t.byte 0x89,0x5c,0x24,0x00\n" /* movl %ebx,0(%esp): argc to reserved stack word */
  201. /* call wld_start(stack, &is_unix_thread) */
  202. "\tleal 4(%ebp),%eax\n"
  203. "\tmovl %eax,0(%esp)\n" /* stack */
  204. "\tleal 8(%esp),%eax\n"
  205. "\tmovl %eax,4(%esp)\n" /* &is_unix_thread */
  206. "\tmovl $0,(%eax)\n"
  207. "\tcall _wld_start\n"
  208. /* jmp based on is_unix_thread */
  209. "\tcmpl $0,8(%esp)\n"
  210. "\tjne 2f\n"
  211. "\tmovl 4(%ebp),%edi\n" /* %edi = argc */
  212. "\tleal 8(%ebp),%esi\n" /* %esi = argv */
  213. "\tleal 4(%esi,%edi,4),%edx\n" /* %edx = env */
  214. "\tmovl %edx,%ecx\n"
  215. "1:\tmovl (%ecx),%ebx\n"
  216. "\tadd $4,%ecx\n"
  217. "\torl %ebx,%ebx\n" /* look for the NULL ending the env[] array */
  218. "\tjnz 1b\n" /* %ecx = apple data */
  219. /* LC_MAIN */
  220. "\tmovl %edi,0(%esp)\n" /* argc */
  221. "\tmovl %esi,4(%esp)\n" /* argv */
  222. "\tmovl %edx,8(%esp)\n" /* env */
  223. "\tmovl %ecx,12(%esp)\n" /* apple data */
  224. "\tcall *%eax\n" /* call main(argc,argv,env,apple) */
  225. "\tmovl %eax,(%esp)\n" /* pass result from main() to exit() */
  226. "\tcall _wld_exit\n" /* need to use call to keep stack aligned */
  227. "\thlt\n"
  228. /* LC_UNIXTHREAD */
  229. "\t2:movl %ebp,%esp\n" /* restore the unaligned stack pointer */
  230. "\taddl $4,%esp\n" /* remove the debugger end frame marker */
  231. "\tmovl $0,%ebp\n" /* restore ebp back to zero */
  232. "\tjmpl *%eax\n" ) /* jump to the entry point */
  233. #elif defined(__x86_64__)
  234. static const size_t page_mask = 0xfff;
  235. #define target_mach_header mach_header_64
  236. #define target_segment_command segment_command_64
  237. #define TARGET_LC_SEGMENT LC_SEGMENT_64
  238. #define target_thread_state_t x86_thread_state64_t
  239. #ifdef __DARWIN_UNIX03
  240. #define target_thread_ip(x) (x)->__rip
  241. #else
  242. #define target_thread_ip(x) (x)->rip
  243. #endif
  244. #define SYSCALL_FUNC( name, nr ) \
  245. __ASM_GLOBAL_FUNC( name, \
  246. "\tmovq %rcx, %r10\n" \
  247. "\tmovq $(" #nr "|0x2000000),%rax\n" \
  248. "\tsyscall\n" \
  249. "\tjnb 1f\n" \
  250. "\tmovq $-1,%rax\n" \
  251. "1:\tret\n" )
  252. #define SYSCALL_NOERR( name, nr ) \
  253. __ASM_GLOBAL_FUNC( name, \
  254. "\tmovq %rcx, %r10\n" \
  255. "\tmovq $(" #nr "|0x2000000),%rax\n" \
  256. "\tsyscall\n" \
  257. "\tret\n" )
  258. __ASM_GLOBAL_FUNC( start,
  259. __ASM_CFI("\t.cfi_undefined %rip\n")
  260. "\tpushq $0\n" /* push a zero for debugger end of frames marker */
  261. "\tmovq %rsp,%rbp\n" /* pointer to base of kernel frame */
  262. "\tandq $-16,%rsp\n" /* force SSE alignment */
  263. "\tsubq $16,%rsp\n" /* room for local variables */
  264. /* call wld_start(stack, &is_unix_thread) */
  265. "\tleaq 8(%rbp),%rdi\n" /* stack */
  266. "\tmovq %rsp,%rsi\n" /* &is_unix_thread */
  267. "\tmovq $0,(%rsi)\n"
  268. "\tcall _wld_start\n"
  269. /* jmp based on is_unix_thread */
  270. "\tcmpl $0,0(%rsp)\n"
  271. "\tjne 2f\n"
  272. /* LC_MAIN */
  273. "\tmovq 8(%rbp),%rdi\n" /* %rdi = argc */
  274. "\tleaq 16(%rbp),%rsi\n" /* %rsi = argv */
  275. "\tleaq 8(%rsi,%rdi,8),%rdx\n" /* %rdx = env */
  276. "\tmovq %rdx,%rcx\n"
  277. "1:\tmovq (%rcx),%r8\n"
  278. "\taddq $8,%rcx\n"
  279. "\torq %r8,%r8\n" /* look for the NULL ending the env[] array */
  280. "\tjnz 1b\n" /* %rcx = apple data */
  281. "\taddq $16,%rsp\n" /* remove local variables */
  282. "\tcall *%rax\n" /* call main(argc,argv,env,apple) */
  283. "\tmovq %rax,%rdi\n" /* pass result from main() to exit() */
  284. "\tcall _wld_exit\n" /* need to use call to keep stack aligned */
  285. "\thlt\n"
  286. /* LC_UNIXTHREAD */
  287. "\t2:movq %rbp,%rsp\n" /* restore the unaligned stack pointer */
  288. "\taddq $8,%rsp\n" /* remove the debugger end frame marker */
  289. "\tmovq $0,%rbp\n" /* restore ebp back to zero */
  290. "\tjmpq *%rax\n" ) /* jump to the entry point */
  291. #else
  292. #error preloader not implemented for this CPU
  293. #endif
  294. void wld_exit( int code ) __attribute__((noreturn));
  295. SYSCALL_NOERR( wld_exit, 1 /* SYS_exit */ );
  296. ssize_t wld_write( int fd, const void *buffer, size_t len );
  297. SYSCALL_FUNC( wld_write, 4 /* SYS_write */ );
  298. void *wld_mmap( void *start, size_t len, int prot, int flags, int fd, off_t offset );
  299. SYSCALL_FUNC( wld_mmap, 197 /* SYS_mmap */ );
  300. void *wld_munmap( void *start, size_t len );
  301. SYSCALL_FUNC( wld_munmap, 73 /* SYS_munmap */ );
  302. static intptr_t (*p_dyld_get_image_slide)( const struct target_mach_header* mh );
  303. #define MAKE_FUNCPTR(f) static typeof(f) * p##f
  304. MAKE_FUNCPTR(dlopen);
  305. MAKE_FUNCPTR(dlsym);
  306. MAKE_FUNCPTR(dladdr);
  307. #undef MAKE_FUNCPTR
  308. extern int _dyld_func_lookup( const char *dyld_func_name, void **address );
  309. /* replacement for libc functions */
  310. void * memmove( void *dst, const void *src, size_t len )
  311. {
  312. char *d = dst;
  313. const char *s = src;
  314. if (d < s)
  315. while (len--)
  316. *d++ = *s++;
  317. else
  318. {
  319. const char *lasts = s + (len-1);
  320. char *lastd = d + (len-1);
  321. while (len--)
  322. *lastd-- = *lasts--;
  323. }
  324. return dst;
  325. }
  326. static int wld_strncmp( const char *str1, const char *str2, size_t len )
  327. {
  328. if (len <= 0) return 0;
  329. while ((--len > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
  330. return *str1 - *str2;
  331. }
  332. /*
  333. * wld_printf - just the basics
  334. *
  335. * %x prints a hex number
  336. * %s prints a string
  337. * %p prints a pointer
  338. */
  339. static int wld_vsprintf(char *buffer, const char *fmt, va_list args )
  340. {
  341. static const char hex_chars[16] = "0123456789abcdef";
  342. const char *p = fmt;
  343. char *str = buffer;
  344. int i;
  345. while( *p )
  346. {
  347. if( *p == '%' )
  348. {
  349. p++;
  350. if( *p == 'x' )
  351. {
  352. unsigned int x = va_arg( args, unsigned int );
  353. for (i = 2*sizeof(x) - 1; i >= 0; i--)
  354. *str++ = hex_chars[(x>>(i*4))&0xf];
  355. }
  356. else if (p[0] == 'l' && p[1] == 'x')
  357. {
  358. unsigned long x = va_arg( args, unsigned long );
  359. for (i = 2*sizeof(x) - 1; i >= 0; i--)
  360. *str++ = hex_chars[(x>>(i*4))&0xf];
  361. p++;
  362. }
  363. else if( *p == 'p' )
  364. {
  365. unsigned long x = (unsigned long)va_arg( args, void * );
  366. for (i = 2*sizeof(x) - 1; i >= 0; i--)
  367. *str++ = hex_chars[(x>>(i*4))&0xf];
  368. }
  369. else if( *p == 's' )
  370. {
  371. char *s = va_arg( args, char * );
  372. while(*s)
  373. *str++ = *s++;
  374. }
  375. else if( *p == 0 )
  376. break;
  377. p++;
  378. }
  379. *str++ = *p++;
  380. }
  381. *str = 0;
  382. return str - buffer;
  383. }
  384. static __attribute__((format(printf,1,2))) void wld_printf(const char *fmt, ... )
  385. {
  386. va_list args;
  387. char buffer[256];
  388. int len;
  389. va_start( args, fmt );
  390. len = wld_vsprintf(buffer, fmt, args );
  391. va_end( args );
  392. wld_write(2, buffer, len);
  393. }
  394. static __attribute__((noreturn,format(printf,1,2))) void fatal_error(const char *fmt, ... )
  395. {
  396. va_list args;
  397. char buffer[256];
  398. int len;
  399. va_start( args, fmt );
  400. len = wld_vsprintf(buffer, fmt, args );
  401. va_end( args );
  402. wld_write(2, buffer, len);
  403. wld_exit(1);
  404. }
  405. static int preloader_overlaps_range( const void *start, const void *end )
  406. {
  407. intptr_t slide = p_dyld_get_image_slide(&_mh_execute_header);
  408. struct load_command *cmd = (struct load_command*)(&_mh_execute_header + 1);
  409. int i;
  410. for (i = 0; i < _mh_execute_header.ncmds; ++i)
  411. {
  412. if (cmd->cmd == TARGET_LC_SEGMENT)
  413. {
  414. struct target_segment_command *seg = (struct target_segment_command*)cmd;
  415. const void *seg_start = (const void*)(seg->vmaddr + slide);
  416. const void *seg_end = (const char*)seg_start + seg->vmsize;
  417. static const char reserved_segname[] = "WINE_RESERVE";
  418. if (!wld_strncmp( seg->segname, reserved_segname, sizeof(reserved_segname)-1 ))
  419. continue;
  420. if (end > seg_start && start <= seg_end)
  421. {
  422. char segname[sizeof(seg->segname) + 1];
  423. memcpy(segname, seg->segname, sizeof(seg->segname));
  424. segname[sizeof(segname) - 1] = 0;
  425. wld_printf( "WINEPRELOADRESERVE range %p-%p overlaps preloader %s segment %p-%p\n",
  426. start, end, segname, seg_start, seg_end );
  427. return 1;
  428. }
  429. }
  430. cmd = (struct load_command*)((char*)cmd + cmd->cmdsize);
  431. }
  432. return 0;
  433. }
  434. /*
  435. * preload_reserve
  436. *
  437. * Reserve a range specified in string format
  438. */
  439. static void preload_reserve( const char *str )
  440. {
  441. const char *p;
  442. unsigned long result = 0;
  443. void *start = NULL, *end = NULL;
  444. int i, first = 1;
  445. for (p = str; *p; p++)
  446. {
  447. if (*p >= '0' && *p <= '9') result = result * 16 + *p - '0';
  448. else if (*p >= 'a' && *p <= 'f') result = result * 16 + *p - 'a' + 10;
  449. else if (*p >= 'A' && *p <= 'F') result = result * 16 + *p - 'A' + 10;
  450. else if (*p == '-')
  451. {
  452. if (!first) goto error;
  453. start = (void *)(result & ~page_mask);
  454. result = 0;
  455. first = 0;
  456. }
  457. else goto error;
  458. }
  459. if (!first) end = (void *)((result + page_mask) & ~page_mask);
  460. else if (result) goto error; /* single value '0' is allowed */
  461. /* sanity checks */
  462. if (end <= start || preloader_overlaps_range(start, end))
  463. start = end = NULL;
  464. /* check for overlap with low memory areas */
  465. for (i = 0; preload_info[i].size; i++)
  466. {
  467. if ((char *)preload_info[i].addr > (char *)0x00110000) break;
  468. if ((char *)end <= (char *)preload_info[i].addr + preload_info[i].size)
  469. {
  470. start = end = NULL;
  471. break;
  472. }
  473. if ((char *)start < (char *)preload_info[i].addr + preload_info[i].size)
  474. start = (char *)preload_info[i].addr + preload_info[i].size;
  475. }
  476. while (preload_info[i].size) i++;
  477. preload_info[i].addr = start;
  478. preload_info[i].size = (char *)end - (char *)start;
  479. return;
  480. error:
  481. fatal_error( "invalid WINEPRELOADRESERVE value '%s'\n", str );
  482. }
  483. /* remove a range from the preload list */
  484. static void remove_preload_range( int i )
  485. {
  486. while (preload_info[i].size)
  487. {
  488. preload_info[i].addr = preload_info[i+1].addr;
  489. preload_info[i].size = preload_info[i+1].size;
  490. i++;
  491. }
  492. }
  493. static void *get_entry_point( struct target_mach_header *mh, intptr_t slide, int *unix_thread )
  494. {
  495. struct entry_point_command *entry;
  496. target_thread_state_t *state;
  497. struct load_command *cmd;
  498. int i;
  499. /* try LC_MAIN first */
  500. cmd = (struct load_command *)(mh + 1);
  501. for (i = 0; i < mh->ncmds; i++)
  502. {
  503. if (cmd->cmd == LC_MAIN)
  504. {
  505. *unix_thread = FALSE;
  506. entry = (struct entry_point_command *)cmd;
  507. return (char *)mh + entry->entryoff;
  508. }
  509. cmd = (struct load_command *)((char *)cmd + cmd->cmdsize);
  510. }
  511. /* then try LC_UNIXTHREAD */
  512. cmd = (struct load_command *)(mh + 1);
  513. for (i = 0; i < mh->ncmds; i++)
  514. {
  515. if (cmd->cmd == LC_UNIXTHREAD)
  516. {
  517. *unix_thread = TRUE;
  518. state = (target_thread_state_t *)((char *)cmd + 16);
  519. return (void *)(target_thread_ip(state) + slide);
  520. }
  521. cmd = (struct load_command *)((char *)cmd + cmd->cmdsize);
  522. }
  523. return NULL;
  524. };
  525. static int is_zerofill( struct wine_preload_info *info )
  526. {
  527. int i;
  528. for (i = 0; zerofill_sections[i].size; i++)
  529. {
  530. if ((zerofill_sections[i].addr == info->addr) &&
  531. (zerofill_sections[i].size == info->size))
  532. return 1;
  533. }
  534. return 0;
  535. }
  536. static int map_region( struct wine_preload_info *info )
  537. {
  538. int flags = MAP_PRIVATE | MAP_ANON;
  539. void *ret;
  540. if (!info->addr || is_zerofill( info )) flags |= MAP_FIXED;
  541. ret = wld_mmap( info->addr, info->size, PROT_NONE, flags, -1, 0 );
  542. if (ret == info->addr) return 1;
  543. if (ret != (void *)-1) wld_munmap( ret, info->size );
  544. /* don't warn for zero page */
  545. if (info->addr >= (void *)0x1000)
  546. wld_printf( "preloader: Warning: failed to reserve range %p-%p\n",
  547. info->addr, (char *)info->addr + info->size );
  548. return 0;
  549. }
  550. static inline void get_dyld_func( const char *name, void **func )
  551. {
  552. _dyld_func_lookup( name, func );
  553. if (!*func) fatal_error( "Failed to get function pointer for %s\n", name );
  554. }
  555. #define LOAD_POSIX_DYLD_FUNC(f) get_dyld_func( "__dyld_" #f, (void **)&p##f )
  556. #define LOAD_MACHO_DYLD_FUNC(f) get_dyld_func( "_" #f, (void **)&p##f )
  557. static void fixup_stack( void *stack )
  558. {
  559. int *pargc;
  560. char **argv, **env_new;
  561. static char dummyvar[] = "WINEPRELOADERDUMMYVAR=1";
  562. pargc = stack;
  563. argv = (char **)pargc + 1;
  564. /* decrement argc, and "remove" argv[0] */
  565. *pargc = *pargc - 1;
  566. memmove( &argv[0], &argv[1], (*pargc + 1) * sizeof(char *) );
  567. env_new = &argv[*pargc-1] + 2;
  568. /* In the launched binary on some OSes, _NSGetEnviron() returns
  569. * the original 'environ' pointer, so env_new[0] would be ignored.
  570. * Put a dummy variable in env_new[0], so nothing is lost in this case.
  571. */
  572. env_new[0] = dummyvar;
  573. }
  574. static void set_program_vars( void *stack, void *mod )
  575. {
  576. int *pargc;
  577. const char **argv, **env;
  578. int *wine_NXArgc = pdlsym( mod, "NXArgc" );
  579. const char ***wine_NXArgv = pdlsym( mod, "NXArgv" );
  580. const char ***wine_environ = pdlsym( mod, "environ" );
  581. pargc = stack;
  582. argv = (const char **)pargc + 1;
  583. env = &argv[*pargc-1] + 2;
  584. /* set vars in the loaded binary */
  585. if (wine_NXArgc)
  586. *wine_NXArgc = *pargc;
  587. else
  588. wld_printf( "preloader: Warning: failed to set NXArgc\n" );
  589. if (wine_NXArgv)
  590. *wine_NXArgv = argv;
  591. else
  592. wld_printf( "preloader: Warning: failed to set NXArgv\n" );
  593. if (wine_environ)
  594. *wine_environ = env;
  595. else
  596. wld_printf( "preloader: Warning: failed to set environ\n" );
  597. /* set vars in the __program_vars section */
  598. NXArgc = *pargc;
  599. NXArgv = argv;
  600. environ = env;
  601. }
  602. void *wld_start( void *stack, int *is_unix_thread )
  603. {
  604. #ifdef __i386__
  605. struct wine_preload_info builtin_dlls = { (void *)0x7a000000, 0x02000000 };
  606. #endif
  607. struct wine_preload_info **wine_main_preload_info;
  608. char **argv, **p, *reserve = NULL;
  609. struct target_mach_header *mh;
  610. void *mod, *entry;
  611. int *pargc, i;
  612. Dl_info info;
  613. pargc = stack;
  614. argv = (char **)pargc + 1;
  615. if (*pargc < 2) fatal_error( "Usage: %s wine_binary [args]\n", argv[0] );
  616. /* skip over the parameters */
  617. p = argv + *pargc + 1;
  618. /* skip over the environment */
  619. while (*p)
  620. {
  621. static const char res[] = "WINEPRELOADRESERVE=";
  622. if (!wld_strncmp( *p, res, sizeof(res)-1 )) reserve = *p + sizeof(res) - 1;
  623. p++;
  624. }
  625. LOAD_POSIX_DYLD_FUNC( dlopen );
  626. LOAD_POSIX_DYLD_FUNC( dlsym );
  627. LOAD_POSIX_DYLD_FUNC( dladdr );
  628. LOAD_MACHO_DYLD_FUNC( _dyld_get_image_slide );
  629. /* reserve memory that Wine needs */
  630. if (reserve) preload_reserve( reserve );
  631. for (i = 0; preload_info[i].size; i++)
  632. {
  633. if (!map_region( &preload_info[i] ))
  634. {
  635. remove_preload_range( i );
  636. i--;
  637. }
  638. }
  639. #ifdef __i386__
  640. if (!map_region( &builtin_dlls ))
  641. builtin_dlls.size = 0;
  642. #endif
  643. /* load the main binary */
  644. if (!(mod = pdlopen( argv[1], RTLD_NOW )))
  645. fatal_error( "%s: could not load binary\n", argv[1] );
  646. #ifdef __i386__
  647. if (builtin_dlls.size)
  648. wld_munmap( builtin_dlls.addr, builtin_dlls.size );
  649. #endif
  650. /* store pointer to the preload info into the appropriate main binary variable */
  651. wine_main_preload_info = pdlsym( mod, "wine_main_preload_info" );
  652. if (wine_main_preload_info) *wine_main_preload_info = preload_info;
  653. else wld_printf( "wine_main_preload_info not found\n" );
  654. if (!pdladdr( wine_main_preload_info, &info ) || !(mh = info.dli_fbase))
  655. fatal_error( "%s: could not find mach header\n", argv[1] );
  656. if (!(entry = get_entry_point( mh, p_dyld_get_image_slide(mh), is_unix_thread )))
  657. fatal_error( "%s: could not find entry point\n", argv[1] );
  658. /* decrement argc and "remove" argv[0] */
  659. fixup_stack(stack);
  660. /* Set NXArgc, NXArgv, and environ in the new binary.
  661. * On different configurations these were either NULL/0 or still had their
  662. * values from this preloader's launch.
  663. *
  664. * In particular, environ was not being updated, resulting in environ[0] being lost.
  665. * And for LC_UNIXTHREAD binaries on Monterey and later, environ was just NULL.
  666. */
  667. set_program_vars( stack, mod );
  668. return entry;
  669. }
  670. #endif /* __APPLE__ */