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
35 #include <sys/types.h>
50 #ifdef HAVE_SYS_AUXV_H
51 # include <sys/auxv.h>
53 #ifdef HAVE_SYS_RESOURCE_H
54 # include <sys/resource.h>
57 #ifdef HAVE_SYS_SYSCTL_H
58 # include <sys/sysctl.h>
61 # include <CoreFoundation/CoreFoundation.h>
62 # define LoadResource MacLoadResource
63 # define GetCurrentThread MacGetCurrentThread
64 # include <CoreServices/CoreServices.h>
66 # undef GetCurrentThread
68 # include <mach/mach.h>
69 # include <mach/mach_error.h>
70 # include <mach-o/getsect.h>
71 # include <crt_externs.h>
73 # ifndef _POSIX_SPAWN_DISABLE_ASLR
74 # define _POSIX_SPAWN_DISABLE_ASLR 0x0100
82 #define WIN32_NO_STATUS
83 #define NONAMELESSUNION
84 #define NONAMELESSSTRUCT
91 #include "unix_private.h"
92 #include "wine/list.h"
93 #include "wine/debug.h"
95 WINE_DEFAULT_DEBUG_CHANNEL(module
);
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";
106 static const char so_dir
[] = "";
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
[] =
125 NtAccessCheckAndAuditAlarm
,
128 NtAdjustPrivilegesToken
,
131 NtAlertThreadByThreadId
,
132 NtAllocateLocallyUniqueId
,
134 NtAllocateVirtualMemory
,
135 NtAllocateVirtualMemoryEx
,
136 NtAreMappedFilesTheSame
,
137 NtAssignProcessToJobObject
,
141 NtCancelSynchronousIoFile
,
147 NtCompleteConnectPort
,
151 NtCreateDirectoryObject
,
154 NtCreateIoCompletion
,
157 NtCreateKeyTransacted
,
160 NtCreateMailslotFile
,
162 NtCreateNamedPipeFile
,
167 NtCreateSymbolicLinkObject
,
173 NtDebugActiveProcess
,
180 NtDeviceIoControlFile
,
189 NtFlushInstructionCache
,
191 NtFlushProcessWriteBuffers
,
192 NtFlushVirtualMemory
,
196 NtGetCurrentProcessorNumber
,
200 NtImpersonateAnonymousToken
,
201 NtInitializeNlsFiles
,
202 NtInitiatePowerAction
,
211 NtMakeTemporaryObject
,
213 NtMapViewOfSectionEx
,
214 NtNotifyChangeDirectoryFile
,
216 NtNotifyChangeMultipleKeys
,
217 NtOpenDirectoryObject
,
225 NtOpenKeyTransactedEx
,
230 NtOpenProcessTokenEx
,
233 NtOpenSymbolicLinkObject
,
240 NtProtectVirtualMemory
,
242 NtQueryAttributesFile
,
243 NtQueryDefaultLocale
,
244 NtQueryDefaultUILanguage
,
245 NtQueryDirectoryFile
,
246 NtQueryDirectoryObject
,
249 NtQueryFullAttributesFile
,
250 NtQueryInformationAtom
,
251 NtQueryInformationFile
,
252 NtQueryInformationJobObject
,
253 NtQueryInformationProcess
,
254 NtQueryInformationThread
,
255 NtQueryInformationToken
,
256 NtQueryInstallUILanguage
,
260 NtQueryMultipleValueKey
,
263 NtQueryPerformanceCounter
,
265 NtQuerySecurityObject
,
267 NtQuerySymbolicLinkObject
,
268 NtQuerySystemEnvironmentValue
,
269 NtQuerySystemEnvironmentValueEx
,
270 NtQuerySystemInformation
,
271 NtQuerySystemInformationEx
,
274 NtQueryTimerResolution
,
276 NtQueryVirtualMemory
,
277 NtQueryVolumeInformationFile
,
284 NtRegisterThreadTerminatePort
,
288 NtRemoveIoCompletion
,
289 NtRemoveIoCompletionEx
,
290 NtRemoveProcessDebug
,
293 NtReplyWaitReceivePort
,
294 NtRequestWaitReplyPort
,
300 NtRollbackTransaction
,
304 NtSetDebugFilterState
,
306 NtSetDefaultUILanguage
,
309 NtSetInformationDebugObject
,
310 NtSetInformationFile
,
311 NtSetInformationJobObject
,
313 NtSetInformationObject
,
314 NtSetInformationProcess
,
315 NtSetInformationThread
,
316 NtSetInformationToken
,
317 NtSetInformationVirtualMemory
,
318 NtSetIntervalProfile
,
322 NtSetSystemInformation
,
324 NtSetThreadExecutionState
,
326 NtSetTimerResolution
,
328 NtSetVolumeInformationFile
,
330 NtSignalAndWaitForSingleObject
,
333 NtSystemDebugControl
,
334 NtTerminateJobObject
,
342 NtUnlockVirtualMemory
,
343 NtUnmapViewOfSection
,
344 NtUnmapViewOfSectionEx
,
345 NtWaitForAlertByThreadId
,
348 NtWaitForMultipleObjects
,
349 NtWaitForSingleObject
,
351 NtWow64AllocateVirtualMemory64
,
352 NtWow64GetNativeSystemInformation
,
353 NtWow64IsProcessorFeaturePresent
,
354 NtWow64ReadVirtualMemory64
,
355 NtWow64WriteVirtualMemory64
,
359 NtWriteVirtualMemory
,
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];
370 static void fatal_error( const char *err
, ... ) __attribute__((noreturn
, format(printf
,1,2)));
373 #if defined(linux) || defined(__APPLE__)
374 static const BOOL use_preloader
= TRUE
;
376 static const BOOL use_preloader
= FALSE
;
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
)
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);
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
, ... )
437 va_start( args
, err
);
438 fprintf( stderr
, "wine: " );
439 vfprintf( stderr
, err
, args
);
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
);
466 /* canonicalize path and return its directory name */
467 static char *realpath_dirname( const char *name
)
469 char *p
, *fullpath
= realpath( name
, NULL
);
473 p
= strrchr( fullpath
, '/' );
474 if (p
== fullpath
) p
++;
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
);
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;
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
);
509 static const char *get_pe_dir( WORD machine
)
511 if (!machine
) machine
= current_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";
524 static void set_dll_path(void)
526 char *p
, *path
= getenv( "WINEDLLPATH" );
529 if (path
) for (p
= path
, count
= 1; *p
; p
++) if (*p
== ':') count
++;
531 dll_paths
= malloc( (count
+ 2) * sizeof(*dll_paths
) );
534 if (!build_dir
) dll_paths
[count
++] = dll_dir
;
539 for (p
= strtok( path
, ":" ); p
; p
= strtok( NULL
, ":" )) dll_paths
[count
++] = strdup( p
);
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
;
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
) );
560 char *path_copy
= strdup(path
);
561 for (p
= strtok( path_copy
, ":" ); p
; p
= strtok( NULL
, ":" ))
562 system_dll_paths
[count
++] = strdup( p
);
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" );
577 struct passwd
*pwd
= getpwuid( getuid() );
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)
595 const char *prefix
= getenv( "WINEPREFIX" );
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;
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
[] )
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
);
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
);
650 set_system_dll_path();
656 /***********************************************************************
657 * get_alternate_wineloader
659 char *get_alternate_wineloader( WORD machine
)
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
);
678 return remove_tail( wineloader
, "64" );
682 static void preloader_exec( char **argv
)
686 static const char *preloader
= "wine-preloader";
689 if (!(p
= strrchr( argv
[1], '/' ))) p
= argv
[1];
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
);
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
);
706 execv( argv
[0], argv
);
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 /***********************************************************************
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 /***********************************************************************
754 * Exec a new wine server.
756 static void exec_wineserver( char **argv
)
762 if (!is_win64
) /* look for 64-bit server */
764 char *loader
= realpath_dirname( build_path( build_dir
, "loader/wine64" ));
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
);
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 /***********************************************************************
799 * Start a new wine server.
801 void start_server( BOOL debug
)
803 static BOOL started
; /* we only try once */
805 static char debug_flag
[] = "-d";
811 if (pid
== -1) fatal_error( "fork: %s", strerror(errno
) );
814 argv
[1] = debug
? debug_flag
: 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 */
828 /*************************************************************************
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 */
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
;
860 dos
->e_cparhdr
= (sizeof(*dos
) + 0xf) / 0x10;
862 dos
->e_maxalloc
= 0xffff;
865 dos
->e_lfanew
= sizeof(*dos
) + sizeof(builtin_signature
);
866 memcpy( dos
+ 1, builtin_signature
, sizeof(builtin_signature
) );
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
;
877 unsigned long data_size
;
878 /* need the mach_header, not the PE header, to give to getsegmentdata(3) */
880 code_end
= getsegmentdata(dli
.dli_fbase
, "__DATA", &data_size
) - addr
;
881 data_end
= (code_end
+ data_size
+ align_mask
) & ~align_mask
;
884 code_end
= data_start
;
885 data_end
= (nt
->OptionalHeader
.SizeOfImage
+ delta
+ align_mask
) & ~align_mask
;
888 fixup_rva_ptrs( &nt
->OptionalHeader
.AddressOfEntryPoint
, addr
, 1 );
890 nt
->FileHeader
.NumberOfSections
= nb_sections
;
891 nt
->OptionalHeader
.BaseOfCode
= code_start
;
893 nt
->OptionalHeader
.BaseOfData
= data_start
;
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
);
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
);
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
];
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
);
945 /* build the resource directory */
947 dir
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_FILE_RESOURCE_DIRECTORY
];
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
];
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
];
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
);
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
,
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;
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;
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
];
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
,
1044 char *page
= get_rva( module
, rel
->VirtualAddress
);
1045 UINT count
= (rel
->SizeOfBlock
- sizeof(*rel
)) / sizeof(USHORT
);
1046 USHORT
*relocs
= (USHORT
*)(rel
+ 1);
1050 USHORT offset
= *relocs
& 0xfff;
1051 switch (*relocs
>> 12)
1053 case IMAGE_REL_BASED_ABSOLUTE
:
1055 case IMAGE_REL_BASED_HIGH
:
1056 *(short *)(page
+ offset
) += HIWORD(delta
);
1058 case IMAGE_REL_BASED_LOW
:
1059 *(short *)(page
+ offset
) += LOWORD(delta
);
1061 case IMAGE_REL_BASED_HIGHLOW
:
1062 *(int *)(page
+ offset
) += delta
;
1064 case IMAGE_REL_BASED_DIR64
:
1065 *(INT64
*)(page
+ offset
) += delta
;
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
;
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);
1085 FIXME("Unknown/unsupported relocation %x\n", *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
;
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 /***********************************************************************
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
);
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
;
1184 return STATUS_SUCCESS
;
1187 if (map_so_dll( nt
, module
))
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
) );
1198 return STATUS_IMAGE_ALREADY_LOADED
;
1201 if (virtual_create_builtin_view( module
, nt_name
, image_info
, 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
)
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 /***********************************************************************
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
= ¶ms
->nt_name
;
1244 OBJECT_ATTRIBUTES attr
;
1245 UNICODE_STRING redir
;
1246 pe_image_info_t info
;
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
);
1267 free( redir
.Buffer
);
1272 static const unixlib_entry_t unix_call_funcs
[] =
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
,
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
[] =
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
,
1299 system_time_precise
,
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
)
1310 struct /* Mach-O header */
1313 unsigned int cputype
;
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 */
1321 struct /* ELF header */
1323 unsigned char magic
[4];
1324 unsigned char class;
1326 unsigned char version
;
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;
1335 if (header
.data
!= 1 /* ELFDATA2LSB */) return 1;
1337 if (sizeof(void *) == sizeof(int)) return header
.class == 1; /* ELFCLASS32 */
1338 else return header
.class == 2; /* ELFCLASS64 */
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
)
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
) );
1362 /***********************************************************************
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
)
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 */
1381 if (!stat( name
, &st
)) return status
;
1383 /* otherwise continue searching */
1384 return STATUS_DLL_NOT_FOUND
;
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
);
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
)
1407 status
= open_dll_file( name
, attr
, &mapping
);
1410 status
= virtual_map_builtin_module( mapping
, module
, size
, image_info
, limit
, machine
, prefer_native
);
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
)
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
;
1450 /***********************************************************************
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;
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
;
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
++)
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 */
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
)
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
) );
1547 if (status
>= 0 && ext
)
1549 strcpy( ext
, ".so" );
1550 load_builtin_unixlib( *module
, ptr
);
1557 /***********************************************************************
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
)
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 */
1591 case LO_NATIVE_BUILTIN
:
1592 return STATUS_IMAGE_ALREADY_LOADED
;
1594 return find_builtin_dll( &nt_name
, module
, size
, &info
, limit
,
1595 image_info
->machine
, machine
, FALSE
);
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
;
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
;
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 /***************************************************************************
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
];
1662 /***********************************************************************
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
;
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
);
1687 status
= virtual_map_module( mapping
, module
, &size
, info
, 0, machine
);
1688 if (!status
&& info
->u
.s
.ComPlusNativeReady
) info
->Machine
= native_machine
;
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
))
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
);
1708 /***********************************************************************
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
;
1718 unsigned int status
;
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
;
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
;
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
;
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 /***********************************************************************
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
;
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
);
1787 MESSAGE( "wine: failed to load start.exe: %x\n", status
);
1788 NtTerminateProcess( GetCurrentProcess(), 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
;
1825 void **p__wine_current_teb
;
1826 GET_FUNC( __wine_current_teb
);
1827 *p__wine_current_teb
= NtCurrentTeb
;
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
);
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
);
1857 p__wine_ctrl_routine
= (void *)find_named_export( module
, exports
, "__wine_ctrl_routine" );
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
;
1867 /* also set the 32-bit LdrSystemDllInitBlock */
1868 memcpy( (void *)(ULONG_PTR
)pLdrSystemDllInitBlock
->pLdrSystemDllInitBlock
,
1869 pLdrSystemDllInitBlock
, sizeof(*pLdrSystemDllInitBlock
) );
1873 /***********************************************************************
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
;
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
);
1904 load_ntdll_functions( module
);
1908 /***********************************************************************
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
;
1922 unsigned int status
;
1923 HANDLE handle
, mapping
;
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 );
1942 status
= NtCreateSection( &mapping
, STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY
| SECTION_MAP_READ
,
1943 NULL
, NULL
, PAGE_READONLY
, SEC_COMMIT
, handle
);
1948 status
= map_section( mapping
, &ptr
, &size
, PAGE_READONLY
);
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
);
1972 NtUnmapViewOfSection( NtCurrentProcess(), ptr
);
1973 status
= STATUS_APISET_NOT_PRESENT
;
1975 ERR( "failed to load apiset: %x\n", status
);
1979 /***********************************************************************
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
;
1988 unsigned int status
;
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
);
1998 case STATUS_IMAGE_NOT_AT_BASE
:
1999 relocate_ntdll( module
);
2001 case STATUS_SUCCESS
:
2002 load_ntdll_wow64_functions( module
);
2003 TRACE("loaded %s at %p\n", debugstr_w(path
), module
);
2006 ERR( "failed to load %s error %x\n", debugstr_w(path
), status
);
2013 /***********************************************************************
2016 static ULONG_PTR
get_image_address(void)
2018 #ifdef HAVE_GETAUXVAL
2019 ULONG_PTR size
, num
, phdr_addr
= getauxval( AT_PHDR
);
2022 if (!phdr_addr
) return 0;
2023 phdr
= (ElfW(Phdr
) *)phdr_addr
;
2024 size
= getauxval( AT_PHENT
);
2025 num
= getauxval( AT_PHNUM
);
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
;
2041 /***********************************************************************
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
);
2052 startup_info_size
= server_init_process();
2053 virtual_map_user_shared_data();
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 );
2062 if (main_image_info
.Machine
!= current_machine
) load_wow64_ntdll( main_image_info
.Machine
);
2064 ntdll_init_syscalls( 0, &syscall_table
, p__wine_syscall_dispatcher
);
2065 server_init_process_done();
2070 #ifndef WINE_JAVA_CLASS
2071 #define WINE_JAVA_CLASS "org/winehq/wine/WineActivity"
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
)
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
);
2109 /* set the environment variables */
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
);
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 );
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
);
2151 init_environment( argc
, argv
, environ
);
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
) );
2163 start_main_thread();
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
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__ */
2188 static void *apple_wine_thread( void *arg
)
2190 start_main_thread();
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
)
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 /***********************************************************************
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__ */
2263 static int pre_exec(void)
2265 #if defined(__i386__) || defined(__x86_64__)
2266 return 1; /* we have a preloader */
2268 return 0; /* no exec needed */
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)
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)
2313 rl
.rlim_cur
= 0x02000000;
2314 rl
.rlim_max
= 0x02000000;
2315 setrlimit( RLIMIT_DATA
, &rl
);
2321 static int pre_exec(void)
2323 return 0; /* no exec needed */
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";
2343 fprintf( stderr
, "%s\n", usage
);
2346 if (!strcmp( argv
[1], "--help" ))
2348 printf( "%s\n", usage
);
2351 if (!strcmp( argv
[1], "--version" ))
2353 printf( "%s\n", wine_build
);
2359 /***********************************************************************
2362 * Main entry point called by the wine loader.
2364 void __wine_main( int argc
, char *argv
[], char *envp
[] )
2368 if (!getenv( "WINELOADERNOEXEC" )) /* first time around */
2370 check_command_line( argc
, argv
);
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
) );
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
);
2387 set_max_limit( RLIMIT_AS
);
2391 init_environment( argc
, argv
, envp
);
2394 apple_main_thread();
2396 start_main_thread();