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,
130 int test_only, int *exists )
132 int i, namelen = strlen(name);
136 if (!init_done) build_dll_path();
138 buffer = malloc( dll_path_maxlen + namelen + 5 );
140 /* store the name at the end of the buffer, followed by .so */
141 p = buffer + dll_path_maxlen;
143 memcpy( p, name, namelen );
144 strcpy( p + namelen, ".so" );
147 for (i = 0; i < nb_dll_paths; i++)
149 int len = strlen(dll_paths[i]);
150 p = buffer + dll_path_maxlen - len;
151 memcpy( p, dll_paths[i], len );
152 if (!test_only && (ret = wine_dlopen( p, RTLD_NOW, error, errorsize ))) break;
153 if ((*exists = file_exists( p ))) break; /* exists but cannot be loaded, return the error */
160 /* adjust an array of pointers to make them into RVAs */
161 static inline void fixup_rva_ptrs( void *array, void *base, int count )
163 void **ptr = (void **)array;
166 if (*ptr) *ptr = (void *)((char *)*ptr - (char *)base);
172 /* fixup RVAs in the import directory */
173 static void fixup_imports( IMAGE_IMPORT_DESCRIPTOR *dir, DWORD size, void *base )
175 int count = size / sizeof(void *);
176 void **ptr = (void **)dir;
178 /* everything is either a pointer or a ordinal value below 0x10000 */
181 if (*ptr >= (void *)0x10000) *ptr = (void *)((char *)*ptr - (char *)base);
182 else if (*ptr) *ptr = (void *)(0x80000000 | (unsigned int)*ptr);
188 /* fixup RVAs in the resource directory */
189 static void fixup_resources( IMAGE_RESOURCE_DIRECTORY *dir, char *root, void *base )
191 IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
194 entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
195 for (i = 0; i < dir->NumberOfNamedEntries + dir->NumberOfIdEntries; i++, entry++)
197 void *ptr = root + entry->u2.s3.OffsetToDirectory;
198 if (entry->u2.s3.DataIsDirectory) fixup_resources( ptr, root, base );
201 IMAGE_RESOURCE_DATA_ENTRY *data = ptr;
202 fixup_rva_ptrs( &data->OffsetToData, base, 1 );
208 /* map a builtin dll in memory and fixup RVAs */
209 static void *map_dll( const IMAGE_NT_HEADERS *nt_descr )
212 IMAGE_DATA_DIRECTORY *dir;
213 IMAGE_DOS_HEADER *dos;
214 IMAGE_NT_HEADERS *nt;
215 IMAGE_SECTION_HEADER *sec;
216 BYTE *addr, *code_start, *data_start;
217 size_t page_size = getpagesize();
218 int nb_sections = 2; /* code + data */
220 size_t size = (sizeof(IMAGE_DOS_HEADER)
221 + sizeof(IMAGE_NT_HEADERS)
222 + nb_sections * sizeof(IMAGE_SECTION_HEADER));
224 assert( size <= page_size );
226 /* module address must be aligned on 64K boundary */
227 addr = (BYTE *)((nt_descr->OptionalHeader.ImageBase + 0xffff) & ~0xffff);
228 if (wine_anon_mmap( addr, page_size, PROT_READ|PROT_WRITE, MAP_FIXED ) != addr) return NULL;
230 dos = (IMAGE_DOS_HEADER *)addr;
231 nt = (IMAGE_NT_HEADERS *)(dos + 1);
232 sec = (IMAGE_SECTION_HEADER *)(nt + 1);
233 code_start = addr + page_size;
236 data_start = code_start + page_size;
238 /* Build the DOS and NT headers */
240 dos->e_magic = IMAGE_DOS_SIGNATURE;
241 dos->e_lfanew = sizeof(*dos);
245 nt->FileHeader.NumberOfSections = nb_sections;
246 nt->OptionalHeader.SizeOfCode = data_start - code_start;
247 nt->OptionalHeader.SizeOfInitializedData = 0;
248 nt->OptionalHeader.SizeOfUninitializedData = 0;
249 nt->OptionalHeader.ImageBase = (DWORD)addr;
251 fixup_rva_ptrs( &nt->OptionalHeader.AddressOfEntryPoint, addr, 1 );
253 /* Build the code section */
255 strcpy( sec->Name, ".text" );
256 sec->SizeOfRawData = data_start - code_start;
257 sec->Misc.VirtualSize = sec->SizeOfRawData;
258 sec->VirtualAddress = code_start - addr;
259 sec->PointerToRawData = code_start - addr;
260 sec->Characteristics = (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ);
263 /* Build the data section */
265 strcpy( sec->Name, ".data" );
266 sec->SizeOfRawData = 0;
267 sec->Misc.VirtualSize = sec->SizeOfRawData;
268 sec->VirtualAddress = data_start - addr;
269 sec->PointerToRawData = data_start - addr;
270 sec->Characteristics = (IMAGE_SCN_CNT_INITIALIZED_DATA |
271 IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ);
274 /* Build the import directory */
276 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY];
279 IMAGE_IMPORT_DESCRIPTOR *imports = (void *)dir->VirtualAddress;
280 fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
281 fixup_imports( imports, dir->Size, addr );
284 /* Build the resource directory */
286 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY];
289 void *ptr = (void *)dir->VirtualAddress;
290 fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
291 fixup_resources( ptr, ptr, addr );
294 /* Build the export directory */
296 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
299 IMAGE_EXPORT_DIRECTORY *exports = (void *)dir->VirtualAddress;
300 fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
301 fixup_rva_ptrs( (void *)exports->AddressOfFunctions, addr, exports->NumberOfFunctions );
302 fixup_rva_ptrs( (void *)exports->AddressOfNames, addr, exports->NumberOfNames );
303 fixup_rva_ptrs( &exports->Name, addr, 1 );
304 fixup_rva_ptrs( &exports->AddressOfFunctions, addr, 1 );
305 fixup_rva_ptrs( &exports->AddressOfNames, addr, 1 );
306 fixup_rva_ptrs( &exports->AddressOfNameOrdinals, addr, 1 );
309 #else /* HAVE_MMAP */
311 #endif /* HAVE_MMAP */
315 /***********************************************************************
316 * __wine_dll_register
318 * Register a built-in DLL descriptor.
320 void __wine_dll_register( const IMAGE_NT_HEADERS *header, const char *filename )
322 if (load_dll_callback) load_dll_callback( map_dll(header), filename );
325 if (!(header->FileHeader.Characteristics & IMAGE_FILE_DLL))
329 assert( nb_dlls < MAX_DLLS );
330 builtin_dlls[nb_dlls].nt = header;
331 builtin_dlls[nb_dlls].filename = filename;
338 /***********************************************************************
339 * wine_dll_set_callback
341 * Set the callback function for dll loading, and call it
342 * for all dlls that were implicitly loaded already.
344 void wine_dll_set_callback( load_dll_callback_t load )
347 load_dll_callback = load;
348 for (i = 0; i < nb_dlls; i++)
350 const IMAGE_NT_HEADERS *nt = builtin_dlls[i].nt;
352 builtin_dlls[i].nt = NULL;
353 load_dll_callback( map_dll(nt), builtin_dlls[i].filename );
356 if (main_exe) load_dll_callback( map_dll(main_exe), "" );
360 /***********************************************************************
363 * Load a builtin dll.
365 void *wine_dll_load( const char *filename, char *error, int errorsize, int *file_exists )
369 /* callback must have been set already */
370 assert( load_dll_callback );
372 /* check if we have it in the list */
373 /* this can happen when initializing pre-loaded dlls in wine_dll_set_callback */
374 for (i = 0; i < nb_dlls; i++)
376 if (!builtin_dlls[i].nt) continue;
377 if (!strcmp( builtin_dlls[i].filename, filename ))
379 const IMAGE_NT_HEADERS *nt = builtin_dlls[i].nt;
380 builtin_dlls[i].nt = NULL;
381 load_dll_callback( map_dll(nt), builtin_dlls[i].filename );
386 return dlopen_dll( filename, error, errorsize, 0, file_exists );
390 /***********************************************************************
393 * Unload a builtin dll.
395 void wine_dll_unload( void *handle )
397 if (handle != (void *)1)
398 wine_dlclose( handle, NULL, 0 );
402 /***********************************************************************
403 * wine_dll_load_main_exe
405 * Try to load the .so for the main exe.
407 void *wine_dll_load_main_exe( const char *name, char *error, int errorsize,
408 int test_only, int *file_exists )
410 return dlopen_dll( name, error, errorsize, test_only, file_exists );
414 /***********************************************************************
417 * Main Wine initialisation.
419 void wine_init( int argc, char *argv[], char *error, int error_size )
423 void (*init_func)(int, char **);
425 if (!(ntdll = dlopen_dll( "ntdll.dll", error, error_size, 0, &file_exists ))) return;
426 if (!(init_func = wine_dlsym( ntdll, "__wine_process_init", error, error_size ))) return;
427 init_func( argc, argv );
431 #if defined(__svr4__) || defined(__NetBSD__)
432 /***********************************************************************
435 * The purpose of this routine is to emulate the behaviour of
436 * the Linux mmap() routine if a non-NULL address is passed,
437 * but the MAP_FIXED flag is not set. Linux in this case tries
438 * to place the mapping at the specified address, *unless* the
439 * range is already in use. Solaris, however, completely ignores
440 * the address argument in this case.
442 * As Wine code occasionally relies on the Linux behaviour, e.g. to
443 * be able to map non-relocateable PE executables to their proper
444 * start addresses, or to map the DOS memory to 0, this routine
445 * emulates the Linux behaviour by checking whether the desired
446 * address range is still available, and placing the mapping there
447 * using MAP_FIXED if so.
449 static int try_mmap_fixed (void *addr, size_t len, int prot, int flags,
450 int fildes, off_t off)
452 char * volatile result = NULL;
453 int pagesize = getpagesize();
456 /* We only try to map to a fixed address if
457 addr is non-NULL and properly aligned,
458 and MAP_FIXED isn't already specified. */
462 if ( (uintptr_t)addr & (pagesize-1) )
464 if ( flags & MAP_FIXED )
467 /* We use vfork() to freeze all threads of the
468 current process. This allows us to check without
469 race condition whether the desired memory range is
470 already in use. Note that because vfork() shares
471 the address spaces between parent and child, we
472 can actually perform the mapping in the child. */
474 if ( (pid = vfork()) == -1 )
476 perror("try_mmap_fixed: vfork");
484 /* We call mincore() for every page in the desired range.
485 If any of these calls succeeds, the page is already
486 mapped and we must fail. */
487 for ( i = 0; i < len; i += pagesize )
488 if ( mincore( (caddr_t)addr + i, pagesize, &vec ) != -1 )
491 /* Perform the mapping with MAP_FIXED set. This is safe
492 now, as none of the pages is currently in use. */
493 result = mmap( addr, len, prot, flags | MAP_FIXED, fildes, off );
494 if ( result == addr )
497 if ( result != (void *) -1 ) /* This should never happen ... */
498 munmap( result, len );
503 /* vfork() lets the parent continue only after the child
504 has exited. Furthermore, Wine sets SIGCHLD to SIG_IGN,
505 so we don't need to wait for the child. */
507 return result == addr;
509 #endif /* __svr4__ || __NetBSD__ */
512 /***********************************************************************
515 * Portable wrapper for anonymous mmaps
517 void *wine_anon_mmap( void *start, size_t size, int prot, int flags )
520 static int fdzero = -1;
527 if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
529 perror( "/dev/zero: open" );
533 #endif /* MAP_ANON */
536 flags &= ~MAP_SHARED;
539 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
541 flags |= MAP_PRIVATE;
544 #if defined(__svr4__) || defined(__NetBSD__)
545 if ( try_mmap_fixed( start, size, prot, flags, fdzero, 0 ) )
549 return mmap( start, size, prot, flags, fdzero, 0 );
557 * These functions provide wrappers around dlopen() and associated
558 * functions. They work around a bug in glibc 2.1.x where calling
559 * a dl*() function after a previous dl*() function has failed
560 * without a dlerror() call between the two will cause a crash.
561 * They all take a pointer to a buffer that
562 * will receive the error description (from dlerror()). This
563 * parameter may be NULL if the error description is not required.
566 /***********************************************************************
569 void *wine_dlopen( const char *filename, int flag, char *error, int errorsize )
574 dlerror(); dlerror();
575 ret = dlopen( filename, flag );
579 strncpy( error, s ? s : "", errorsize );
580 error[errorsize - 1] = '\0';
587 strncpy( error, "dlopen interface not detected by configure", errorsize );
588 error[errorsize - 1] = '\0';
594 /***********************************************************************
597 void *wine_dlsym( void *handle, const char *symbol, char *error, int errorsize )
602 dlerror(); dlerror();
603 ret = dlsym( handle, symbol );
607 strncpy( error, s ? s : "", errorsize );
608 error[errorsize - 1] = '\0';
615 strncpy( error, "dlopen interface not detected by configure", errorsize );
616 error[errorsize - 1] = '\0';
622 /***********************************************************************
625 int wine_dlclose( void *handle, char *error, int errorsize )
630 dlerror(); dlerror();
631 ret = dlclose( handle );
635 strncpy( error, s ? s : "", errorsize );
636 error[errorsize - 1] = '\0';
643 strncpy( error, "dlopen interface not detected by configure", errorsize );
644 error[errorsize - 1] = '\0';