2 * Win32 builtin dlls support
4 * Copyright 2000 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "wine/port.h"
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_MMAN_H
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
43 #include "wine/library.h"
45 /* argc/argv for the Windows application */
46 int __wine_main_argc = 0;
47 char **__wine_main_argv = NULL;
48 WCHAR **__wine_main_wargv = NULL;
54 const IMAGE_NT_HEADERS *nt; /* NT header */
55 const char *filename; /* DLL file name */
56 } builtin_dlls[MAX_DLLS];
60 static const IMAGE_NT_HEADERS *main_exe;
62 static load_dll_callback_t load_dll_callback;
64 static const char **dll_paths;
65 static int nb_dll_paths;
66 static int dll_path_maxlen;
70 /* build the dll load path from the WINEDLLPATH variable */
71 static void build_dll_path(void)
73 static const char * const dlldir = DLLDIR;
75 char *p, *path = getenv( "WINEDLLPATH" );
81 /* count how many path elements we need */
86 while (*p == ':') p++;
89 while (*p && *p != ':') p++;
93 dll_paths = malloc( (count+1) * sizeof(*dll_paths) );
101 while (*p == ':') *p++ = 0;
103 dll_paths[nb_dll_paths] = p;
104 while (*p && *p != ':') p++;
105 if (p - dll_paths[nb_dll_paths] > dll_path_maxlen)
106 dll_path_maxlen = p - dll_paths[nb_dll_paths];
111 /* append default dll dir (if not empty) to path */
112 if ((len = strlen(dlldir)))
114 if (len > dll_path_maxlen) dll_path_maxlen = len;
115 dll_paths[nb_dll_paths++] = dlldir;
119 /* check if a given file can be opened */
120 inline static int file_exists( const char *name )
122 int fd = open( name, O_RDONLY );
123 if (fd != -1) close( fd );
127 /* open a library for a given dll, searching in the dll path
128 * 'name' must be the Windows dll name (e.g. "kernel32.dll") */
129 static void *dlopen_dll( const char *name, char *error, int errorsize, int test_only )
131 int i, namelen = strlen(name);
135 if (!init_done) build_dll_path();
137 buffer = malloc( dll_path_maxlen + namelen + 5 );
139 /* store the name at the end of the buffer, followed by .so */
140 p = buffer + dll_path_maxlen;
142 memcpy( p, name, namelen );
143 strcpy( p + namelen, ".so" );
145 for (i = 0; i < nb_dll_paths; i++)
147 int len = strlen(dll_paths[i]);
148 p = buffer + dll_path_maxlen - len;
149 memcpy( p, dll_paths[i], len );
150 if (test_only) /* just test for file existence */
152 if ((ret = (void *)file_exists( p ))) break;
156 if ((ret = wine_dlopen( p, RTLD_NOW, error, errorsize ))) break;
157 if (file_exists( p )) break; /* exists but cannot be loaded, return the error */
165 /* adjust an array of pointers to make them into RVAs */
166 static inline void fixup_rva_ptrs( void *array, void *base, int count )
168 void **ptr = (void **)array;
171 if (*ptr) *ptr = (void *)((char *)*ptr - (char *)base);
177 /* fixup RVAs in the import directory */
178 static void fixup_imports( IMAGE_IMPORT_DESCRIPTOR *dir, DWORD size, void *base )
180 int count = size / sizeof(void *);
181 void **ptr = (void **)dir;
183 /* everything is either a pointer or a ordinal value below 0x10000 */
186 if (*ptr >= (void *)0x10000) *ptr = (void *)((char *)*ptr - (char *)base);
187 else if (*ptr) *ptr = (void *)(0x80000000 | (unsigned int)*ptr);
193 /* fixup RVAs in the resource directory */
194 static void fixup_resources( IMAGE_RESOURCE_DIRECTORY *dir, char *root, void *base )
196 IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
199 entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
200 for (i = 0; i < dir->NumberOfNamedEntries + dir->NumberOfIdEntries; i++, entry++)
202 void *ptr = root + entry->u2.s3.OffsetToDirectory;
203 if (entry->u2.s3.DataIsDirectory) fixup_resources( ptr, root, base );
206 IMAGE_RESOURCE_DATA_ENTRY *data = ptr;
207 fixup_rva_ptrs( &data->OffsetToData, base, 1 );
213 /* map a builtin dll in memory and fixup RVAs */
214 static void *map_dll( const IMAGE_NT_HEADERS *nt_descr )
217 IMAGE_DATA_DIRECTORY *dir;
218 IMAGE_DOS_HEADER *dos;
219 IMAGE_NT_HEADERS *nt;
220 IMAGE_SECTION_HEADER *sec;
221 BYTE *addr, *code_start, *data_start;
222 size_t page_size = getpagesize();
223 int nb_sections = 2; /* code + data */
225 size_t size = (sizeof(IMAGE_DOS_HEADER)
226 + sizeof(IMAGE_NT_HEADERS)
227 + nb_sections * sizeof(IMAGE_SECTION_HEADER));
229 assert( size <= page_size );
231 /* module address must be aligned on 64K boundary */
232 addr = (BYTE *)((nt_descr->OptionalHeader.ImageBase + 0xffff) & ~0xffff);
233 if (wine_anon_mmap( addr, page_size, PROT_READ|PROT_WRITE, MAP_FIXED ) != addr) return NULL;
235 dos = (IMAGE_DOS_HEADER *)addr;
236 nt = (IMAGE_NT_HEADERS *)(dos + 1);
237 sec = (IMAGE_SECTION_HEADER *)(nt + 1);
238 code_start = addr + page_size;
241 data_start = code_start + page_size;
243 /* Build the DOS and NT headers */
245 dos->e_magic = IMAGE_DOS_SIGNATURE;
246 dos->e_lfanew = sizeof(*dos);
250 nt->FileHeader.NumberOfSections = nb_sections;
251 nt->OptionalHeader.SizeOfCode = data_start - code_start;
252 nt->OptionalHeader.SizeOfInitializedData = 0;
253 nt->OptionalHeader.SizeOfUninitializedData = 0;
254 nt->OptionalHeader.ImageBase = (DWORD)addr;
256 fixup_rva_ptrs( &nt->OptionalHeader.AddressOfEntryPoint, addr, 1 );
258 /* Build the code section */
260 strcpy( sec->Name, ".text" );
261 sec->SizeOfRawData = data_start - code_start;
262 sec->Misc.VirtualSize = sec->SizeOfRawData;
263 sec->VirtualAddress = code_start - addr;
264 sec->PointerToRawData = code_start - addr;
265 sec->Characteristics = (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ);
268 /* Build the data section */
270 strcpy( sec->Name, ".data" );
271 sec->SizeOfRawData = 0;
272 sec->Misc.VirtualSize = sec->SizeOfRawData;
273 sec->VirtualAddress = data_start - addr;
274 sec->PointerToRawData = data_start - addr;
275 sec->Characteristics = (IMAGE_SCN_CNT_INITIALIZED_DATA |
276 IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ);
279 /* Build the import directory */
281 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY];
284 IMAGE_IMPORT_DESCRIPTOR *imports = (void *)dir->VirtualAddress;
285 fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
286 fixup_imports( imports, dir->Size, addr );
289 /* Build the resource directory */
291 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY];
294 void *ptr = (void *)dir->VirtualAddress;
295 fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
296 fixup_resources( ptr, ptr, addr );
299 /* Build the export directory */
301 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
304 IMAGE_EXPORT_DIRECTORY *exports = (void *)dir->VirtualAddress;
305 fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
306 fixup_rva_ptrs( (void *)exports->AddressOfFunctions, addr, exports->NumberOfFunctions );
307 fixup_rva_ptrs( (void *)exports->AddressOfNames, addr, exports->NumberOfNames );
308 fixup_rva_ptrs( &exports->Name, addr, 1 );
309 fixup_rva_ptrs( &exports->AddressOfFunctions, addr, 1 );
310 fixup_rva_ptrs( &exports->AddressOfNames, addr, 1 );
311 fixup_rva_ptrs( &exports->AddressOfNameOrdinals, addr, 1 );
314 #else /* HAVE_MMAP */
316 #endif /* HAVE_MMAP */
320 /***********************************************************************
321 * __wine_dll_register
323 * Register a built-in DLL descriptor.
325 void __wine_dll_register( const IMAGE_NT_HEADERS *header, const char *filename )
327 if (load_dll_callback) load_dll_callback( map_dll(header), filename );
330 if (!(header->FileHeader.Characteristics & IMAGE_FILE_DLL))
334 assert( nb_dlls < MAX_DLLS );
335 builtin_dlls[nb_dlls].nt = header;
336 builtin_dlls[nb_dlls].filename = filename;
343 /***********************************************************************
344 * wine_dll_set_callback
346 * Set the callback function for dll loading, and call it
347 * for all dlls that were implicitly loaded already.
349 void wine_dll_set_callback( load_dll_callback_t load )
352 load_dll_callback = load;
353 for (i = 0; i < nb_dlls; i++)
355 const IMAGE_NT_HEADERS *nt = builtin_dlls[i].nt;
357 builtin_dlls[i].nt = NULL;
358 load_dll_callback( map_dll(nt), builtin_dlls[i].filename );
361 if (main_exe) load_dll_callback( map_dll(main_exe), "" );
365 /***********************************************************************
368 * Load a builtin dll.
370 void *wine_dll_load( const char *filename, char *error, int errorsize )
374 /* callback must have been set already */
375 assert( load_dll_callback );
377 /* check if we have it in the list */
378 /* this can happen when initializing pre-loaded dlls in wine_dll_set_callback */
379 for (i = 0; i < nb_dlls; i++)
381 if (!builtin_dlls[i].nt) continue;
382 if (!strcmp( builtin_dlls[i].filename, filename ))
384 const IMAGE_NT_HEADERS *nt = builtin_dlls[i].nt;
385 builtin_dlls[i].nt = NULL;
386 load_dll_callback( map_dll(nt), builtin_dlls[i].filename );
390 return dlopen_dll( filename, error, errorsize, 0 );
394 /***********************************************************************
397 * Unload a builtin dll.
399 void wine_dll_unload( void *handle )
401 if (handle != (void *)1)
402 wine_dlclose( handle, NULL, 0 );
406 /***********************************************************************
407 * wine_dll_load_main_exe
409 * Try to load the .so for the main exe.
411 void *wine_dll_load_main_exe( const char *name, char *error, int errorsize, int test_only )
413 return dlopen_dll( name, error, errorsize, test_only );
417 /***********************************************************************
420 * Main Wine initialisation.
422 void wine_init( int argc, char *argv[], char *error, int error_size )
425 void (*init_func)(int, char **);
427 if (!(ntdll = dlopen_dll( "ntdll.dll", error, error_size, 0 ))) return;
428 if (!(init_func = wine_dlsym( ntdll, "__wine_process_init", error, error_size ))) return;
429 init_func( argc, argv );
433 #if defined(__svr4__) || defined(__NetBSD__)
434 /***********************************************************************
437 * The purpose of this routine is to emulate the behaviour of
438 * the Linux mmap() routine if a non-NULL address is passed,
439 * but the MAP_FIXED flag is not set. Linux in this case tries
440 * to place the mapping at the specified address, *unless* the
441 * range is already in use. Solaris, however, completely ignores
442 * the address argument in this case.
444 * As Wine code occasionally relies on the Linux behaviour, e.g. to
445 * be able to map non-relocateable PE executables to their proper
446 * start addresses, or to map the DOS memory to 0, this routine
447 * emulates the Linux behaviour by checking whether the desired
448 * address range is still available, and placing the mapping there
449 * using MAP_FIXED if so.
451 static int try_mmap_fixed (void *addr, size_t len, int prot, int flags,
452 int fildes, off_t off)
454 char * volatile result = NULL;
455 int pagesize = getpagesize();
458 /* We only try to map to a fixed address if
459 addr is non-NULL and properly aligned,
460 and MAP_FIXED isn't already specified. */
464 if ( (uintptr_t)addr & (pagesize-1) )
466 if ( flags & MAP_FIXED )
469 /* We use vfork() to freeze all threads of the
470 current process. This allows us to check without
471 race condition whether the desired memory range is
472 already in use. Note that because vfork() shares
473 the address spaces between parent and child, we
474 can actually perform the mapping in the child. */
476 if ( (pid = vfork()) == -1 )
478 perror("try_mmap_fixed: vfork");
486 /* We call mincore() for every page in the desired range.
487 If any of these calls succeeds, the page is already
488 mapped and we must fail. */
489 for ( i = 0; i < len; i += pagesize )
490 if ( mincore( (caddr_t)addr + i, pagesize, &vec ) != -1 )
493 /* Perform the mapping with MAP_FIXED set. This is safe
494 now, as none of the pages is currently in use. */
495 result = mmap( addr, len, prot, flags | MAP_FIXED, fildes, off );
496 if ( result == addr )
499 if ( result != (void *) -1 ) /* This should never happen ... */
500 munmap( result, len );
505 /* vfork() lets the parent continue only after the child
506 has exited. Furthermore, Wine sets SIGCHLD to SIG_IGN,
507 so we don't need to wait for the child. */
509 return result == addr;
511 #endif /* __svr4__ || __NetBSD__ */
514 /***********************************************************************
517 * Portable wrapper for anonymous mmaps
519 void *wine_anon_mmap( void *start, size_t size, int prot, int flags )
522 static int fdzero = -1;
529 if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
531 perror( "/dev/zero: open" );
535 #endif /* MAP_ANON */
538 flags &= ~MAP_SHARED;
541 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
543 flags |= MAP_PRIVATE;
546 #if defined(__svr4__) || defined(__NetBSD__)
547 if ( try_mmap_fixed( start, size, prot, flags, fdzero, 0 ) )
551 return mmap( start, size, prot, flags, fdzero, 0 );
559 * These functions provide wrappers around dlopen() and associated
560 * functions. They work around a bug in glibc 2.1.x where calling
561 * a dl*() function after a previous dl*() function has failed
562 * without a dlerror() call between the two will cause a crash.
563 * They all take a pointer to a buffer that
564 * will receive the error description (from dlerror()). This
565 * parameter may be NULL if the error description is not required.
568 /***********************************************************************
571 void *wine_dlopen( const char *filename, int flag, char *error, int errorsize )
576 dlerror(); dlerror();
577 ret = dlopen( filename, flag );
581 strncpy( error, s ? s : "", errorsize );
582 error[errorsize - 1] = '\0';
589 strncpy( error, "dlopen interface not detected by configure", errorsize );
590 error[errorsize - 1] = '\0';
596 /***********************************************************************
599 void *wine_dlsym( void *handle, const char *symbol, char *error, int errorsize )
604 dlerror(); dlerror();
605 ret = dlsym( handle, symbol );
609 strncpy( error, s ? s : "", errorsize );
610 error[errorsize - 1] = '\0';
617 strncpy( error, "dlopen interface not detected by configure", errorsize );
618 error[errorsize - 1] = '\0';
624 /***********************************************************************
627 int wine_dlclose( void *handle, char *error, int errorsize )
632 dlerror(); dlerror();
633 ret = dlclose( handle );
637 strncpy( error, s ? s : "", errorsize );
638 error[errorsize - 1] = '\0';
645 strncpy( error, "dlopen interface not detected by configure", errorsize );
646 error[errorsize - 1] = '\0';