Moved the functionality of starting Win16 and DOS programs from the
[wine.git] / libs / wine / loader.c
blobdbac56bf8a723614f67d147f9d6b26ce5e617017
1 /*
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <ctype.h>
26 #include <fcntl.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_MMAN_H
31 #include <sys/mman.h>
32 #endif
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #ifdef HAVE_STDINT_H
37 # include <stdint.h>
38 #endif
40 #define NONAMELESSUNION
41 #define NONAMELESSSTRUCT
42 #include "windef.h"
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;
50 #define MAX_DLLS 100
52 static struct
54 const IMAGE_NT_HEADERS *nt; /* NT header */
55 const char *filename; /* DLL file name */
56 } builtin_dlls[MAX_DLLS];
58 static int nb_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;
67 static int init_done;
70 /* build the dll load path from the WINEDLLPATH variable */
71 static void build_dll_path(void)
73 static const char * const dlldir = DLLDIR;
74 int len, count = 0;
75 char *p, *path = getenv( "WINEDLLPATH" );
77 init_done = 1;
79 if (path)
81 /* count how many path elements we need */
82 path = strdup(path);
83 p = path;
84 while (*p)
86 while (*p == ':') p++;
87 if (!*p) break;
88 count++;
89 while (*p && *p != ':') p++;
93 dll_paths = malloc( (count+1) * sizeof(*dll_paths) );
95 if (count)
97 p = path;
98 nb_dll_paths = 0;
99 while (*p)
101 while (*p == ':') *p++ = 0;
102 if (!*p) break;
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];
107 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 );
124 return (fd != -1);
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);
132 char *buffer, *p;
133 void *ret = NULL;
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;
141 *p++ = '/';
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;
154 else
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 */
160 free( buffer );
161 return ret;
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;
169 while (count--)
171 if (*ptr) *ptr = (void *)((char *)*ptr - (char *)base);
172 ptr++;
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 */
184 while (count--)
186 if (*ptr >= (void *)0x10000) *ptr = (void *)((char *)*ptr - (char *)base);
187 else if (*ptr) *ptr = (void *)(0x80000000 | (unsigned int)*ptr);
188 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;
197 int i;
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 );
204 else
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 )
216 #ifdef HAVE_MMAP
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;
240 /* HACK! */
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);
248 *nt = *nt_descr;
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);
266 sec++;
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);
277 sec++;
279 /* Build the import directory */
281 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY];
282 if (dir->Size)
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];
292 if (dir->Size)
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];
302 if (dir->Size)
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 );
313 return addr;
314 #else /* HAVE_MMAP */
315 return NULL;
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 );
328 else
330 if (!(header->FileHeader.Characteristics & IMAGE_FILE_DLL))
331 main_exe = header;
332 else
334 assert( nb_dlls < MAX_DLLS );
335 builtin_dlls[nb_dlls].nt = header;
336 builtin_dlls[nb_dlls].filename = filename;
337 nb_dlls++;
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 )
351 int i;
352 load_dll_callback = load;
353 for (i = 0; i < nb_dlls; i++)
355 const IMAGE_NT_HEADERS *nt = builtin_dlls[i].nt;
356 if (!nt) continue;
357 builtin_dlls[i].nt = NULL;
358 load_dll_callback( map_dll(nt), builtin_dlls[i].filename );
360 nb_dlls = 0;
361 if (main_exe) load_dll_callback( map_dll(main_exe), "" );
365 /***********************************************************************
366 * wine_dll_load
368 * Load a builtin dll.
370 void *wine_dll_load( const char *filename, char *error, int errorsize )
372 int i;
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 );
387 return (void *)1;
390 return dlopen_dll( filename, error, errorsize, 0 );
394 /***********************************************************************
395 * wine_dll_unload
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 /***********************************************************************
418 * wine_init
420 * Main Wine initialisation.
422 void wine_init( int argc, char *argv[], char *error, int error_size )
424 void *ntdll;
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 /***********************************************************************
435 * try_mmap_fixed
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();
456 pid_t pid;
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. */
462 if ( !addr )
463 return 0;
464 if ( (uintptr_t)addr & (pagesize-1) )
465 return 0;
466 if ( flags & MAP_FIXED )
467 return 0;
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");
479 exit(1);
481 if ( pid == 0 )
483 int i;
484 char vec;
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 )
491 _exit(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 )
497 _exit(0);
499 if ( result != (void *) -1 ) /* This should never happen ... */
500 munmap( result, len );
502 _exit(1);
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 /***********************************************************************
515 * wine_anon_mmap
517 * Portable wrapper for anonymous mmaps
519 void *wine_anon_mmap( void *start, size_t size, int prot, int flags )
521 #ifdef HAVE_MMAP
522 static int fdzero = -1;
524 #ifdef MAP_ANON
525 flags |= MAP_ANON;
526 #else
527 if (fdzero == -1)
529 if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
531 perror( "/dev/zero: open" );
532 exit(1);
535 #endif /* MAP_ANON */
537 #ifdef MAP_SHARED
538 flags &= ~MAP_SHARED;
539 #endif
541 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
542 #ifdef MAP_PRIVATE
543 flags |= MAP_PRIVATE;
544 #endif
546 #if defined(__svr4__) || defined(__NetBSD__)
547 if ( try_mmap_fixed( start, size, prot, flags, fdzero, 0 ) )
548 return start;
549 #endif
551 return mmap( start, size, prot, flags, fdzero, 0 );
552 #else
553 return (void *)-1;
554 #endif
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 /***********************************************************************
569 * wine_dlopen
571 void *wine_dlopen( const char *filename, int flag, char *error, int errorsize )
573 #ifdef HAVE_DLOPEN
574 void *ret;
575 const char *s;
576 dlerror(); dlerror();
577 ret = dlopen( filename, flag );
578 s = dlerror();
579 if (error)
581 strncpy( error, s ? s : "", errorsize );
582 error[errorsize - 1] = '\0';
584 dlerror();
585 return ret;
586 #else
587 if (error)
589 strncpy( error, "dlopen interface not detected by configure", errorsize );
590 error[errorsize - 1] = '\0';
592 return NULL;
593 #endif
596 /***********************************************************************
597 * wine_dlsym
599 void *wine_dlsym( void *handle, const char *symbol, char *error, int errorsize )
601 #ifdef HAVE_DLOPEN
602 void *ret;
603 const char *s;
604 dlerror(); dlerror();
605 ret = dlsym( handle, symbol );
606 s = dlerror();
607 if (error)
609 strncpy( error, s ? s : "", errorsize );
610 error[errorsize - 1] = '\0';
612 dlerror();
613 return ret;
614 #else
615 if (error)
617 strncpy( error, "dlopen interface not detected by configure", errorsize );
618 error[errorsize - 1] = '\0';
620 return NULL;
621 #endif
624 /***********************************************************************
625 * wine_dlclose
627 int wine_dlclose( void *handle, char *error, int errorsize )
629 #ifdef HAVE_DLOPEN
630 int ret;
631 const char *s;
632 dlerror(); dlerror();
633 ret = dlclose( handle );
634 s = dlerror();
635 if (error)
637 strncpy( error, s ? s : "", errorsize );
638 error[errorsize - 1] = '\0';
640 dlerror();
641 return ret;
642 #else
643 if (error)
645 strncpy( error, "dlopen interface not detected by configure", errorsize );
646 error[errorsize - 1] = '\0';
648 return 1;
649 #endif