123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770 |
- #ifdef __APPLE__
- #include "config.h"
- #include <stdarg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/mman.h>
- #ifdef HAVE_SYS_SYSCALL_H
- # include <sys/syscall.h>
- #endif
- #include <unistd.h>
- #include <dlfcn.h>
- #ifdef HAVE_MACH_O_LOADER_H
- #include <mach/thread_status.h>
- #include <mach-o/loader.h>
- #include <mach-o/ldsyms.h>
- #endif
- #include "wine/asm.h"
- #include "main.h"
- #if defined(__x86_64__)
- __asm__(".zerofill WINE_RESERVE,WINE_RESERVE,___wine_reserve,0x1fffff000");
- static const struct wine_preload_info zerofill_sections[] =
- {
- { (void *)0x000000001000, 0x1fffff000 },
- { 0, 0 }
- };
- #else
- static const struct wine_preload_info zerofill_sections[] =
- {
- { 0, 0 }
- };
- #endif
- #ifndef LC_MAIN
- #define LC_MAIN 0x80000028
- struct entry_point_command
- {
- uint32_t cmd;
- uint32_t cmdsize;
- uint64_t entryoff;
- uint64_t stacksize;
- };
- #endif
- static struct wine_preload_info preload_info[] =
- {
-
- #ifdef __i386__
- { (void *)0x00000000, 0x00001000 },
- { (void *)0x00001000, 0x0000f000 },
- { (void *)0x00010000, 0x00100000 },
- { (void *)0x00110000, 0x67ef0000 },
- { (void *)0x7f000000, 0x03000000 },
- #else
- { (void *)0x000000001000, 0x1fffff000 },
- { (void *)0x7ff000000000, 0x01ff0000 },
- #endif
- { 0, 0 },
- { 0, 0 }
- };
- void *__stack_chk_guard = 0;
- void __stack_chk_fail_local(void) { return; }
- void __stack_chk_fail(void) { return; }
- int NXArgc = 0;
- const char** NXArgv = NULL;
- const char** environ = NULL;
- const char* __progname = NULL;
- extern void* __dso_handle;
- struct ProgramVars
- {
- void* mh;
- int* NXArgcPtr;
- const char*** NXArgvPtr;
- const char*** environPtr;
- const char** __prognamePtr;
- };
- __attribute__((used)) static struct ProgramVars pvars
- __attribute__ ((section ("__DATA,__program_vars"))) = { &__dso_handle, &NXArgc, &NXArgv, &environ, &__progname };
- #ifdef __i386__
- static const size_t page_mask = 0xfff;
- #define target_mach_header mach_header
- #define target_segment_command segment_command
- #define TARGET_LC_SEGMENT LC_SEGMENT
- #define target_thread_state_t i386_thread_state_t
- #ifdef __DARWIN_UNIX03
- #define target_thread_ip(x) (x)->__eip
- #else
- #define target_thread_ip(x) (x)->eip
- #endif
- #define SYSCALL_FUNC( name, nr ) \
- __ASM_GLOBAL_FUNC( name, \
- "\tmovl $" #nr ",%eax\n" \
- "\tint $0x80\n" \
- "\tjnb 1f\n" \
- "\tmovl $-1,%eax\n" \
- "1:\tret\n" )
- #define SYSCALL_NOERR( name, nr ) \
- __ASM_GLOBAL_FUNC( name, \
- "\tmovl $" #nr ",%eax\n" \
- "\tint $0x80\n" \
- "\tret\n" )
- __ASM_GLOBAL_FUNC( start,
- __ASM_CFI("\t.cfi_undefined %eip\n")
-
- "\t.byte 0x6a,0x00\n"
- "\t.byte 0x89,0xe5\n"
- "\t.byte 0x83,0xe4,0xf0\n"
- "\t.byte 0x83,0xec,0x10\n"
- "\t.byte 0x8b,0x5d,0x04\n"
- "\t.byte 0x89,0x5c,0x24,0x00\n"
-
- "\tleal 4(%ebp),%eax\n"
- "\tmovl %eax,0(%esp)\n"
- "\tleal 8(%esp),%eax\n"
- "\tmovl %eax,4(%esp)\n"
- "\tmovl $0,(%eax)\n"
- "\tcall _wld_start\n"
-
- "\tcmpl $0,8(%esp)\n"
- "\tjne 2f\n"
- "\tmovl 4(%ebp),%edi\n"
- "\tleal 8(%ebp),%esi\n"
- "\tleal 4(%esi,%edi,4),%edx\n"
- "\tmovl %edx,%ecx\n"
- "1:\tmovl (%ecx),%ebx\n"
- "\tadd $4,%ecx\n"
- "\torl %ebx,%ebx\n"
- "\tjnz 1b\n"
-
- "\tmovl %edi,0(%esp)\n"
- "\tmovl %esi,4(%esp)\n"
- "\tmovl %edx,8(%esp)\n"
- "\tmovl %ecx,12(%esp)\n"
- "\tcall *%eax\n"
- "\tmovl %eax,(%esp)\n"
- "\tcall _wld_exit\n"
- "\thlt\n"
-
- "\t2:movl %ebp,%esp\n"
- "\taddl $4,%esp\n"
- "\tmovl $0,%ebp\n"
- "\tjmpl *%eax\n" )
- #elif defined(__x86_64__)
- static const size_t page_mask = 0xfff;
- #define target_mach_header mach_header_64
- #define target_segment_command segment_command_64
- #define TARGET_LC_SEGMENT LC_SEGMENT_64
- #define target_thread_state_t x86_thread_state64_t
- #ifdef __DARWIN_UNIX03
- #define target_thread_ip(x) (x)->__rip
- #else
- #define target_thread_ip(x) (x)->rip
- #endif
- #define SYSCALL_FUNC( name, nr ) \
- __ASM_GLOBAL_FUNC( name, \
- "\tmovq %rcx, %r10\n" \
- "\tmovq $(" #nr "|0x2000000),%rax\n" \
- "\tsyscall\n" \
- "\tjnb 1f\n" \
- "\tmovq $-1,%rax\n" \
- "1:\tret\n" )
- #define SYSCALL_NOERR( name, nr ) \
- __ASM_GLOBAL_FUNC( name, \
- "\tmovq %rcx, %r10\n" \
- "\tmovq $(" #nr "|0x2000000),%rax\n" \
- "\tsyscall\n" \
- "\tret\n" )
- __ASM_GLOBAL_FUNC( start,
- __ASM_CFI("\t.cfi_undefined %rip\n")
- "\tpushq $0\n"
- "\tmovq %rsp,%rbp\n"
- "\tandq $-16,%rsp\n"
- "\tsubq $16,%rsp\n"
-
- "\tleaq 8(%rbp),%rdi\n"
- "\tmovq %rsp,%rsi\n"
- "\tmovq $0,(%rsi)\n"
- "\tcall _wld_start\n"
-
- "\tcmpl $0,0(%rsp)\n"
- "\tjne 2f\n"
-
- "\tmovq 8(%rbp),%rdi\n"
- "\tleaq 16(%rbp),%rsi\n"
- "\tleaq 8(%rsi,%rdi,8),%rdx\n"
- "\tmovq %rdx,%rcx\n"
- "1:\tmovq (%rcx),%r8\n"
- "\taddq $8,%rcx\n"
- "\torq %r8,%r8\n"
- "\tjnz 1b\n"
- "\taddq $16,%rsp\n"
- "\tcall *%rax\n"
- "\tmovq %rax,%rdi\n"
- "\tcall _wld_exit\n"
- "\thlt\n"
-
- "\t2:movq %rbp,%rsp\n"
- "\taddq $8,%rsp\n"
- "\tmovq $0,%rbp\n"
- "\tjmpq *%rax\n" )
- #else
- #error preloader not implemented for this CPU
- #endif
- void wld_exit( int code ) __attribute__((noreturn));
- SYSCALL_NOERR( wld_exit, 1 );
- ssize_t wld_write( int fd, const void *buffer, size_t len );
- SYSCALL_FUNC( wld_write, 4 );
- void *wld_mmap( void *start, size_t len, int prot, int flags, int fd, off_t offset );
- SYSCALL_FUNC( wld_mmap, 197 );
- void *wld_munmap( void *start, size_t len );
- SYSCALL_FUNC( wld_munmap, 73 );
- static intptr_t (*p_dyld_get_image_slide)( const struct target_mach_header* mh );
- #define MAKE_FUNCPTR(f) static typeof(f) * p##f
- MAKE_FUNCPTR(dlopen);
- MAKE_FUNCPTR(dlsym);
- MAKE_FUNCPTR(dladdr);
- #undef MAKE_FUNCPTR
- extern int _dyld_func_lookup( const char *dyld_func_name, void **address );
- void * memmove( void *dst, const void *src, size_t len )
- {
- char *d = dst;
- const char *s = src;
- if (d < s)
- while (len--)
- *d++ = *s++;
- else
- {
- const char *lasts = s + (len-1);
- char *lastd = d + (len-1);
- while (len--)
- *lastd-- = *lasts--;
- }
- return dst;
- }
- static int wld_strncmp( const char *str1, const char *str2, size_t len )
- {
- if (len <= 0) return 0;
- while ((--len > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
- return *str1 - *str2;
- }
- static int wld_vsprintf(char *buffer, const char *fmt, va_list args )
- {
- static const char hex_chars[16] = "0123456789abcdef";
- const char *p = fmt;
- char *str = buffer;
- int i;
- while( *p )
- {
- if( *p == '%' )
- {
- p++;
- if( *p == 'x' )
- {
- unsigned int x = va_arg( args, unsigned int );
- for (i = 2*sizeof(x) - 1; i >= 0; i--)
- *str++ = hex_chars[(x>>(i*4))&0xf];
- }
- else if (p[0] == 'l' && p[1] == 'x')
- {
- unsigned long x = va_arg( args, unsigned long );
- for (i = 2*sizeof(x) - 1; i >= 0; i--)
- *str++ = hex_chars[(x>>(i*4))&0xf];
- p++;
- }
- else if( *p == 'p' )
- {
- unsigned long x = (unsigned long)va_arg( args, void * );
- for (i = 2*sizeof(x) - 1; i >= 0; i--)
- *str++ = hex_chars[(x>>(i*4))&0xf];
- }
- else if( *p == 's' )
- {
- char *s = va_arg( args, char * );
- while(*s)
- *str++ = *s++;
- }
- else if( *p == 0 )
- break;
- p++;
- }
- *str++ = *p++;
- }
- *str = 0;
- return str - buffer;
- }
- static __attribute__((format(printf,1,2))) void wld_printf(const char *fmt, ... )
- {
- va_list args;
- char buffer[256];
- int len;
- va_start( args, fmt );
- len = wld_vsprintf(buffer, fmt, args );
- va_end( args );
- wld_write(2, buffer, len);
- }
- static __attribute__((noreturn,format(printf,1,2))) void fatal_error(const char *fmt, ... )
- {
- va_list args;
- char buffer[256];
- int len;
- va_start( args, fmt );
- len = wld_vsprintf(buffer, fmt, args );
- va_end( args );
- wld_write(2, buffer, len);
- wld_exit(1);
- }
- static int preloader_overlaps_range( const void *start, const void *end )
- {
- intptr_t slide = p_dyld_get_image_slide(&_mh_execute_header);
- struct load_command *cmd = (struct load_command*)(&_mh_execute_header + 1);
- int i;
- for (i = 0; i < _mh_execute_header.ncmds; ++i)
- {
- if (cmd->cmd == TARGET_LC_SEGMENT)
- {
- struct target_segment_command *seg = (struct target_segment_command*)cmd;
- const void *seg_start = (const void*)(seg->vmaddr + slide);
- const void *seg_end = (const char*)seg_start + seg->vmsize;
- static const char reserved_segname[] = "WINE_RESERVE";
- if (!wld_strncmp( seg->segname, reserved_segname, sizeof(reserved_segname)-1 ))
- continue;
- if (end > seg_start && start <= seg_end)
- {
- char segname[sizeof(seg->segname) + 1];
- memcpy(segname, seg->segname, sizeof(seg->segname));
- segname[sizeof(segname) - 1] = 0;
- wld_printf( "WINEPRELOADRESERVE range %p-%p overlaps preloader %s segment %p-%p\n",
- start, end, segname, seg_start, seg_end );
- return 1;
- }
- }
- cmd = (struct load_command*)((char*)cmd + cmd->cmdsize);
- }
- return 0;
- }
- static void preload_reserve( const char *str )
- {
- const char *p;
- unsigned long result = 0;
- void *start = NULL, *end = NULL;
- int i, first = 1;
- for (p = str; *p; p++)
- {
- if (*p >= '0' && *p <= '9') result = result * 16 + *p - '0';
- else if (*p >= 'a' && *p <= 'f') result = result * 16 + *p - 'a' + 10;
- else if (*p >= 'A' && *p <= 'F') result = result * 16 + *p - 'A' + 10;
- else if (*p == '-')
- {
- if (!first) goto error;
- start = (void *)(result & ~page_mask);
- result = 0;
- first = 0;
- }
- else goto error;
- }
- if (!first) end = (void *)((result + page_mask) & ~page_mask);
- else if (result) goto error;
-
- if (end <= start || preloader_overlaps_range(start, end))
- start = end = NULL;
-
- for (i = 0; preload_info[i].size; i++)
- {
- if ((char *)preload_info[i].addr > (char *)0x00110000) break;
- if ((char *)end <= (char *)preload_info[i].addr + preload_info[i].size)
- {
- start = end = NULL;
- break;
- }
- if ((char *)start < (char *)preload_info[i].addr + preload_info[i].size)
- start = (char *)preload_info[i].addr + preload_info[i].size;
- }
- while (preload_info[i].size) i++;
- preload_info[i].addr = start;
- preload_info[i].size = (char *)end - (char *)start;
- return;
- error:
- fatal_error( "invalid WINEPRELOADRESERVE value '%s'\n", str );
- }
- static void remove_preload_range( int i )
- {
- while (preload_info[i].size)
- {
- preload_info[i].addr = preload_info[i+1].addr;
- preload_info[i].size = preload_info[i+1].size;
- i++;
- }
- }
- static void *get_entry_point( struct target_mach_header *mh, intptr_t slide, int *unix_thread )
- {
- struct entry_point_command *entry;
- target_thread_state_t *state;
- struct load_command *cmd;
- int i;
-
- cmd = (struct load_command *)(mh + 1);
- for (i = 0; i < mh->ncmds; i++)
- {
- if (cmd->cmd == LC_MAIN)
- {
- *unix_thread = FALSE;
- entry = (struct entry_point_command *)cmd;
- return (char *)mh + entry->entryoff;
- }
- cmd = (struct load_command *)((char *)cmd + cmd->cmdsize);
- }
-
- cmd = (struct load_command *)(mh + 1);
- for (i = 0; i < mh->ncmds; i++)
- {
- if (cmd->cmd == LC_UNIXTHREAD)
- {
- *unix_thread = TRUE;
- state = (target_thread_state_t *)((char *)cmd + 16);
- return (void *)(target_thread_ip(state) + slide);
- }
- cmd = (struct load_command *)((char *)cmd + cmd->cmdsize);
- }
- return NULL;
- };
- static int is_zerofill( struct wine_preload_info *info )
- {
- int i;
- for (i = 0; zerofill_sections[i].size; i++)
- {
- if ((zerofill_sections[i].addr == info->addr) &&
- (zerofill_sections[i].size == info->size))
- return 1;
- }
- return 0;
- }
- static int map_region( struct wine_preload_info *info )
- {
- int flags = MAP_PRIVATE | MAP_ANON;
- void *ret;
- if (!info->addr || is_zerofill( info )) flags |= MAP_FIXED;
- ret = wld_mmap( info->addr, info->size, PROT_NONE, flags, -1, 0 );
- if (ret == info->addr) return 1;
- if (ret != (void *)-1) wld_munmap( ret, info->size );
-
- if (info->addr >= (void *)0x1000)
- wld_printf( "preloader: Warning: failed to reserve range %p-%p\n",
- info->addr, (char *)info->addr + info->size );
- return 0;
- }
- static inline void get_dyld_func( const char *name, void **func )
- {
- _dyld_func_lookup( name, func );
- if (!*func) fatal_error( "Failed to get function pointer for %s\n", name );
- }
- #define LOAD_POSIX_DYLD_FUNC(f) get_dyld_func( "__dyld_" #f, (void **)&p##f )
- #define LOAD_MACHO_DYLD_FUNC(f) get_dyld_func( "_" #f, (void **)&p##f )
- static void fixup_stack( void *stack )
- {
- int *pargc;
- char **argv, **env_new;
- static char dummyvar[] = "WINEPRELOADERDUMMYVAR=1";
- pargc = stack;
- argv = (char **)pargc + 1;
-
- *pargc = *pargc - 1;
- memmove( &argv[0], &argv[1], (*pargc + 1) * sizeof(char *) );
- env_new = &argv[*pargc-1] + 2;
-
- env_new[0] = dummyvar;
- }
- static void set_program_vars( void *stack, void *mod )
- {
- int *pargc;
- const char **argv, **env;
- int *wine_NXArgc = pdlsym( mod, "NXArgc" );
- const char ***wine_NXArgv = pdlsym( mod, "NXArgv" );
- const char ***wine_environ = pdlsym( mod, "environ" );
- pargc = stack;
- argv = (const char **)pargc + 1;
- env = &argv[*pargc-1] + 2;
-
- if (wine_NXArgc)
- *wine_NXArgc = *pargc;
- else
- wld_printf( "preloader: Warning: failed to set NXArgc\n" );
- if (wine_NXArgv)
- *wine_NXArgv = argv;
- else
- wld_printf( "preloader: Warning: failed to set NXArgv\n" );
- if (wine_environ)
- *wine_environ = env;
- else
- wld_printf( "preloader: Warning: failed to set environ\n" );
-
- NXArgc = *pargc;
- NXArgv = argv;
- environ = env;
- }
- void *wld_start( void *stack, int *is_unix_thread )
- {
- #ifdef __i386__
- struct wine_preload_info builtin_dlls = { (void *)0x7a000000, 0x02000000 };
- #endif
- struct wine_preload_info **wine_main_preload_info;
- char **argv, **p, *reserve = NULL;
- struct target_mach_header *mh;
- void *mod, *entry;
- int *pargc, i;
- Dl_info info;
- pargc = stack;
- argv = (char **)pargc + 1;
- if (*pargc < 2) fatal_error( "Usage: %s wine_binary [args]\n", argv[0] );
-
- p = argv + *pargc + 1;
-
- while (*p)
- {
- static const char res[] = "WINEPRELOADRESERVE=";
- if (!wld_strncmp( *p, res, sizeof(res)-1 )) reserve = *p + sizeof(res) - 1;
- p++;
- }
- LOAD_POSIX_DYLD_FUNC( dlopen );
- LOAD_POSIX_DYLD_FUNC( dlsym );
- LOAD_POSIX_DYLD_FUNC( dladdr );
- LOAD_MACHO_DYLD_FUNC( _dyld_get_image_slide );
-
- if (reserve) preload_reserve( reserve );
- for (i = 0; preload_info[i].size; i++)
- {
- if (!map_region( &preload_info[i] ))
- {
- remove_preload_range( i );
- i--;
- }
- }
- #ifdef __i386__
- if (!map_region( &builtin_dlls ))
- builtin_dlls.size = 0;
- #endif
-
- if (!(mod = pdlopen( argv[1], RTLD_NOW )))
- fatal_error( "%s: could not load binary\n", argv[1] );
- #ifdef __i386__
- if (builtin_dlls.size)
- wld_munmap( builtin_dlls.addr, builtin_dlls.size );
- #endif
-
- wine_main_preload_info = pdlsym( mod, "wine_main_preload_info" );
- if (wine_main_preload_info) *wine_main_preload_info = preload_info;
- else wld_printf( "wine_main_preload_info not found\n" );
- if (!pdladdr( wine_main_preload_info, &info ) || !(mh = info.dli_fbase))
- fatal_error( "%s: could not find mach header\n", argv[1] );
- if (!(entry = get_entry_point( mh, p_dyld_get_image_slide(mh), is_unix_thread )))
- fatal_error( "%s: could not find entry point\n", argv[1] );
-
- fixup_stack(stack);
-
- set_program_vars( stack, mod );
- return entry;
- }
- #endif
|