preloader_mac.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  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 "wine/port.h"
  27. #include <stdarg.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <sys/types.h>
  32. #ifdef HAVE_SYS_STAT_H
  33. # include <sys/stat.h>
  34. #endif
  35. #include <fcntl.h>
  36. #ifdef HAVE_SYS_MMAN_H
  37. # include <sys/mman.h>
  38. #endif
  39. #ifdef HAVE_SYS_SYSCALL_H
  40. # include <sys/syscall.h>
  41. #endif
  42. #ifdef HAVE_UNISTD_H
  43. # include <unistd.h>
  44. #endif
  45. #ifdef HAVE_MACH_O_LOADER_H
  46. #include <mach/thread_status.h>
  47. #include <mach-o/loader.h>
  48. #include <mach-o/ldsyms.h>
  49. #endif
  50. #include "wine/asm.h"
  51. #include "main.h"
  52. /* Rosetta on Apple Silicon allocates memory starting at 0x100000000 (the 4GB line)
  53. * before the preloader runs, which prevents any nonrelocatable EXEs with that
  54. * base address from running.
  55. *
  56. * This empty linker section forces Rosetta's allocations (currently ~132 MB)
  57. * to start at 0x114000000, and they should end below 0x120000000.
  58. */
  59. #if defined(__x86_64__)
  60. __asm__(".zerofill WINE_4GB_RESERVE,WINE_4GB_RESERVE,___wine_4gb_reserve,0x14000000");
  61. #endif
  62. #ifndef LC_MAIN
  63. #define LC_MAIN 0x80000028
  64. struct entry_point_command
  65. {
  66. uint32_t cmd;
  67. uint32_t cmdsize;
  68. uint64_t entryoff;
  69. uint64_t stacksize;
  70. };
  71. #endif
  72. static struct wine_preload_info preload_info[] =
  73. {
  74. /* On macOS, we allocate the low 64k area in two steps because PAGEZERO
  75. * might not always be available. */
  76. #ifdef __i386__
  77. { (void *)0x00000000, 0x00001000 }, /* first page */
  78. { (void *)0x00001000, 0x0000f000 }, /* low 64k */
  79. { (void *)0x00010000, 0x00100000 }, /* DOS area */
  80. { (void *)0x00110000, 0x67ef0000 }, /* low memory area */
  81. { (void *)0x7f000000, 0x03000000 }, /* top-down allocations + shared heap + virtual heap */
  82. #else /* __i386__ */
  83. { (void *)0x000000010000, 0x00100000 }, /* DOS area */
  84. { (void *)0x000000110000, 0x67ef0000 }, /* low memory area */
  85. { (void *)0x00007ff00000, 0x000f0000 }, /* shared user data */
  86. { (void *)0x000100000000, 0x14000000 }, /* WINE_4GB_RESERVE section */
  87. { (void *)0x7ffd00000000, 0x01ff0000 }, /* top-down allocations + virtual heap */
  88. #endif /* __i386__ */
  89. { 0, 0 }, /* PE exe range set with WINEPRELOADRESERVE */
  90. { 0, 0 } /* end of list */
  91. };
  92. /*
  93. * These functions are only called when file is compiled with -fstack-protector.
  94. * They are normally provided by libc's startup files, but since we
  95. * build the preloader with "-nostartfiles -nodefaultlibs", we have to
  96. * provide our own versions, otherwise the linker fails.
  97. */
  98. void *__stack_chk_guard = 0;
  99. void __stack_chk_fail_local(void) { return; }
  100. void __stack_chk_fail(void) { return; }
  101. #ifdef __i386__
  102. static const size_t page_size = 0x1000;
  103. static const size_t page_mask = 0xfff;
  104. #define target_mach_header mach_header
  105. #define target_segment_command segment_command
  106. #define TARGET_LC_SEGMENT LC_SEGMENT
  107. #define target_thread_state_t i386_thread_state_t
  108. #ifdef __DARWIN_UNIX03
  109. #define target_thread_ip(x) (x)->__eip
  110. #else
  111. #define target_thread_ip(x) (x)->eip
  112. #endif
  113. #define SYSCALL_FUNC( name, nr ) \
  114. __ASM_GLOBAL_FUNC( name, \
  115. "\tmovl $" #nr ",%eax\n" \
  116. "\tint $0x80\n" \
  117. "\tjnb 1f\n" \
  118. "\tmovl $-1,%eax\n" \
  119. "1:\tret\n" )
  120. #define SYSCALL_NOERR( name, nr ) \
  121. __ASM_GLOBAL_FUNC( name, \
  122. "\tmovl $" #nr ",%eax\n" \
  123. "\tint $0x80\n" \
  124. "\tret\n" )
  125. __ASM_GLOBAL_FUNC( start,
  126. __ASM_CFI("\t.cfi_undefined %eip\n")
  127. /* The first 16 bytes are used as a function signature on i386 */
  128. "\t.byte 0x6a,0x00\n" /* pushl $0 */
  129. "\t.byte 0x89,0xe5\n" /* movl %esp,%ebp */
  130. "\t.byte 0x83,0xe4,0xf0\n" /* andl $-16,%esp */
  131. "\t.byte 0x83,0xec,0x10\n" /* subl $16,%esp */
  132. "\t.byte 0x8b,0x5d,0x04\n" /* movl 4(%ebp),%ebx */
  133. "\t.byte 0x89,0x5c,0x24,0x00\n" /* movl %ebx,0(%esp) */
  134. "\tleal 4(%ebp),%eax\n"
  135. "\tmovl %eax,0(%esp)\n" /* stack */
  136. "\tleal 8(%esp),%eax\n"
  137. "\tmovl %eax,4(%esp)\n" /* &is_unix_thread */
  138. "\tmovl $0,(%eax)\n"
  139. "\tcall _wld_start\n"
  140. "\tmovl 4(%ebp),%edi\n"
  141. "\tdecl %edi\n" /* argc */
  142. "\tleal 12(%ebp),%esi\n" /* argv */
  143. "\tleal 4(%esi,%edi,4),%edx\n" /* env */
  144. "\tmovl %edx,%ecx\n" /* apple data */
  145. "1:\tmovl (%ecx),%ebx\n"
  146. "\tadd $4,%ecx\n"
  147. "\torl %ebx,%ebx\n"
  148. "\tjnz 1b\n"
  149. "\tcmpl $0,8(%esp)\n"
  150. "\tjne 2f\n"
  151. /* LC_MAIN */
  152. "\tmovl %edi,0(%esp)\n" /* argc */
  153. "\tmovl %esi,4(%esp)\n" /* argv */
  154. "\tmovl %edx,8(%esp)\n" /* env */
  155. "\tmovl %ecx,12(%esp)\n" /* apple data */
  156. "\tcall *%eax\n"
  157. "\tmovl %eax,(%esp)\n"
  158. "\tcall _wld_exit\n"
  159. "\thlt\n"
  160. /* LC_UNIXTHREAD */
  161. "2:\tmovl (%ecx),%ebx\n"
  162. "\tadd $4,%ecx\n"
  163. "\torl %ebx,%ebx\n"
  164. "\tjnz 2b\n"
  165. "\tsubl %ebp,%ecx\n"
  166. "\tsubl $8,%ecx\n"
  167. "\tleal 4(%ebp),%esp\n"
  168. "\tsubl %ecx,%esp\n"
  169. "\tmovl %edi,(%esp)\n" /* argc */
  170. "\tleal 4(%esp),%edi\n"
  171. "\tshrl $2,%ecx\n"
  172. "\tcld\n"
  173. "\trep; movsd\n" /* argv, ... */
  174. "\tmovl $0,%ebp\n"
  175. "\tjmpl *%eax\n" )
  176. #elif defined(__x86_64__)
  177. static const size_t page_size = 0x1000;
  178. static const size_t page_mask = 0xfff;
  179. #define target_mach_header mach_header_64
  180. #define target_segment_command segment_command_64
  181. #define TARGET_LC_SEGMENT LC_SEGMENT_64
  182. #define target_thread_state_t x86_thread_state64_t
  183. #ifdef __DARWIN_UNIX03
  184. #define target_thread_ip(x) (x)->__rip
  185. #else
  186. #define target_thread_ip(x) (x)->rip
  187. #endif
  188. #define SYSCALL_FUNC( name, nr ) \
  189. __ASM_GLOBAL_FUNC( name, \
  190. "\tmovq %rcx, %r10\n" \
  191. "\tmovq $(" #nr "|0x2000000),%rax\n" \
  192. "\tsyscall\n" \
  193. "\tjnb 1f\n" \
  194. "\tmovq $-1,%rax\n" \
  195. "1:\tret\n" )
  196. #define SYSCALL_NOERR( name, nr ) \
  197. __ASM_GLOBAL_FUNC( name, \
  198. "\tmovq %rcx, %r10\n" \
  199. "\tmovq $(" #nr "|0x2000000),%rax\n" \
  200. "\tsyscall\n" \
  201. "\tret\n" )
  202. __ASM_GLOBAL_FUNC( start,
  203. __ASM_CFI("\t.cfi_undefined %rip\n")
  204. "\tpushq $0\n"
  205. "\tmovq %rsp,%rbp\n"
  206. "\tandq $-16,%rsp\n"
  207. "\tsubq $16,%rsp\n"
  208. "\tleaq 8(%rbp),%rdi\n" /* stack */
  209. "\tmovq %rsp,%rsi\n" /* &is_unix_thread */
  210. "\tmovq $0,(%rsi)\n"
  211. "\tcall _wld_start\n"
  212. "\tmovq 8(%rbp),%rdi\n"
  213. "\tdec %rdi\n" /* argc */
  214. "\tleaq 24(%rbp),%rsi\n" /* argv */
  215. "\tleaq 8(%rsi,%rdi,8),%rdx\n" /* env */
  216. "\tmovq %rdx,%rcx\n" /* apple data */
  217. "1:\tmovq (%rcx),%r8\n"
  218. "\taddq $8,%rcx\n"
  219. "\torq %r8,%r8\n"
  220. "\tjnz 1b\n"
  221. "\tcmpl $0,0(%rsp)\n"
  222. "\tjne 2f\n"
  223. /* LC_MAIN */
  224. "\taddq $16,%rsp\n"
  225. "\tcall *%rax\n"
  226. "\tmovq %rax,%rdi\n"
  227. "\tcall _wld_exit\n"
  228. "\thlt\n"
  229. /* LC_UNIXTHREAD */
  230. "2:\tmovq (%rcx),%r8\n"
  231. "\taddq $8,%rcx\n"
  232. "\torq %r8,%r8\n"
  233. "\tjnz 2b\n"
  234. "\tsubq %rbp,%rcx\n"
  235. "\tsubq $16,%rcx\n"
  236. "\tleaq 8(%rbp),%rsp\n"
  237. "\tsubq %rcx,%rsp\n"
  238. "\tmovq %rdi,(%rsp)\n" /* argc */
  239. "\tleaq 8(%rsp),%rdi\n"
  240. "\tshrq $3,%rcx\n"
  241. "\tcld\n"
  242. "\trep; movsq\n" /* argv, ... */
  243. "\tmovq $0,%rbp\n"
  244. "\tjmpq *%rax\n" )
  245. #else
  246. #error preloader not implemented for this CPU
  247. #endif
  248. void wld_exit( int code ) __attribute__((noreturn));
  249. SYSCALL_NOERR( wld_exit, 1 /* SYS_exit */ );
  250. ssize_t wld_write( int fd, const void *buffer, size_t len );
  251. SYSCALL_FUNC( wld_write, 4 /* SYS_write */ );
  252. void *wld_mmap( void *start, size_t len, int prot, int flags, int fd, off_t offset );
  253. SYSCALL_FUNC( wld_mmap, 197 /* SYS_mmap */ );
  254. void *wld_munmap( void *start, size_t len );
  255. SYSCALL_FUNC( wld_munmap, 73 /* SYS_munmap */ );
  256. int wld_mincore( void *addr, size_t length, unsigned char *vec );
  257. SYSCALL_FUNC( wld_mincore, 78 /* SYS_mincore */ );
  258. static intptr_t (*p_dyld_get_image_slide)( const struct target_mach_header* mh );
  259. #define MAKE_FUNCPTR(f) static typeof(f) * p##f
  260. MAKE_FUNCPTR(dlopen);
  261. MAKE_FUNCPTR(dlsym);
  262. MAKE_FUNCPTR(dladdr);
  263. #undef MAKE_FUNCPTR
  264. extern int _dyld_func_lookup( const char *dyld_func_name, void **address );
  265. /* replacement for libc functions */
  266. static int wld_strncmp( const char *str1, const char *str2, size_t len )
  267. {
  268. if (len <= 0) return 0;
  269. while ((--len > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
  270. return *str1 - *str2;
  271. }
  272. /*
  273. * wld_printf - just the basics
  274. *
  275. * %x prints a hex number
  276. * %s prints a string
  277. * %p prints a pointer
  278. */
  279. static int wld_vsprintf(char *buffer, const char *fmt, va_list args )
  280. {
  281. static const char hex_chars[16] = "0123456789abcdef";
  282. const char *p = fmt;
  283. char *str = buffer;
  284. int i;
  285. while( *p )
  286. {
  287. if( *p == '%' )
  288. {
  289. p++;
  290. if( *p == 'x' )
  291. {
  292. unsigned int x = va_arg( args, unsigned int );
  293. for (i = 2*sizeof(x) - 1; i >= 0; i--)
  294. *str++ = hex_chars[(x>>(i*4))&0xf];
  295. }
  296. else if (p[0] == 'l' && p[1] == 'x')
  297. {
  298. unsigned long x = va_arg( args, unsigned long );
  299. for (i = 2*sizeof(x) - 1; i >= 0; i--)
  300. *str++ = hex_chars[(x>>(i*4))&0xf];
  301. p++;
  302. }
  303. else if( *p == 'p' )
  304. {
  305. unsigned long x = (unsigned long)va_arg( args, void * );
  306. for (i = 2*sizeof(x) - 1; i >= 0; i--)
  307. *str++ = hex_chars[(x>>(i*4))&0xf];
  308. }
  309. else if( *p == 's' )
  310. {
  311. char *s = va_arg( args, char * );
  312. while(*s)
  313. *str++ = *s++;
  314. }
  315. else if( *p == 0 )
  316. break;
  317. p++;
  318. }
  319. *str++ = *p++;
  320. }
  321. *str = 0;
  322. return str - buffer;
  323. }
  324. static __attribute__((format(printf,1,2))) void wld_printf(const char *fmt, ... )
  325. {
  326. va_list args;
  327. char buffer[256];
  328. int len;
  329. va_start( args, fmt );
  330. len = wld_vsprintf(buffer, fmt, args );
  331. va_end( args );
  332. wld_write(2, buffer, len);
  333. }
  334. static __attribute__((noreturn,format(printf,1,2))) void fatal_error(const char *fmt, ... )
  335. {
  336. va_list args;
  337. char buffer[256];
  338. int len;
  339. va_start( args, fmt );
  340. len = wld_vsprintf(buffer, fmt, args );
  341. va_end( args );
  342. wld_write(2, buffer, len);
  343. wld_exit(1);
  344. }
  345. static int preloader_overlaps_range( const void *start, const void *end )
  346. {
  347. intptr_t slide = p_dyld_get_image_slide(&_mh_execute_header);
  348. struct load_command *cmd = (struct load_command*)(&_mh_execute_header + 1);
  349. int i;
  350. for (i = 0; i < _mh_execute_header.ncmds; ++i)
  351. {
  352. if (cmd->cmd == TARGET_LC_SEGMENT)
  353. {
  354. struct target_segment_command *seg = (struct target_segment_command*)cmd;
  355. const void *seg_start = (const void*)(seg->vmaddr + slide);
  356. const void *seg_end = (const char*)seg_start + seg->vmsize;
  357. static const char reserved_segname[] = "WINE_4GB_RESERVE";
  358. if (!wld_strncmp( seg->segname, reserved_segname, sizeof(reserved_segname)-1 ))
  359. continue;
  360. if (end > seg_start && start <= seg_end)
  361. {
  362. char segname[sizeof(seg->segname) + 1];
  363. memcpy(segname, seg->segname, sizeof(seg->segname));
  364. segname[sizeof(segname) - 1] = 0;
  365. wld_printf( "WINEPRELOADRESERVE range %p-%p overlaps preloader %s segment %p-%p\n",
  366. start, end, segname, seg_start, seg_end );
  367. return 1;
  368. }
  369. }
  370. cmd = (struct load_command*)((char*)cmd + cmd->cmdsize);
  371. }
  372. return 0;
  373. }
  374. /*
  375. * preload_reserve
  376. *
  377. * Reserve a range specified in string format
  378. */
  379. static void preload_reserve( const char *str )
  380. {
  381. const char *p;
  382. unsigned long result = 0;
  383. void *start = NULL, *end = NULL;
  384. int i, first = 1;
  385. for (p = str; *p; p++)
  386. {
  387. if (*p >= '0' && *p <= '9') result = result * 16 + *p - '0';
  388. else if (*p >= 'a' && *p <= 'f') result = result * 16 + *p - 'a' + 10;
  389. else if (*p >= 'A' && *p <= 'F') result = result * 16 + *p - 'A' + 10;
  390. else if (*p == '-')
  391. {
  392. if (!first) goto error;
  393. start = (void *)(result & ~page_mask);
  394. result = 0;
  395. first = 0;
  396. }
  397. else goto error;
  398. }
  399. if (!first) end = (void *)((result + page_mask) & ~page_mask);
  400. else if (result) goto error; /* single value '0' is allowed */
  401. /* sanity checks */
  402. if (end <= start || preloader_overlaps_range(start, end))
  403. start = end = NULL;
  404. /* check for overlap with low memory areas */
  405. for (i = 0; preload_info[i].size; i++)
  406. {
  407. if ((char *)preload_info[i].addr > (char *)0x00110000) break;
  408. if ((char *)end <= (char *)preload_info[i].addr + preload_info[i].size)
  409. {
  410. start = end = NULL;
  411. break;
  412. }
  413. if ((char *)start < (char *)preload_info[i].addr + preload_info[i].size)
  414. start = (char *)preload_info[i].addr + preload_info[i].size;
  415. }
  416. while (preload_info[i].size) i++;
  417. preload_info[i].addr = start;
  418. preload_info[i].size = (char *)end - (char *)start;
  419. return;
  420. error:
  421. fatal_error( "invalid WINEPRELOADRESERVE value '%s'\n", str );
  422. }
  423. /* remove a range from the preload list */
  424. static void remove_preload_range( int i )
  425. {
  426. while (preload_info[i].size)
  427. {
  428. preload_info[i].addr = preload_info[i+1].addr;
  429. preload_info[i].size = preload_info[i+1].size;
  430. i++;
  431. }
  432. }
  433. static void *get_entry_point( struct target_mach_header *mh, intptr_t slide, int *unix_thread )
  434. {
  435. struct entry_point_command *entry;
  436. target_thread_state_t *state;
  437. struct load_command *cmd;
  438. int i;
  439. /* try LC_MAIN first */
  440. cmd = (struct load_command *)(mh + 1);
  441. for (i = 0; i < mh->ncmds; i++)
  442. {
  443. if (cmd->cmd == LC_MAIN)
  444. {
  445. *unix_thread = FALSE;
  446. entry = (struct entry_point_command *)cmd;
  447. return (char *)mh + entry->entryoff;
  448. }
  449. cmd = (struct load_command *)((char *)cmd + cmd->cmdsize);
  450. }
  451. /* then try LC_UNIXTHREAD */
  452. cmd = (struct load_command *)(mh + 1);
  453. for (i = 0; i < mh->ncmds; i++)
  454. {
  455. if (cmd->cmd == LC_UNIXTHREAD)
  456. {
  457. *unix_thread = TRUE;
  458. state = (target_thread_state_t *)((char *)cmd + 16);
  459. return (void *)(target_thread_ip(state) + slide);
  460. }
  461. cmd = (struct load_command *)((char *)cmd + cmd->cmdsize);
  462. }
  463. return NULL;
  464. };
  465. static int is_region_empty( struct wine_preload_info *info )
  466. {
  467. unsigned char vec[1024];
  468. size_t pos, size, block = 1024 * page_size;
  469. int i;
  470. for (pos = 0; pos < info->size; pos += size)
  471. {
  472. size = (pos + block <= info->size) ? block : (info->size - pos);
  473. if (wld_mincore( (char *)info->addr + pos, size, vec ) == -1)
  474. {
  475. if (size <= page_size) continue;
  476. block = page_size; size = 0; /* retry with smaller block size */
  477. }
  478. else
  479. {
  480. for (i = 0; i < size / page_size; i++)
  481. if (vec[i] & 1) return 0;
  482. }
  483. }
  484. return 1;
  485. }
  486. static int map_region( struct wine_preload_info *info )
  487. {
  488. int flags = MAP_PRIVATE | MAP_ANON;
  489. void *ret;
  490. if (!info->addr) flags |= MAP_FIXED;
  491. for (;;)
  492. {
  493. ret = wld_mmap( info->addr, info->size, PROT_NONE, flags, -1, 0 );
  494. if (ret == info->addr) return 1;
  495. if (ret != (void *)-1) wld_munmap( ret, info->size );
  496. if (flags & MAP_FIXED) break;
  497. /* Some versions of macOS ignore the address hint passed to mmap -
  498. * use mincore() to check if its empty and then use MAP_FIXED */
  499. if (!is_region_empty( info )) break;
  500. flags |= MAP_FIXED;
  501. }
  502. /* don't warn for zero page */
  503. if (info->addr >= (void *)0x1000)
  504. wld_printf( "preloader: Warning: failed to reserve range %p-%p\n",
  505. info->addr, (char *)info->addr + info->size );
  506. return 0;
  507. }
  508. static inline void get_dyld_func( const char *name, void **func )
  509. {
  510. _dyld_func_lookup( name, func );
  511. if (!*func) fatal_error( "Failed to get function pointer for %s\n", name );
  512. }
  513. #define LOAD_POSIX_DYLD_FUNC(f) get_dyld_func( "__dyld_" #f, (void **)&p##f )
  514. #define LOAD_MACHO_DYLD_FUNC(f) get_dyld_func( "_" #f, (void **)&p##f )
  515. void *wld_start( void *stack, int *is_unix_thread )
  516. {
  517. struct wine_preload_info builtin_dlls = { (void *)0x7a000000, 0x02000000 };
  518. struct wine_preload_info **wine_main_preload_info;
  519. char **argv, **p, *reserve = NULL;
  520. struct target_mach_header *mh;
  521. void *mod, *entry;
  522. int *pargc, i;
  523. Dl_info info;
  524. pargc = stack;
  525. argv = (char **)pargc + 1;
  526. if (*pargc < 2) fatal_error( "Usage: %s wine_binary [args]\n", argv[0] );
  527. /* skip over the parameters */
  528. p = argv + *pargc + 1;
  529. /* skip over the environment */
  530. while (*p)
  531. {
  532. static const char res[] = "WINEPRELOADRESERVE=";
  533. if (!wld_strncmp( *p, res, sizeof(res)-1 )) reserve = *p + sizeof(res) - 1;
  534. p++;
  535. }
  536. LOAD_POSIX_DYLD_FUNC( dlopen );
  537. LOAD_POSIX_DYLD_FUNC( dlsym );
  538. LOAD_POSIX_DYLD_FUNC( dladdr );
  539. LOAD_MACHO_DYLD_FUNC( _dyld_get_image_slide );
  540. /* reserve memory that Wine needs */
  541. if (reserve) preload_reserve( reserve );
  542. for (i = 0; preload_info[i].size; i++)
  543. {
  544. if (!map_region( &preload_info[i] ))
  545. {
  546. remove_preload_range( i );
  547. i--;
  548. }
  549. }
  550. if (!map_region( &builtin_dlls ))
  551. builtin_dlls.size = 0;
  552. /* load the main binary */
  553. if (!(mod = pdlopen( argv[1], RTLD_NOW )))
  554. fatal_error( "%s: could not load binary\n", argv[1] );
  555. if (builtin_dlls.size)
  556. wld_munmap( builtin_dlls.addr, builtin_dlls.size );
  557. /* store pointer to the preload info into the appropriate main binary variable */
  558. wine_main_preload_info = pdlsym( mod, "wine_main_preload_info" );
  559. if (wine_main_preload_info) *wine_main_preload_info = preload_info;
  560. else wld_printf( "wine_main_preload_info not found\n" );
  561. if (!pdladdr( wine_main_preload_info, &info ) || !(mh = info.dli_fbase))
  562. fatal_error( "%s: could not find mach header\n", argv[1] );
  563. if (!(entry = get_entry_point( mh, p_dyld_get_image_slide(mh), is_unix_thread )))
  564. fatal_error( "%s: could not find entry point\n", argv[1] );
  565. return entry;
  566. }
  567. #endif /* __APPLE__ */