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 NTSTATUS (WINAPI
*pKiRaiseUserExceptionDispatcher
)(void) = NULL
;
110 NTSTATUS (WINAPI
*pKiUserExceptionDispatcher
)(EXCEPTION_RECORD
*,CONTEXT
*) = NULL
;
111 void (WINAPI
*pKiUserApcDispatcher
)(CONTEXT
*,ULONG_PTR
,ULONG_PTR
,ULONG_PTR
,PNTAPCFUNC
) = NULL
;
112 void (WINAPI
*pKiUserCallbackDispatcher
)(ULONG
,void*,ULONG
) = NULL
;
113 void (WINAPI
*pLdrInitializeThunk
)(CONTEXT
*,void**,ULONG_PTR
,ULONG_PTR
) = NULL
;
114 void (WINAPI
*pRtlUserThreadStart
)( PRTL_THREAD_START_ROUTINE entry
, void *arg
) = NULL
;
115 void (WINAPI
*p__wine_ctrl_routine
)(void*);
116 SYSTEM_DLL_INIT_BLOCK
*pLdrSystemDllInitBlock
= NULL
;
118 static NTSTATUS (CDECL
*p__wine_set_unix_funcs
)( int version
, const struct unix_funcs
*funcs
);
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
,
145 NtCompleteConnectPort
,
149 NtCreateDirectoryObject
,
152 NtCreateIoCompletion
,
155 NtCreateKeyTransacted
,
158 NtCreateMailslotFile
,
160 NtCreateNamedPipeFile
,
165 NtCreateSymbolicLinkObject
,
170 NtDebugActiveProcess
,
177 NtDeviceIoControlFile
,
186 NtFlushInstructionCache
,
188 NtFlushProcessWriteBuffers
,
189 NtFlushVirtualMemory
,
193 NtGetCurrentProcessorNumber
,
197 NtImpersonateAnonymousToken
,
198 NtInitiatePowerAction
,
206 NtMakeTemporaryObject
,
208 NtNotifyChangeDirectoryFile
,
210 NtNotifyChangeMultipleKeys
,
211 NtOpenDirectoryObject
,
219 NtOpenKeyTransactedEx
,
224 NtOpenProcessTokenEx
,
227 NtOpenSymbolicLinkObject
,
234 NtProtectVirtualMemory
,
236 NtQueryAttributesFile
,
237 NtQueryDefaultLocale
,
238 NtQueryDefaultUILanguage
,
239 NtQueryDirectoryFile
,
240 NtQueryDirectoryObject
,
243 NtQueryFullAttributesFile
,
244 NtQueryInformationAtom
,
245 NtQueryInformationFile
,
246 NtQueryInformationJobObject
,
247 NtQueryInformationProcess
,
248 NtQueryInformationThread
,
249 NtQueryInformationToken
,
250 NtQueryInstallUILanguage
,
254 NtQueryMultipleValueKey
,
257 NtQueryPerformanceCounter
,
259 NtQuerySecurityObject
,
261 NtQuerySymbolicLinkObject
,
262 NtQuerySystemEnvironmentValue
,
263 NtQuerySystemEnvironmentValueEx
,
264 NtQuerySystemInformation
,
265 NtQuerySystemInformationEx
,
268 NtQueryTimerResolution
,
270 NtQueryVirtualMemory
,
271 NtQueryVolumeInformationFile
,
278 NtRegisterThreadTerminatePort
,
282 NtRemoveIoCompletion
,
283 NtRemoveIoCompletionEx
,
284 NtRemoveProcessDebug
,
287 NtReplyWaitReceivePort
,
288 NtRequestWaitReplyPort
,
297 NtSetDebugFilterState
,
299 NtSetDefaultUILanguage
,
302 NtSetInformationDebugObject
,
303 NtSetInformationFile
,
304 NtSetInformationJobObject
,
306 NtSetInformationObject
,
307 NtSetInformationProcess
,
308 NtSetInformationThread
,
309 NtSetInformationToken
,
310 NtSetIntervalProfile
,
314 NtSetSystemInformation
,
316 NtSetThreadExecutionState
,
318 NtSetTimerResolution
,
320 NtSetVolumeInformationFile
,
322 NtSignalAndWaitForSingleObject
,
325 NtSystemDebugControl
,
326 NtTerminateJobObject
,
334 NtUnlockVirtualMemory
,
335 NtUnmapViewOfSection
,
336 NtWaitForAlertByThreadId
,
339 NtWaitForMultipleObjects
,
340 NtWaitForSingleObject
,
342 NtWow64AllocateVirtualMemory64
,
343 NtWow64GetNativeSystemInformation
,
344 NtWow64ReadVirtualMemory64
,
345 NtWow64WriteVirtualMemory64
,
349 NtWriteVirtualMemory
,
354 wine_nt_to_unix_file_name
,
356 wine_server_fd_to_handle
,
357 wine_server_handle_to_fd
,
358 wine_unix_to_nt_file_name
,
361 static BYTE syscall_args
[ARRAY_SIZE(syscalls
)];
363 SYSTEM_SERVICE_TABLE KeServiceDescriptorTable
[4];
366 static void fatal_error( const char *err
, ... ) __attribute__((noreturn
, format(printf
,1,2)));
369 #if defined(linux) || defined(__APPLE__)
370 static const BOOL use_preloader
= TRUE
;
372 static const BOOL use_preloader
= FALSE
;
376 static const char *bin_dir
;
377 static const char *dll_dir
;
378 static const char *ntdll_dir
;
379 static SIZE_T dll_path_maxlen
;
380 static int *p___wine_main_argc
;
381 static char ***p___wine_main_argv
;
382 static WCHAR
***p___wine_main_wargv
;
384 const char *home_dir
= NULL
;
385 const char *data_dir
= NULL
;
386 const char *build_dir
= NULL
;
387 const char *config_dir
= NULL
;
388 const char **dll_paths
= NULL
;
389 const char **system_dll_paths
= NULL
;
390 const char *user_name
= NULL
;
391 SECTION_IMAGE_INFORMATION main_image_info
= { NULL
};
392 static HMODULE ntdll_module
;
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
[] )
616 argv0
= strdup( argv
[0] );
618 if (!dladdr( init_paths
, &info
) || !(ntdll_dir
= realpath_dirname( info
.dli_fname
)))
619 fatal_error( "cannot get path to ntdll.so\n" );
621 if (!(build_dir
= remove_tail( ntdll_dir
, "/dlls/ntdll" )))
623 if (!(dll_dir
= remove_tail( ntdll_dir
, so_dir
))) dll_dir
= ntdll_dir
;
624 #if (defined(__linux__) && !defined(__ANDROID__)) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
625 bin_dir
= realpath_dirname( "/proc/self/exe" );
626 #elif defined (__FreeBSD__) || defined(__DragonFly__)
628 static int pathname
[] = { CTL_KERN
, KERN_PROC
, KERN_PROC_PATHNAME
, -1 };
629 size_t path_size
= PATH_MAX
;
630 char *path
= malloc( path_size
);
631 if (path
&& !sysctl( pathname
, sizeof(pathname
)/sizeof(pathname
[0]), path
, &path_size
, NULL
, 0 ))
632 bin_dir
= realpath_dirname( path
);
636 bin_dir
= realpath_dirname( argv0
);
638 if (!bin_dir
) bin_dir
= build_path( dll_dir
, DLL_TO_BINDIR
);
639 data_dir
= build_path( bin_dir
, BIN_TO_DATADIR
);
643 set_system_dll_path();
649 static void preloader_exec( char **argv
)
653 static const char *preloader
= "wine-preloader";
656 if (!(p
= strrchr( argv
[1], '/' ))) p
= argv
[1];
659 if (strlen(p
) > 2 && !strcmp( p
+ strlen(p
) - 2, "64" )) preloader
= "wine64-preloader";
660 argv
[0] = malloc( p
- argv
[1] + strlen(preloader
) + 1 );
661 memcpy( argv
[0], argv
[1], p
- argv
[1] );
662 strcpy( argv
[0] + (p
- argv
[1]), preloader
);
666 posix_spawnattr_t attr
;
667 posix_spawnattr_init( &attr
);
668 posix_spawnattr_setflags( &attr
, POSIX_SPAWN_SETEXEC
| _POSIX_SPAWN_DISABLE_ASLR
);
669 posix_spawn( NULL
, argv
[0], NULL
, &attr
, argv
, *_NSGetEnviron() );
670 posix_spawnattr_destroy( &attr
);
673 execv( argv
[0], argv
);
676 execv( argv
[1], argv
+ 1 );
679 static NTSTATUS
loader_exec( const char *loader
, char **argv
, WORD machine
)
685 argv
[1] = build_path( build_dir
, (machine
== IMAGE_FILE_MACHINE_AMD64
) ? "loader/wine64" : "loader/wine" );
686 preloader_exec( argv
);
687 return STATUS_INVALID_IMAGE_FORMAT
;
690 if ((p
= strrchr( loader
, '/' ))) loader
= p
+ 1;
692 argv
[1] = build_path( bin_dir
, loader
);
693 preloader_exec( argv
);
695 argv
[1] = getenv( "WINELOADER" );
696 if (argv
[1]) preloader_exec( argv
);
698 if ((path
= getenv( "PATH" )))
700 for (p
= strtok( strdup( path
), ":" ); p
; p
= strtok( NULL
, ":" ))
702 argv
[1] = build_path( p
, loader
);
703 preloader_exec( argv
);
707 argv
[1] = build_path( BINDIR
, loader
);
708 preloader_exec( argv
);
709 return STATUS_INVALID_IMAGE_FORMAT
;
713 /***********************************************************************
716 * argv[0] and argv[1] must be reserved for the preloader and loader respectively.
718 NTSTATUS
exec_wineloader( char **argv
, int socketfd
, const pe_image_info_t
*pe_info
)
720 WORD machine
= pe_info
->machine
;
721 ULONGLONG res_start
= pe_info
->base
;
722 ULONGLONG res_end
= pe_info
->base
+ pe_info
->map_size
;
723 const char *loader
= argv0
;
724 const char *loader_env
= getenv( "WINELOADER" );
725 char preloader_reserve
[64], socket_env
[64];
728 if (pe_info
->image_flags
& IMAGE_FLAGS_WineFakeDll
) res_start
= res_end
= 0;
729 if (pe_info
->image_flags
& IMAGE_FLAGS_ComPlusNativeReady
) machine
= native_machine
;
731 is_child_64bit
= is_machine_64bit( machine
);
733 if (!is_win64
^ !is_child_64bit
)
735 /* remap WINELOADER to the alternate 32/64-bit version if necessary */
738 int len
= strlen( loader_env
);
739 char *env
= malloc( sizeof("WINELOADER=") + len
+ 2 );
741 if (!env
) return STATUS_NO_MEMORY
;
742 strcpy( env
, "WINELOADER=" );
743 strcat( env
, loader_env
);
750 len
+= sizeof("WINELOADER=") - 1;
751 if (!strcmp( env
+ len
- 2, "64" )) env
[len
- 2] = 0;
756 else loader
= is_child_64bit
? "wine64" : "wine";
759 signal( SIGPIPE
, SIG_DFL
);
761 sprintf( socket_env
, "WINESERVERSOCKET=%u", socketfd
);
762 sprintf( preloader_reserve
, "WINEPRELOADRESERVE=%x%08x-%x%08x",
763 (ULONG
)(res_start
>> 32), (ULONG
)res_start
, (ULONG
)(res_end
>> 32), (ULONG
)res_end
);
765 putenv( preloader_reserve
);
766 putenv( socket_env
);
768 return loader_exec( loader
, argv
, machine
);
772 /***********************************************************************
775 * Exec a new wine server.
777 static void exec_wineserver( char **argv
)
783 if (!is_win64
) /* look for 64-bit server */
785 char *loader
= realpath_dirname( build_path( build_dir
, "loader/wine64" ));
788 argv
[0] = build_path( loader
, "../server/wineserver" );
789 execv( argv
[0], argv
);
792 argv
[0] = build_path( build_dir
, "server/wineserver" );
793 execv( argv
[0], argv
);
797 argv
[0] = build_path( bin_dir
, "wineserver" );
798 execv( argv
[0], argv
);
800 argv
[0] = getenv( "WINESERVER" );
801 if (argv
[0]) execv( argv
[0], argv
);
803 if ((path
= getenv( "PATH" )))
805 for (path
= strtok( strdup( path
), ":" ); path
; path
= strtok( NULL
, ":" ))
807 argv
[0] = build_path( path
, "wineserver" );
808 execvp( argv
[0], argv
);
812 argv
[0] = build_path( BINDIR
, "wineserver" );
813 execv( argv
[0], argv
);
817 /***********************************************************************
820 * Start a new wine server.
822 void start_server( BOOL debug
)
824 static BOOL started
; /* we only try once */
826 static char debug_flag
[] = "-d";
832 if (pid
== -1) fatal_error( "fork: %s", strerror(errno
) );
835 argv
[1] = debug
? debug_flag
: NULL
;
837 exec_wineserver( argv
);
838 fatal_error( "could not exec wineserver\n" );
840 waitpid( pid
, &status
, 0 );
841 status
= WIFEXITED(status
) ? WEXITSTATUS(status
) : 1;
842 if (status
== 2) return; /* server lock held by someone else, will retry later */
843 if (status
) exit(status
); /* server failed */
849 /*************************************************************************
852 * Map a builtin dll in memory and fixup RVAs.
854 static NTSTATUS
map_so_dll( const IMAGE_NT_HEADERS
*nt_descr
, HMODULE module
)
856 static const char builtin_signature
[32] = "Wine builtin DLL";
857 IMAGE_DATA_DIRECTORY
*dir
;
858 IMAGE_DOS_HEADER
*dos
;
859 IMAGE_NT_HEADERS
*nt
;
860 IMAGE_SECTION_HEADER
*sec
;
861 BYTE
*addr
= (BYTE
*)module
;
862 DWORD code_start
, code_end
, data_start
, data_end
, align_mask
;
863 int delta
, nb_sections
= 2; /* code + data */
865 DWORD size
= (sizeof(IMAGE_DOS_HEADER
)
866 + sizeof(builtin_signature
)
867 + sizeof(IMAGE_NT_HEADERS
)
868 + nb_sections
* sizeof(IMAGE_SECTION_HEADER
));
870 if (anon_mmap_fixed( addr
, size
, PROT_READ
| PROT_WRITE
, 0 ) != addr
) return STATUS_NO_MEMORY
;
872 dos
= (IMAGE_DOS_HEADER
*)addr
;
873 nt
= (IMAGE_NT_HEADERS
*)((BYTE
*)(dos
+ 1) + sizeof(builtin_signature
));
874 sec
= (IMAGE_SECTION_HEADER
*)(nt
+ 1);
876 /* build the DOS and NT headers */
878 dos
->e_magic
= IMAGE_DOS_SIGNATURE
;
881 dos
->e_cparhdr
= (sizeof(*dos
) + 0xf) / 0x10;
883 dos
->e_maxalloc
= 0xffff;
886 dos
->e_lfanew
= sizeof(*dos
) + sizeof(builtin_signature
);
887 memcpy( dos
+ 1, builtin_signature
, sizeof(builtin_signature
) );
891 delta
= (const BYTE
*)nt_descr
- addr
;
892 align_mask
= nt
->OptionalHeader
.SectionAlignment
- 1;
893 code_start
= (size
+ align_mask
) & ~align_mask
;
894 data_start
= delta
& ~align_mask
;
898 unsigned long data_size
;
899 /* need the mach_header, not the PE header, to give to getsegmentdata(3) */
901 code_end
= getsegmentdata(dli
.dli_fbase
, "__DATA", &data_size
) - addr
;
902 data_end
= (code_end
+ data_size
+ align_mask
) & ~align_mask
;
905 code_end
= data_start
;
906 data_end
= (nt
->OptionalHeader
.SizeOfImage
+ delta
+ align_mask
) & ~align_mask
;
909 fixup_rva_ptrs( &nt
->OptionalHeader
.AddressOfEntryPoint
, addr
, 1 );
911 nt
->FileHeader
.NumberOfSections
= nb_sections
;
912 nt
->OptionalHeader
.BaseOfCode
= code_start
;
914 nt
->OptionalHeader
.BaseOfData
= data_start
;
916 nt
->OptionalHeader
.SizeOfCode
= code_end
- code_start
;
917 nt
->OptionalHeader
.SizeOfInitializedData
= data_end
- data_start
;
918 nt
->OptionalHeader
.SizeOfUninitializedData
= 0;
919 nt
->OptionalHeader
.SizeOfImage
= data_end
;
920 nt
->OptionalHeader
.ImageBase
= (ULONG_PTR
)addr
;
922 /* build the code section */
924 memcpy( sec
->Name
, ".text", sizeof(".text") );
925 sec
->SizeOfRawData
= code_end
- code_start
;
926 sec
->Misc
.VirtualSize
= sec
->SizeOfRawData
;
927 sec
->VirtualAddress
= code_start
;
928 sec
->PointerToRawData
= code_start
;
929 sec
->Characteristics
= (IMAGE_SCN_CNT_CODE
| IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
);
932 /* build the data section */
934 memcpy( sec
->Name
, ".data", sizeof(".data") );
935 sec
->SizeOfRawData
= data_end
- data_start
;
936 sec
->Misc
.VirtualSize
= sec
->SizeOfRawData
;
937 sec
->VirtualAddress
= data_start
;
938 sec
->PointerToRawData
= data_start
;
939 sec
->Characteristics
= (IMAGE_SCN_CNT_INITIALIZED_DATA
|
940 IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
);
943 for (i
= 0; i
< nt
->OptionalHeader
.NumberOfRvaAndSizes
; i
++)
944 fixup_rva_dwords( &nt
->OptionalHeader
.DataDirectory
[i
].VirtualAddress
, delta
, 1 );
946 /* build the import directory */
948 dir
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_FILE_IMPORT_DIRECTORY
];
951 IMAGE_IMPORT_DESCRIPTOR
*imports
= (IMAGE_IMPORT_DESCRIPTOR
*)(addr
+ dir
->VirtualAddress
);
953 while (imports
->Name
)
955 fixup_rva_dwords( &imports
->u
.OriginalFirstThunk
, delta
, 1 );
956 fixup_rva_dwords( &imports
->Name
, delta
, 1 );
957 fixup_rva_dwords( &imports
->FirstThunk
, delta
, 1 );
958 if (imports
->u
.OriginalFirstThunk
)
959 fixup_rva_names( (UINT_PTR
*)(addr
+ imports
->u
.OriginalFirstThunk
), delta
);
960 if (imports
->FirstThunk
)
961 fixup_rva_names( (UINT_PTR
*)(addr
+ imports
->FirstThunk
), delta
);
966 /* build the resource directory */
968 dir
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_FILE_RESOURCE_DIRECTORY
];
971 void *ptr
= addr
+ dir
->VirtualAddress
;
972 fixup_so_resources( ptr
, ptr
, delta
);
975 /* build the export directory */
977 dir
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_FILE_EXPORT_DIRECTORY
];
980 IMAGE_EXPORT_DIRECTORY
*exports
= (IMAGE_EXPORT_DIRECTORY
*)(addr
+ dir
->VirtualAddress
);
982 fixup_rva_dwords( &exports
->Name
, delta
, 1 );
983 fixup_rva_dwords( &exports
->AddressOfFunctions
, delta
, 1 );
984 fixup_rva_dwords( &exports
->AddressOfNames
, delta
, 1 );
985 fixup_rva_dwords( &exports
->AddressOfNameOrdinals
, delta
, 1 );
986 fixup_rva_dwords( (DWORD
*)(addr
+ exports
->AddressOfNames
), delta
, exports
->NumberOfNames
);
987 fixup_rva_ptrs( addr
+ exports
->AddressOfFunctions
, addr
, exports
->NumberOfFunctions
);
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 static void load_ntdll_functions( HMODULE module
)
1042 ntdll_exports
= get_module_data_dir( module
, IMAGE_FILE_EXPORT_DIRECTORY
, NULL
);
1043 assert( ntdll_exports
);
1045 #define GET_FUNC(name) \
1046 if (!(p##name = (void *)find_named_export( module, ntdll_exports, #name ))) \
1047 ERR( "%s not found\n", #name )
1049 GET_FUNC( KiRaiseUserExceptionDispatcher
);
1050 GET_FUNC( KiUserExceptionDispatcher
);
1051 GET_FUNC( KiUserApcDispatcher
);
1052 GET_FUNC( KiUserCallbackDispatcher
);
1053 GET_FUNC( LdrInitializeThunk
);
1054 GET_FUNC( LdrSystemDllInitBlock
);
1055 GET_FUNC( RtlUserThreadStart
);
1056 GET_FUNC( __wine_ctrl_routine
);
1057 GET_FUNC( __wine_set_unix_funcs
);
1058 GET_FUNC( __wine_syscall_dispatcher
);
1061 void **p__wine_ldt_copy
;
1062 GET_FUNC( __wine_ldt_copy
);
1063 *p__wine_ldt_copy
= &__wine_ldt_copy
;
1069 static void load_ntdll_wow64_functions( HMODULE module
)
1071 const IMAGE_EXPORT_DIRECTORY
*exports
;
1073 exports
= get_module_data_dir( module
, IMAGE_FILE_EXPORT_DIRECTORY
, NULL
);
1076 pLdrSystemDllInitBlock
->ntdll_handle
= (ULONG_PTR
)module
;
1078 #define GET_FUNC(name) pLdrSystemDllInitBlock->p##name = find_named_export( module, exports, #name )
1079 GET_FUNC( KiUserApcDispatcher
);
1080 GET_FUNC( KiUserCallbackDispatcher
);
1081 GET_FUNC( KiUserExceptionDispatcher
);
1082 GET_FUNC( LdrInitializeThunk
);
1083 GET_FUNC( LdrSystemDllInitBlock
);
1084 GET_FUNC( RtlUserThreadStart
);
1085 GET_FUNC( RtlpFreezeTimeBias
);
1086 GET_FUNC( RtlpQueryProcessDebugInformationRemote
);
1089 p__wine_ctrl_routine
= (void *)find_named_export( module
, exports
, "__wine_ctrl_routine" );
1091 /* also set the 32-bit LdrSystemDllInitBlock */
1092 memcpy( (void *)(ULONG_PTR
)pLdrSystemDllInitBlock
->pLdrSystemDllInitBlock
,
1093 pLdrSystemDllInitBlock
, sizeof(*pLdrSystemDllInitBlock
) );
1096 /* reimplementation of LdrProcessRelocationBlock */
1097 static const IMAGE_BASE_RELOCATION
*process_relocation_block( void *module
, const IMAGE_BASE_RELOCATION
*rel
,
1100 char *page
= get_rva( module
, rel
->VirtualAddress
);
1101 UINT count
= (rel
->SizeOfBlock
- sizeof(*rel
)) / sizeof(USHORT
);
1102 USHORT
*relocs
= (USHORT
*)(rel
+ 1);
1106 USHORT offset
= *relocs
& 0xfff;
1107 switch (*relocs
>> 12)
1109 case IMAGE_REL_BASED_ABSOLUTE
:
1111 case IMAGE_REL_BASED_HIGH
:
1112 *(short *)(page
+ offset
) += HIWORD(delta
);
1114 case IMAGE_REL_BASED_LOW
:
1115 *(short *)(page
+ offset
) += LOWORD(delta
);
1117 case IMAGE_REL_BASED_HIGHLOW
:
1118 *(int *)(page
+ offset
) += delta
;
1120 case IMAGE_REL_BASED_DIR64
:
1121 *(INT64
*)(page
+ offset
) += delta
;
1123 case IMAGE_REL_BASED_THUMB_MOV32
:
1125 DWORD
*inst
= (DWORD
*)(page
+ offset
);
1126 WORD lo
= ((inst
[0] << 1) & 0x0800) + ((inst
[0] << 12) & 0xf000) +
1127 ((inst
[0] >> 20) & 0x0700) + ((inst
[0] >> 16) & 0x00ff);
1128 WORD hi
= ((inst
[1] << 1) & 0x0800) + ((inst
[1] << 12) & 0xf000) +
1129 ((inst
[1] >> 20) & 0x0700) + ((inst
[1] >> 16) & 0x00ff);
1130 DWORD imm
= MAKELONG( lo
, hi
) + delta
;
1134 inst
[0] = (inst
[0] & 0x8f00fbf0) + ((lo
>> 1) & 0x0400) + ((lo
>> 12) & 0x000f) +
1135 ((lo
<< 20) & 0x70000000) + ((lo
<< 16) & 0xff0000);
1136 inst
[1] = (inst
[1] & 0x8f00fbf0) + ((hi
>> 1) & 0x0400) + ((hi
>> 12) & 0x000f) +
1137 ((hi
<< 20) & 0x70000000) + ((hi
<< 16) & 0xff0000);
1141 FIXME("Unknown/unsupported relocation %x\n", *relocs
);
1146 return (IMAGE_BASE_RELOCATION
*)relocs
; /* return address of next block */
1149 static void relocate_ntdll( void *module
)
1151 const IMAGE_NT_HEADERS
*nt
= get_rva( module
, ((IMAGE_DOS_HEADER
*)module
)->e_lfanew
);
1152 const IMAGE_BASE_RELOCATION
*rel
, *end
;
1153 const IMAGE_SECTION_HEADER
*sec
;
1154 ULONG protect_old
[96], i
, size
;
1157 ERR( "ntdll could not be mapped at preferred address (%p), expect trouble\n", module
);
1159 if (!(rel
= get_module_data_dir( module
, IMAGE_DIRECTORY_ENTRY_BASERELOC
, &size
))) return;
1161 sec
= (IMAGE_SECTION_HEADER
*)((char *)&nt
->OptionalHeader
+ nt
->FileHeader
.SizeOfOptionalHeader
);
1162 for (i
= 0; i
< nt
->FileHeader
.NumberOfSections
; i
++)
1164 void *addr
= get_rva( module
, sec
[i
].VirtualAddress
);
1165 SIZE_T size
= sec
[i
].SizeOfRawData
;
1166 NtProtectVirtualMemory( NtCurrentProcess(), &addr
, &size
, PAGE_READWRITE
, &protect_old
[i
] );
1169 end
= (IMAGE_BASE_RELOCATION
*)((const char *)rel
+ size
);
1170 delta
= (char *)module
- (char *)nt
->OptionalHeader
.ImageBase
;
1171 while (rel
&& rel
< end
- 1 && rel
->SizeOfBlock
) rel
= process_relocation_block( module
, rel
, delta
);
1173 for (i
= 0; i
< nt
->FileHeader
.NumberOfSections
; i
++)
1175 void *addr
= get_rva( module
, sec
[i
].VirtualAddress
);
1176 SIZE_T size
= sec
[i
].SizeOfRawData
;
1177 NtProtectVirtualMemory( NtCurrentProcess(), &addr
, &size
, protect_old
[i
], &protect_old
[i
] );
1182 static void *callback_module
;
1184 /***********************************************************************
1185 * load_builtin_callback
1187 * Load a library in memory; callback function for wine_dll_register
1189 static void load_builtin_callback( void *module
, const char *filename
)
1191 callback_module
= module
;
1195 /***********************************************************************
1198 static void load_libwine(void)
1201 #define LIBWINE "libwine.1.dylib"
1203 #define LIBWINE "libwine.so.1"
1205 typedef void (*load_dll_callback_t
)( void *, const char * );
1206 void (*p_wine_dll_set_callback
)( load_dll_callback_t load
);
1207 char ***p___wine_main_environ
;
1212 if (build_dir
) path
= build_path( build_dir
, "libs/wine/" LIBWINE
);
1213 else path
= build_path( ntdll_dir
, LIBWINE
);
1215 handle
= dlopen( path
, RTLD_NOW
);
1217 if (!handle
&& !(handle
= dlopen( LIBWINE
, RTLD_NOW
))) return;
1219 p_wine_dll_set_callback
= dlsym( handle
, "wine_dll_set_callback" );
1220 p___wine_main_argc
= dlsym( handle
, "__wine_main_argc" );
1221 p___wine_main_argv
= dlsym( handle
, "__wine_main_argv" );
1222 p___wine_main_wargv
= dlsym( handle
, "__wine_main_wargv" );
1223 p___wine_main_environ
= dlsym( handle
, "__wine_main_environ" );
1225 if (p_wine_dll_set_callback
) p_wine_dll_set_callback( load_builtin_callback
);
1226 if (p___wine_main_environ
) *p___wine_main_environ
= main_envp
;
1230 /***********************************************************************
1231 * fill_builtin_image_info
1233 static void fill_builtin_image_info( void *module
, pe_image_info_t
*info
)
1235 const IMAGE_DOS_HEADER
*dos
= (const IMAGE_DOS_HEADER
*)module
;
1236 const IMAGE_NT_HEADERS
*nt
= (IMAGE_NT_HEADERS
*)((const BYTE
*)dos
+ dos
->e_lfanew
);
1238 info
->base
= nt
->OptionalHeader
.ImageBase
;
1239 info
->entry_point
= nt
->OptionalHeader
.AddressOfEntryPoint
;
1240 info
->map_size
= nt
->OptionalHeader
.SizeOfImage
;
1241 info
->stack_size
= nt
->OptionalHeader
.SizeOfStackReserve
;
1242 info
->stack_commit
= nt
->OptionalHeader
.SizeOfStackCommit
;
1244 info
->subsystem
= nt
->OptionalHeader
.Subsystem
;
1245 info
->subsystem_minor
= nt
->OptionalHeader
.MinorSubsystemVersion
;
1246 info
->subsystem_major
= nt
->OptionalHeader
.MajorSubsystemVersion
;
1247 info
->osversion_major
= nt
->OptionalHeader
.MajorOperatingSystemVersion
;
1248 info
->osversion_minor
= nt
->OptionalHeader
.MinorOperatingSystemVersion
;
1249 info
->image_charact
= nt
->FileHeader
.Characteristics
;
1250 info
->dll_charact
= nt
->OptionalHeader
.DllCharacteristics
;
1251 info
->machine
= nt
->FileHeader
.Machine
;
1252 info
->contains_code
= TRUE
;
1253 info
->image_flags
= IMAGE_FLAGS_WineBuiltin
;
1254 info
->loader_flags
= 0;
1255 info
->header_size
= nt
->OptionalHeader
.SizeOfHeaders
;
1256 info
->file_size
= nt
->OptionalHeader
.SizeOfImage
;
1257 info
->checksum
= nt
->OptionalHeader
.CheckSum
;
1258 info
->dbg_offset
= 0;
1263 /***********************************************************************
1266 static NTSTATUS
dlopen_dll( const char *so_name
, UNICODE_STRING
*nt_name
, void **ret_module
,
1267 pe_image_info_t
*image_info
, BOOL prefer_native
)
1269 void *module
, *handle
;
1270 const IMAGE_NT_HEADERS
*nt
;
1272 callback_module
= (void *)1;
1273 handle
= dlopen( so_name
, RTLD_NOW
);
1276 WARN( "failed to load .so lib %s: %s\n", debugstr_a(so_name
), dlerror() );
1277 return STATUS_INVALID_IMAGE_FORMAT
;
1279 if (callback_module
!= (void *)1) /* callback was called */
1281 if (!callback_module
) return STATUS_NO_MEMORY
;
1282 WARN( "got old-style builtin library %s, constructors won't work\n", debugstr_a(so_name
) );
1283 module
= callback_module
;
1284 if (get_builtin_so_handle( module
)) goto already_loaded
;
1286 else if ((nt
= dlsym( handle
, "__wine_spec_nt_header" )))
1288 module
= (HMODULE
)((nt
->OptionalHeader
.ImageBase
+ 0xffff) & ~0xffff);
1289 if (get_builtin_so_handle( module
)) goto already_loaded
;
1290 if (map_so_dll( nt
, module
))
1293 return STATUS_NO_MEMORY
;
1296 else /* already loaded .so */
1298 WARN( "%s already loaded?\n", debugstr_a(so_name
));
1299 return STATUS_INVALID_IMAGE_FORMAT
;
1302 fill_builtin_image_info( module
, image_info
);
1303 if (prefer_native
&& (image_info
->dll_charact
& IMAGE_DLLCHARACTERISTICS_PREFER_NATIVE
))
1305 TRACE( "%s has prefer-native flag, ignoring builtin\n", debugstr_a(so_name
) );
1307 return STATUS_IMAGE_ALREADY_LOADED
;
1310 if (virtual_create_builtin_view( module
, nt_name
, image_info
, handle
))
1313 return STATUS_NO_MEMORY
;
1315 *ret_module
= module
;
1316 return STATUS_SUCCESS
;
1319 fill_builtin_image_info( module
, image_info
);
1320 *ret_module
= module
;
1322 return STATUS_SUCCESS
;
1326 /***********************************************************************
1327 * ntdll_init_syscalls
1329 NTSTATUS
ntdll_init_syscalls( ULONG id
, SYSTEM_SERVICE_TABLE
*table
, void **dispatcher
)
1336 } *info
= (struct syscall_info
*)dispatcher
;
1338 if (id
> 3) return STATUS_INVALID_PARAMETER
;
1339 if (info
->limit
!= table
->ServiceLimit
)
1341 ERR( "syscall count mismatch %u / %lu\n", info
->limit
, table
->ServiceLimit
);
1342 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_PARAMETER
);
1344 info
->dispatcher
= __wine_syscall_dispatcher
;
1345 memcpy( table
->ArgumentTable
, info
->args
, table
->ServiceLimit
);
1346 KeServiceDescriptorTable
[id
] = *table
;
1347 return STATUS_SUCCESS
;
1351 /***********************************************************************
1354 NTSTATUS WINAPI
__wine_unix_call( unixlib_handle_t handle
, unsigned int code
, void *args
)
1356 return ((unixlib_entry_t
*)(UINT_PTR
)handle
)[code
]( args
);
1360 /***********************************************************************
1363 static NTSTATUS CDECL
load_so_dll( UNICODE_STRING
*nt_name
, void **module
)
1365 static const WCHAR soW
[] = {'.','s','o',0};
1366 OBJECT_ATTRIBUTES attr
;
1367 UNICODE_STRING redir
;
1368 pe_image_info_t info
;
1373 if (get_load_order( nt_name
) == LO_DISABLED
) return STATUS_DLL_NOT_FOUND
;
1374 InitializeObjectAttributes( &attr
, nt_name
, OBJ_CASE_INSENSITIVE
, 0, 0 );
1375 get_redirect( &attr
, &redir
);
1377 if (nt_to_unix_file_name( &attr
, &unix_name
, FILE_OPEN
))
1379 free( redir
.Buffer
);
1380 return STATUS_DLL_NOT_FOUND
;
1383 /* remove .so extension from Windows name */
1384 len
= nt_name
->Length
/ sizeof(WCHAR
);
1385 if (len
> 3 && !wcsicmp( nt_name
->Buffer
+ len
- 3, soW
)) nt_name
->Length
-= 3 * sizeof(WCHAR
);
1387 status
= dlopen_dll( unix_name
, nt_name
, module
, &info
, FALSE
);
1389 free( redir
.Buffer
);
1394 /* check if the library is the correct architecture */
1395 /* only returns false for a valid library of the wrong arch */
1396 static int check_library_arch( int fd
)
1399 struct /* Mach-O header */
1402 unsigned int cputype
;
1405 if (read( fd
, &header
, sizeof(header
) ) != sizeof(header
)) return 1;
1406 if (header
.magic
!= 0xfeedface) return 1;
1407 if (sizeof(void *) == sizeof(int)) return !(header
.cputype
>> 24);
1408 else return (header
.cputype
>> 24) == 1; /* CPU_ARCH_ABI64 */
1410 struct /* ELF header */
1412 unsigned char magic
[4];
1413 unsigned char class;
1415 unsigned char version
;
1418 if (read( fd
, &header
, sizeof(header
) ) != sizeof(header
)) return 1;
1419 if (memcmp( header
.magic
, "\177ELF", 4 )) return 1;
1420 if (header
.version
!= 1 /* EV_CURRENT */) return 1;
1421 #ifdef WORDS_BIGENDIAN
1422 if (header
.data
!= 2 /* ELFDATA2MSB */) return 1;
1424 if (header
.data
!= 1 /* ELFDATA2LSB */) return 1;
1426 if (sizeof(void *) == sizeof(int)) return header
.class == 1; /* ELFCLASS32 */
1427 else return header
.class == 2; /* ELFCLASS64 */
1431 static inline char *prepend( char *buffer
, const char *str
, size_t len
)
1433 return memcpy( buffer
- len
, str
, len
);
1436 /***********************************************************************
1439 * Open a file for a new dll. Helper for open_builtin_pe_file.
1441 static NTSTATUS
open_dll_file( const char *name
, OBJECT_ATTRIBUTES
*attr
, HANDLE
*mapping
)
1447 if ((status
= open_unix_file( &handle
, name
, GENERIC_READ
| SYNCHRONIZE
, attr
, 0,
1448 FILE_SHARE_READ
| FILE_SHARE_DELETE
, FILE_OPEN
,
1449 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
, NULL
, 0 )))
1451 if (status
!= STATUS_OBJECT_PATH_NOT_FOUND
&& status
!= STATUS_OBJECT_NAME_NOT_FOUND
)
1453 /* if the file exists but failed to open, report the error */
1455 if (!stat( name
, &st
)) return status
;
1457 /* otherwise continue searching */
1458 return STATUS_DLL_NOT_FOUND
;
1462 status
= NtCreateSection( mapping
, STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY
|
1463 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
,
1464 NULL
, &size
, PAGE_EXECUTE_READ
, SEC_IMAGE
, handle
);
1470 /***********************************************************************
1471 * open_builtin_pe_file
1473 static NTSTATUS
open_builtin_pe_file( const char *name
, OBJECT_ATTRIBUTES
*attr
, void **module
,
1474 SIZE_T
*size
, SECTION_IMAGE_INFORMATION
*image_info
,
1475 WORD machine
, BOOL prefer_native
)
1481 status
= open_dll_file( name
, attr
, &mapping
);
1484 status
= virtual_map_builtin_module( mapping
, module
, size
, image_info
, machine
, prefer_native
);
1491 /***********************************************************************
1492 * open_builtin_so_file
1494 static NTSTATUS
open_builtin_so_file( const char *name
, OBJECT_ATTRIBUTES
*attr
, void **module
,
1495 SECTION_IMAGE_INFORMATION
*image_info
,
1496 WORD machine
, BOOL prefer_native
)
1502 if (machine
!= current_machine
) return STATUS_DLL_NOT_FOUND
;
1503 if ((fd
= open( name
, O_RDONLY
)) == -1) return STATUS_DLL_NOT_FOUND
;
1505 if (check_library_arch( fd
))
1507 pe_image_info_t info
;
1509 status
= dlopen_dll( name
, attr
->ObjectName
, module
, &info
, prefer_native
);
1510 if (!status
) virtual_fill_image_information( &info
, image_info
);
1511 else if (status
!= STATUS_IMAGE_ALREADY_LOADED
)
1513 ERR( "failed to load .so lib %s\n", debugstr_a(name
) );
1514 status
= STATUS_PROCEDURE_NOT_FOUND
;
1517 else status
= STATUS_IMAGE_MACHINE_TYPE_MISMATCH
;
1524 /***********************************************************************
1527 static NTSTATUS
find_builtin_dll( UNICODE_STRING
*nt_name
, void **module
, SIZE_T
*size_ptr
,
1528 SECTION_IMAGE_INFORMATION
*image_info
, WORD machine
, BOOL prefer_native
)
1530 unsigned int i
, pos
, namepos
, namelen
, maxlen
= 0;
1531 unsigned int len
= nt_name
->Length
/ sizeof(WCHAR
);
1532 char *ptr
= NULL
, *file
, *ext
= NULL
;
1533 const char *pe_dir
= get_pe_dir( machine
);
1534 OBJECT_ATTRIBUTES attr
;
1535 NTSTATUS status
= STATUS_DLL_NOT_FOUND
;
1536 BOOL found_image
= FALSE
;
1538 for (i
= namepos
= 0; i
< len
; i
++)
1539 if (nt_name
->Buffer
[i
] == '/' || nt_name
->Buffer
[i
] == '\\') namepos
= i
+ 1;
1541 if (!len
) return STATUS_DLL_NOT_FOUND
;
1542 InitializeObjectAttributes( &attr
, nt_name
, 0, 0, NULL
);
1544 if (build_dir
) maxlen
= strlen(build_dir
) + sizeof("/programs/") + len
;
1545 maxlen
= max( maxlen
, dll_path_maxlen
+ 1 ) + len
+ sizeof("/aarch64-windows") + sizeof(".so");
1547 if (!(file
= malloc( maxlen
))) return STATUS_NO_MEMORY
;
1549 pos
= maxlen
- len
- sizeof(".so");
1550 /* we don't want to depend on the current codepage here */
1551 for (i
= 0; i
< len
; i
++)
1553 if (nt_name
->Buffer
[namepos
+ i
] > 127) goto done
;
1554 file
[pos
+ i
] = (char)nt_name
->Buffer
[namepos
+ i
];
1555 if (file
[pos
+ i
] >= 'A' && file
[pos
+ i
] <= 'Z') file
[pos
+ i
] += 'a' - 'A';
1556 else if (file
[pos
+ i
] == '.') ext
= file
+ pos
+ i
;
1565 file
[pos
+ len
+ 1] = 0;
1566 if (ext
&& !strcmp( ext
, ".dll" )) namelen
-= 4;
1567 ptr
= prepend( ptr
, ptr
, namelen
);
1568 ptr
= prepend( ptr
, "/dlls", sizeof("/dlls") - 1 );
1569 ptr
= prepend( ptr
, build_dir
, strlen(build_dir
) );
1570 status
= open_builtin_pe_file( ptr
, &attr
, module
, size_ptr
, image_info
, machine
, prefer_native
);
1571 if (status
!= STATUS_DLL_NOT_FOUND
) goto done
;
1572 strcpy( file
+ pos
+ len
+ 1, ".so" );
1573 status
= open_builtin_so_file( ptr
, &attr
, module
, image_info
, machine
, prefer_native
);
1574 if (status
!= STATUS_DLL_NOT_FOUND
) goto done
;
1576 /* now as a program */
1579 file
[pos
+ len
+ 1] = 0;
1580 if (ext
&& !strcmp( ext
, ".exe" )) namelen
-= 4;
1581 ptr
= prepend( ptr
, ptr
, namelen
);
1582 ptr
= prepend( ptr
, "/programs", sizeof("/programs") - 1 );
1583 ptr
= prepend( ptr
, build_dir
, strlen(build_dir
) );
1584 status
= open_builtin_pe_file( ptr
, &attr
, module
, size_ptr
, image_info
, machine
, prefer_native
);
1585 if (status
!= STATUS_DLL_NOT_FOUND
) goto done
;
1586 strcpy( file
+ pos
+ len
+ 1, ".so" );
1587 status
= open_builtin_so_file( ptr
, &attr
, module
, image_info
, machine
, prefer_native
);
1588 if (status
!= STATUS_DLL_NOT_FOUND
) goto done
;
1591 for (i
= 0; dll_paths
[i
]; i
++)
1594 file
[pos
+ len
+ 1] = 0;
1595 ptr
= prepend( ptr
, pe_dir
, strlen(pe_dir
) );
1596 ptr
= prepend( ptr
, dll_paths
[i
], strlen(dll_paths
[i
]) );
1597 status
= open_builtin_pe_file( ptr
, &attr
, module
, size_ptr
, image_info
, machine
, prefer_native
);
1598 /* use so dir for unix lib */
1600 ptr
= prepend( ptr
, so_dir
, strlen(so_dir
) );
1601 ptr
= prepend( ptr
, dll_paths
[i
], strlen(dll_paths
[i
]) );
1602 if (status
!= STATUS_DLL_NOT_FOUND
) goto done
;
1603 strcpy( file
+ pos
+ len
+ 1, ".so" );
1604 status
= open_builtin_so_file( ptr
, &attr
, module
, image_info
, machine
, prefer_native
);
1605 if (status
!= STATUS_DLL_NOT_FOUND
) goto done
;
1606 file
[pos
+ len
+ 1] = 0;
1607 ptr
= prepend( file
+ pos
, dll_paths
[i
], strlen(dll_paths
[i
]) );
1608 status
= open_builtin_pe_file( ptr
, &attr
, module
, size_ptr
, image_info
, machine
, prefer_native
);
1609 if (status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
1614 if (status
!= STATUS_DLL_NOT_FOUND
) goto done
;
1615 strcpy( file
+ pos
+ len
+ 1, ".so" );
1616 status
= open_builtin_so_file( ptr
, &attr
, module
, image_info
, machine
, prefer_native
);
1617 if (status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
) found_image
= TRUE
;
1618 else if (status
!= STATUS_DLL_NOT_FOUND
) goto done
;
1621 if (found_image
) status
= STATUS_IMAGE_MACHINE_TYPE_MISMATCH
;
1622 WARN( "cannot find builtin library for %s\n", debugstr_us(nt_name
) );
1624 if (status
>= 0 && ext
)
1626 strcpy( ext
, ".so" );
1627 load_builtin_unixlib( *module
, ptr
);
1634 /***********************************************************************
1637 * Load the builtin dll if specified by load order configuration.
1638 * Return STATUS_IMAGE_ALREADY_LOADED if we should keep the native one that we have found.
1640 NTSTATUS
load_builtin( const pe_image_info_t
*image_info
, WCHAR
*filename
,
1641 void **module
, SIZE_T
*size
)
1643 WORD machine
= image_info
->machine
; /* request same machine as the native one */
1645 UNICODE_STRING nt_name
;
1646 SECTION_IMAGE_INFORMATION info
;
1647 enum loadorder loadorder
;
1649 init_unicode_string( &nt_name
, filename
);
1650 loadorder
= get_load_order( &nt_name
);
1652 if (loadorder
== LO_DISABLED
) return STATUS_DLL_NOT_FOUND
;
1654 if (image_info
->image_flags
& IMAGE_FLAGS_WineBuiltin
)
1656 if (loadorder
== LO_NATIVE
) return STATUS_DLL_NOT_FOUND
;
1657 loadorder
= LO_BUILTIN_NATIVE
; /* load builtin, then fallback to the file we found */
1659 else if (image_info
->image_flags
& IMAGE_FLAGS_WineFakeDll
)
1661 TRACE( "%s is a fake Wine dll\n", debugstr_w(filename
) );
1662 if (loadorder
== LO_NATIVE
) return STATUS_DLL_NOT_FOUND
;
1663 loadorder
= LO_BUILTIN
; /* builtin with no fallback since mapping a fake dll is not useful */
1669 case LO_NATIVE_BUILTIN
:
1670 return STATUS_IMAGE_ALREADY_LOADED
;
1672 return find_builtin_dll( &nt_name
, module
, size
, &info
, machine
, FALSE
);
1674 status
= find_builtin_dll( &nt_name
, module
, size
, &info
, machine
, (loadorder
== LO_DEFAULT
) );
1675 if (status
== STATUS_DLL_NOT_FOUND
|| status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
)
1676 return STATUS_IMAGE_ALREADY_LOADED
;
1682 /***************************************************************************
1683 * get_machine_wow64_dir
1685 * cf. GetSystemWow64Directory2.
1687 static const WCHAR
*get_machine_wow64_dir( WORD machine
)
1689 static const WCHAR system32
[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\','s','y','s','t','e','m','3','2','\\',0};
1690 static const WCHAR syswow64
[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\','s','y','s','w','o','w','6','4','\\',0};
1691 static const WCHAR sysarm32
[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\','s','y','s','a','r','m','3','2','\\',0};
1692 static const WCHAR sysx8664
[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\','s','y','s','x','8','6','6','4','\\',0};
1693 static const WCHAR sysarm64
[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\','s','y','s','a','r','m','6','4','\\',0};
1695 if (machine
== native_machine
) machine
= IMAGE_FILE_MACHINE_TARGET_HOST
;
1699 case IMAGE_FILE_MACHINE_TARGET_HOST
: return system32
;
1700 case IMAGE_FILE_MACHINE_I386
: return syswow64
;
1701 case IMAGE_FILE_MACHINE_ARMNT
: return sysarm32
;
1702 case IMAGE_FILE_MACHINE_AMD64
: return sysx8664
;
1703 case IMAGE_FILE_MACHINE_ARM64
: return sysarm64
;
1704 default: return NULL
;
1709 /***************************************************************************
1712 * Check if path is inside a system directory, to support loading builtins
1713 * when the corresponding file doesn't exist yet.
1715 BOOL
is_builtin_path( const UNICODE_STRING
*path
, WORD
*machine
)
1717 unsigned int i
, len
= path
->Length
/ sizeof(WCHAR
), dirlen
;
1718 const WCHAR
*sysdir
, *p
= path
->Buffer
;
1720 /* only fake builtin existence during prefix bootstrap */
1721 if (!is_prefix_bootstrap
) return FALSE
;
1723 for (i
= 0; i
< supported_machines_count
; i
++)
1725 sysdir
= get_machine_wow64_dir( supported_machines
[i
] );
1726 dirlen
= wcslen( sysdir
);
1727 if (len
<= dirlen
) continue;
1728 if (wcsnicmp( p
, sysdir
, dirlen
)) continue;
1729 /* check for remaining path components */
1730 for (p
+= dirlen
, len
-= dirlen
; len
; p
++, len
--) if (*p
== '\\') return FALSE
;
1731 *machine
= supported_machines
[i
];
1738 /***********************************************************************
1741 static NTSTATUS
open_main_image( WCHAR
*image
, void **module
, SECTION_IMAGE_INFORMATION
*info
,
1742 enum loadorder loadorder
)
1744 static const WCHAR soW
[] = {'.','s','o',0};
1745 UNICODE_STRING nt_name
;
1746 OBJECT_ATTRIBUTES attr
;
1747 pe_image_info_t pe_info
;
1754 if (loadorder
== LO_DISABLED
) NtTerminateProcess( GetCurrentProcess(), STATUS_DLL_NOT_FOUND
);
1756 init_unicode_string( &nt_name
, image
);
1757 InitializeObjectAttributes( &attr
, &nt_name
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
1758 if (nt_to_unix_file_name( &attr
, &unix_name
, FILE_OPEN
)) return STATUS_DLL_NOT_FOUND
;
1760 status
= open_dll_file( unix_name
, &attr
, &mapping
);
1764 status
= NtMapViewOfSection( mapping
, NtCurrentProcess(), module
, 0, 0, NULL
, &size
,
1765 ViewShare
, 0, PAGE_EXECUTE_READ
);
1768 NtQuerySection( mapping
, SectionImageInformation
, info
, sizeof(*info
), NULL
);
1769 if (info
->u
.s
.ComPlusNativeReady
) info
->Machine
= native_machine
;
1773 else if (status
== STATUS_INVALID_IMAGE_NOT_MZ
&& loadorder
!= LO_NATIVE
)
1775 /* remove .so extension from Windows name */
1776 p
= image
+ wcslen(image
);
1777 if (p
- image
> 3 && !wcsicmp( p
- 3, soW
))
1780 nt_name
.Length
-= 3 * sizeof(WCHAR
);
1782 status
= dlopen_dll( unix_name
, &nt_name
, module
, &pe_info
, FALSE
);
1783 if (!status
) virtual_fill_image_information( &pe_info
, info
);
1790 /***********************************************************************
1793 NTSTATUS
load_main_exe( const WCHAR
*dos_name
, const char *unix_name
, const WCHAR
*curdir
,
1794 WCHAR
**image
, void **module
)
1796 enum loadorder loadorder
= LO_INVALID
;
1797 UNICODE_STRING nt_name
;
1805 /* special case for Unix file name */
1806 if (unix_name
&& unix_name
[0] == '/' && !stat( unix_name
, &st
))
1808 if ((status
= unix_to_nt_file_name( unix_name
, image
))) goto failed
;
1809 init_unicode_string( &nt_name
, *image
);
1810 loadorder
= get_load_order( &nt_name
);
1811 status
= open_main_image( *image
, module
, &main_image_info
, loadorder
);
1812 if (status
!= STATUS_DLL_NOT_FOUND
) return status
;
1818 dos_name
= tmp
= malloc( (strlen(unix_name
) + 1) * sizeof(WCHAR
) );
1819 ntdll_umbstowcs( unix_name
, strlen(unix_name
) + 1, tmp
, strlen(unix_name
) + 1 );
1821 contains_path
= (wcschr( dos_name
, '/' ) ||
1822 wcschr( dos_name
, '\\' ) ||
1823 (dos_name
[0] && dos_name
[1] == ':'));
1825 if ((status
= get_full_path( dos_name
, curdir
, image
))) goto failed
;
1828 init_unicode_string( &nt_name
, *image
);
1829 if (loadorder
== LO_INVALID
) loadorder
= get_load_order( &nt_name
);
1831 status
= open_main_image( *image
, module
, &main_image_info
, loadorder
);
1832 if (status
!= STATUS_DLL_NOT_FOUND
) return status
;
1834 /* if path is in system dir, we can load the builtin even if the file itself doesn't exist */
1835 if (loadorder
!= LO_NATIVE
&& is_builtin_path( &nt_name
, &machine
))
1837 status
= find_builtin_dll( &nt_name
, module
, &size
, &main_image_info
, machine
, FALSE
);
1838 if (status
!= STATUS_DLL_NOT_FOUND
) return status
;
1840 if (!contains_path
) return STATUS_DLL_NOT_FOUND
;
1843 MESSAGE( "wine: failed to open %s: %x\n",
1844 unix_name
? debugstr_a(unix_name
) : debugstr_w(dos_name
), status
);
1845 NtTerminateProcess( GetCurrentProcess(), status
);
1846 return status
; /* unreached */
1850 /***********************************************************************
1853 * Load start.exe as main image.
1855 NTSTATUS
load_start_exe( WCHAR
**image
, void **module
)
1857 static const WCHAR startW
[] = {'s','t','a','r','t','.','e','x','e',0};
1858 UNICODE_STRING nt_name
;
1862 *image
= malloc( sizeof("\\??\\C:\\windows\\system32\\start.exe") * sizeof(WCHAR
) );
1863 wcscpy( *image
, get_machine_wow64_dir( current_machine
));
1864 wcscat( *image
, startW
);
1865 init_unicode_string( &nt_name
, *image
);
1866 status
= find_builtin_dll( &nt_name
, module
, &size
, &main_image_info
, current_machine
, FALSE
);
1869 MESSAGE( "wine: failed to load start.exe: %x\n", status
);
1870 NtTerminateProcess( GetCurrentProcess(), status
);
1877 /* The PT_LOAD segments are sorted in increasing order, and the first
1878 * starts at the beginning of the ELF file. By parsing the file, we can
1879 * find that first PT_LOAD segment, from which we can find the base
1880 * address it wanted, and knowing mapbase where the binary was actually
1881 * loaded, use them to work out the relocbase offset. */
1882 static BOOL
get_relocbase(caddr_t mapbase
, caddr_t
*relocbase
)
1886 const Elf64_Ehdr
*elf_header
= (Elf64_Ehdr
*) mapbase
;
1888 const Elf32_Ehdr
*elf_header
= (Elf32_Ehdr
*) mapbase
;
1890 const Elf_Phdr
*prog_header
= (const Elf_Phdr
*)(mapbase
+ elf_header
->e_phoff
);
1892 for (i
= 0; i
< elf_header
->e_phnum
; i
++)
1894 if (prog_header
->p_type
== PT_LOAD
)
1896 caddr_t desired_base
= (caddr_t
)((prog_header
->p_vaddr
/ prog_header
->p_align
) * prog_header
->p_align
);
1897 *relocbase
= (caddr_t
) (mapbase
- desired_base
);
1906 /*************************************************************************
1909 static void CDECL
init_builtin_dll( void *module
)
1912 void *handle
= NULL
;
1913 struct link_map
*map
;
1914 void (*init_func
)(int, char **, char **) = NULL
;
1915 void (**init_array
)(int, char **, char **) = NULL
;
1916 ULONG_PTR i
, init_arraysz
= 0;
1918 const Elf64_Dyn
*dyn
;
1920 const Elf32_Dyn
*dyn
;
1923 if (!(handle
= get_builtin_so_handle( module
))) return;
1924 if (dlinfo( handle
, RTLD_DI_LINKMAP
, &map
)) map
= NULL
;
1925 release_builtin_module( module
);
1928 for (dyn
= map
->l_ld
; dyn
->d_tag
; dyn
++)
1930 caddr_t relocbase
= (caddr_t
)map
->l_addr
;
1933 /* On older FreeBSD versions, l_addr was the absolute load address, now it's the relocation offset. */
1934 if (offsetof(struct link_map
, l_addr
) == 0)
1935 if (!get_relocbase(map
->l_addr
, &relocbase
))
1940 case 0x60009990: init_array
= (void *)(relocbase
+ dyn
->d_un
.d_val
); break;
1941 case 0x60009991: init_arraysz
= dyn
->d_un
.d_val
; break;
1942 case 0x60009992: init_func
= (void *)(relocbase
+ dyn
->d_un
.d_val
); break;
1946 TRACE( "%p: got init_func %p init_array %p %lu\n", module
, init_func
, init_array
, init_arraysz
);
1948 if (init_func
) init_func( main_argc
, main_argv
, main_envp
);
1951 for (i
= 0; i
< init_arraysz
/ sizeof(*init_array
); i
++)
1952 init_array
[i
]( main_argc
, main_argv
, main_envp
);
1957 /***********************************************************************
1960 static void load_ntdll(void)
1962 static WCHAR path
[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\',
1963 's','y','s','t','e','m','3','2','\\','n','t','d','l','l','.','d','l','l',0};
1964 const char *pe_dir
= get_pe_dir( current_machine
);
1966 SECTION_IMAGE_INFORMATION info
;
1967 OBJECT_ATTRIBUTES attr
;
1973 init_unicode_string( &str
, path
);
1974 InitializeObjectAttributes( &attr
, &str
, 0, 0, NULL
);
1976 name
= malloc( strlen( ntdll_dir
) + strlen( pe_dir
) + sizeof("/ntdll.dll.so") );
1977 if (build_dir
) sprintf( name
, "%s/ntdll.dll", ntdll_dir
);
1978 else sprintf( name
, "%s%s/ntdll.dll", dll_dir
, pe_dir
);
1979 status
= open_builtin_pe_file( name
, &attr
, &module
, &size
, &info
, current_machine
, FALSE
);
1980 if (status
== STATUS_DLL_NOT_FOUND
)
1982 sprintf( name
, "%s/ntdll.dll.so", ntdll_dir
);
1983 status
= open_builtin_so_file( name
, &attr
, &module
, &info
, current_machine
, FALSE
);
1985 if (status
== STATUS_IMAGE_NOT_AT_BASE
) relocate_ntdll( module
);
1986 else if (status
) fatal_error( "failed to load %s error %x\n", name
, status
);
1988 load_ntdll_functions( module
);
1989 ntdll_module
= module
;
1993 /***********************************************************************
1996 static void load_wow64_ntdll( USHORT machine
)
1998 static const WCHAR ntdllW
[] = {'n','t','d','l','l','.','d','l','l',0};
1999 SECTION_IMAGE_INFORMATION info
;
2000 UNICODE_STRING nt_name
;
2004 WCHAR
*path
= malloc( sizeof("\\??\\C:\\windows\\system32\\ntdll.dll") * sizeof(WCHAR
) );
2006 wcscpy( path
, get_machine_wow64_dir( machine
));
2007 wcscat( path
, ntdllW
);
2008 init_unicode_string( &nt_name
, path
);
2009 status
= find_builtin_dll( &nt_name
, &module
, &size
, &info
, machine
, FALSE
);
2012 case STATUS_IMAGE_NOT_AT_BASE
:
2013 relocate_ntdll( module
);
2015 case STATUS_SUCCESS
:
2016 load_ntdll_wow64_functions( module
);
2017 TRACE("loaded %s at %p\n", debugstr_w(path
), module
);
2020 ERR( "failed to load %s error %x\n", debugstr_w(path
), status
);
2027 /***********************************************************************
2030 static ULONG_PTR
get_image_address(void)
2032 #ifdef HAVE_GETAUXVAL
2033 ULONG_PTR size
, num
, phdr_addr
= getauxval( AT_PHDR
);
2036 if (!phdr_addr
) return 0;
2037 phdr
= (ElfW(Phdr
) *)phdr_addr
;
2038 size
= getauxval( AT_PHENT
);
2039 num
= getauxval( AT_PHNUM
);
2042 if (phdr
->p_type
== PT_PHDR
) return phdr_addr
- phdr
->p_offset
;
2043 phdr
= (ElfW(Phdr
) *)((char *)phdr
+ size
);
2045 #elif defined(__APPLE__) && defined(TASK_DYLD_INFO)
2046 struct task_dyld_info dyld_info
;
2047 mach_msg_type_number_t size
= TASK_DYLD_INFO_COUNT
;
2049 if (task_info(mach_task_self(), TASK_DYLD_INFO
, (task_info_t
)&dyld_info
, &size
) == KERN_SUCCESS
)
2050 return dyld_info
.all_image_info_addr
;
2056 /***********************************************************************
2059 static struct unix_funcs unix_funcs
=
2064 RtlGetSystemTimePrecise
,
2071 /***********************************************************************
2074 static void start_main_thread(void)
2076 SYSTEM_SERVICE_TABLE syscall_table
= { (ULONG_PTR
*)syscalls
, NULL
, ARRAY_SIZE(syscalls
), syscall_args
};
2078 TEB
*teb
= virtual_alloc_first_teb();
2080 signal_init_threading();
2081 signal_alloc_thread( teb
);
2082 signal_init_thread( teb
);
2084 startup_info_size
= server_init_process();
2085 virtual_map_user_shared_data();
2089 init_startup_info();
2090 if (p___wine_main_argc
) *p___wine_main_argc
= main_argc
;
2091 if (p___wine_main_argv
) *p___wine_main_argv
= main_argv
;
2092 if (p___wine_main_wargv
) *p___wine_main_wargv
= main_wargv
;
2093 *(ULONG_PTR
*)&peb
->CloudFileFlags
= get_image_address();
2094 set_load_order_app_name( main_wargv
[0] );
2095 init_thread_stack( teb
, is_win64
? 0x7fffffff : 0, 0, 0 );
2096 NtCreateKeyedEvent( &keyed_event
, GENERIC_READ
| GENERIC_WRITE
, NULL
, 0 );
2098 if (main_image_info
.Machine
!= current_machine
) load_wow64_ntdll( main_image_info
.Machine
);
2099 ntdll_init_syscalls( 0, &syscall_table
, p__wine_syscall_dispatcher
);
2100 status
= p__wine_set_unix_funcs( NTDLL_UNIXLIB_VERSION
, &unix_funcs
);
2101 if (status
== STATUS_REVISION_MISMATCH
)
2103 ERR( "ntdll library version mismatch\n" );
2104 NtTerminateProcess( GetCurrentProcess(), status
);
2106 server_init_process_done();
2111 #ifndef WINE_JAVA_CLASS
2112 #define WINE_JAVA_CLASS "org/winehq/wine/WineActivity"
2115 JavaVM
*java_vm
= NULL
;
2116 jobject java_object
= 0;
2117 unsigned short java_gdt_sel
= 0;
2119 /* main Wine initialisation */
2120 static jstring
wine_init_jni( JNIEnv
*env
, jobject obj
, jobjectArray cmdline
, jobjectArray environment
)
2125 int i
, argc
, length
;
2127 /* get the command line array */
2129 argc
= (*env
)->GetArrayLength( env
, cmdline
);
2130 for (i
= length
= 0; i
< argc
; i
++)
2132 jobject str_obj
= (*env
)->GetObjectArrayElement( env
, cmdline
, i
);
2133 length
+= (*env
)->GetStringUTFLength( env
, str_obj
) + 1;
2136 argv
= malloc( (argc
+ 1) * sizeof(*argv
) + length
);
2137 str
= (char *)(argv
+ argc
+ 1);
2138 for (i
= 0; i
< argc
; i
++)
2140 jobject str_obj
= (*env
)->GetObjectArrayElement( env
, cmdline
, i
);
2141 length
= (*env
)->GetStringUTFLength( env
, str_obj
);
2142 (*env
)->GetStringUTFRegion( env
, str_obj
, 0,
2143 (*env
)->GetStringLength( env
, str_obj
), str
);
2150 /* set the environment variables */
2154 int count
= (*env
)->GetArrayLength( env
, environment
);
2155 for (i
= 0; i
< count
- 1; i
+= 2)
2157 jobject var_obj
= (*env
)->GetObjectArrayElement( env
, environment
, i
);
2158 jobject val_obj
= (*env
)->GetObjectArrayElement( env
, environment
, i
+ 1 );
2159 const char *var
= (*env
)->GetStringUTFChars( env
, var_obj
, NULL
);
2163 const char *val
= (*env
)->GetStringUTFChars( env
, val_obj
, NULL
);
2164 setenv( var
, val
, 1 );
2165 if (!strcmp( var
, "LD_LIBRARY_PATH" ))
2167 void (*update_func
)( const char * ) = dlsym( RTLD_DEFAULT
,
2168 "android_update_LD_LIBRARY_PATH" );
2169 if (update_func
) update_func( val
);
2171 else if (!strcmp( var
, "WINEDEBUGLOG" ))
2173 int fd
= open( val
, O_WRONLY
| O_CREAT
| O_APPEND
, 0666 );
2180 (*env
)->ReleaseStringUTFChars( env
, val_obj
, val
);
2182 else unsetenv( var
);
2184 (*env
)->ReleaseStringUTFChars( env
, var_obj
, var
);
2188 java_object
= (*env
)->NewGlobalRef( env
, obj
);
2192 init_environment( argc
, argv
, environ
);
2196 unsigned short java_fs
;
2197 __asm__( "mov %%fs,%0" : "=r" (java_fs
) );
2198 if (!(java_fs
& 4)) java_gdt_sel
= java_fs
;
2199 __asm__( "mov %0,%%fs" :: "r" (0) );
2200 start_main_thread();
2201 __asm__( "mov %0,%%fs" :: "r" (java_fs
) );
2204 start_main_thread();
2206 return (*env
)->NewStringUTF( env
, error
);
2209 jint
JNI_OnLoad( JavaVM
*vm
, void *reserved
)
2211 static const JNINativeMethod method
=
2213 "wine_init", "([Ljava/lang/String;[Ljava/lang/String;)Ljava/lang/String;", wine_init_jni
2220 if ((*vm
)->AttachCurrentThread( vm
, &env
, NULL
) != JNI_OK
) return JNI_ERR
;
2221 if (!(class = (*env
)->FindClass( env
, WINE_JAVA_CLASS
))) return JNI_ERR
;
2222 (*env
)->RegisterNatives( env
, class, &method
, 1 );
2223 return JNI_VERSION_1_6
;
2226 #endif /* __ANDROID__ */
2229 static void *apple_wine_thread( void *arg
)
2231 start_main_thread();
2235 /***********************************************************************
2236 * apple_create_wine_thread
2238 * Spin off a secondary thread to complete Wine initialization, leaving
2239 * the original thread for the Mac frameworks.
2241 * Invoked as a CFRunLoopSource perform callback.
2243 static void apple_create_wine_thread( void *arg
)
2246 pthread_attr_t attr
;
2248 pthread_attr_init( &attr
);
2249 pthread_attr_setdetachstate( &attr
, PTHREAD_CREATE_JOINABLE
);
2250 if (pthread_create( &thread
, &attr
, apple_wine_thread
, NULL
)) exit(1);
2251 pthread_attr_destroy( &attr
);
2255 /***********************************************************************
2258 * Park the process's original thread in a Core Foundation run loop for
2259 * use by the Mac frameworks, especially receiving and handling
2260 * distributed notifications. Spin off a new thread for the rest of the
2261 * Wine initialization.
2263 static void apple_main_thread(void)
2265 CFRunLoopSourceContext source_context
= { 0 };
2266 CFRunLoopSourceRef source
;
2268 if (!pthread_main_np()) return;
2270 /* Multi-processing Services can get confused about the main thread if the
2271 * first time it's used is on a secondary thread. Use it here to make sure
2272 * that doesn't happen. */
2273 MPTaskIsPreemptive(MPCurrentTaskID());
2275 /* Give ourselves the best chance of having the distributed notification
2276 * center scheduled on this thread's run loop. In theory, it's scheduled
2277 * in the first thread to ask for it. */
2278 CFNotificationCenterGetDistributedCenter();
2280 /* We use this run loop source for two purposes. First, a run loop exits
2281 * if it has no more sources scheduled. So, we need at least one source
2282 * to keep the run loop running. Second, although it's not critical, it's
2283 * preferable for the Wine initialization to not proceed until we know
2284 * the run loop is running. So, we signal our source immediately after
2285 * adding it and have its callback spin off the Wine thread. */
2286 source_context
.perform
= apple_create_wine_thread
;
2287 source
= CFRunLoopSourceCreate( NULL
, 0, &source_context
);
2288 CFRunLoopAddSource( CFRunLoopGetCurrent(), source
, kCFRunLoopCommonModes
);
2289 CFRunLoopSourceSignal( source
);
2290 CFRelease( source
);
2291 CFRunLoopRun(); /* Should never return, except on error. */
2293 #endif /* __APPLE__ */
2298 static int pre_exec(void)
2300 #if defined(__i386__) || defined(__x86_64__)
2301 return 1; /* we have a preloader */
2303 return 0; /* no exec needed */
2307 #elif defined(__linux__) && (defined(__i386__) || defined(__arm__))
2309 static void check_vmsplit( void *stack
)
2311 if (stack
< (void *)0x80000000)
2313 /* if the stack is below 0x80000000, assume we can safely try a munmap there */
2314 if (munmap( (void *)0x80000000, 1 ) == -1 && errno
== EINVAL
)
2315 ERR( "Warning: memory above 0x80000000 doesn't seem to be accessible.\n"
2316 "Wine requires a 3G/1G user/kernel memory split to work properly.\n" );
2320 static int pre_exec(void)
2324 check_vmsplit( &temp
);
2325 return 1; /* we have a preloader on x86/arm */
2328 #elif defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__))
2330 static int pre_exec(void)
2332 return 1; /* we have a preloader on x86-64/arm64 */
2335 #elif defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__))
2337 static int pre_exec(void)
2339 return 1; /* we have a preloader */
2342 #elif (defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__))
2344 static int pre_exec(void)
2348 rl
.rlim_cur
= 0x02000000;
2349 rl
.rlim_max
= 0x02000000;
2350 setrlimit( RLIMIT_DATA
, &rl
);
2356 static int pre_exec(void)
2358 return 0; /* no exec needed */
2364 /***********************************************************************
2365 * check_command_line
2367 * Check if command line is one that needs to be handled specially.
2369 static void check_command_line( int argc
, char *argv
[] )
2371 static const char usage
[] =
2372 "Usage: wine PROGRAM [ARGUMENTS...] Run the specified program\n"
2373 " wine --help Display this help and exit\n"
2374 " wine --version Output version information and exit";
2378 fprintf( stderr
, "%s\n", usage
);
2381 if (!strcmp( argv
[1], "--help" ))
2383 printf( "%s\n", usage
);
2386 if (!strcmp( argv
[1], "--version" ))
2388 printf( "%s\n", wine_build
);
2394 /***********************************************************************
2397 * Main entry point called by the wine loader.
2399 void __wine_main( int argc
, char *argv
[], char *envp
[] )
2403 if (!getenv( "WINELOADERNOEXEC" )) /* first time around */
2405 check_command_line( argc
, argv
);
2408 static char noexec
[] = "WINELOADERNOEXEC=1";
2409 char **new_argv
= malloc( (argc
+ 2) * sizeof(*argv
) );
2411 memcpy( new_argv
+ 1, argv
, (argc
+ 1) * sizeof(*argv
) );
2413 loader_exec( argv0
, new_argv
, current_machine
);
2414 fatal_error( "could not exec the wine loader\n" );
2418 #ifdef RLIMIT_NOFILE
2419 set_max_limit( RLIMIT_NOFILE
);
2422 set_max_limit( RLIMIT_AS
);
2426 init_environment( argc
, argv
, envp
);
2429 apple_main_thread();
2431 start_main_thread();