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
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.
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.
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
28 #include "wine/port.h"
34 #include <sys/types.h>
35 #ifdef HAVE_SYS_STAT_H
36 # include <sys/stat.h>
39 #ifdef HAVE_SYS_MMAN_H
40 # include <sys/mman.h>
42 #ifdef HAVE_SYS_SYSCALL_H
43 # include <sys/syscall.h>
48 #ifdef HAVE_MACH_O_LOADER_H
49 #include <mach/thread_status.h>
50 #include <mach-o/loader.h>
51 #include <mach-o/ldsyms.h>
58 #define LC_MAIN 0x80000028
59 struct entry_point_command
68 static struct wine_preload_info preload_info
[] =
70 /* On macOS, we allocate the low 64k area in two steps because PAGEZERO
71 * might not always be available. */
73 { (void *)0x00000000, 0x00001000 }, /* first page */
74 { (void *)0x00001000, 0x0000f000 }, /* low 64k */
75 { (void *)0x00010000, 0x00100000 }, /* DOS area */
76 { (void *)0x00110000, 0x67ef0000 }, /* low memory area */
77 { (void *)0x7f000000, 0x03000000 }, /* top-down allocations + shared heap + virtual heap */
79 { (void *)0x000000010000, 0x00100000 }, /* DOS area */
80 { (void *)0x000000110000, 0x67ef0000 }, /* low memory area */
81 { (void *)0x00007ff00000, 0x000f0000 }, /* shared user data */
82 { (void *)0x7ffd00000000, 0x01ff0000 }, /* top-down allocations + virtual heap */
84 { 0, 0 }, /* PE exe range set with WINEPRELOADRESERVE */
85 { 0, 0 } /* end of list */
89 * These functions are only called when file is compiled with -fstack-protector.
90 * They are normally provided by libc's startup files, but since we
91 * build the preloader with "-nostartfiles -nodefaultlibs", we have to
92 * provide our own versions, otherwise the linker fails.
94 void *__stack_chk_guard
= 0;
95 void __stack_chk_fail_local(void) { return; }
96 void __stack_chk_fail(void) { return; }
100 static const size_t page_size
= 0x1000;
101 static const size_t page_mask
= 0xfff;
102 #define target_mach_header mach_header
103 #define target_segment_command segment_command
104 #define TARGET_LC_SEGMENT LC_SEGMENT
105 #define target_thread_state_t i386_thread_state_t
106 #ifdef __DARWIN_UNIX03
107 #define target_thread_ip(x) (x)->__eip
109 #define target_thread_ip(x) (x)->eip
112 #define SYSCALL_FUNC( name, nr ) \
113 __ASM_GLOBAL_FUNC( name, \
114 "\tmovl $" #nr ",%eax\n" \
117 "\tmovl $-1,%eax\n" \
120 #define SYSCALL_NOERR( name, nr ) \
121 __ASM_GLOBAL_FUNC( name, \
122 "\tmovl $" #nr ",%eax\n" \
126 __ASM_GLOBAL_FUNC( start
,
127 __ASM_CFI("\t.cfi_undefined %eip\n")
128 /* The first 16 bytes are used as a function signature on i386 */
129 "\t.byte 0x6a,0x00\n" /* pushl $0 */
130 "\t.byte 0x89,0xe5\n" /* movl %esp,%ebp */
131 "\t.byte 0x83,0xe4,0xf0\n" /* andl $-16,%esp */
132 "\t.byte 0x83,0xec,0x10\n" /* subl $16,%esp */
133 "\t.byte 0x8b,0x5d,0x04\n" /* movl 4(%ebp),%ebx */
134 "\t.byte 0x89,0x5c,0x24,0x00\n" /* movl %ebx,0(%esp) */
136 "\tleal 4(%ebp),%eax\n"
137 "\tmovl %eax,0(%esp)\n" /* stack */
138 "\tleal 8(%esp),%eax\n"
139 "\tmovl %eax,4(%esp)\n" /* &is_unix_thread */
141 "\tcall _wld_start\n"
143 "\tmovl 4(%ebp),%edi\n"
144 "\tdecl %edi\n" /* argc */
145 "\tleal 12(%ebp),%esi\n" /* argv */
146 "\tleal 4(%esi,%edi,4),%edx\n" /* env */
147 "\tmovl %edx,%ecx\n" /* apple data */
148 "1:\tmovl (%ecx),%ebx\n"
153 "\tcmpl $0,8(%esp)\n"
157 "\tmovl %edi,0(%esp)\n" /* argc */
158 "\tmovl %esi,4(%esp)\n" /* argv */
159 "\tmovl %edx,8(%esp)\n" /* env */
160 "\tmovl %ecx,12(%esp)\n" /* apple data */
162 "\tmovl %eax,(%esp)\n"
167 "2:\tmovl (%ecx),%ebx\n"
174 "\tleal 4(%ebp),%esp\n"
177 "\tmovl %edi,(%esp)\n" /* argc */
178 "\tleal 4(%esp),%edi\n"
181 "\trep; movsd\n" /* argv, ... */
186 #elif defined(__x86_64__)
188 static const size_t page_size
= 0x1000;
189 static const size_t page_mask
= 0xfff;
190 #define target_mach_header mach_header_64
191 #define target_segment_command segment_command_64
192 #define TARGET_LC_SEGMENT LC_SEGMENT_64
193 #define target_thread_state_t x86_thread_state64_t
194 #ifdef __DARWIN_UNIX03
195 #define target_thread_ip(x) (x)->__rip
197 #define target_thread_ip(x) (x)->rip
200 #define SYSCALL_FUNC( name, nr ) \
201 __ASM_GLOBAL_FUNC( name, \
202 "\tmovq %rcx, %r10\n" \
203 "\tmovq $(" #nr "|0x2000000),%rax\n" \
206 "\tmovq $-1,%rax\n" \
209 #define SYSCALL_NOERR( name, nr ) \
210 __ASM_GLOBAL_FUNC( name, \
211 "\tmovq %rcx, %r10\n" \
212 "\tmovq $(" #nr "|0x2000000),%rax\n" \
216 __ASM_GLOBAL_FUNC( start
,
217 __ASM_CFI("\t.cfi_undefined %rip\n")
223 "\tleaq 8(%rbp),%rdi\n" /* stack */
224 "\tmovq %rsp,%rsi\n" /* &is_unix_thread */
226 "\tcall _wld_start\n"
228 "\tmovq 8(%rbp),%rdi\n"
229 "\tdec %rdi\n" /* argc */
230 "\tleaq 24(%rbp),%rsi\n" /* argv */
231 "\tleaq 8(%rsi,%rdi,8),%rdx\n" /* env */
232 "\tmovq %rdx,%rcx\n" /* apple data */
233 "1:\tmovq (%rcx),%r8\n"
238 "\tcmpl $0,0(%rsp)\n"
249 "2:\tmovq (%rcx),%r8\n"
256 "\tleaq 8(%rbp),%rsp\n"
259 "\tmovq %rdi,(%rsp)\n" /* argc */
260 "\tleaq 8(%rsp),%rdi\n"
263 "\trep; movsq\n" /* argv, ... */
269 #error preloader not implemented for this CPU
272 void wld_exit( int code
) __attribute__((noreturn
));
273 SYSCALL_NOERR( wld_exit
, 1 /* SYS_exit */ );
275 ssize_t
wld_write( int fd
, const void *buffer
, size_t len
);
276 SYSCALL_FUNC( wld_write
, 4 /* SYS_write */ );
278 void *wld_mmap( void *start
, size_t len
, int prot
, int flags
, int fd
, off_t offset
);
279 SYSCALL_FUNC( wld_mmap
, 197 /* SYS_mmap */ );
281 void *wld_munmap( void *start
, size_t len
);
282 SYSCALL_FUNC( wld_munmap
, 73 /* SYS_munmap */ );
284 int wld_mincore( void *addr
, size_t length
, unsigned char *vec
);
285 SYSCALL_FUNC( wld_mincore
, 78 /* SYS_mincore */ );
287 static intptr_t (*p_dyld_get_image_slide
)( const struct target_mach_header
* mh
);
289 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
290 MAKE_FUNCPTR(dlopen
);
292 MAKE_FUNCPTR(dladdr
);
295 extern int _dyld_func_lookup( const char *dyld_func_name
, void **address
);
297 /* replacement for libc functions */
299 static int wld_strncmp( const char *str1
, const char *str2
, size_t len
)
301 if (len
<= 0) return 0;
302 while ((--len
> 0) && *str1
&& (*str1
== *str2
)) { str1
++; str2
++; }
303 return *str1
- *str2
;
307 * wld_printf - just the basics
309 * %x prints a hex number
311 * %p prints a pointer
313 static int wld_vsprintf(char *buffer
, const char *fmt
, va_list args
)
315 static const char hex_chars
[16] = "0123456789abcdef";
327 unsigned int x
= va_arg( args
, unsigned int );
328 for (i
= 2*sizeof(x
) - 1; i
>= 0; i
--)
329 *str
++ = hex_chars
[(x
>>(i
*4))&0xf];
331 else if (p
[0] == 'l' && p
[1] == 'x')
333 unsigned long x
= va_arg( args
, unsigned long );
334 for (i
= 2*sizeof(x
) - 1; i
>= 0; i
--)
335 *str
++ = hex_chars
[(x
>>(i
*4))&0xf];
340 unsigned long x
= (unsigned long)va_arg( args
, void * );
341 for (i
= 2*sizeof(x
) - 1; i
>= 0; i
--)
342 *str
++ = hex_chars
[(x
>>(i
*4))&0xf];
346 char *s
= va_arg( args
, char * );
360 static __attribute__((format(printf
,1,2))) void wld_printf(const char *fmt
, ... )
366 va_start( args
, fmt
);
367 len
= wld_vsprintf(buffer
, fmt
, args
);
369 wld_write(2, buffer
, len
);
372 static __attribute__((noreturn
,format(printf
,1,2))) void fatal_error(const char *fmt
, ... )
378 va_start( args
, fmt
);
379 len
= wld_vsprintf(buffer
, fmt
, args
);
381 wld_write(2, buffer
, len
);
385 static int preloader_overlaps_range( const void *start
, const void *end
)
387 intptr_t slide
= p_dyld_get_image_slide(&_mh_execute_header
);
388 struct load_command
*cmd
= (struct load_command
*)(&_mh_execute_header
+ 1);
391 for (i
= 0; i
< _mh_execute_header
.ncmds
; ++i
)
393 if (cmd
->cmd
== TARGET_LC_SEGMENT
)
395 struct target_segment_command
*seg
= (struct target_segment_command
*)cmd
;
396 const void *seg_start
= (const void*)(seg
->vmaddr
+ slide
);
397 const void *seg_end
= (const char*)seg_start
+ seg
->vmsize
;
399 if (end
> seg_start
&& start
<= seg_end
)
401 char segname
[sizeof(seg
->segname
) + 1];
402 memcpy(segname
, seg
->segname
, sizeof(seg
->segname
));
403 segname
[sizeof(segname
) - 1] = 0;
404 wld_printf( "WINEPRELOADRESERVE range %p-%p overlaps preloader %s segment %p-%p\n",
405 start
, end
, segname
, seg_start
, seg_end
);
409 cmd
= (struct load_command
*)((char*)cmd
+ cmd
->cmdsize
);
418 * Reserve a range specified in string format
420 static void preload_reserve( const char *str
)
423 unsigned long result
= 0;
424 void *start
= NULL
, *end
= NULL
;
427 for (p
= str
; *p
; p
++)
429 if (*p
>= '0' && *p
<= '9') result
= result
* 16 + *p
- '0';
430 else if (*p
>= 'a' && *p
<= 'f') result
= result
* 16 + *p
- 'a' + 10;
431 else if (*p
>= 'A' && *p
<= 'F') result
= result
* 16 + *p
- 'A' + 10;
434 if (!first
) goto error
;
435 start
= (void *)(result
& ~page_mask
);
441 if (!first
) end
= (void *)((result
+ page_mask
) & ~page_mask
);
442 else if (result
) goto error
; /* single value '0' is allowed */
445 if (end
<= start
|| preloader_overlaps_range(start
, end
))
448 /* check for overlap with low memory areas */
449 for (i
= 0; preload_info
[i
].size
; i
++)
451 if ((char *)preload_info
[i
].addr
> (char *)0x00110000) break;
452 if ((char *)end
<= (char *)preload_info
[i
].addr
+ preload_info
[i
].size
)
457 if ((char *)start
< (char *)preload_info
[i
].addr
+ preload_info
[i
].size
)
458 start
= (char *)preload_info
[i
].addr
+ preload_info
[i
].size
;
461 while (preload_info
[i
].size
) i
++;
462 preload_info
[i
].addr
= start
;
463 preload_info
[i
].size
= (char *)end
- (char *)start
;
467 fatal_error( "invalid WINEPRELOADRESERVE value '%s'\n", str
);
470 /* remove a range from the preload list */
471 static void remove_preload_range( int i
)
473 while (preload_info
[i
].size
)
475 preload_info
[i
].addr
= preload_info
[i
+1].addr
;
476 preload_info
[i
].size
= preload_info
[i
+1].size
;
481 static void *get_entry_point( struct target_mach_header
*mh
, intptr_t slide
, int *unix_thread
)
483 struct entry_point_command
*entry
;
484 target_thread_state_t
*state
;
485 struct load_command
*cmd
;
488 /* try LC_MAIN first */
489 cmd
= (struct load_command
*)(mh
+ 1);
490 for (i
= 0; i
< mh
->ncmds
; i
++)
492 if (cmd
->cmd
== LC_MAIN
)
494 *unix_thread
= FALSE
;
495 entry
= (struct entry_point_command
*)cmd
;
496 return (char *)mh
+ entry
->entryoff
;
498 cmd
= (struct load_command
*)((char *)cmd
+ cmd
->cmdsize
);
501 /* then try LC_UNIXTHREAD */
502 cmd
= (struct load_command
*)(mh
+ 1);
503 for (i
= 0; i
< mh
->ncmds
; i
++)
505 if (cmd
->cmd
== LC_UNIXTHREAD
)
508 state
= (target_thread_state_t
*)((char *)cmd
+ 16);
509 return (void *)(target_thread_ip(state
) + slide
);
511 cmd
= (struct load_command
*)((char *)cmd
+ cmd
->cmdsize
);
517 static int is_region_empty( struct wine_preload_info
*info
)
519 unsigned char vec
[1024];
520 size_t pos
, size
, block
= 1024 * page_size
;
523 for (pos
= 0; pos
< info
->size
; pos
+= size
)
525 size
= (pos
+ block
<= info
->size
) ? block
: (info
->size
- pos
);
526 if (wld_mincore( (char *)info
->addr
+ pos
, size
, vec
) == -1)
528 if (size
<= page_size
) continue;
529 block
= page_size
; size
= 0; /* retry with smaller block size */
533 for (i
= 0; i
< size
/ page_size
; i
++)
534 if (vec
[i
] & 1) return 0;
541 static int map_region( struct wine_preload_info
*info
)
543 int flags
= MAP_PRIVATE
| MAP_ANON
;
546 if (!info
->addr
) flags
|= MAP_FIXED
;
550 ret
= wld_mmap( info
->addr
, info
->size
, PROT_NONE
, flags
, -1, 0 );
551 if (ret
== info
->addr
) return 1;
552 if (ret
!= (void *)-1) wld_munmap( ret
, info
->size
);
553 if (flags
& MAP_FIXED
) break;
555 /* Some versions of macOS ignore the address hint passed to mmap -
556 * use mincore() to check if its empty and then use MAP_FIXED */
557 if (!is_region_empty( info
)) break;
561 /* don't warn for zero page */
562 if (info
->addr
>= (void *)0x1000)
563 wld_printf( "preloader: Warning: failed to reserve range %p-%p\n",
564 info
->addr
, (char *)info
->addr
+ info
->size
);
568 static inline void get_dyld_func( const char *name
, void **func
)
570 _dyld_func_lookup( name
, func
);
571 if (!*func
) fatal_error( "Failed to get function pointer for %s\n", name
);
574 #define LOAD_POSIX_DYLD_FUNC(f) get_dyld_func( "__dyld_" #f, (void **)&p##f )
575 #define LOAD_MACHO_DYLD_FUNC(f) get_dyld_func( "_" #f, (void **)&p##f )
577 void *wld_start( void *stack
, int *is_unix_thread
)
579 struct wine_preload_info builtin_dlls
= { (void *)0x7a000000, 0x02000000 };
580 struct wine_preload_info
**wine_main_preload_info
;
581 char **argv
, **p
, *reserve
= NULL
;
582 struct target_mach_header
*mh
;
588 argv
= (char **)pargc
+ 1;
589 if (*pargc
< 2) fatal_error( "Usage: %s wine_binary [args]\n", argv
[0] );
591 /* skip over the parameters */
592 p
= argv
+ *pargc
+ 1;
594 /* skip over the environment */
597 static const char res
[] = "WINEPRELOADRESERVE=";
598 if (!wld_strncmp( *p
, res
, sizeof(res
)-1 )) reserve
= *p
+ sizeof(res
) - 1;
602 LOAD_POSIX_DYLD_FUNC( dlopen
);
603 LOAD_POSIX_DYLD_FUNC( dlsym
);
604 LOAD_POSIX_DYLD_FUNC( dladdr
);
605 LOAD_MACHO_DYLD_FUNC( _dyld_get_image_slide
);
607 /* reserve memory that Wine needs */
608 if (reserve
) preload_reserve( reserve
);
609 for (i
= 0; preload_info
[i
].size
; i
++)
611 if (!map_region( &preload_info
[i
] ))
613 remove_preload_range( i
);
618 if (!map_region( &builtin_dlls
))
619 builtin_dlls
.size
= 0;
621 /* load the main binary */
622 if (!(mod
= pdlopen( argv
[1], RTLD_NOW
)))
623 fatal_error( "%s: could not load binary\n", argv
[1] );
625 if (builtin_dlls
.size
)
626 wld_munmap( builtin_dlls
.addr
, builtin_dlls
.size
);
628 /* store pointer to the preload info into the appropriate main binary variable */
629 wine_main_preload_info
= pdlsym( mod
, "wine_main_preload_info" );
630 if (wine_main_preload_info
) *wine_main_preload_info
= preload_info
;
631 else wld_printf( "wine_main_preload_info not found\n" );
633 if (!pdladdr( wine_main_preload_info
, &info
) || !(mh
= info
.dli_fbase
))
634 fatal_error( "%s: could not find mach header\n", argv
[1] );
635 if (!(entry
= get_entry_point( mh
, p_dyld_get_image_slide(mh
), is_unix_thread
)))
636 fatal_error( "%s: could not find entry point\n", argv
[1] );
641 #endif /* __APPLE__ */