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
|
---|
62 | extern char **environ;
|
---|
63 | # endif
|
---|
64 | #endif
|
---|
65 |
|
---|
66 | /* argc/argv for the Windows application */
|
---|
67 | int __wine_main_argc = 0;
|
---|
68 | char **__wine_main_argv = NULL;
|
---|
69 | WCHAR **__wine_main_wargv = NULL;
|
---|
70 | char **__wine_main_environ = NULL;
|
---|
71 |
|
---|
72 | struct 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 |
|
---|
83 | static struct
|
---|
84 | {
|
---|
85 | const IMAGE_NT_HEADERS *nt; /* NT header */
|
---|
86 | const char *filename; /* DLL file name */
|
---|
87 | } builtin_dlls[MAX_DLLS];
|
---|
88 |
|
---|
89 | static int nb_dlls;
|
---|
90 |
|
---|
91 | static const IMAGE_NT_HEADERS *main_exe;
|
---|
92 |
|
---|
93 | static load_dll_callback_t load_dll_callback;
|
---|
94 |
|
---|
95 | static const char *build_dir;
|
---|
96 | static const char *default_dlldir;
|
---|
97 | static const char **dll_paths;
|
---|
98 | static unsigned int nb_dll_paths;
|
---|
99 | static int dll_path_maxlen;
|
---|
100 |
|
---|
101 | extern void mmap_init(void);
|
---|
102 | extern const char *get_dlldir( const char **default_dlldir );
|
---|
103 |
|
---|
104 | /* build the dll load path from the WINEDLLPATH variable */
|
---|
105 | static 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 */
|
---|
163 | static 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 */
|
---|
199 | static 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 |
|
---|
211 | static 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 */
|
---|
217 | static 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 */
|
---|
253 | static 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 */
|
---|
275 | static 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") */
|
---|
283 | static 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 */
|
---|
302 | static 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 */
|
---|
314 | static 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 */
|
---|
325 | static 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 */
|
---|
346 | static 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 */
|
---|
358 | static 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 */
|
---|
378 | static 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 | */
|
---|
502 | char **__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 | */
|
---|
517 | void __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 | */
|
---|
541 | void 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 | */
|
---|
562 | void *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 | */
|
---|
592 | void 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 | */
|
---|
604 | void *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 | */
|
---|
616 | const 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 | */
|
---|
629 | int 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 | */
|
---|
661 | static 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 | */
|
---|
691 | void 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 | */
|
---|
747 | void *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 | */
|
---|
812 | void *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 | */
|
---|
848 | int 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 | }
|
---|