Moved date/time/currency format handling to new lcformat.c.
[wine/multimedia.git] / library / loader.c
blob922b7de1602e09467fb69d1b5d8fcce41fbd9599
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
37 #define NONAMELESSUNION
38 #define NONAMELESSSTRUCT
39 #include "windef.h"
40 #include "wine/library.h"
42 /* argc/argv for the Windows application */
43 int __wine_main_argc = 0;
44 char **__wine_main_argv = NULL;
45 WCHAR **__wine_main_wargv = NULL;
47 #define MAX_DLLS 100
49 static struct
51 const IMAGE_NT_HEADERS *nt; /* NT header */
52 const char *filename; /* DLL file name */
53 } builtin_dlls[MAX_DLLS];
55 static int nb_dlls;
57 static const IMAGE_NT_HEADERS *main_exe;
59 static load_dll_callback_t load_dll_callback;
61 static const char **dll_paths;
62 static int nb_dll_paths;
63 static int dll_path_maxlen;
64 static int init_done;
67 /* build the dll load path from the WINEDLLPATH variable */
68 static void build_dll_path(void)
70 static const char * const dlldir = DLLDIR;
71 int len, count = 0;
72 char *p, *path = getenv( "WINEDLLPATH" );
74 init_done = 1;
76 if (path)
78 /* count how many path elements we need */
79 path = strdup(path);
80 p = path;
81 while (*p)
83 while (*p == ':') p++;
84 if (!*p) break;
85 count++;
86 while (*p && *p != ':') p++;
90 dll_paths = malloc( (count+1) * sizeof(*dll_paths) );
92 if (count)
94 p = path;
95 nb_dll_paths = 0;
96 while (*p)
98 while (*p == ':') *p++ = 0;
99 if (!*p) break;
100 dll_paths[nb_dll_paths] = p;
101 while (*p && *p != ':') p++;
102 if (p - dll_paths[nb_dll_paths] > dll_path_maxlen)
103 dll_path_maxlen = p - dll_paths[nb_dll_paths];
104 nb_dll_paths++;
108 /* append default dll dir (if not empty) to path */
109 if ((len = strlen(dlldir)))
111 if (len > dll_path_maxlen) dll_path_maxlen = len;
112 dll_paths[nb_dll_paths++] = dlldir;
116 /* check if a given file can be opened */
117 inline static int file_exists( const char *name )
119 int fd = open( name, O_RDONLY );
120 if (fd != -1) close( fd );
121 return (fd != -1);
124 /* open a library for a given dll, searching in the dll path
125 * 'name' must be the Windows dll name (e.g. "kernel32.dll") */
126 static void *dlopen_dll( const char *name, char *error, int errorsize, int test_only )
128 int i, namelen = strlen(name);
129 char *buffer, *p;
130 void *ret = NULL;
132 if (!init_done) build_dll_path();
134 buffer = malloc( dll_path_maxlen + namelen + 5 );
136 /* store the name at the end of the buffer, followed by .so */
137 p = buffer + dll_path_maxlen;
138 *p++ = '/';
139 memcpy( p, name, namelen );
140 strcpy( p + namelen, ".so" );
142 for (i = 0; i < nb_dll_paths; i++)
144 int len = strlen(dll_paths[i]);
145 p = buffer + dll_path_maxlen - len;
146 memcpy( p, dll_paths[i], len );
147 if (test_only) /* just test for file existence */
149 if ((ret = (void *)file_exists( p ))) break;
151 else
153 if ((ret = wine_dlopen( p, RTLD_NOW, error, errorsize ))) break;
154 if (file_exists( p )) break; /* exists but cannot be loaded, return the error */
157 free( buffer );
158 return ret;
162 /* adjust an array of pointers to make them into RVAs */
163 static inline void fixup_rva_ptrs( void *array, void *base, int count )
165 void **ptr = (void **)array;
166 while (count--)
168 if (*ptr) *ptr = (void *)((char *)*ptr - (char *)base);
169 ptr++;
174 /* fixup RVAs in the import directory */
175 static void fixup_imports( IMAGE_IMPORT_DESCRIPTOR *dir, DWORD size, void *base )
177 int count = size / sizeof(void *);
178 void **ptr = (void **)dir;
180 /* everything is either a pointer or a ordinal value below 0x10000 */
181 while (count--)
183 if (*ptr >= (void *)0x10000) *ptr = (void *)((char *)*ptr - (char *)base);
184 else if (*ptr) *ptr = (void *)(0x80000000 | (unsigned int)*ptr);
185 ptr++;
190 /* fixup RVAs in the resource directory */
191 static void fixup_resources( IMAGE_RESOURCE_DIRECTORY *dir, char *root, void *base )
193 IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
194 int i;
196 entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
197 for (i = 0; i < dir->NumberOfNamedEntries + dir->NumberOfIdEntries; i++, entry++)
199 void *ptr = root + entry->u2.s3.OffsetToDirectory;
200 if (entry->u2.s3.DataIsDirectory) fixup_resources( ptr, root, base );
201 else
203 IMAGE_RESOURCE_DATA_ENTRY *data = ptr;
204 fixup_rva_ptrs( &data->OffsetToData, base, 1 );
210 /* map a builtin dll in memory and fixup RVAs */
211 static void *map_dll( const IMAGE_NT_HEADERS *nt_descr )
213 #ifdef HAVE_MMAP
214 IMAGE_DATA_DIRECTORY *dir;
215 IMAGE_DOS_HEADER *dos;
216 IMAGE_NT_HEADERS *nt;
217 IMAGE_SECTION_HEADER *sec;
218 BYTE *addr, *code_start, *data_start;
219 size_t page_size = getpagesize();
220 int nb_sections = 2; /* code + data */
222 size_t size = (sizeof(IMAGE_DOS_HEADER)
223 + sizeof(IMAGE_NT_HEADERS)
224 + nb_sections * sizeof(IMAGE_SECTION_HEADER));
226 assert( size <= page_size );
228 /* module address must be aligned on 64K boundary */
229 addr = (BYTE *)((nt_descr->OptionalHeader.ImageBase + 0xffff) & ~0xffff);
230 if (wine_anon_mmap( addr, page_size, PROT_READ|PROT_WRITE, MAP_FIXED ) != addr) return NULL;
232 dos = (IMAGE_DOS_HEADER *)addr;
233 nt = (IMAGE_NT_HEADERS *)(dos + 1);
234 sec = (IMAGE_SECTION_HEADER *)(nt + 1);
235 code_start = addr + page_size;
237 /* HACK! */
238 data_start = code_start + page_size;
240 /* Build the DOS and NT headers */
242 dos->e_magic = IMAGE_DOS_SIGNATURE;
243 dos->e_lfanew = sizeof(*dos);
245 *nt = *nt_descr;
247 nt->FileHeader.NumberOfSections = nb_sections;
248 nt->OptionalHeader.SizeOfCode = data_start - code_start;
249 nt->OptionalHeader.SizeOfInitializedData = 0;
250 nt->OptionalHeader.SizeOfUninitializedData = 0;
251 nt->OptionalHeader.ImageBase = (DWORD)addr;
253 fixup_rva_ptrs( &nt->OptionalHeader.AddressOfEntryPoint, addr, 1 );
255 /* Build the code section */
257 strcpy( sec->Name, ".text" );
258 sec->SizeOfRawData = data_start - code_start;
259 sec->Misc.VirtualSize = sec->SizeOfRawData;
260 sec->VirtualAddress = code_start - addr;
261 sec->PointerToRawData = code_start - addr;
262 sec->Characteristics = (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ);
263 sec++;
265 /* Build the data section */
267 strcpy( sec->Name, ".data" );
268 sec->SizeOfRawData = 0;
269 sec->Misc.VirtualSize = sec->SizeOfRawData;
270 sec->VirtualAddress = data_start - addr;
271 sec->PointerToRawData = data_start - addr;
272 sec->Characteristics = (IMAGE_SCN_CNT_INITIALIZED_DATA |
273 IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ);
274 sec++;
276 /* Build the import directory */
278 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY];
279 if (dir->Size)
281 IMAGE_IMPORT_DESCRIPTOR *imports = (void *)dir->VirtualAddress;
282 fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
283 fixup_imports( imports, dir->Size, addr );
286 /* Build the resource directory */
288 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY];
289 if (dir->Size)
291 void *ptr = (void *)dir->VirtualAddress;
292 fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
293 fixup_resources( ptr, ptr, addr );
296 /* Build the export directory */
298 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
299 if (dir->Size)
301 IMAGE_EXPORT_DIRECTORY *exports = (void *)dir->VirtualAddress;
302 fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
303 fixup_rva_ptrs( (void *)exports->AddressOfFunctions, addr, exports->NumberOfFunctions );
304 fixup_rva_ptrs( (void *)exports->AddressOfNames, addr, exports->NumberOfNames );
305 fixup_rva_ptrs( &exports->Name, addr, 1 );
306 fixup_rva_ptrs( &exports->AddressOfFunctions, addr, 1 );
307 fixup_rva_ptrs( &exports->AddressOfNames, addr, 1 );
308 fixup_rva_ptrs( &exports->AddressOfNameOrdinals, addr, 1 );
310 return addr;
311 #else /* HAVE_MMAP */
312 return NULL;
313 #endif /* HAVE_MMAP */
317 /***********************************************************************
318 * __wine_dll_register
320 * Register a built-in DLL descriptor.
322 void __wine_dll_register( const IMAGE_NT_HEADERS *header, const char *filename )
324 if (load_dll_callback) load_dll_callback( map_dll(header), filename );
325 else
327 if (!(header->FileHeader.Characteristics & IMAGE_FILE_DLL))
328 main_exe = header;
329 else
331 assert( nb_dlls < MAX_DLLS );
332 builtin_dlls[nb_dlls].nt = header;
333 builtin_dlls[nb_dlls].filename = filename;
334 nb_dlls++;
340 /***********************************************************************
341 * wine_dll_set_callback
343 * Set the callback function for dll loading, and call it
344 * for all dlls that were implicitly loaded already.
346 void wine_dll_set_callback( load_dll_callback_t load )
348 int i;
349 load_dll_callback = load;
350 for (i = 0; i < nb_dlls; i++)
352 const IMAGE_NT_HEADERS *nt = builtin_dlls[i].nt;
353 if (!nt) continue;
354 builtin_dlls[i].nt = NULL;
355 load_dll_callback( map_dll(nt), builtin_dlls[i].filename );
357 nb_dlls = 0;
358 if (main_exe) load_dll_callback( map_dll(main_exe), "" );
362 /***********************************************************************
363 * wine_dll_load
365 * Load a builtin dll.
367 void *wine_dll_load( const char *filename, char *error, int errorsize )
369 int i;
371 /* callback must have been set already */
372 assert( load_dll_callback );
374 /* check if we have it in the list */
375 /* this can happen when initializing pre-loaded dlls in wine_dll_set_callback */
376 for (i = 0; i < nb_dlls; i++)
378 if (!builtin_dlls[i].nt) continue;
379 if (!strcmp( builtin_dlls[i].filename, filename ))
381 const IMAGE_NT_HEADERS *nt = builtin_dlls[i].nt;
382 builtin_dlls[i].nt = NULL;
383 load_dll_callback( map_dll(nt), builtin_dlls[i].filename );
384 return (void *)1;
387 return dlopen_dll( filename, error, errorsize, 0 );
391 /***********************************************************************
392 * wine_dll_unload
394 * Unload a builtin dll.
396 void wine_dll_unload( void *handle )
398 if (handle != (void *)1)
399 wine_dlclose( handle, NULL, 0 );
403 /***********************************************************************
404 * wine_dll_load_main_exe
406 * Try to load the .so for the main exe.
408 void *wine_dll_load_main_exe( const char *name, char *error, int errorsize, int test_only )
410 return dlopen_dll( name, error, errorsize, test_only );
415 #if defined(__svr4__) || defined(__NetBSD__)
416 /***********************************************************************
417 * try_mmap_fixed
419 * The purpose of this routine is to emulate the behaviour of
420 * the Linux mmap() routine if a non-NULL address is passed,
421 * but the MAP_FIXED flag is not set. Linux in this case tries
422 * to place the mapping at the specified address, *unless* the
423 * range is already in use. Solaris, however, completely ignores
424 * the address argument in this case.
426 * As Wine code occasionally relies on the Linux behaviour, e.g. to
427 * be able to map non-relocateable PE executables to their proper
428 * start addresses, or to map the DOS memory to 0, this routine
429 * emulates the Linux behaviour by checking whether the desired
430 * address range is still available, and placing the mapping there
431 * using MAP_FIXED if so.
433 static int try_mmap_fixed (void *addr, size_t len, int prot, int flags,
434 int fildes, off_t off)
436 char * volatile result = NULL;
437 int pagesize = getpagesize();
438 pid_t pid;
440 /* We only try to map to a fixed address if
441 addr is non-NULL and properly aligned,
442 and MAP_FIXED isn't already specified. */
444 if ( !addr )
445 return 0;
446 if ( (uintptr_t)addr & (pagesize-1) )
447 return 0;
448 if ( flags & MAP_FIXED )
449 return 0;
451 /* We use vfork() to freeze all threads of the
452 current process. This allows us to check without
453 race condition whether the desired memory range is
454 already in use. Note that because vfork() shares
455 the address spaces between parent and child, we
456 can actually perform the mapping in the child. */
458 if ( (pid = vfork()) == -1 )
460 perror("try_mmap_fixed: vfork");
461 exit(1);
463 if ( pid == 0 )
465 int i;
466 char vec;
468 /* We call mincore() for every page in the desired range.
469 If any of these calls succeeds, the page is already
470 mapped and we must fail. */
471 for ( i = 0; i < len; i += pagesize )
472 if ( mincore( (caddr_t)addr + i, pagesize, &vec ) != -1 )
473 _exit(1);
475 /* Perform the mapping with MAP_FIXED set. This is safe
476 now, as none of the pages is currently in use. */
477 result = mmap( addr, len, prot, flags | MAP_FIXED, fildes, off );
478 if ( result == addr )
479 _exit(0);
481 if ( result != (void *) -1 ) /* This should never happen ... */
482 munmap( result, len );
484 _exit(1);
487 /* vfork() lets the parent continue only after the child
488 has exited. Furthermore, Wine sets SIGCHLD to SIG_IGN,
489 so we don't need to wait for the child. */
491 return result == addr;
493 #endif /* __svr4__ || __NetBSD__ */
496 /***********************************************************************
497 * wine_anon_mmap
499 * Portable wrapper for anonymous mmaps
501 void *wine_anon_mmap( void *start, size_t size, int prot, int flags )
503 #ifdef HAVE_MMAP
504 static int fdzero = -1;
506 #ifdef MAP_ANON
507 flags |= MAP_ANON;
508 #else
509 if (fdzero == -1)
511 if ((fdzero = open( "/dev/zero", O_RDONLY )) == -1)
513 perror( "/dev/zero: open" );
514 exit(1);
517 #endif /* MAP_ANON */
519 #ifdef MAP_SHARED
520 flags &= ~MAP_SHARED;
521 #endif
523 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
524 #ifdef MAP_PRIVATE
525 flags |= MAP_PRIVATE;
526 #endif
528 #if defined(__svr4__) || defined(__NetBSD__)
529 if ( try_mmap_fixed( start, size, prot, flags, fdzero, 0 ) )
530 return start;
531 #endif
533 return mmap( start, size, prot, flags, fdzero, 0 );
534 #else
535 return (void *)-1;
536 #endif
541 * These functions provide wrappers around dlopen() and associated
542 * functions. They work around a bug in glibc 2.1.x where calling
543 * a dl*() function after a previous dl*() function has failed
544 * without a dlerror() call between the two will cause a crash.
545 * They all take a pointer to a buffer that
546 * will receive the error description (from dlerror()). This
547 * parameter may be NULL if the error description is not required.
550 /***********************************************************************
551 * wine_dlopen
553 void *wine_dlopen( const char *filename, int flag, char *error, int errorsize )
555 #ifdef HAVE_DLOPEN
556 void *ret;
557 const char *s;
558 dlerror(); dlerror();
559 ret = dlopen( filename, flag );
560 s = dlerror();
561 if (error)
563 strncpy( error, s ? s : "", errorsize );
564 error[errorsize - 1] = '\0';
566 dlerror();
567 return ret;
568 #else
569 if (error)
571 strncpy( error, "dlopen interface not detected by configure", errorsize );
572 error[errorsize - 1] = '\0';
574 return NULL;
575 #endif
578 /***********************************************************************
579 * wine_dlsym
581 void *wine_dlsym( void *handle, const char *symbol, char *error, int errorsize )
583 #ifdef HAVE_DLOPEN
584 void *ret;
585 const char *s;
586 dlerror(); dlerror();
587 ret = dlsym( handle, symbol );
588 s = dlerror();
589 if (error)
591 strncpy( error, s ? s : "", errorsize );
592 error[errorsize - 1] = '\0';
594 dlerror();
595 return ret;
596 #else
597 if (error)
599 strncpy( error, "dlopen interface not detected by configure", errorsize );
600 error[errorsize - 1] = '\0';
602 return NULL;
603 #endif
606 /***********************************************************************
607 * wine_dlclose
609 int wine_dlclose( void *handle, char *error, int errorsize )
611 #ifdef HAVE_DLOPEN
612 int ret;
613 const char *s;
614 dlerror(); dlerror();
615 ret = dlclose( handle );
616 s = dlerror();
617 if (error)
619 strncpy( error, s ? s : "", errorsize );
620 error[errorsize - 1] = '\0';
622 dlerror();
623 return ret;
624 #else
625 if (error)
627 strncpy( error, "dlopen interface not detected by configure", errorsize );
628 error[errorsize - 1] = '\0';
630 return 1;
631 #endif