ntdll: Add a helper function to map the main exe module.
[wine.git] / dlls / ntdll / unix / loader.c
blob4f485655fe259b42bda98f9464c2c9a2ddf9abe6
1 /*
2 * Unix interface for loader functions
4 * Copyright (C) 2020 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
27 #include <assert.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <signal.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/mman.h>
38 #include <sys/wait.h>
39 #include <unistd.h>
40 #include <dlfcn.h>
41 #ifdef HAVE_PWD_H
42 # include <pwd.h>
43 #endif
44 #ifdef HAVE_ELF_H
45 # include <elf.h>
46 #endif
47 #ifdef HAVE_LINK_H
48 # include <link.h>
49 #endif
50 #ifdef HAVE_SYS_AUXV_H
51 # include <sys/auxv.h>
52 #endif
53 #ifdef HAVE_SYS_RESOURCE_H
54 # include <sys/resource.h>
55 #endif
56 #include <limits.h>
57 #ifdef HAVE_SYS_SYSCTL_H
58 # include <sys/sysctl.h>
59 #endif
60 #ifdef __APPLE__
61 # include <CoreFoundation/CoreFoundation.h>
62 # define LoadResource MacLoadResource
63 # define GetCurrentThread MacGetCurrentThread
64 # include <CoreServices/CoreServices.h>
65 # undef LoadResource
66 # undef GetCurrentThread
67 # include <pthread.h>
68 # include <mach/mach.h>
69 # include <mach/mach_error.h>
70 # include <mach-o/getsect.h>
71 # include <crt_externs.h>
72 # include <spawn.h>
73 # ifndef _POSIX_SPAWN_DISABLE_ASLR
74 # define _POSIX_SPAWN_DISABLE_ASLR 0x0100
75 # endif
76 #endif
77 #ifdef __ANDROID__
78 # include <jni.h>
79 #endif
81 #include "ntstatus.h"
82 #define WIN32_NO_STATUS
83 #define NONAMELESSUNION
84 #define NONAMELESSSTRUCT
85 #include "windef.h"
86 #include "winnt.h"
87 #include "winbase.h"
88 #include "winnls.h"
89 #include "winioctl.h"
90 #include "winternl.h"
91 #include "unix_private.h"
92 #include "wine/list.h"
93 #include "wine/debug.h"
95 WINE_DEFAULT_DEBUG_CHANNEL(module);
97 #ifdef __i386__
98 static const char so_dir[] = "/i386-unix";
99 #elif defined(__x86_64__)
100 static const char so_dir[] = "/x86_64-unix";
101 #elif defined(__arm__)
102 static const char so_dir[] = "/arm-unix";
103 #elif defined(__aarch64__)
104 static const char so_dir[] = "/aarch64-unix";
105 #else
106 static const char so_dir[] = "";
107 #endif
109 void (WINAPI *pDbgUiRemoteBreakin)( void *arg ) = NULL;
110 NTSTATUS (WINAPI *pKiRaiseUserExceptionDispatcher)(void) = NULL;
111 NTSTATUS (WINAPI *pKiUserExceptionDispatcher)(EXCEPTION_RECORD*,CONTEXT*) = NULL;
112 void (WINAPI *pKiUserApcDispatcher)(CONTEXT*,ULONG_PTR,ULONG_PTR,ULONG_PTR,PNTAPCFUNC) = NULL;
113 void (WINAPI *pKiUserCallbackDispatcher)(ULONG,void*,ULONG) = NULL;
114 void (WINAPI *pLdrInitializeThunk)(CONTEXT*,void**,ULONG_PTR,ULONG_PTR) = NULL;
115 void (WINAPI *pRtlUserThreadStart)( PRTL_THREAD_START_ROUTINE entry, void *arg ) = NULL;
116 void (WINAPI *p__wine_ctrl_routine)(void*);
117 SYSTEM_DLL_INIT_BLOCK *pLdrSystemDllInitBlock = NULL;
119 static void *p__wine_syscall_dispatcher;
121 static void * const syscalls[] =
123 NtAcceptConnectPort,
124 NtAccessCheck,
125 NtAccessCheckAndAuditAlarm,
126 NtAddAtom,
127 NtAdjustGroupsToken,
128 NtAdjustPrivilegesToken,
129 NtAlertResumeThread,
130 NtAlertThread,
131 NtAlertThreadByThreadId,
132 NtAllocateLocallyUniqueId,
133 NtAllocateUuids,
134 NtAllocateVirtualMemory,
135 NtAllocateVirtualMemoryEx,
136 NtAreMappedFilesTheSame,
137 NtAssignProcessToJobObject,
138 NtCallbackReturn,
139 NtCancelIoFile,
140 NtCancelIoFileEx,
141 NtCancelSynchronousIoFile,
142 NtCancelTimer,
143 NtClearEvent,
144 NtClose,
145 NtCommitTransaction,
146 NtCompareObjects,
147 NtCompleteConnectPort,
148 NtConnectPort,
149 NtContinue,
150 NtCreateDebugObject,
151 NtCreateDirectoryObject,
152 NtCreateEvent,
153 NtCreateFile,
154 NtCreateIoCompletion,
155 NtCreateJobObject,
156 NtCreateKey,
157 NtCreateKeyTransacted,
158 NtCreateKeyedEvent,
159 NtCreateLowBoxToken,
160 NtCreateMailslotFile,
161 NtCreateMutant,
162 NtCreateNamedPipeFile,
163 NtCreatePagingFile,
164 NtCreatePort,
165 NtCreateSection,
166 NtCreateSemaphore,
167 NtCreateSymbolicLinkObject,
168 NtCreateThread,
169 NtCreateThreadEx,
170 NtCreateTimer,
171 NtCreateTransaction,
172 NtCreateUserProcess,
173 NtDebugActiveProcess,
174 NtDebugContinue,
175 NtDelayExecution,
176 NtDeleteAtom,
177 NtDeleteFile,
178 NtDeleteKey,
179 NtDeleteValueKey,
180 NtDeviceIoControlFile,
181 NtDisplayString,
182 NtDuplicateObject,
183 NtDuplicateToken,
184 NtEnumerateKey,
185 NtEnumerateValueKey,
186 NtFilterToken,
187 NtFindAtom,
188 NtFlushBuffersFile,
189 NtFlushInstructionCache,
190 NtFlushKey,
191 NtFlushProcessWriteBuffers,
192 NtFlushVirtualMemory,
193 NtFreeVirtualMemory,
194 NtFsControlFile,
195 NtGetContextThread,
196 NtGetCurrentProcessorNumber,
197 NtGetNextThread,
198 NtGetNlsSectionPtr,
199 NtGetWriteWatch,
200 NtImpersonateAnonymousToken,
201 NtInitializeNlsFiles,
202 NtInitiatePowerAction,
203 NtIsProcessInJob,
204 NtListenPort,
205 NtLoadDriver,
206 NtLoadKey,
207 NtLoadKey2,
208 NtLoadKeyEx,
209 NtLockFile,
210 NtLockVirtualMemory,
211 NtMakeTemporaryObject,
212 NtMapViewOfSection,
213 NtMapViewOfSectionEx,
214 NtNotifyChangeDirectoryFile,
215 NtNotifyChangeKey,
216 NtNotifyChangeMultipleKeys,
217 NtOpenDirectoryObject,
218 NtOpenEvent,
219 NtOpenFile,
220 NtOpenIoCompletion,
221 NtOpenJobObject,
222 NtOpenKey,
223 NtOpenKeyEx,
224 NtOpenKeyTransacted,
225 NtOpenKeyTransactedEx,
226 NtOpenKeyedEvent,
227 NtOpenMutant,
228 NtOpenProcess,
229 NtOpenProcessToken,
230 NtOpenProcessTokenEx,
231 NtOpenSection,
232 NtOpenSemaphore,
233 NtOpenSymbolicLinkObject ,
234 NtOpenThread,
235 NtOpenThreadToken,
236 NtOpenThreadTokenEx,
237 NtOpenTimer,
238 NtPowerInformation,
239 NtPrivilegeCheck,
240 NtProtectVirtualMemory,
241 NtPulseEvent,
242 NtQueryAttributesFile,
243 NtQueryDefaultLocale,
244 NtQueryDefaultUILanguage,
245 NtQueryDirectoryFile,
246 NtQueryDirectoryObject,
247 NtQueryEaFile,
248 NtQueryEvent,
249 NtQueryFullAttributesFile,
250 NtQueryInformationAtom,
251 NtQueryInformationFile,
252 NtQueryInformationJobObject,
253 NtQueryInformationProcess,
254 NtQueryInformationThread,
255 NtQueryInformationToken,
256 NtQueryInstallUILanguage,
257 NtQueryIoCompletion,
258 NtQueryKey,
259 NtQueryLicenseValue,
260 NtQueryMultipleValueKey,
261 NtQueryMutant,
262 NtQueryObject,
263 NtQueryPerformanceCounter,
264 NtQuerySection,
265 NtQuerySecurityObject,
266 NtQuerySemaphore ,
267 NtQuerySymbolicLinkObject,
268 NtQuerySystemEnvironmentValue,
269 NtQuerySystemEnvironmentValueEx,
270 NtQuerySystemInformation,
271 NtQuerySystemInformationEx,
272 NtQuerySystemTime,
273 NtQueryTimer,
274 NtQueryTimerResolution,
275 NtQueryValueKey,
276 NtQueryVirtualMemory,
277 NtQueryVolumeInformationFile,
278 NtQueueApcThread,
279 NtRaiseException,
280 NtRaiseHardError,
281 NtReadFile,
282 NtReadFileScatter,
283 NtReadVirtualMemory,
284 NtRegisterThreadTerminatePort,
285 NtReleaseKeyedEvent,
286 NtReleaseMutant,
287 NtReleaseSemaphore,
288 NtRemoveIoCompletion,
289 NtRemoveIoCompletionEx,
290 NtRemoveProcessDebug,
291 NtRenameKey,
292 NtReplaceKey,
293 NtReplyWaitReceivePort,
294 NtRequestWaitReplyPort,
295 NtResetEvent,
296 NtResetWriteWatch,
297 NtRestoreKey,
298 NtResumeProcess,
299 NtResumeThread,
300 NtRollbackTransaction,
301 NtSaveKey,
302 NtSecureConnectPort,
303 NtSetContextThread,
304 NtSetDebugFilterState,
305 NtSetDefaultLocale,
306 NtSetDefaultUILanguage,
307 NtSetEaFile,
308 NtSetEvent,
309 NtSetInformationDebugObject,
310 NtSetInformationFile,
311 NtSetInformationJobObject,
312 NtSetInformationKey,
313 NtSetInformationObject,
314 NtSetInformationProcess,
315 NtSetInformationThread,
316 NtSetInformationToken,
317 NtSetInformationVirtualMemory,
318 NtSetIntervalProfile,
319 NtSetIoCompletion,
320 NtSetLdtEntries,
321 NtSetSecurityObject,
322 NtSetSystemInformation,
323 NtSetSystemTime,
324 NtSetThreadExecutionState,
325 NtSetTimer,
326 NtSetTimerResolution,
327 NtSetValueKey,
328 NtSetVolumeInformationFile,
329 NtShutdownSystem,
330 NtSignalAndWaitForSingleObject,
331 NtSuspendProcess,
332 NtSuspendThread,
333 NtSystemDebugControl,
334 NtTerminateJobObject,
335 NtTerminateProcess,
336 NtTerminateThread,
337 NtTestAlert,
338 NtTraceControl,
339 NtUnloadDriver,
340 NtUnloadKey,
341 NtUnlockFile,
342 NtUnlockVirtualMemory,
343 NtUnmapViewOfSection,
344 NtUnmapViewOfSectionEx,
345 NtWaitForAlertByThreadId,
346 NtWaitForDebugEvent,
347 NtWaitForKeyedEvent,
348 NtWaitForMultipleObjects,
349 NtWaitForSingleObject,
350 #ifndef _WIN64
351 NtWow64AllocateVirtualMemory64,
352 NtWow64GetNativeSystemInformation,
353 NtWow64IsProcessorFeaturePresent,
354 NtWow64ReadVirtualMemory64,
355 NtWow64WriteVirtualMemory64,
356 #endif
357 NtWriteFile,
358 NtWriteFileGather,
359 NtWriteVirtualMemory,
360 NtYieldExecution,
361 wine_nt_to_unix_file_name,
362 wine_unix_to_nt_file_name,
365 static BYTE syscall_args[ARRAY_SIZE(syscalls)];
367 SYSTEM_SERVICE_TABLE KeServiceDescriptorTable[4];
369 #ifdef __GNUC__
370 static void fatal_error( const char *err, ... ) __attribute__((noreturn, format(printf,1,2)));
371 #endif
373 #if defined(linux) || defined(__APPLE__)
374 static const BOOL use_preloader = TRUE;
375 #else
376 static const BOOL use_preloader = FALSE;
377 #endif
379 static const char *bin_dir;
380 static const char *dll_dir;
381 static const char *ntdll_dir;
382 static const char *wineloader;
383 static SIZE_T dll_path_maxlen;
385 const char *home_dir = NULL;
386 const char *data_dir = NULL;
387 const char *build_dir = NULL;
388 const char *config_dir = NULL;
389 const char **dll_paths = NULL;
390 const char **system_dll_paths = NULL;
391 const char *user_name = NULL;
392 SECTION_IMAGE_INFORMATION main_image_info = { NULL };
393 static const IMAGE_EXPORT_DIRECTORY *ntdll_exports;
395 /* adjust an array of pointers to make them into RVAs */
396 static inline void fixup_rva_ptrs( void *array, BYTE *base, unsigned int count )
398 BYTE **src = array;
399 DWORD *dst = array;
401 for ( ; count; count--, src++, dst++) *dst = *src ? *src - base : 0;
404 /* fixup an array of RVAs by adding the specified delta */
405 static inline void fixup_rva_dwords( DWORD *ptr, int delta, unsigned int count )
407 for ( ; count; count--, ptr++) if (*ptr) *ptr += delta;
411 /* fixup an array of name/ordinal RVAs by adding the specified delta */
412 static inline void fixup_rva_names( UINT_PTR *ptr, int delta )
414 for ( ; *ptr; ptr++) if (!(*ptr & IMAGE_ORDINAL_FLAG)) *ptr += delta;
418 /* fixup RVAs in the resource directory */
419 static void fixup_so_resources( IMAGE_RESOURCE_DIRECTORY *dir, BYTE *root, int delta )
421 IMAGE_RESOURCE_DIRECTORY_ENTRY *entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
422 unsigned int i;
424 for (i = 0; i < dir->NumberOfNamedEntries + dir->NumberOfIdEntries; i++, entry++)
426 void *ptr = root + entry->u2.s2.OffsetToDirectory;
427 if (entry->u2.s2.DataIsDirectory) fixup_so_resources( ptr, root, delta );
428 else fixup_rva_dwords( &((IMAGE_RESOURCE_DATA_ENTRY *)ptr)->OffsetToData, delta, 1 );
432 /* die on a fatal error; use only during initialization */
433 static void fatal_error( const char *err, ... )
435 va_list args;
437 va_start( args, err );
438 fprintf( stderr, "wine: " );
439 vfprintf( stderr, err, args );
440 va_end( args );
441 exit(1);
444 static void set_max_limit( int limit )
446 struct rlimit rlimit;
448 if (!getrlimit( limit, &rlimit ))
450 rlimit.rlim_cur = rlimit.rlim_max;
451 if (setrlimit( limit, &rlimit ) != 0)
453 #if defined(__APPLE__) && defined(RLIMIT_NOFILE) && defined(OPEN_MAX)
454 /* On Leopard, setrlimit(RLIMIT_NOFILE, ...) fails on attempts to set
455 * rlim_cur above OPEN_MAX (even if rlim_max > OPEN_MAX). */
456 if (limit == RLIMIT_NOFILE && rlimit.rlim_cur > OPEN_MAX)
458 rlimit.rlim_cur = OPEN_MAX;
459 setrlimit( limit, &rlimit );
461 #endif
466 /* canonicalize path and return its directory name */
467 static char *realpath_dirname( const char *name )
469 char *p, *fullpath = realpath( name, NULL );
471 if (fullpath)
473 p = strrchr( fullpath, '/' );
474 if (p == fullpath) p++;
475 if (p) *p = 0;
477 return fullpath;
480 /* if string ends with tail, remove it */
481 static char *remove_tail( const char *str, const char *tail )
483 size_t len = strlen( str );
484 size_t tail_len = strlen( tail );
485 char *ret;
487 if (len < tail_len) return NULL;
488 if (strcmp( str + len - tail_len, tail )) return NULL;
489 ret = malloc( len - tail_len + 1 );
490 memcpy( ret, str, len - tail_len );
491 ret[len - tail_len] = 0;
492 return ret;
495 /* build a path from the specified dir and name */
496 static char *build_path( const char *dir, const char *name )
498 size_t len = strlen( dir );
499 char *ret = malloc( len + strlen( name ) + 2 );
501 memcpy( ret, dir, len );
502 if (len && ret[len - 1] != '/') ret[len++] = '/';
503 if (name[0] == '/') name++;
504 strcpy( ret + len, name );
505 return ret;
509 static const char *get_pe_dir( WORD machine )
511 if (!machine) machine = current_machine;
513 switch(machine)
515 case IMAGE_FILE_MACHINE_I386: return "/i386-windows";
516 case IMAGE_FILE_MACHINE_AMD64: return "/x86_64-windows";
517 case IMAGE_FILE_MACHINE_ARMNT: return "/arm-windows";
518 case IMAGE_FILE_MACHINE_ARM64: return "/aarch64-windows";
519 default: return "";
524 static void set_dll_path(void)
526 char *p, *path = getenv( "WINEDLLPATH" );
527 int i, count = 0;
529 if (path) for (p = path, count = 1; *p; p++) if (*p == ':') count++;
531 dll_paths = malloc( (count + 2) * sizeof(*dll_paths) );
532 count = 0;
534 if (!build_dir) dll_paths[count++] = dll_dir;
536 if (path)
538 path = strdup(path);
539 for (p = strtok( path, ":" ); p; p = strtok( NULL, ":" )) dll_paths[count++] = strdup( p );
540 free( path );
543 for (i = 0; i < count; i++) dll_path_maxlen = max( dll_path_maxlen, strlen(dll_paths[i]) );
544 dll_paths[count] = NULL;
548 static void set_system_dll_path(void)
550 const char *p, *path = SYSTEMDLLPATH;
551 int count = 0;
553 if (path && *path) for (p = path, count = 1; *p; p++) if (*p == ':') count++;
555 system_dll_paths = malloc( (count + 1) * sizeof(*system_dll_paths) );
556 count = 0;
558 if (path && *path)
560 char *path_copy = strdup(path);
561 for (p = strtok( path_copy, ":" ); p; p = strtok( NULL, ":" ))
562 system_dll_paths[count++] = strdup( p );
563 free( path_copy );
565 system_dll_paths[count] = NULL;
569 static void set_home_dir(void)
571 const char *home = getenv( "HOME" );
572 const char *name = getenv( "USER" );
573 const char *p;
575 if (!home || !name)
577 struct passwd *pwd = getpwuid( getuid() );
578 if (pwd)
580 if (!home) home = pwd->pw_dir;
581 if (!name) name = pwd->pw_name;
583 if (!name) name = "wine";
585 if ((p = strrchr( name, '/' ))) name = p + 1;
586 if ((p = strrchr( name, '\\' ))) name = p + 1;
587 home_dir = strdup( home );
588 user_name = strdup( name );
592 static void set_config_dir(void)
594 char *p, *dir;
595 const char *prefix = getenv( "WINEPREFIX" );
597 if (prefix)
599 if (prefix[0] != '/')
600 fatal_error( "invalid directory %s in WINEPREFIX: not an absolute path\n", prefix );
601 config_dir = dir = strdup( prefix );
602 for (p = dir + strlen(dir) - 1; p > dir && *p == '/'; p--) *p = 0;
604 else
606 if (!home_dir) fatal_error( "could not determine your home directory\n" );
607 if (home_dir[0] != '/') fatal_error( "the home directory %s is not an absolute path\n", home_dir );
608 config_dir = build_path( home_dir, ".wine" );
612 static void init_paths( char *argv[] )
614 Dl_info info;
615 char *basename, *env;
617 if ((basename = strrchr( argv[0], '/' ))) basename++;
618 else basename = argv[0];
620 if (!dladdr( init_paths, &info ) || !(ntdll_dir = realpath_dirname( info.dli_fname )))
621 fatal_error( "cannot get path to ntdll.so\n" );
623 if (!(build_dir = remove_tail( ntdll_dir, "/dlls/ntdll" )))
625 if (!(dll_dir = remove_tail( ntdll_dir, so_dir ))) dll_dir = ntdll_dir;
626 #if (defined(__linux__) && !defined(__ANDROID__)) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
627 bin_dir = realpath_dirname( "/proc/self/exe" );
628 #elif defined (__FreeBSD__) || defined(__DragonFly__)
630 static int pathname[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
631 size_t path_size = PATH_MAX;
632 char *path = malloc( path_size );
633 if (path && !sysctl( pathname, ARRAY_SIZE(pathname), path, &path_size, NULL, 0 ))
634 bin_dir = realpath_dirname( path );
635 free( path );
637 #endif
638 if (!bin_dir) bin_dir = build_path( dll_dir, DLL_TO_BINDIR );
639 data_dir = build_path( bin_dir, BIN_TO_DATADIR );
640 wineloader = build_path( bin_dir, basename );
642 else wineloader = build_path( build_path( build_dir, "loader" ), basename );
644 env = malloc( sizeof("WINELOADER=") + strlen(wineloader) );
645 strcpy( env, "WINELOADER=" );
646 strcat( env, wineloader );
647 putenv( env );
649 set_dll_path();
650 set_system_dll_path();
651 set_home_dir();
652 set_config_dir();
656 /***********************************************************************
657 * get_alternate_wineloader
659 char *get_alternate_wineloader( WORD machine )
661 char *ret = NULL;
663 if (machine == current_machine) return NULL;
665 if (machine == IMAGE_FILE_MACHINE_AMD64) /* try the 64-bit loader */
667 size_t len = strlen(wineloader);
669 if (len <= 2 || strcmp( wineloader + len - 2, "64" ))
671 ret = malloc( len + 3 );
672 strcpy( ret, wineloader );
673 strcat( ret, "64" );
675 return ret;
678 return remove_tail( wineloader, "64" );
682 static void preloader_exec( char **argv )
684 if (use_preloader)
686 static const char *preloader = "wine-preloader";
687 char *p;
689 if (!(p = strrchr( argv[1], '/' ))) p = argv[1];
690 else p++;
692 if (strlen(p) > 2 && !strcmp( p + strlen(p) - 2, "64" )) preloader = "wine64-preloader";
693 argv[0] = malloc( p - argv[1] + strlen(preloader) + 1 );
694 memcpy( argv[0], argv[1], p - argv[1] );
695 strcpy( argv[0] + (p - argv[1]), preloader );
697 #ifdef __APPLE__
699 posix_spawnattr_t attr;
700 posix_spawnattr_init( &attr );
701 posix_spawnattr_setflags( &attr, POSIX_SPAWN_SETEXEC | _POSIX_SPAWN_DISABLE_ASLR );
702 posix_spawn( NULL, argv[0], NULL, &attr, argv, *_NSGetEnviron() );
703 posix_spawnattr_destroy( &attr );
705 #endif
706 execv( argv[0], argv );
707 free( argv[0] );
709 execv( argv[1], argv + 1 );
712 /* exec the appropriate wine loader for the specified machine */
713 static NTSTATUS loader_exec( char **argv, WORD machine )
715 if (((argv[1] = get_alternate_wineloader( machine )))) preloader_exec( argv );
717 argv[1] = strdup( wineloader );
718 preloader_exec( argv );
719 return STATUS_INVALID_IMAGE_FORMAT;
723 /***********************************************************************
724 * exec_wineloader
726 * argv[0] and argv[1] must be reserved for the preloader and loader respectively.
728 NTSTATUS exec_wineloader( char **argv, int socketfd, const pe_image_info_t *pe_info )
730 WORD machine = pe_info->machine;
731 ULONGLONG res_start = pe_info->base;
732 ULONGLONG res_end = pe_info->base + pe_info->map_size;
733 char preloader_reserve[64], socket_env[64];
735 if (pe_info->wine_fakedll) res_start = res_end = 0;
736 if (pe_info->image_flags & IMAGE_FLAGS_ComPlusNativeReady) machine = native_machine;
738 signal( SIGPIPE, SIG_DFL );
740 sprintf( socket_env, "WINESERVERSOCKET=%u", socketfd );
741 sprintf( preloader_reserve, "WINEPRELOADRESERVE=%x%08x-%x%08x",
742 (UINT)(res_start >> 32), (UINT)res_start, (UINT)(res_end >> 32), (UINT)res_end );
744 putenv( preloader_reserve );
745 putenv( socket_env );
747 return loader_exec( argv, machine );
751 /***********************************************************************
752 * exec_wineserver
754 * Exec a new wine server.
756 static void exec_wineserver( char **argv )
758 char *path;
760 if (build_dir)
762 if (!is_win64) /* look for 64-bit server */
764 char *loader = realpath_dirname( build_path( build_dir, "loader/wine64" ));
765 if (loader)
767 argv[0] = build_path( loader, "../server/wineserver" );
768 execv( argv[0], argv );
771 argv[0] = build_path( build_dir, "server/wineserver" );
772 execv( argv[0], argv );
773 return;
776 argv[0] = build_path( bin_dir, "wineserver" );
777 execv( argv[0], argv );
779 argv[0] = getenv( "WINESERVER" );
780 if (argv[0]) execv( argv[0], argv );
782 if ((path = getenv( "PATH" )))
784 for (path = strtok( strdup( path ), ":" ); path; path = strtok( NULL, ":" ))
786 argv[0] = build_path( path, "wineserver" );
787 execvp( argv[0], argv );
791 argv[0] = build_path( BINDIR, "wineserver" );
792 execv( argv[0], argv );
796 /***********************************************************************
797 * start_server
799 * Start a new wine server.
801 void start_server( BOOL debug )
803 static BOOL started; /* we only try once */
804 char *argv[3];
805 static char debug_flag[] = "-d";
807 if (!started)
809 int status;
810 int pid = fork();
811 if (pid == -1) fatal_error( "fork: %s", strerror(errno) );
812 if (!pid)
814 argv[1] = debug ? debug_flag : NULL;
815 argv[2] = NULL;
816 exec_wineserver( argv );
817 fatal_error( "could not exec wineserver\n" );
819 waitpid( pid, &status, 0 );
820 status = WIFEXITED(status) ? WEXITSTATUS(status) : 1;
821 if (status == 2) return; /* server lock held by someone else, will retry later */
822 if (status) exit(status); /* server failed */
823 started = TRUE;
828 /*************************************************************************
829 * map_so_dll
831 * Map a builtin dll in memory and fixup RVAs.
833 static NTSTATUS map_so_dll( const IMAGE_NT_HEADERS *nt_descr, HMODULE module )
835 static const char builtin_signature[32] = "Wine builtin DLL";
836 IMAGE_DATA_DIRECTORY *dir;
837 IMAGE_DOS_HEADER *dos;
838 IMAGE_NT_HEADERS *nt;
839 IMAGE_SECTION_HEADER *sec;
840 BYTE *addr = (BYTE *)module;
841 DWORD code_start, code_end, data_start, data_end, align_mask;
842 int delta, nb_sections = 2; /* code + data */
843 unsigned int i;
844 DWORD size = (sizeof(IMAGE_DOS_HEADER)
845 + sizeof(builtin_signature)
846 + sizeof(IMAGE_NT_HEADERS)
847 + nb_sections * sizeof(IMAGE_SECTION_HEADER));
849 if (anon_mmap_fixed( addr, size, PROT_READ | PROT_WRITE, 0 ) != addr) return STATUS_NO_MEMORY;
851 dos = (IMAGE_DOS_HEADER *)addr;
852 nt = (IMAGE_NT_HEADERS *)((BYTE *)(dos + 1) + sizeof(builtin_signature));
853 sec = (IMAGE_SECTION_HEADER *)(nt + 1);
855 /* build the DOS and NT headers */
857 dos->e_magic = IMAGE_DOS_SIGNATURE;
858 dos->e_cblp = 0x90;
859 dos->e_cp = 3;
860 dos->e_cparhdr = (sizeof(*dos) + 0xf) / 0x10;
861 dos->e_minalloc = 0;
862 dos->e_maxalloc = 0xffff;
863 dos->e_ss = 0x0000;
864 dos->e_sp = 0x00b8;
865 dos->e_lfanew = sizeof(*dos) + sizeof(builtin_signature);
866 memcpy( dos + 1, builtin_signature, sizeof(builtin_signature) );
868 *nt = *nt_descr;
870 delta = (const BYTE *)nt_descr - addr;
871 align_mask = nt->OptionalHeader.SectionAlignment - 1;
872 code_start = (size + align_mask) & ~align_mask;
873 data_start = delta & ~align_mask;
874 #ifdef __APPLE__
876 Dl_info dli;
877 unsigned long data_size;
878 /* need the mach_header, not the PE header, to give to getsegmentdata(3) */
879 dladdr(addr, &dli);
880 code_end = getsegmentdata(dli.dli_fbase, "__DATA", &data_size) - addr;
881 data_end = (code_end + data_size + align_mask) & ~align_mask;
883 #else
884 code_end = data_start;
885 data_end = (nt->OptionalHeader.SizeOfImage + delta + align_mask) & ~align_mask;
886 #endif
888 fixup_rva_ptrs( &nt->OptionalHeader.AddressOfEntryPoint, addr, 1 );
890 nt->FileHeader.NumberOfSections = nb_sections;
891 nt->OptionalHeader.BaseOfCode = code_start;
892 #ifndef _WIN64
893 nt->OptionalHeader.BaseOfData = data_start;
894 #endif
895 nt->OptionalHeader.SizeOfCode = code_end - code_start;
896 nt->OptionalHeader.SizeOfInitializedData = data_end - data_start;
897 nt->OptionalHeader.SizeOfUninitializedData = 0;
898 nt->OptionalHeader.SizeOfImage = data_end;
899 nt->OptionalHeader.ImageBase = (ULONG_PTR)addr;
901 /* build the code section */
903 memcpy( sec->Name, ".text", sizeof(".text") );
904 sec->SizeOfRawData = code_end - code_start;
905 sec->Misc.VirtualSize = sec->SizeOfRawData;
906 sec->VirtualAddress = code_start;
907 sec->PointerToRawData = code_start;
908 sec->Characteristics = (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ);
909 sec++;
911 /* build the data section */
913 memcpy( sec->Name, ".data", sizeof(".data") );
914 sec->SizeOfRawData = data_end - data_start;
915 sec->Misc.VirtualSize = sec->SizeOfRawData;
916 sec->VirtualAddress = data_start;
917 sec->PointerToRawData = data_start;
918 sec->Characteristics = (IMAGE_SCN_CNT_INITIALIZED_DATA |
919 IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ);
920 sec++;
922 for (i = 0; i < nt->OptionalHeader.NumberOfRvaAndSizes; i++)
923 fixup_rva_dwords( &nt->OptionalHeader.DataDirectory[i].VirtualAddress, delta, 1 );
925 /* build the import directory */
927 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY];
928 if (dir->Size)
930 IMAGE_IMPORT_DESCRIPTOR *imports = (IMAGE_IMPORT_DESCRIPTOR *)(addr + dir->VirtualAddress);
932 while (imports->Name)
934 fixup_rva_dwords( &imports->u.OriginalFirstThunk, delta, 1 );
935 fixup_rva_dwords( &imports->Name, delta, 1 );
936 fixup_rva_dwords( &imports->FirstThunk, delta, 1 );
937 if (imports->u.OriginalFirstThunk)
938 fixup_rva_names( (UINT_PTR *)(addr + imports->u.OriginalFirstThunk), delta );
939 if (imports->FirstThunk)
940 fixup_rva_names( (UINT_PTR *)(addr + imports->FirstThunk), delta );
941 imports++;
945 /* build the resource directory */
947 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY];
948 if (dir->Size)
950 void *ptr = addr + dir->VirtualAddress;
951 fixup_so_resources( ptr, ptr, delta );
954 /* build the export directory */
956 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
957 if (dir->Size)
959 IMAGE_EXPORT_DIRECTORY *exports = (IMAGE_EXPORT_DIRECTORY *)(addr + dir->VirtualAddress);
961 fixup_rva_dwords( &exports->Name, delta, 1 );
962 fixup_rva_dwords( &exports->AddressOfFunctions, delta, 1 );
963 fixup_rva_dwords( &exports->AddressOfNames, delta, 1 );
964 fixup_rva_dwords( &exports->AddressOfNameOrdinals, delta, 1 );
965 fixup_rva_dwords( (DWORD *)(addr + exports->AddressOfNames), delta, exports->NumberOfNames );
966 fixup_rva_ptrs( addr + exports->AddressOfFunctions, addr, exports->NumberOfFunctions );
969 /* build the delay import directory */
971 dir = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT];
972 if (dir->Size)
974 IMAGE_DELAYLOAD_DESCRIPTOR *imports = (IMAGE_DELAYLOAD_DESCRIPTOR *)(addr + dir->VirtualAddress);
976 while (imports->DllNameRVA)
978 fixup_rva_dwords( &imports->DllNameRVA, delta, 1 );
979 fixup_rva_dwords( &imports->ModuleHandleRVA, delta, 1 );
980 fixup_rva_dwords( &imports->ImportAddressTableRVA, delta, 1 );
981 fixup_rva_dwords( &imports->ImportNameTableRVA, delta, 1 );
982 fixup_rva_dwords( &imports->BoundImportAddressTableRVA, delta, 1 );
983 fixup_rva_dwords( &imports->UnloadInformationTableRVA, delta, 1 );
984 fixup_rva_names( (UINT_PTR *)(addr + imports->ImportNameTableRVA), delta );
985 imports++;
989 return STATUS_SUCCESS;
992 static ULONG_PTR find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports, DWORD ordinal )
994 const DWORD *functions = (const DWORD *)((BYTE *)module + exports->AddressOfFunctions);
996 if (ordinal >= exports->NumberOfFunctions) return 0;
997 if (!functions[ordinal]) return 0;
998 return (ULONG_PTR)module + functions[ordinal];
1001 static ULONG_PTR find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
1002 const char *name )
1004 const WORD *ordinals = (const WORD *)((BYTE *)module + exports->AddressOfNameOrdinals);
1005 const DWORD *names = (const DWORD *)((BYTE *)module + exports->AddressOfNames);
1006 int min = 0, max = exports->NumberOfNames - 1;
1008 while (min <= max)
1010 int res, pos = (min + max) / 2;
1011 char *ename = (char *)module + names[pos];
1012 if (!(res = strcmp( ename, name ))) return find_ordinal_export( module, exports, ordinals[pos] );
1013 if (res > 0) max = pos - 1;
1014 else min = pos + 1;
1016 return 0;
1019 static inline void *get_rva( void *module, ULONG_PTR addr )
1021 return (BYTE *)module + addr;
1024 static const void *get_module_data_dir( HMODULE module, ULONG dir, ULONG *size )
1026 const IMAGE_NT_HEADERS *nt = get_rva( module, ((IMAGE_DOS_HEADER *)module)->e_lfanew );
1027 const IMAGE_DATA_DIRECTORY *data;
1029 if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
1030 data = &((const IMAGE_NT_HEADERS64 *)nt)->OptionalHeader.DataDirectory[dir];
1031 else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
1032 data = &((const IMAGE_NT_HEADERS32 *)nt)->OptionalHeader.DataDirectory[dir];
1033 else
1034 return NULL;
1035 if (!data->VirtualAddress || !data->Size) return NULL;
1036 if (size) *size = data->Size;
1037 return get_rva( module, data->VirtualAddress );
1040 /* reimplementation of LdrProcessRelocationBlock */
1041 static const IMAGE_BASE_RELOCATION *process_relocation_block( void *module, const IMAGE_BASE_RELOCATION *rel,
1042 INT_PTR delta )
1044 char *page = get_rva( module, rel->VirtualAddress );
1045 UINT count = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT);
1046 USHORT *relocs = (USHORT *)(rel + 1);
1048 while (count--)
1050 USHORT offset = *relocs & 0xfff;
1051 switch (*relocs >> 12)
1053 case IMAGE_REL_BASED_ABSOLUTE:
1054 break;
1055 case IMAGE_REL_BASED_HIGH:
1056 *(short *)(page + offset) += HIWORD(delta);
1057 break;
1058 case IMAGE_REL_BASED_LOW:
1059 *(short *)(page + offset) += LOWORD(delta);
1060 break;
1061 case IMAGE_REL_BASED_HIGHLOW:
1062 *(int *)(page + offset) += delta;
1063 break;
1064 case IMAGE_REL_BASED_DIR64:
1065 *(INT64 *)(page + offset) += delta;
1066 break;
1067 case IMAGE_REL_BASED_THUMB_MOV32:
1069 DWORD *inst = (DWORD *)(page + offset);
1070 WORD lo = ((inst[0] << 1) & 0x0800) + ((inst[0] << 12) & 0xf000) +
1071 ((inst[0] >> 20) & 0x0700) + ((inst[0] >> 16) & 0x00ff);
1072 WORD hi = ((inst[1] << 1) & 0x0800) + ((inst[1] << 12) & 0xf000) +
1073 ((inst[1] >> 20) & 0x0700) + ((inst[1] >> 16) & 0x00ff);
1074 DWORD imm = MAKELONG( lo, hi ) + delta;
1076 lo = LOWORD( imm );
1077 hi = HIWORD( imm );
1078 inst[0] = (inst[0] & 0x8f00fbf0) + ((lo >> 1) & 0x0400) + ((lo >> 12) & 0x000f) +
1079 ((lo << 20) & 0x70000000) + ((lo << 16) & 0xff0000);
1080 inst[1] = (inst[1] & 0x8f00fbf0) + ((hi >> 1) & 0x0400) + ((hi >> 12) & 0x000f) +
1081 ((hi << 20) & 0x70000000) + ((hi << 16) & 0xff0000);
1082 break;
1084 default:
1085 FIXME("Unknown/unsupported relocation %x\n", *relocs);
1086 return NULL;
1088 relocs++;
1090 return (IMAGE_BASE_RELOCATION *)relocs; /* return address of next block */
1093 static void relocate_ntdll( void *module )
1095 const IMAGE_NT_HEADERS *nt = get_rva( module, ((IMAGE_DOS_HEADER *)module)->e_lfanew );
1096 const IMAGE_BASE_RELOCATION *rel, *end;
1097 const IMAGE_SECTION_HEADER *sec;
1098 ULONG protect_old[96], i, size;
1099 INT_PTR delta;
1101 ERR( "ntdll could not be mapped at preferred address (%p), expect trouble\n", module );
1103 if (!(rel = get_module_data_dir( module, IMAGE_DIRECTORY_ENTRY_BASERELOC, &size ))) return;
1105 sec = (IMAGE_SECTION_HEADER *)((char *)&nt->OptionalHeader + nt->FileHeader.SizeOfOptionalHeader);
1106 for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
1108 void *addr = get_rva( module, sec[i].VirtualAddress );
1109 SIZE_T size = sec[i].SizeOfRawData;
1110 NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, PAGE_READWRITE, &protect_old[i] );
1113 end = (IMAGE_BASE_RELOCATION *)((const char *)rel + size);
1114 delta = (char *)module - (char *)nt->OptionalHeader.ImageBase;
1115 while (rel && rel < end - 1 && rel->SizeOfBlock) rel = process_relocation_block( module, rel, delta );
1117 for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
1119 void *addr = get_rva( module, sec[i].VirtualAddress );
1120 SIZE_T size = sec[i].SizeOfRawData;
1121 NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, protect_old[i], &protect_old[i] );
1126 /***********************************************************************
1127 * fill_builtin_image_info
1129 static void fill_builtin_image_info( void *module, pe_image_info_t *info )
1131 const IMAGE_DOS_HEADER *dos = (const IMAGE_DOS_HEADER *)module;
1132 const IMAGE_NT_HEADERS *nt = (IMAGE_NT_HEADERS *)((const BYTE *)dos + dos->e_lfanew);
1134 memset( info, 0, sizeof(*info) );
1135 info->base = nt->OptionalHeader.ImageBase;
1136 info->entry_point = nt->OptionalHeader.AddressOfEntryPoint;
1137 info->map_size = nt->OptionalHeader.SizeOfImage;
1138 info->stack_size = nt->OptionalHeader.SizeOfStackReserve;
1139 info->stack_commit = nt->OptionalHeader.SizeOfStackCommit;
1140 info->subsystem = nt->OptionalHeader.Subsystem;
1141 info->subsystem_minor = nt->OptionalHeader.MinorSubsystemVersion;
1142 info->subsystem_major = nt->OptionalHeader.MajorSubsystemVersion;
1143 info->osversion_major = nt->OptionalHeader.MajorOperatingSystemVersion;
1144 info->osversion_minor = nt->OptionalHeader.MinorOperatingSystemVersion;
1145 info->image_charact = nt->FileHeader.Characteristics;
1146 info->dll_charact = nt->OptionalHeader.DllCharacteristics;
1147 info->machine = nt->FileHeader.Machine;
1148 info->contains_code = TRUE;
1149 info->wine_builtin = TRUE;
1150 info->header_size = nt->OptionalHeader.SizeOfHeaders;
1151 info->file_size = nt->OptionalHeader.SizeOfImage;
1152 info->checksum = nt->OptionalHeader.CheckSum;
1156 /***********************************************************************
1157 * dlopen_dll
1159 static NTSTATUS dlopen_dll( const char *so_name, UNICODE_STRING *nt_name, void **ret_module,
1160 pe_image_info_t *image_info, BOOL prefer_native )
1162 void *module, *handle;
1163 const IMAGE_NT_HEADERS *nt;
1165 handle = dlopen( so_name, RTLD_NOW );
1166 if (!handle)
1168 WARN( "failed to load .so lib %s: %s\n", debugstr_a(so_name), dlerror() );
1169 return STATUS_INVALID_IMAGE_FORMAT;
1172 if (!(nt = dlsym( handle, "__wine_spec_nt_header" )))
1174 ERR( "invalid .so library %s, too old?\n", debugstr_a(so_name));
1175 return STATUS_INVALID_IMAGE_FORMAT;
1178 module = (HMODULE)((nt->OptionalHeader.ImageBase + 0xffff) & ~0xffff);
1179 if (get_builtin_so_handle( module )) /* already loaded */
1181 fill_builtin_image_info( module, image_info );
1182 *ret_module = module;
1183 dlclose( handle );
1184 return STATUS_SUCCESS;
1187 if (map_so_dll( nt, module ))
1189 dlclose( handle );
1190 return STATUS_NO_MEMORY;
1193 fill_builtin_image_info( module, image_info );
1194 if (prefer_native && (image_info->dll_charact & IMAGE_DLLCHARACTERISTICS_PREFER_NATIVE))
1196 TRACE( "%s has prefer-native flag, ignoring builtin\n", debugstr_a(so_name) );
1197 dlclose( handle );
1198 return STATUS_IMAGE_ALREADY_LOADED;
1201 if (virtual_create_builtin_view( module, nt_name, image_info, handle ))
1203 dlclose( handle );
1204 return STATUS_NO_MEMORY;
1206 *ret_module = module;
1207 return STATUS_SUCCESS;
1211 /***********************************************************************
1212 * ntdll_init_syscalls
1214 NTSTATUS ntdll_init_syscalls( ULONG id, SYSTEM_SERVICE_TABLE *table, void **dispatcher )
1216 struct syscall_info
1218 void *dispatcher;
1219 USHORT limit;
1220 BYTE args[1];
1221 } *info = (struct syscall_info *)dispatcher;
1223 if (id > 3) return STATUS_INVALID_PARAMETER;
1224 if (info->limit != table->ServiceLimit)
1226 ERR( "syscall count mismatch %u / %lu\n", info->limit, table->ServiceLimit );
1227 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_PARAMETER );
1229 info->dispatcher = __wine_syscall_dispatcher;
1230 memcpy( table->ArgumentTable, info->args, table->ServiceLimit );
1231 KeServiceDescriptorTable[id] = *table;
1232 return STATUS_SUCCESS;
1236 /***********************************************************************
1237 * load_so_dll
1239 static NTSTATUS load_so_dll( void *args )
1241 static const WCHAR soW[] = {'.','s','o',0};
1242 struct load_so_dll_params *params = args;
1243 UNICODE_STRING *nt_name = &params->nt_name;
1244 OBJECT_ATTRIBUTES attr;
1245 UNICODE_STRING redir;
1246 pe_image_info_t info;
1247 char *unix_name;
1248 NTSTATUS status;
1249 DWORD len;
1251 if (get_load_order( nt_name ) == LO_DISABLED) return STATUS_DLL_NOT_FOUND;
1252 InitializeObjectAttributes( &attr, nt_name, OBJ_CASE_INSENSITIVE, 0, 0 );
1253 get_redirect( &attr, &redir );
1255 if (nt_to_unix_file_name( &attr, &unix_name, FILE_OPEN ))
1257 free( redir.Buffer );
1258 return STATUS_DLL_NOT_FOUND;
1261 /* remove .so extension from Windows name */
1262 len = nt_name->Length / sizeof(WCHAR);
1263 if (len > 3 && !wcsicmp( nt_name->Buffer + len - 3, soW )) nt_name->Length -= 3 * sizeof(WCHAR);
1265 status = dlopen_dll( unix_name, nt_name, params->module, &info, FALSE );
1266 free( unix_name );
1267 free( redir.Buffer );
1268 return status;
1272 static const unixlib_entry_t unix_call_funcs[] =
1274 load_so_dll,
1275 unwind_builtin_dll,
1276 unixcall_wine_dbg_write,
1277 unixcall_wine_server_call,
1278 unixcall_wine_server_fd_to_handle,
1279 unixcall_wine_server_handle_to_fd,
1280 unixcall_wine_spawnvp,
1281 system_time_precise,
1285 #ifdef _WIN64
1287 static NTSTATUS wow64_load_so_dll( void *args ) { return STATUS_INVALID_IMAGE_FORMAT; }
1288 static NTSTATUS wow64_unwind_builtin_dll( void *args ) { return STATUS_UNSUCCESSFUL; }
1290 const unixlib_entry_t unix_call_wow64_funcs[] =
1292 wow64_load_so_dll,
1293 wow64_unwind_builtin_dll,
1294 wow64_wine_dbg_write,
1295 wow64_wine_server_call,
1296 wow64_wine_server_fd_to_handle,
1297 wow64_wine_server_handle_to_fd,
1298 wow64_wine_spawnvp,
1299 system_time_precise,
1302 #endif /* _WIN64 */
1305 /* check if the library is the correct architecture */
1306 /* only returns false for a valid library of the wrong arch */
1307 static int check_library_arch( int fd )
1309 #ifdef __APPLE__
1310 struct /* Mach-O header */
1312 unsigned int magic;
1313 unsigned int cputype;
1314 } header;
1316 if (read( fd, &header, sizeof(header) ) != sizeof(header)) return 1;
1317 if (header.magic != 0xfeedface) return 1;
1318 if (sizeof(void *) == sizeof(int)) return !(header.cputype >> 24);
1319 else return (header.cputype >> 24) == 1; /* CPU_ARCH_ABI64 */
1320 #else
1321 struct /* ELF header */
1323 unsigned char magic[4];
1324 unsigned char class;
1325 unsigned char data;
1326 unsigned char version;
1327 } header;
1329 if (read( fd, &header, sizeof(header) ) != sizeof(header)) return 1;
1330 if (memcmp( header.magic, "\177ELF", 4 )) return 1;
1331 if (header.version != 1 /* EV_CURRENT */) return 1;
1332 #ifdef WORDS_BIGENDIAN
1333 if (header.data != 2 /* ELFDATA2MSB */) return 1;
1334 #else
1335 if (header.data != 1 /* ELFDATA2LSB */) return 1;
1336 #endif
1337 if (sizeof(void *) == sizeof(int)) return header.class == 1; /* ELFCLASS32 */
1338 else return header.class == 2; /* ELFCLASS64 */
1339 #endif
1342 static inline char *prepend( char *buffer, const char *str, size_t len )
1344 return memcpy( buffer - len, str, len );
1347 static inline char *prepend_build_dir_path( char *ptr, const char *ext, const char *arch_dir,
1348 const char *top_dir )
1350 char *name = ptr;
1351 unsigned int namelen = strlen(name), extlen = strlen(ext);
1353 if (namelen > extlen && !strcmp( name + namelen - extlen, ext )) namelen -= extlen;
1354 ptr = prepend( ptr, arch_dir, strlen(arch_dir) );
1355 ptr = prepend( ptr, name, namelen );
1356 ptr = prepend( ptr, top_dir, strlen(top_dir) );
1357 ptr = prepend( ptr, build_dir, strlen(build_dir) );
1358 return ptr;
1362 /***********************************************************************
1363 * open_dll_file
1365 * Open a file for a new dll. Helper for open_builtin_pe_file.
1367 static NTSTATUS open_dll_file( const char *name, OBJECT_ATTRIBUTES *attr, HANDLE *mapping )
1369 LARGE_INTEGER size;
1370 NTSTATUS status;
1371 HANDLE handle;
1373 if ((status = open_unix_file( &handle, name, GENERIC_READ | SYNCHRONIZE, attr, 0,
1374 FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_OPEN,
1375 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, NULL, 0 )))
1377 if (status != STATUS_OBJECT_PATH_NOT_FOUND && status != STATUS_OBJECT_NAME_NOT_FOUND)
1379 /* if the file exists but failed to open, report the error */
1380 struct stat st;
1381 if (!stat( name, &st )) return status;
1383 /* otherwise continue searching */
1384 return STATUS_DLL_NOT_FOUND;
1387 size.QuadPart = 0;
1388 status = NtCreateSection( mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
1389 SECTION_MAP_READ | SECTION_MAP_EXECUTE,
1390 NULL, &size, PAGE_EXECUTE_READ, SEC_IMAGE, handle );
1391 NtClose( handle );
1392 return status;
1396 /***********************************************************************
1397 * open_builtin_pe_file
1399 static NTSTATUS open_builtin_pe_file( const char *name, OBJECT_ATTRIBUTES *attr, void **module,
1400 SIZE_T *size, SECTION_IMAGE_INFORMATION *image_info,
1401 ULONG_PTR limit, WORD machine, BOOL prefer_native )
1403 NTSTATUS status;
1404 HANDLE mapping;
1406 *module = NULL;
1407 status = open_dll_file( name, attr, &mapping );
1408 if (!status)
1410 status = virtual_map_builtin_module( mapping, module, size, image_info, limit, machine, prefer_native );
1411 NtClose( mapping );
1413 return status;
1417 /***********************************************************************
1418 * open_builtin_so_file
1420 static NTSTATUS open_builtin_so_file( const char *name, OBJECT_ATTRIBUTES *attr, void **module,
1421 SECTION_IMAGE_INFORMATION *image_info,
1422 WORD machine, BOOL prefer_native )
1424 NTSTATUS status;
1425 int fd;
1427 *module = NULL;
1428 if (machine != current_machine) return STATUS_DLL_NOT_FOUND;
1429 if ((fd = open( name, O_RDONLY )) == -1) return STATUS_DLL_NOT_FOUND;
1431 if (check_library_arch( fd ))
1433 pe_image_info_t info;
1435 status = dlopen_dll( name, attr->ObjectName, module, &info, prefer_native );
1436 if (!status) virtual_fill_image_information( &info, image_info );
1437 else if (status != STATUS_IMAGE_ALREADY_LOADED)
1439 ERR( "failed to load .so lib %s\n", debugstr_a(name) );
1440 status = STATUS_PROCEDURE_NOT_FOUND;
1443 else status = STATUS_NOT_SUPPORTED;
1445 close( fd );
1446 return status;
1450 /***********************************************************************
1451 * find_builtin_dll
1453 static NTSTATUS find_builtin_dll( UNICODE_STRING *nt_name, void **module, SIZE_T *size_ptr,
1454 SECTION_IMAGE_INFORMATION *image_info, ULONG_PTR limit,
1455 USHORT search_machine, USHORT load_machine, BOOL prefer_native )
1457 unsigned int i, pos, namepos, maxlen = 0;
1458 unsigned int len = nt_name->Length / sizeof(WCHAR);
1459 char *ptr = NULL, *file, *ext = NULL;
1460 const char *pe_dir = get_pe_dir( search_machine );
1461 OBJECT_ATTRIBUTES attr;
1462 NTSTATUS status = STATUS_DLL_NOT_FOUND;
1463 BOOL found_image = FALSE;
1465 for (i = namepos = 0; i < len; i++)
1466 if (nt_name->Buffer[i] == '/' || nt_name->Buffer[i] == '\\') namepos = i + 1;
1467 len -= namepos;
1468 if (!len) return STATUS_DLL_NOT_FOUND;
1469 InitializeObjectAttributes( &attr, nt_name, 0, 0, NULL );
1471 if (build_dir) maxlen = strlen(build_dir) + sizeof("/programs/") + len;
1472 maxlen = max( maxlen, dll_path_maxlen + 1 ) + len + sizeof("/aarch64-windows") + sizeof(".so");
1474 if (!(file = malloc( maxlen ))) return STATUS_NO_MEMORY;
1476 pos = maxlen - len - sizeof(".so");
1477 /* we don't want to depend on the current codepage here */
1478 for (i = 0; i < len; i++)
1480 if (nt_name->Buffer[namepos + i] > 127) goto done;
1481 file[pos + i] = (char)nt_name->Buffer[namepos + i];
1482 if (file[pos + i] >= 'A' && file[pos + i] <= 'Z') file[pos + i] += 'a' - 'A';
1483 else if (file[pos + i] == '.') ext = file + pos + i;
1485 file[--pos] = '/';
1487 if (build_dir)
1489 /* try as a dll */
1490 file[pos + len + 1] = 0;
1491 ptr = prepend_build_dir_path( file + pos, ".dll", pe_dir, "/dlls" );
1492 status = open_builtin_pe_file( ptr, &attr, module, size_ptr, image_info,
1493 limit, load_machine, prefer_native );
1494 ptr = prepend_build_dir_path( file + pos, ".dll", "", "/dlls" );
1495 if (status != STATUS_DLL_NOT_FOUND) goto done;
1496 strcpy( file + pos + len + 1, ".so" );
1497 status = open_builtin_so_file( ptr, &attr, module, image_info, load_machine, prefer_native );
1498 if (status != STATUS_DLL_NOT_FOUND) goto done;
1500 /* now as a program */
1501 file[pos + len + 1] = 0;
1502 ptr = prepend_build_dir_path( file + pos, ".exe", pe_dir, "/programs" );
1503 status = open_builtin_pe_file( ptr, &attr, module, size_ptr, image_info,
1504 limit, load_machine, prefer_native );
1505 ptr = prepend_build_dir_path( file + pos, ".exe", "", "/programs" );
1506 if (status != STATUS_DLL_NOT_FOUND) goto done;
1507 strcpy( file + pos + len + 1, ".so" );
1508 status = open_builtin_so_file( ptr, &attr, module, image_info, load_machine, prefer_native );
1509 if (status != STATUS_DLL_NOT_FOUND) goto done;
1512 for (i = 0; dll_paths[i]; i++)
1514 ptr = file + pos;
1515 file[pos + len + 1] = 0;
1516 ptr = prepend( ptr, pe_dir, strlen(pe_dir) );
1517 ptr = prepend( ptr, dll_paths[i], strlen(dll_paths[i]) );
1518 status = open_builtin_pe_file( ptr, &attr, module, size_ptr, image_info, limit,
1519 load_machine, prefer_native );
1520 /* use so dir for unix lib */
1521 ptr = file + pos;
1522 ptr = prepend( ptr, so_dir, strlen(so_dir) );
1523 ptr = prepend( ptr, dll_paths[i], strlen(dll_paths[i]) );
1524 if (status != STATUS_DLL_NOT_FOUND) goto done;
1525 strcpy( file + pos + len + 1, ".so" );
1526 status = open_builtin_so_file( ptr, &attr, module, image_info, load_machine, prefer_native );
1527 if (status != STATUS_DLL_NOT_FOUND) goto done;
1528 file[pos + len + 1] = 0;
1529 ptr = prepend( file + pos, dll_paths[i], strlen(dll_paths[i]) );
1530 status = open_builtin_pe_file( ptr, &attr, module, size_ptr, image_info, limit,
1531 load_machine, prefer_native );
1532 if (status == STATUS_NOT_SUPPORTED)
1534 found_image = TRUE;
1535 continue;
1537 if (status != STATUS_DLL_NOT_FOUND) goto done;
1538 strcpy( file + pos + len + 1, ".so" );
1539 status = open_builtin_so_file( ptr, &attr, module, image_info, load_machine, prefer_native );
1540 if (status == STATUS_NOT_SUPPORTED) found_image = TRUE;
1541 else if (status != STATUS_DLL_NOT_FOUND) goto done;
1544 if (found_image) status = STATUS_NOT_SUPPORTED;
1545 WARN( "cannot find builtin library for %s\n", debugstr_us(nt_name) );
1546 done:
1547 if (status >= 0 && ext)
1549 strcpy( ext, ".so" );
1550 load_builtin_unixlib( *module, ptr );
1552 free( file );
1553 return status;
1557 /***********************************************************************
1558 * load_builtin
1560 * Load the builtin dll if specified by load order configuration.
1561 * Return STATUS_IMAGE_ALREADY_LOADED if we should keep the native one that we have found.
1563 NTSTATUS load_builtin( const pe_image_info_t *image_info, WCHAR *filename, USHORT machine,
1564 void **module, SIZE_T *size, ULONG_PTR limit )
1566 NTSTATUS status;
1567 UNICODE_STRING nt_name;
1568 SECTION_IMAGE_INFORMATION info;
1569 enum loadorder loadorder;
1571 init_unicode_string( &nt_name, filename );
1572 loadorder = get_load_order( &nt_name );
1574 if (loadorder == LO_DISABLED) return STATUS_DLL_NOT_FOUND;
1576 if (image_info->wine_builtin)
1578 if (loadorder == LO_NATIVE) return STATUS_DLL_NOT_FOUND;
1579 loadorder = LO_BUILTIN_NATIVE; /* load builtin, then fallback to the file we found */
1581 else if (image_info->wine_fakedll)
1583 TRACE( "%s is a fake Wine dll\n", debugstr_w(filename) );
1584 if (loadorder == LO_NATIVE) return STATUS_DLL_NOT_FOUND;
1585 loadorder = LO_BUILTIN; /* builtin with no fallback since mapping a fake dll is not useful */
1588 switch (loadorder)
1590 case LO_NATIVE:
1591 case LO_NATIVE_BUILTIN:
1592 return STATUS_IMAGE_ALREADY_LOADED;
1593 case LO_BUILTIN:
1594 return find_builtin_dll( &nt_name, module, size, &info, limit,
1595 image_info->machine, machine, FALSE );
1596 default:
1597 status = find_builtin_dll( &nt_name, module, size, &info, limit,
1598 image_info->machine, machine, (loadorder == LO_DEFAULT) );
1599 if (status == STATUS_DLL_NOT_FOUND || status == STATUS_NOT_SUPPORTED)
1600 return STATUS_IMAGE_ALREADY_LOADED;
1601 return status;
1606 /***************************************************************************
1607 * get_machine_wow64_dir
1609 * cf. GetSystemWow64Directory2.
1611 static const WCHAR *get_machine_wow64_dir( WORD machine )
1613 static const WCHAR system32[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\','s','y','s','t','e','m','3','2','\\',0};
1614 static const WCHAR syswow64[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\','s','y','s','w','o','w','6','4','\\',0};
1615 static const WCHAR sysarm32[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\','s','y','s','a','r','m','3','2','\\',0};
1616 static const WCHAR sysx8664[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\','s','y','s','x','8','6','6','4','\\',0};
1617 static const WCHAR sysarm64[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\','s','y','s','a','r','m','6','4','\\',0};
1619 if (machine == native_machine) machine = IMAGE_FILE_MACHINE_TARGET_HOST;
1621 switch (machine)
1623 case IMAGE_FILE_MACHINE_TARGET_HOST: return system32;
1624 case IMAGE_FILE_MACHINE_I386: return syswow64;
1625 case IMAGE_FILE_MACHINE_ARMNT: return sysarm32;
1626 case IMAGE_FILE_MACHINE_AMD64: return sysx8664;
1627 case IMAGE_FILE_MACHINE_ARM64: return sysarm64;
1628 default: return NULL;
1633 /***************************************************************************
1634 * is_builtin_path
1636 * Check if path is inside a system directory, to support loading builtins
1637 * when the corresponding file doesn't exist yet.
1639 BOOL is_builtin_path( const UNICODE_STRING *path, WORD *machine )
1641 unsigned int i, len = path->Length / sizeof(WCHAR), dirlen;
1642 const WCHAR *sysdir, *p = path->Buffer;
1644 /* only fake builtin existence during prefix bootstrap */
1645 if (!is_prefix_bootstrap) return FALSE;
1647 for (i = 0; i < supported_machines_count; i++)
1649 sysdir = get_machine_wow64_dir( supported_machines[i] );
1650 dirlen = wcslen( sysdir );
1651 if (len <= dirlen) continue;
1652 if (wcsnicmp( p, sysdir, dirlen )) continue;
1653 /* check for remaining path components */
1654 for (p += dirlen, len -= dirlen; len; p++, len--) if (*p == '\\') return FALSE;
1655 *machine = supported_machines[i];
1656 return TRUE;
1658 return FALSE;
1662 /***********************************************************************
1663 * open_main_image
1665 static NTSTATUS open_main_image( WCHAR *image, void **module, SECTION_IMAGE_INFORMATION *info,
1666 enum loadorder loadorder, USHORT machine )
1668 static const WCHAR soW[] = {'.','s','o',0};
1669 UNICODE_STRING nt_name;
1670 OBJECT_ATTRIBUTES attr;
1671 pe_image_info_t pe_info;
1672 SIZE_T size = 0;
1673 char *unix_name;
1674 NTSTATUS status;
1675 HANDLE mapping;
1676 WCHAR *p;
1678 if (loadorder == LO_DISABLED) NtTerminateProcess( GetCurrentProcess(), STATUS_DLL_NOT_FOUND );
1680 init_unicode_string( &nt_name, image );
1681 InitializeObjectAttributes( &attr, &nt_name, OBJ_CASE_INSENSITIVE, 0, NULL );
1682 if (nt_to_unix_file_name( &attr, &unix_name, FILE_OPEN )) return STATUS_DLL_NOT_FOUND;
1684 status = open_dll_file( unix_name, &attr, &mapping );
1685 if (!status)
1687 status = virtual_map_module( mapping, module, &size, info, 0, machine );
1688 if (!status && info->u.s.ComPlusNativeReady) info->Machine = native_machine;
1689 NtClose( mapping );
1691 else if (status == STATUS_INVALID_IMAGE_NOT_MZ && loadorder != LO_NATIVE)
1693 /* remove .so extension from Windows name */
1694 p = image + wcslen(image);
1695 if (p - image > 3 && !wcsicmp( p - 3, soW ))
1697 p[-3] = 0;
1698 nt_name.Length -= 3 * sizeof(WCHAR);
1700 status = dlopen_dll( unix_name, &nt_name, module, &pe_info, FALSE );
1701 if (!status) virtual_fill_image_information( &pe_info, info );
1703 free( unix_name );
1704 return status;
1708 /***********************************************************************
1709 * load_main_exe
1711 NTSTATUS load_main_exe( const WCHAR *dos_name, const char *unix_name, const WCHAR *curdir,
1712 WCHAR **image, void **module )
1714 enum loadorder loadorder = LO_INVALID;
1715 UNICODE_STRING nt_name;
1716 WCHAR *tmp = NULL;
1717 BOOL contains_path;
1718 unsigned int status;
1719 SIZE_T size;
1720 struct stat st;
1721 WORD machine;
1723 /* special case for Unix file name */
1724 if (unix_name && unix_name[0] == '/' && !stat( unix_name, &st ))
1726 if ((status = unix_to_nt_file_name( unix_name, image ))) goto failed;
1727 init_unicode_string( &nt_name, *image );
1728 loadorder = get_load_order( &nt_name );
1729 status = open_main_image( *image, module, &main_image_info, loadorder, 0 );
1730 if (status != STATUS_DLL_NOT_FOUND) return status;
1731 free( *image );
1734 if (!dos_name)
1736 dos_name = tmp = malloc( (strlen(unix_name) + 1) * sizeof(WCHAR) );
1737 ntdll_umbstowcs( unix_name, strlen(unix_name) + 1, tmp, strlen(unix_name) + 1 );
1739 contains_path = (wcschr( dos_name, '/' ) ||
1740 wcschr( dos_name, '\\' ) ||
1741 (dos_name[0] && dos_name[1] == ':'));
1743 if ((status = get_full_path( dos_name, curdir, image ))) goto failed;
1744 free( tmp );
1746 init_unicode_string( &nt_name, *image );
1747 if (loadorder == LO_INVALID) loadorder = get_load_order( &nt_name );
1749 status = open_main_image( *image, module, &main_image_info, loadorder, 0 );
1750 if (status != STATUS_DLL_NOT_FOUND) return status;
1752 /* if path is in system dir, we can load the builtin even if the file itself doesn't exist */
1753 if (loadorder != LO_NATIVE && is_builtin_path( &nt_name, &machine ))
1755 status = find_builtin_dll( &nt_name, module, &size, &main_image_info, 0, machine, 0, FALSE );
1756 if (status != STATUS_DLL_NOT_FOUND) return status;
1758 if (!contains_path) return STATUS_DLL_NOT_FOUND;
1760 failed:
1761 MESSAGE( "wine: failed to open %s: %x\n",
1762 unix_name ? debugstr_a(unix_name) : debugstr_w(dos_name), status );
1763 NtTerminateProcess( GetCurrentProcess(), status );
1764 return status; /* unreached */
1768 /***********************************************************************
1769 * load_start_exe
1771 * Load start.exe as main image.
1773 NTSTATUS load_start_exe( WCHAR **image, void **module )
1775 static const WCHAR startW[] = {'s','t','a','r','t','.','e','x','e',0};
1776 UNICODE_STRING nt_name;
1777 unsigned int status;
1778 SIZE_T size;
1780 *image = malloc( sizeof("\\??\\C:\\windows\\system32\\start.exe") * sizeof(WCHAR) );
1781 wcscpy( *image, get_machine_wow64_dir( current_machine ));
1782 wcscat( *image, startW );
1783 init_unicode_string( &nt_name, *image );
1784 status = find_builtin_dll( &nt_name, module, &size, &main_image_info, 0, current_machine, 0, FALSE );
1785 if (status)
1787 MESSAGE( "wine: failed to load start.exe: %x\n", status );
1788 NtTerminateProcess( GetCurrentProcess(), status );
1790 return status;
1794 /***********************************************************************
1795 * load_ntdll_functions
1797 static void load_ntdll_functions( HMODULE module )
1799 void **p__wine_unix_call_dispatcher;
1800 unixlib_handle_t *p__wine_unixlib_handle;
1802 ntdll_exports = get_module_data_dir( module, IMAGE_FILE_EXPORT_DIRECTORY, NULL );
1803 assert( ntdll_exports );
1805 #define GET_FUNC(name) \
1806 if (!(p##name = (void *)find_named_export( module, ntdll_exports, #name ))) \
1807 ERR( "%s not found\n", #name )
1809 GET_FUNC( DbgUiRemoteBreakin );
1810 GET_FUNC( KiRaiseUserExceptionDispatcher );
1811 GET_FUNC( KiUserExceptionDispatcher );
1812 GET_FUNC( KiUserApcDispatcher );
1813 GET_FUNC( KiUserCallbackDispatcher );
1814 GET_FUNC( LdrInitializeThunk );
1815 GET_FUNC( LdrSystemDllInitBlock );
1816 GET_FUNC( RtlUserThreadStart );
1817 GET_FUNC( __wine_ctrl_routine );
1818 GET_FUNC( __wine_syscall_dispatcher );
1819 GET_FUNC( __wine_unix_call_dispatcher );
1820 GET_FUNC( __wine_unixlib_handle );
1821 *p__wine_unix_call_dispatcher = __wine_unix_call_dispatcher;
1822 *p__wine_unixlib_handle = (UINT_PTR)unix_call_funcs;
1823 #ifdef __aarch64__
1825 void **p__wine_current_teb;
1826 GET_FUNC( __wine_current_teb );
1827 *p__wine_current_teb = NtCurrentTeb;
1829 #endif
1830 #undef GET_FUNC
1834 /***********************************************************************
1835 * load_ntdll_wow64_functions
1837 static void load_ntdll_wow64_functions( HMODULE module )
1839 const IMAGE_EXPORT_DIRECTORY *exports;
1841 exports = get_module_data_dir( module, IMAGE_FILE_EXPORT_DIRECTORY, NULL );
1842 assert( exports );
1844 pLdrSystemDllInitBlock->ntdll_handle = (ULONG_PTR)module;
1846 #define GET_FUNC(name) pLdrSystemDllInitBlock->p##name = find_named_export( module, exports, #name )
1847 GET_FUNC( KiUserApcDispatcher );
1848 GET_FUNC( KiUserCallbackDispatcher );
1849 GET_FUNC( KiUserExceptionDispatcher );
1850 GET_FUNC( LdrInitializeThunk );
1851 GET_FUNC( LdrSystemDllInitBlock );
1852 GET_FUNC( RtlUserThreadStart );
1853 GET_FUNC( RtlpFreezeTimeBias );
1854 GET_FUNC( RtlpQueryProcessDebugInformationRemote );
1855 #undef GET_FUNC
1857 p__wine_ctrl_routine = (void *)find_named_export( module, exports, "__wine_ctrl_routine" );
1859 #ifdef _WIN64
1861 unixlib_handle_t *p__wine_unixlib_handle = (void *)find_named_export( module, exports,
1862 "__wine_unixlib_handle" );
1863 *p__wine_unixlib_handle = (UINT_PTR)unix_call_wow64_funcs;
1865 #endif
1867 /* also set the 32-bit LdrSystemDllInitBlock */
1868 memcpy( (void *)(ULONG_PTR)pLdrSystemDllInitBlock->pLdrSystemDllInitBlock,
1869 pLdrSystemDllInitBlock, sizeof(*pLdrSystemDllInitBlock) );
1873 /***********************************************************************
1874 * load_ntdll
1876 static void load_ntdll(void)
1878 static WCHAR path[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\',
1879 's','y','s','t','e','m','3','2','\\','n','t','d','l','l','.','d','l','l',0};
1880 const char *pe_dir = get_pe_dir( current_machine );
1881 unsigned int status;
1882 SECTION_IMAGE_INFORMATION info;
1883 OBJECT_ATTRIBUTES attr;
1884 UNICODE_STRING str;
1885 void *module;
1886 SIZE_T size = 0;
1887 char *name;
1889 init_unicode_string( &str, path );
1890 InitializeObjectAttributes( &attr, &str, 0, 0, NULL );
1892 name = malloc( strlen( ntdll_dir ) + strlen( pe_dir ) + sizeof("/ntdll.dll.so") );
1893 if (build_dir) sprintf( name, "%s%s/ntdll.dll", ntdll_dir, pe_dir );
1894 else sprintf( name, "%s%s/ntdll.dll", dll_dir, pe_dir );
1895 status = open_builtin_pe_file( name, &attr, &module, &size, &info, 0, current_machine, FALSE );
1896 if (status == STATUS_DLL_NOT_FOUND)
1898 sprintf( name, "%s/ntdll.dll.so", ntdll_dir );
1899 status = open_builtin_so_file( name, &attr, &module, &info, current_machine, FALSE );
1901 if (status == STATUS_IMAGE_NOT_AT_BASE) relocate_ntdll( module );
1902 else if (status) fatal_error( "failed to load %s error %x\n", name, status );
1903 free( name );
1904 load_ntdll_functions( module );
1908 /***********************************************************************
1909 * load_apiset_dll
1911 static void load_apiset_dll(void)
1913 static WCHAR path[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\',
1914 's','y','s','t','e','m','3','2','\\',
1915 'a','p','i','s','e','t','s','c','h','e','m','a','.','d','l','l',0};
1916 const char *pe_dir = get_pe_dir( current_machine );
1917 const IMAGE_NT_HEADERS *nt;
1918 const IMAGE_SECTION_HEADER *sec;
1919 API_SET_NAMESPACE *map;
1920 OBJECT_ATTRIBUTES attr;
1921 UNICODE_STRING str;
1922 unsigned int status;
1923 HANDLE handle, mapping;
1924 SIZE_T size;
1925 char *name;
1926 void *ptr;
1927 UINT i;
1929 init_unicode_string( &str, path );
1930 InitializeObjectAttributes( &attr, &str, 0, 0, NULL );
1932 name = malloc( strlen( ntdll_dir ) + strlen( pe_dir ) + sizeof("/apisetschema/apisetschema.dll") );
1933 if (build_dir) sprintf( name, "%s/dlls/apisetschema%s/apisetschema.dll", build_dir, pe_dir );
1934 else sprintf( name, "%s%s/apisetschema.dll", dll_dir, pe_dir );
1935 status = open_unix_file( &handle, name, GENERIC_READ | SYNCHRONIZE, &attr, 0,
1936 FILE_SHARE_READ | FILE_SHARE_DELETE, FILE_OPEN,
1937 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE, NULL, 0 );
1938 free( name );
1940 if (!status)
1942 status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ,
1943 NULL, NULL, PAGE_READONLY, SEC_COMMIT, handle );
1944 NtClose( handle );
1946 if (!status)
1948 status = map_section( mapping, &ptr, &size, PAGE_READONLY );
1949 NtClose( mapping );
1951 if (!status)
1953 nt = get_rva( ptr, ((IMAGE_DOS_HEADER *)ptr)->e_lfanew );
1954 sec = (IMAGE_SECTION_HEADER *)((char *)&nt->OptionalHeader + nt->FileHeader.SizeOfOptionalHeader);
1956 for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
1958 if (memcmp( (char *)sec->Name, ".apiset", 8 )) continue;
1959 map = (API_SET_NAMESPACE *)((char *)ptr + sec->PointerToRawData);
1960 if (sec->PointerToRawData < size &&
1961 size - sec->PointerToRawData >= sec->Misc.VirtualSize &&
1962 map->Version == 6 &&
1963 map->Size <= sec->Misc.VirtualSize)
1965 peb->ApiSetMap = map;
1966 if (wow_peb) wow_peb->ApiSetMap = PtrToUlong(map);
1967 TRACE( "loaded %s apiset at %p\n", debugstr_w(path), map );
1968 return;
1970 break;
1972 NtUnmapViewOfSection( NtCurrentProcess(), ptr );
1973 status = STATUS_APISET_NOT_PRESENT;
1975 ERR( "failed to load apiset: %x\n", status );
1979 /***********************************************************************
1980 * load_wow64_ntdll
1982 static void load_wow64_ntdll( USHORT machine )
1984 static const WCHAR ntdllW[] = {'n','t','d','l','l','.','d','l','l',0};
1985 SECTION_IMAGE_INFORMATION info;
1986 UNICODE_STRING nt_name;
1987 void *module;
1988 unsigned int status;
1989 SIZE_T size;
1990 WCHAR *path = malloc( sizeof("\\??\\C:\\windows\\system32\\ntdll.dll") * sizeof(WCHAR) );
1992 wcscpy( path, get_machine_wow64_dir( machine ));
1993 wcscat( path, ntdllW );
1994 init_unicode_string( &nt_name, path );
1995 status = find_builtin_dll( &nt_name, &module, &size, &info, 0, machine, 0, FALSE );
1996 switch (status)
1998 case STATUS_IMAGE_NOT_AT_BASE:
1999 relocate_ntdll( module );
2000 /* fall through */
2001 case STATUS_SUCCESS:
2002 load_ntdll_wow64_functions( module );
2003 TRACE("loaded %s at %p\n", debugstr_w(path), module );
2004 break;
2005 default:
2006 ERR( "failed to load %s error %x\n", debugstr_w(path), status );
2007 break;
2009 free( path );
2013 /***********************************************************************
2014 * get_image_address
2016 static ULONG_PTR get_image_address(void)
2018 #ifdef HAVE_GETAUXVAL
2019 ULONG_PTR size, num, phdr_addr = getauxval( AT_PHDR );
2020 ElfW(Phdr) *phdr;
2022 if (!phdr_addr) return 0;
2023 phdr = (ElfW(Phdr) *)phdr_addr;
2024 size = getauxval( AT_PHENT );
2025 num = getauxval( AT_PHNUM );
2026 while (num--)
2028 if (phdr->p_type == PT_PHDR) return phdr_addr - phdr->p_offset;
2029 phdr = (ElfW(Phdr) *)((char *)phdr + size);
2031 #elif defined(__APPLE__) && defined(TASK_DYLD_INFO)
2032 struct task_dyld_info dyld_info;
2033 mach_msg_type_number_t size = TASK_DYLD_INFO_COUNT;
2035 if (task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&dyld_info, &size) == KERN_SUCCESS)
2036 return dyld_info.all_image_info_addr;
2037 #endif
2038 return 0;
2041 /***********************************************************************
2042 * start_main_thread
2044 static void start_main_thread(void)
2046 SYSTEM_SERVICE_TABLE syscall_table = { (ULONG_PTR *)syscalls, NULL, ARRAY_SIZE(syscalls), syscall_args };
2047 TEB *teb = virtual_alloc_first_teb();
2049 signal_init_threading();
2050 signal_alloc_thread( teb );
2051 dbg_init();
2052 startup_info_size = server_init_process();
2053 virtual_map_user_shared_data();
2054 init_cpu_info();
2055 init_files();
2056 init_startup_info();
2057 *(ULONG_PTR *)&peb->CloudFileFlags = get_image_address();
2058 set_load_order_app_name( main_wargv[0] );
2059 init_thread_stack( teb, 0, 0, 0 );
2060 NtCreateKeyedEvent( &keyed_event, GENERIC_READ | GENERIC_WRITE, NULL, 0 );
2061 load_ntdll();
2062 if (main_image_info.Machine != current_machine) load_wow64_ntdll( main_image_info.Machine );
2063 load_apiset_dll();
2064 ntdll_init_syscalls( 0, &syscall_table, p__wine_syscall_dispatcher );
2065 server_init_process_done();
2068 #ifdef __ANDROID__
2070 #ifndef WINE_JAVA_CLASS
2071 #define WINE_JAVA_CLASS "org/winehq/wine/WineActivity"
2072 #endif
2074 JavaVM *java_vm = NULL;
2075 jobject java_object = 0;
2076 unsigned short java_gdt_sel = 0;
2078 /* main Wine initialisation */
2079 static jstring wine_init_jni( JNIEnv *env, jobject obj, jobjectArray cmdline, jobjectArray environment )
2081 char **argv;
2082 char *str;
2083 char error[1024];
2084 int i, argc, length;
2086 /* get the command line array */
2088 argc = (*env)->GetArrayLength( env, cmdline );
2089 for (i = length = 0; i < argc; i++)
2091 jobject str_obj = (*env)->GetObjectArrayElement( env, cmdline, i );
2092 length += (*env)->GetStringUTFLength( env, str_obj ) + 1;
2095 argv = malloc( (argc + 1) * sizeof(*argv) + length );
2096 str = (char *)(argv + argc + 1);
2097 for (i = 0; i < argc; i++)
2099 jobject str_obj = (*env)->GetObjectArrayElement( env, cmdline, i );
2100 length = (*env)->GetStringUTFLength( env, str_obj );
2101 (*env)->GetStringUTFRegion( env, str_obj, 0,
2102 (*env)->GetStringLength( env, str_obj ), str );
2103 argv[i] = str;
2104 str[length] = 0;
2105 str += length + 1;
2107 argv[argc] = NULL;
2109 /* set the environment variables */
2111 if (environment)
2113 int count = (*env)->GetArrayLength( env, environment );
2114 for (i = 0; i < count - 1; i += 2)
2116 jobject var_obj = (*env)->GetObjectArrayElement( env, environment, i );
2117 jobject val_obj = (*env)->GetObjectArrayElement( env, environment, i + 1 );
2118 const char *var = (*env)->GetStringUTFChars( env, var_obj, NULL );
2120 if (val_obj)
2122 const char *val = (*env)->GetStringUTFChars( env, val_obj, NULL );
2123 setenv( var, val, 1 );
2124 if (!strcmp( var, "LD_LIBRARY_PATH" ))
2126 void (*update_func)( const char * ) = dlsym( RTLD_DEFAULT,
2127 "android_update_LD_LIBRARY_PATH" );
2128 if (update_func) update_func( val );
2130 else if (!strcmp( var, "WINEDEBUGLOG" ))
2132 int fd = open( val, O_WRONLY | O_CREAT | O_APPEND, 0666 );
2133 if (fd != -1)
2135 dup2( fd, 2 );
2136 close( fd );
2139 (*env)->ReleaseStringUTFChars( env, val_obj, val );
2141 else unsetenv( var );
2143 (*env)->ReleaseStringUTFChars( env, var_obj, var );
2147 java_object = (*env)->NewGlobalRef( env, obj );
2149 init_paths( argv );
2150 virtual_init();
2151 init_environment( argc, argv, environ );
2153 #ifdef __i386__
2155 unsigned short java_fs;
2156 __asm__( "mov %%fs,%0" : "=r" (java_fs) );
2157 if (!(java_fs & 4)) java_gdt_sel = java_fs;
2158 __asm__( "mov %0,%%fs" :: "r" (0) );
2159 start_main_thread();
2160 __asm__( "mov %0,%%fs" :: "r" (java_fs) );
2162 #else
2163 start_main_thread();
2164 #endif
2165 return (*env)->NewStringUTF( env, error );
2168 jint JNI_OnLoad( JavaVM *vm, void *reserved )
2170 static const JNINativeMethod method =
2172 "wine_init", "([Ljava/lang/String;[Ljava/lang/String;)Ljava/lang/String;", wine_init_jni
2175 JNIEnv *env;
2176 jclass class;
2178 java_vm = vm;
2179 if ((*vm)->AttachCurrentThread( vm, &env, NULL ) != JNI_OK) return JNI_ERR;
2180 if (!(class = (*env)->FindClass( env, WINE_JAVA_CLASS ))) return JNI_ERR;
2181 (*env)->RegisterNatives( env, class, &method, 1 );
2182 return JNI_VERSION_1_6;
2185 #endif /* __ANDROID__ */
2187 #ifdef __APPLE__
2188 static void *apple_wine_thread( void *arg )
2190 start_main_thread();
2191 return NULL;
2194 /***********************************************************************
2195 * apple_create_wine_thread
2197 * Spin off a secondary thread to complete Wine initialization, leaving
2198 * the original thread for the Mac frameworks.
2200 * Invoked as a CFRunLoopSource perform callback.
2202 static void apple_create_wine_thread( void *arg )
2204 pthread_t thread;
2205 pthread_attr_t attr;
2207 pthread_attr_init( &attr );
2208 pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
2209 /* Use the same QoS class as the process main thread (user-interactive). */
2210 if (&pthread_attr_set_qos_class_np)
2211 pthread_attr_set_qos_class_np( &attr, QOS_CLASS_USER_INTERACTIVE, 0 );
2212 if (pthread_create( &thread, &attr, apple_wine_thread, NULL )) exit(1);
2213 pthread_attr_destroy( &attr );
2217 /***********************************************************************
2218 * apple_main_thread
2220 * Park the process's original thread in a Core Foundation run loop for
2221 * use by the Mac frameworks, especially receiving and handling
2222 * distributed notifications. Spin off a new thread for the rest of the
2223 * Wine initialization.
2225 static void apple_main_thread(void)
2227 CFRunLoopSourceContext source_context = { 0 };
2228 CFRunLoopSourceRef source;
2230 if (!pthread_main_np()) return;
2232 #pragma clang diagnostic push
2233 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
2234 /* Multi-processing Services can get confused about the main thread if the
2235 * first time it's used is on a secondary thread. Use it here to make sure
2236 * that doesn't happen. */
2237 MPTaskIsPreemptive(MPCurrentTaskID());
2238 #pragma clang diagnostic pop
2240 /* Give ourselves the best chance of having the distributed notification
2241 * center scheduled on this thread's run loop. In theory, it's scheduled
2242 * in the first thread to ask for it. */
2243 CFNotificationCenterGetDistributedCenter();
2245 /* We use this run loop source for two purposes. First, a run loop exits
2246 * if it has no more sources scheduled. So, we need at least one source
2247 * to keep the run loop running. Second, although it's not critical, it's
2248 * preferable for the Wine initialization to not proceed until we know
2249 * the run loop is running. So, we signal our source immediately after
2250 * adding it and have its callback spin off the Wine thread. */
2251 source_context.perform = apple_create_wine_thread;
2252 source = CFRunLoopSourceCreate( NULL, 0, &source_context );
2253 CFRunLoopAddSource( CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes );
2254 CFRunLoopSourceSignal( source );
2255 CFRelease( source );
2256 CFRunLoopRun(); /* Should never return, except on error. */
2258 #endif /* __APPLE__ */
2261 #ifdef __ANDROID__
2263 static int pre_exec(void)
2265 #if defined(__i386__) || defined(__x86_64__)
2266 return 1; /* we have a preloader */
2267 #else
2268 return 0; /* no exec needed */
2269 #endif
2272 #elif defined(__linux__) && (defined(__i386__) || defined(__arm__))
2274 static void check_vmsplit( void *stack )
2276 if (stack < (void *)0x80000000)
2278 /* if the stack is below 0x80000000, assume we can safely try a munmap there */
2279 if (munmap( (void *)0x80000000, 1 ) == -1 && errno == EINVAL)
2280 ERR( "Warning: memory above 0x80000000 doesn't seem to be accessible.\n"
2281 "Wine requires a 3G/1G user/kernel memory split to work properly.\n" );
2285 static int pre_exec(void)
2287 int temp;
2289 check_vmsplit( &temp );
2290 return 1; /* we have a preloader on x86/arm */
2293 #elif defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__))
2295 static int pre_exec(void)
2297 return 1; /* we have a preloader on x86-64/arm64 */
2300 #elif defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__))
2302 static int pre_exec(void)
2304 return 1; /* we have a preloader */
2307 #elif (defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__))
2309 static int pre_exec(void)
2311 struct rlimit rl;
2313 rl.rlim_cur = 0x02000000;
2314 rl.rlim_max = 0x02000000;
2315 setrlimit( RLIMIT_DATA, &rl );
2316 return 1;
2319 #else
2321 static int pre_exec(void)
2323 return 0; /* no exec needed */
2326 #endif
2329 /***********************************************************************
2330 * check_command_line
2332 * Check if command line is one that needs to be handled specially.
2334 static void check_command_line( int argc, char *argv[] )
2336 static const char usage[] =
2337 "Usage: wine PROGRAM [ARGUMENTS...] Run the specified program\n"
2338 " wine --help Display this help and exit\n"
2339 " wine --version Output version information and exit";
2341 if (argc <= 1)
2343 fprintf( stderr, "%s\n", usage );
2344 exit(1);
2346 if (!strcmp( argv[1], "--help" ))
2348 printf( "%s\n", usage );
2349 exit(0);
2351 if (!strcmp( argv[1], "--version" ))
2353 printf( "%s\n", wine_build );
2354 exit(0);
2359 /***********************************************************************
2360 * __wine_main
2362 * Main entry point called by the wine loader.
2364 void __wine_main( int argc, char *argv[], char *envp[] )
2366 init_paths( argv );
2368 if (!getenv( "WINELOADERNOEXEC" )) /* first time around */
2370 check_command_line( argc, argv );
2371 if (pre_exec())
2373 static char noexec[] = "WINELOADERNOEXEC=1";
2374 char **new_argv = malloc( (argc + 2) * sizeof(*argv) );
2376 memcpy( new_argv + 1, argv, (argc + 1) * sizeof(*argv) );
2377 putenv( noexec );
2378 loader_exec( new_argv, current_machine );
2379 fatal_error( "could not exec the wine loader\n" );
2383 #ifdef RLIMIT_NOFILE
2384 set_max_limit( RLIMIT_NOFILE );
2385 #endif
2386 #ifdef RLIMIT_AS
2387 set_max_limit( RLIMIT_AS );
2388 #endif
2390 virtual_init();
2391 init_environment( argc, argv, envp );
2393 #ifdef __APPLE__
2394 apple_main_thread();
2395 #endif
2396 start_main_thread();