VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine/libWine/loader.c@ 30720

Last change on this file since 30720 was 23571, checked in by vboxsync, 15 years ago

crOpenGL: update to wine 1.1.30

  • Property svn:eol-style set to native
File size: 25.0 KB
Line 
1/*
2 * Win32 builtin dlls support
3 *
4 * Copyright 2000 Alexandre Julliard
5 *
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.
10 *
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.
15 *
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
19 */
20
21/*
22 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
23 * other than GPL or LGPL is available it will apply instead, Sun elects to use only
24 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
25 * a choice of LGPL license versions is made available with the language indicating
26 * that LGPLv2 or any later version may be used, or where a choice of which version
27 * of the LGPL is applied is otherwise unspecified.
28 */
29
30#include "config.h"
31#include "wine/port.h"
32
33#include <assert.h>
34#include <ctype.h>
35#include <fcntl.h>
36#include <limits.h>
37#include <stdarg.h>
38#include <stdlib.h>
39#include <string.h>
40#include <sys/types.h>
41#ifdef HAVE_SYS_MMAN_H
42#include <sys/mman.h>
43#endif
44#ifdef HAVE_SYS_RESOURCE_H
45# include <sys/resource.h>
46#endif
47#ifdef HAVE_UNISTD_H
48# include <unistd.h>
49#endif
50
51#define NONAMELESSUNION
52#define NONAMELESSSTRUCT
53#include "windef.h"
54#include "winbase.h"
55#include "wine/library.h"
56
57#ifdef __APPLE__
58#include <crt_externs.h>
59#define environ (*_NSGetEnviron())
60#else
61# ifndef _MSC_VER
62extern char **environ;
63# endif
64#endif
65
66/* argc/argv for the Windows application */
67int __wine_main_argc = 0;
68char **__wine_main_argv = NULL;
69WCHAR **__wine_main_wargv = NULL;
70char **__wine_main_environ = NULL;
71
72struct dll_path_context
73{
74 unsigned int index; /* current index in the dll path list */
75 char *buffer; /* buffer used for storing path names */
76 char *name; /* start of file name part in buffer (including leading slash) */
77 int namelen; /* length of file name without .so extension */
78 int win16; /* 16-bit dll search */
79};
80
81#define MAX_DLLS 100
82
83static struct
84{
85 const IMAGE_NT_HEADERS *nt; /* NT header */
86 const char *filename; /* DLL file name */
87} builtin_dlls[MAX_DLLS];
88
89static int nb_dlls;
90
91static const IMAGE_NT_HEADERS *main_exe;
92
93static load_dll_callback_t load_dll_callback;
94
95static const char *build_dir;
96static const char *default_dlldir;
97static const char **dll_paths;
98static unsigned int nb_dll_paths;
99static int dll_path_maxlen;
100
101extern void mmap_init(void);
102extern const char *get_dlldir( const char **default_dlldir );
103
104/* build the dll load path from the WINEDLLPATH variable */
105static void build_dll_path(void)
106{
107 int len, count = 0;
108 char *p, *path = getenv( "WINEDLLPATH" );
109 const char *dlldir = get_dlldir( &default_dlldir );
110
111 if (path)
112 {
113 /* count how many path elements we need */
114 path = strdup(path);
115 p = path;
116 while (*p)
117 {
118 while (*p == ':') p++;
119 if (!*p) break;
120 count++;
121 while (*p && *p != ':') p++;
122 }
123 }
124
125 dll_paths = malloc( (count+2) * sizeof(*dll_paths) );
126 nb_dll_paths = 0;
127
128 if (dlldir)
129 {
130 dll_path_maxlen = strlen(dlldir);
131 dll_paths[nb_dll_paths++] = dlldir;
132 }
133 else if ((build_dir = wine_get_build_dir()))
134 {
135 dll_path_maxlen = strlen(build_dir) + sizeof("/programs");
136 }
137
138 if (count)
139 {
140 p = path;
141 while (*p)
142 {
143 while (*p == ':') *p++ = 0;
144 if (!*p) break;
145 dll_paths[nb_dll_paths] = p;
146 while (*p && *p != ':') p++;
147 if (p - dll_paths[nb_dll_paths] > dll_path_maxlen)
148 dll_path_maxlen = p - dll_paths[nb_dll_paths];
149 nb_dll_paths++;
150 }
151 }
152
153 /* append default dll dir (if not empty) to path */
154 if ((len = strlen(default_dlldir)) > 0)
155 {
156 if (len > dll_path_maxlen) dll_path_maxlen = len;
157 dll_paths[nb_dll_paths++] = default_dlldir;
158 }
159}
160
161/* check if the library is the correct architecture */
162/* only returns false for a valid library of the wrong arch */
163static int check_library_arch( int fd )
164{
165#ifdef __APPLE__
166 struct /* Mach-O header */
167 {
168 unsigned int magic;
169 unsigned int cputype;
170 } header;
171
172 if (read( fd, &header, sizeof(header) ) != sizeof(header)) return 1;
173 if (header.magic != 0xfeedface) return 1;
174 if (sizeof(void *) == sizeof(int)) return !(header.cputype >> 24);
175 else return (header.cputype >> 24) == 1; /* CPU_ARCH_ABI64 */
176#else
177 struct /* ELF header */
178 {
179 unsigned char magic[4];
180 unsigned char class;
181 unsigned char data;
182 unsigned char version;
183 } header;
184
185 if (read( fd, &header, sizeof(header) ) != sizeof(header)) return 1;
186 if (memcmp( header.magic, "\177ELF", 4 )) return 1;
187 if (header.version != 1 /* EV_CURRENT */) return 1;
188#ifdef WORDS_BIGENDIAN
189 if (header.data != 2 /* ELFDATA2MSB */) return 1;
190#else
191 if (header.data != 1 /* ELFDATA2LSB */) return 1;
192#endif
193 if (sizeof(void *) == sizeof(int)) return header.class == 1; /* ELFCLASS32 */
194 else return header.class == 2; /* ELFCLASS64 */
195#endif
196}
197
198/* check if a given file can be opened */
199static inline int file_exists( const char *name )
200{
201 int ret = 0;
202 int fd = open( name, O_RDONLY );
203 if (fd != -1)
204 {
205 ret = check_library_arch( fd );
206 close( fd );
207 }
208 return ret;
209}
210
211static inline char *prepend( char *buffer, const char *str, size_t len )
212{
213 return memcpy( buffer - len, str, len );
214}
215
216/* get a filename from the next entry in the dll path */
217static char *next_dll_path( struct dll_path_context *context )
218{
219 unsigned int index = context->index++;
220 int namelen = context->namelen;
221 char *path = context->name;
222
223 switch(index)
224 {
225 case 0: /* try dlls dir with subdir prefix */
226 if (namelen > 4 && !memcmp( context->name + namelen - 4, ".dll", 4 )) namelen -= 4;
227 if (!context->win16) path = prepend( path, context->name, namelen );
228 path = prepend( path, "/dlls", sizeof("/dlls") - 1 );
229 path = prepend( path, build_dir, strlen(build_dir) );
230 return path;
231 case 1: /* try programs dir with subdir prefix */
232 if (!context->win16)
233 {
234 if (namelen > 4 && !memcmp( context->name + namelen - 4, ".exe", 4 )) namelen -= 4;
235 path = prepend( path, context->name, namelen );
236 path = prepend( path, "/programs", sizeof("/programs") - 1 );
237 path = prepend( path, build_dir, strlen(build_dir) );
238 return path;
239 }
240 context->index++;
241 /* fall through */
242 default:
243 index -= 2;
244 if (index < nb_dll_paths)
245 return prepend( context->name, dll_paths[index], strlen( dll_paths[index] ));
246 break;
247 }
248 return NULL;
249}
250
251
252/* get a filename from the first entry in the dll path */
253static char *first_dll_path( const char *name, int win16, struct dll_path_context *context )
254{
255 char *p;
256 int namelen = strlen( name );
257 const char *ext = win16 ? "16" : ".so";
258
259 context->buffer = malloc( dll_path_maxlen + 2 * namelen + strlen(ext) + 3 );
260 context->index = build_dir ? 0 : 2; /* if no build dir skip all the build dir magic cases */
261 context->name = context->buffer + dll_path_maxlen + namelen + 1;
262 context->namelen = namelen + 1;
263 context->win16 = win16;
264
265 /* store the name at the end of the buffer, followed by extension */
266 p = context->name;
267 *p++ = '/';
268 memcpy( p, name, namelen );
269 strcpy( p + namelen, ext );
270 return next_dll_path( context );
271}
272
273
274/* free the dll path context created by first_dll_path */
275static inline void free_dll_path( struct dll_path_context *context )
276{
277 free( context->buffer );
278}
279
280
281/* open a library for a given dll, searching in the dll path
282 * 'name' must be the Windows dll name (e.g. "kernel32.dll") */
283static void *dlopen_dll( const char *name, char *error, int errorsize,
284 int test_only, int *exists )
285{
286 struct dll_path_context context;
287 char *path;
288 void *ret = NULL;
289
290 *exists = 0;
291 for (path = first_dll_path( name, 0, &context ); path; path = next_dll_path( &context ))
292 {
293 if (!test_only && (ret = wine_dlopen( path, RTLD_NOW, error, errorsize ))) break;
294 if ((*exists = file_exists( path ))) break; /* exists but cannot be loaded, return the error */
295 }
296 free_dll_path( &context );
297 return ret;
298}
299
300
301/* adjust an array of pointers to make them into RVAs */
302static inline void fixup_rva_ptrs( void *array, BYTE *base, unsigned int count )
303{
304 void **src = (void **)array;
305 DWORD *dst = (DWORD *)array;
306 while (count--)
307 {
308 *dst++ = *src ? (BYTE *)*src - base : 0;
309 src++;
310 }
311}
312
313/* fixup an array of RVAs by adding the specified delta */
314static inline void fixup_rva_dwords( DWORD *ptr, int delta, unsigned int count )
315{
316 while (count--)
317 {
318 if (*ptr) *ptr += delta;
319 ptr++;
320 }
321}
322
323
324/* fixup RVAs in the import directory */
325static void fixup_imports( IMAGE_IMPORT_DESCRIPTOR *dir, BYTE *base, int delta )
326{
327 UINT_PTR *ptr;
328
329 while (dir->Name)
330 {
331 fixup_rva_dwords( &dir->u.OriginalFirstThunk, delta, 1 );
332 fixup_rva_dwords( &dir->Name, delta, 1 );
333 fixup_rva_dwords( &dir->FirstThunk, delta, 1 );
334 ptr = (UINT_PTR *)(base + (dir->u.OriginalFirstThunk ? dir->u.OriginalFirstThunk : dir->FirstThunk));
335 while (*ptr)
336 {
337 if (!(*ptr & IMAGE_ORDINAL_FLAG)) *ptr += delta;
338 ptr++;
339 }
340 dir++;
341 }
342}
343
344
345/* fixup RVAs in the export directory */
346static void fixup_exports( IMAGE_EXPORT_DIRECTORY *dir, BYTE *base, int delta )
347{
348 fixup_rva_dwords( &dir->Name, delta, 1 );
349 fixup_rva_dwords( &dir->AddressOfFunctions, delta, 1 );
350 fixup_rva_dwords( &dir->AddressOfNames, delta, 1 );
351 fixup_rva_dwords( &dir->AddressOfNameOrdinals, delta, 1 );
352 fixup_rva_dwords( (DWORD *)(base + dir->AddressOfNames), delta, dir->NumberOfNames );
353 fixup_rva_ptrs( (base + dir->AddressOfFunctions), base, dir->NumberOfFunctions );
354}
355
356
357/* fixup RVAs in the resource directory */
358static void fixup_resources( IMAGE_RESOURCE_DIRECTORY *dir, BYTE *root, int delta )
359{
360 IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
361 int i;
362
363 entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
364 for (i = 0; i < dir->NumberOfNamedEntries + dir->NumberOfIdEntries; i++, entry++)
365 {
366 void *ptr = root + entry->u2.s3.OffsetToDirectory;
367 if (entry->u2.s3.DataIsDirectory) fixup_resources( ptr, root, delta );
368 else
369 {
370 IMAGE_RESOURCE_DATA_ENTRY *data = ptr;
371 fixup_rva_dwords( &data->OffsetToData, delta, 1 );
372 }
373 }
374}
375
376
377/* map a builtin dll in memory and fixup RVAs */
378static void *map_dll( const IMAGE_NT_HEADERS *nt_descr )
379{
380#ifdef HAVE_MMAP
381 IMAGE_DATA_DIRECTORY *dir;
382 IMAGE_DOS_HEADER *dos;
383 IMAGE_NT_HEADERS *nt;
384 IMAGE_SECTION_HEADER *sec;
385 BYTE *addr;
386 DWORD code_start, data_start, data_end;
387 const size_t page_size = getpagesize();
388 const size_t page_mask = page_size - 1;
389 int delta, nb_sections = 2; /* code + data */
390 unsigned int i;
391
392 size_t size = (sizeof(IMAGE_DOS_HEADER)
393 + sizeof(IMAGE_NT_HEADERS)
394 + nb_sections * sizeof(IMAGE_SECTION_HEADER));
395
396 assert( size <= page_size );
397
398 /* module address must be aligned on 64K boundary */
399 addr = (BYTE *)((nt_descr->OptionalHeader.ImageBase + 0xffff) & ~0xffff);
400 if (wine_anon_mmap( addr, page_size, PROT_READ|PROT_WRITE, MAP_FIXED ) != addr) return NULL;
401
402 dos = (IMAGE_DOS_HEADER *)addr;
403 nt = (IMAGE_NT_HEADERS *)(dos + 1);
404 sec = (IMAGE_SECTION_HEADER *)(nt + 1);
405
406 /* Build the DOS and NT headers */
407
408 dos->e_magic = IMAGE_DOS_SIGNATURE;
409 dos->e_cblp = 0x90;
410 dos->e_cp = 3;
411 dos->e_cparhdr = (sizeof(*dos)+0xf)/0x10;
412 dos->e_minalloc = 0;
413 dos->e_maxalloc = 0xffff;
414 dos->e_ss = 0x0000;
415 dos->e_sp = 0x00b8;
416 dos->e_lfarlc = sizeof(*dos);
417 dos->e_lfanew = sizeof(*dos);
418
419 *nt = *nt_descr;
420
421 delta = (const BYTE *)nt_descr - addr;
422 code_start = page_size;
423 data_start = delta & ~page_mask;
424 data_end = (nt->OptionalHeader.SizeOfImage + delta + page_mask) & ~page_mask;
425
426 fixup_rva_ptrs( &nt->OptionalHeader.AddressOfEntryPoint, addr, 1 );
427
428 nt->FileHeader.NumberOfSections = nb_sections;
429 nt->OptionalHeader.BaseOfCode = code_start;
430#ifndef _WIN64
431 nt->OptionalHeader.BaseOfData = data_start;
432#endif
433 nt->OptionalHeader.SizeOfCode = data_start - code_start;
434 nt->OptionalHeader.SizeOfInitializedData = data_end - data_start;
435 nt->OptionalHeader.SizeOfUninitializedData = 0;
436 nt->OptionalHeader.SizeOfImage = data_end;
437 nt->OptionalHeader.ImageBase = (ULONG_PTR)addr;
438
439 /* Build the code section */
440
441 memcpy( sec->Name, ".text", sizeof(".text") );
442 sec->SizeOfRawData = data_start - code_start;
443 sec->Misc.VirtualSize = sec->SizeOfRawData;
444 sec->VirtualAddress = code_start;
445 sec->PointerToRawData = code_start;
446 sec->Characteristics = (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ);
447 sec++;
448
449 /* Build the data section */
450
451 memcpy( sec->Name, ".data", sizeof(".data") );
452 sec->SizeOfRawData = data_end - data_start;
453 sec->Misc.VirtualSize = sec->SizeOfRawData;
454 sec->VirtualAddress = data_start;
455 sec->PointerToRawData = data_start;
456 sec->Characteristics = (IMAGE_SCN_CNT_INITIALIZED_DATA |
457 IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ);
458 sec++;
459
460 for (i = 0; i < nt->OptionalHeader.NumberOfRvaAndSizes; i++)
461 fixup_rva_dwords( &nt->OptionalHeader.DataDirectory[i].VirtualAddress, delta, 1 );
462
463 /* Build the import directory */
464
465 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY];
466 if (dir->Size)
467 {
468 IMAGE_IMPORT_DESCRIPTOR *imports = (void *)(addr + dir->VirtualAddress);
469 fixup_imports( imports, addr, delta );
470 }
471
472 /* Build the resource directory */
473
474 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY];
475 if (dir->Size)
476 {
477 void *ptr = (void *)(addr + dir->VirtualAddress);
478 fixup_resources( ptr, ptr, delta );
479 }
480
481 /* Build the export directory */
482
483 dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
484 if (dir->Size)
485 {
486 IMAGE_EXPORT_DIRECTORY *exports = (void *)(addr + dir->VirtualAddress);
487 fixup_exports( exports, addr, delta );
488 }
489 return addr;
490#else /* HAVE_MMAP */
491 return NULL;
492#endif /* HAVE_MMAP */
493}
494
495
496/***********************************************************************
497 * __wine_get_main_environment
498 *
499 * Return an environment pointer to work around lack of environ variable.
500 * Only exported on Mac OS.
501 */
502char **__wine_get_main_environment(void)
503{
504#ifndef _MSC_VER
505 return environ;
506#else
507 return _environ;
508#endif
509}
510
511
512/***********************************************************************
513 * __wine_dll_register
514 *
515 * Register a built-in DLL descriptor.
516 */
517void __wine_dll_register( const IMAGE_NT_HEADERS *header, const char *filename )
518{
519 if (load_dll_callback) load_dll_callback( map_dll(header), filename );
520 else
521 {
522 if (!(header->FileHeader.Characteristics & IMAGE_FILE_DLL))
523 main_exe = header;
524 else
525 {
526 assert( nb_dlls < MAX_DLLS );
527 builtin_dlls[nb_dlls].nt = header;
528 builtin_dlls[nb_dlls].filename = filename;
529 nb_dlls++;
530 }
531 }
532}
533
534
535/***********************************************************************
536 * wine_dll_set_callback
537 *
538 * Set the callback function for dll loading, and call it
539 * for all dlls that were implicitly loaded already.
540 */
541void wine_dll_set_callback( load_dll_callback_t load )
542{
543 int i;
544 load_dll_callback = load;
545 for (i = 0; i < nb_dlls; i++)
546 {
547 const IMAGE_NT_HEADERS *nt = builtin_dlls[i].nt;
548 if (!nt) continue;
549 builtin_dlls[i].nt = NULL;
550 load_dll_callback( map_dll(nt), builtin_dlls[i].filename );
551 }
552 nb_dlls = 0;
553 if (main_exe) load_dll_callback( map_dll(main_exe), "" );
554}
555
556
557/***********************************************************************
558 * wine_dll_load
559 *
560 * Load a builtin dll.
561 */
562void *wine_dll_load( const char *filename, char *error, int errorsize, int *file_exists )
563{
564 int i;
565
566 /* callback must have been set already */
567 assert( load_dll_callback );
568
569 /* check if we have it in the list */
570 /* this can happen when initializing pre-loaded dlls in wine_dll_set_callback */
571 for (i = 0; i < nb_dlls; i++)
572 {
573 if (!builtin_dlls[i].nt) continue;
574 if (!strcmp( builtin_dlls[i].filename, filename ))
575 {
576 const IMAGE_NT_HEADERS *nt = builtin_dlls[i].nt;
577 builtin_dlls[i].nt = NULL;
578 load_dll_callback( map_dll(nt), builtin_dlls[i].filename );
579 *file_exists = 1;
580 return (void *)1;
581 }
582 }
583 return dlopen_dll( filename, error, errorsize, 0, file_exists );
584}
585
586
587/***********************************************************************
588 * wine_dll_unload
589 *
590 * Unload a builtin dll.
591 */
592void wine_dll_unload( void *handle )
593{
594 if (handle != (void *)1)
595 wine_dlclose( handle, NULL, 0 );
596}
597
598
599/***********************************************************************
600 * wine_dll_load_main_exe
601 *
602 * Try to load the .so for the main exe.
603 */
604void *wine_dll_load_main_exe( const char *name, char *error, int errorsize,
605 int test_only, int *file_exists )
606{
607 return dlopen_dll( name, error, errorsize, test_only, file_exists );
608}
609
610
611/***********************************************************************
612 * wine_dll_enum_load_path
613 *
614 * Enumerate the dll load path.
615 */
616const char *wine_dll_enum_load_path( unsigned int index )
617{
618 if (index >= nb_dll_paths) return NULL;
619 return dll_paths[index];
620}
621
622
623/***********************************************************************
624 * wine_dll_get_owner
625 *
626 * Retrieve the name of the 32-bit owner dll for a 16-bit dll.
627 * Return 0 if OK, -1 on error.
628 */
629int wine_dll_get_owner( const char *name, char *buffer, int size, int *exists )
630{
631 int ret = -1;
632 char *path;
633 struct dll_path_context context;
634
635 *exists = 0;
636
637 for (path = first_dll_path( name, 1, &context ); path; path = next_dll_path( &context ))
638 {
639 int fd = open( path, O_RDONLY );
640 if (fd != -1)
641 {
642 int res = read( fd, buffer, size - 1 );
643 while (res > 0 && (buffer[res-1] == '\n' || buffer[res-1] == '\r')) res--;
644 buffer[res] = 0;
645 close( fd );
646 *exists = 1;
647 ret = 0;
648 break;
649 }
650 }
651 free_dll_path( &context );
652 return ret;
653}
654
655
656/***********************************************************************
657 * set_max_limit
658 *
659 * Set a user limit to the maximum allowed value.
660 */
661static void set_max_limit( int limit )
662{
663#ifdef HAVE_SETRLIMIT
664 struct rlimit rlimit;
665
666 if (!getrlimit( limit, &rlimit ))
667 {
668 rlimit.rlim_cur = rlimit.rlim_max;
669 if (setrlimit( limit, &rlimit ) != 0)
670 {
671#if defined(__APPLE__) && defined(RLIMIT_NOFILE) && defined(OPEN_MAX)
672 /* On Leopard, setrlimit(RLIMIT_NOFILE, ...) fails on attempts to set
673 * rlim_cur above OPEN_MAX (even if rlim_max > OPEN_MAX). */
674 if (limit == RLIMIT_NOFILE && rlimit.rlim_cur > OPEN_MAX)
675 {
676 rlimit.rlim_cur = OPEN_MAX;
677 setrlimit( limit, &rlimit );
678 }
679#endif
680 }
681 }
682#endif
683}
684
685
686/***********************************************************************
687 * wine_init
688 *
689 * Main Wine initialisation.
690 */
691void wine_init( int argc, char *argv[], char *error, int error_size )
692{
693 struct dll_path_context context;
694 char *path;
695 void *ntdll = NULL;
696 void (*init_func)(void);
697
698 /* force a few limits that are set too low on some platforms */
699#ifdef RLIMIT_NOFILE
700 set_max_limit( RLIMIT_NOFILE );
701#endif
702#ifdef RLIMIT_AS
703 set_max_limit( RLIMIT_AS );
704#endif
705
706 wine_init_argv0_path( argv[0] );
707 build_dll_path();
708 __wine_main_argc = argc;
709 __wine_main_argv = argv;
710 __wine_main_environ = __wine_get_main_environment();
711 mmap_init();
712
713 for (path = first_dll_path( "ntdll.dll", 0, &context ); path; path = next_dll_path( &context ))
714 {
715 if ((ntdll = wine_dlopen( path, RTLD_NOW, error, error_size )))
716 {
717 /* if we didn't use the default dll dir, remove it from the search path */
718 if (default_dlldir[0] && context.index < nb_dll_paths + 2) nb_dll_paths--;
719 break;
720 }
721 }
722 free_dll_path( &context );
723
724 if (!ntdll) return;
725 if (!(init_func = wine_dlsym( ntdll, "__wine_process_init", error, error_size ))) return;
726 init_func();
727}
728
729
730/*
731 * These functions provide wrappers around dlopen() and associated
732 * functions. They work around a bug in glibc 2.1.x where calling
733 * a dl*() function after a previous dl*() function has failed
734 * without a dlerror() call between the two will cause a crash.
735 * They all take a pointer to a buffer that
736 * will receive the error description (from dlerror()). This
737 * parameter may be NULL if the error description is not required.
738 */
739
740#ifndef RTLD_FIRST
741#define RTLD_FIRST 0
742#endif
743
744/***********************************************************************
745 * wine_dlopen
746 */
747void *wine_dlopen( const char *filename, int flag, char *error, size_t errorsize )
748{
749#ifdef HAVE_DLOPEN
750 void *ret;
751 const char *s;
752
753#ifdef __APPLE__
754 /* the Mac OS loader pretends to be able to load PE files, so avoid them here */
755 unsigned char magic[2];
756 int fd = open( filename, O_RDONLY );
757 if (fd != -1)
758 {
759 if (pread( fd, magic, 2, 0 ) == 2 && magic[0] == 'M' && magic[1] == 'Z')
760 {
761 static const char msg[] = "MZ format";
762 size_t len = min( errorsize, sizeof(msg) );
763 memcpy( error, msg, len );
764 error[len - 1] = 0;
765 close( fd );
766 return NULL;
767 }
768 close( fd );
769 }
770#endif
771 dlerror(); dlerror();
772#ifdef __sun
773 if (strchr( filename, ':' ))
774 {
775 char path[PATH_MAX];
776 /* Solaris' brain damaged dlopen() treats ':' as a path separator */
777 realpath( filename, path );
778 ret = dlopen( path, flag | RTLD_FIRST );
779 }
780 else
781#endif
782 ret = dlopen( filename, flag | RTLD_FIRST );
783 s = dlerror();
784 if (error && errorsize)
785 {
786 if (s)
787 {
788 size_t len = strlen(s);
789 if (len >= errorsize) len = errorsize - 1;
790 memcpy( error, s, len );
791 error[len] = 0;
792 }
793 else error[0] = 0;
794 }
795 dlerror();
796 return ret;
797#else
798 if (error)
799 {
800 static const char msg[] = "dlopen interface not detected by configure";
801 size_t len = min( errorsize, sizeof(msg) );
802 memcpy( error, msg, len );
803 error[len - 1] = 0;
804 }
805 return NULL;
806#endif
807}
808
809/***********************************************************************
810 * wine_dlsym
811 */
812void *wine_dlsym( void *handle, const char *symbol, char *error, size_t errorsize )
813{
814#ifdef HAVE_DLOPEN
815 void *ret;
816 const char *s;
817 dlerror(); dlerror();
818 ret = dlsym( handle, symbol );
819 s = dlerror();
820 if (error && errorsize)
821 {
822 if (s)
823 {
824 size_t len = strlen(s);
825 if (len >= errorsize) len = errorsize - 1;
826 memcpy( error, s, len );
827 error[len] = 0;
828 }
829 else error[0] = 0;
830 }
831 dlerror();
832 return ret;
833#else
834 if (error)
835 {
836 static const char msg[] = "dlopen interface not detected by configure";
837 size_t len = min( errorsize, sizeof(msg) );
838 memcpy( error, msg, len );
839 error[len - 1] = 0;
840 }
841 return NULL;
842#endif
843}
844
845/***********************************************************************
846 * wine_dlclose
847 */
848int wine_dlclose( void *handle, char *error, size_t errorsize )
849{
850#ifdef HAVE_DLOPEN
851 int ret;
852 const char *s;
853 dlerror(); dlerror();
854 ret = dlclose( handle );
855 s = dlerror();
856 if (error && errorsize)
857 {
858 if (s)
859 {
860 size_t len = strlen(s);
861 if (len >= errorsize) len = errorsize - 1;
862 memcpy( error, s, len );
863 error[len] = 0;
864 }
865 else error[0] = 0;
866 }
867 dlerror();
868 return ret;
869#else
870 if (error)
871 {
872 static const char msg[] = "dlopen interface not detected by configure";
873 size_t len = min( errorsize, sizeof(msg) );
874 memcpy( error, msg, len );
875 error[len - 1] = 0;
876 }
877 return 1;
878#endif
879}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette