Moved almost all remaining process, thread, fiber and exception
[wine] / libs / wine / loader.c
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <ctype.h>
26 #include <fcntl.h>
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_MMAN_H
32 #include <sys/mman.h>
33 #endif
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37
38 #define NONAMELESSUNION
39 #define NONAMELESSSTRUCT
40 #include "windef.h"
41 #include "winbase.h"
42 #include "wine/library.h"
43
44 /* argc/argv for the Windows application */
45 int __wine_main_argc = 0;
46 char **__wine_main_argv = NULL;
47 WCHAR **__wine_main_wargv = NULL;
48
49 #define MAX_DLLS 100
50
51 static struct
52 {
53     const IMAGE_NT_HEADERS *nt;           /* NT header */
54     const char             *filename;     /* DLL file name */
55 } builtin_dlls[MAX_DLLS];
56
57 static int nb_dlls;
58
59 static const IMAGE_NT_HEADERS *main_exe;
60
61 static load_dll_callback_t load_dll_callback;
62
63 static const char **dll_paths;
64 static int nb_dll_paths;
65 static int dll_path_maxlen;
66 static int init_done;
67
68
69 /* build the dll load path from the WINEDLLPATH variable */
70 static void build_dll_path(void)
71 {
72     static const char * const dlldir = DLLDIR;
73     int len, count = 0;
74     char *p, *path = getenv( "WINEDLLPATH" );
75
76     init_done = 1;
77
78     if (path)
79     {
80         /* count how many path elements we need */
81         path = strdup(path);
82         p = path;
83         while (*p)
84         {
85             while (*p == ':') p++;
86             if (!*p) break;
87             count++;
88             while (*p && *p != ':') p++;
89         }
90     }
91
92     dll_paths = malloc( (count+1) * sizeof(*dll_paths) );
93
94     if (count)
95     {
96         p = path;
97         nb_dll_paths = 0;
98         while (*p)
99         {
100             while (*p == ':') *p++ = 0;
101             if (!*p) break;
102             dll_paths[nb_dll_paths] = p;
103             while (*p && *p != ':') p++;
104             if (p - dll_paths[nb_dll_paths] > dll_path_maxlen)
105                 dll_path_maxlen = p - dll_paths[nb_dll_paths];
106             nb_dll_paths++;
107         }
108     }
109
110     /* append default dll dir (if not empty) to path */
111     if ((len = strlen(dlldir)))
112     {
113         if (len > dll_path_maxlen) dll_path_maxlen = len;
114         dll_paths[nb_dll_paths++] = dlldir;
115     }
116 }
117
118 /* check if a given file can be opened */
119 inline static int file_exists( const char *name )
120 {
121     int fd = open( name, O_RDONLY );
122     if (fd != -1) close( fd );
123     return (fd != -1);
124 }
125
126 /* open a library for a given dll, searching in the dll path
127  * 'name' must be the Windows dll name (e.g. "kernel32.dll") */
128 static void *dlopen_dll( const char *name, char *error, int errorsize,
129                          int test_only, int *exists )
130 {
131     int i, namelen = strlen(name);
132     char *buffer, *p;
133     void *ret = NULL;
134
135     if (!init_done) build_dll_path();
136
137     buffer = malloc( dll_path_maxlen + namelen + 5 );
138
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" );
144     *exists = 0;
145
146     for (i = 0; i < nb_dll_paths; i++)
147     {
148         int len = strlen(dll_paths[i]);
149         p = buffer + dll_path_maxlen - len;
150         memcpy( p, dll_paths[i], len );
151         if (!test_only && (ret = wine_dlopen( p, RTLD_NOW, error, errorsize ))) break;
152         if ((*exists = file_exists( p ))) break; /* exists but cannot be loaded, return the error */
153     }
154     free( buffer );
155     return ret;
156 }
157
158
159 /* adjust an array of pointers to make them into RVAs */
160 static inline void fixup_rva_ptrs( void *array, void *base, int count )
161 {
162     void **ptr = (void **)array;
163     while (count--)
164     {
165         if (*ptr) *ptr = (void *)((char *)*ptr - (char *)base);
166         ptr++;
167     }
168 }
169
170
171 /* fixup RVAs in the import directory */
172 static void fixup_imports( IMAGE_IMPORT_DESCRIPTOR *dir, DWORD size, void *base )
173 {
174     int count = size / sizeof(void *);
175     void **ptr = (void **)dir;
176
177     /* everything is either a pointer or a ordinal value below 0x10000 */
178     while (count--)
179     {
180         if (*ptr >= (void *)0x10000) *ptr = (void *)((char *)*ptr - (char *)base);
181         else if (*ptr) *ptr = (void *)(0x80000000 | (unsigned int)*ptr);
182         ptr++;
183     }
184 }
185
186
187 /* fixup RVAs in the resource directory */
188 static void fixup_resources( IMAGE_RESOURCE_DIRECTORY *dir, char *root, void *base )
189 {
190     IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
191     int i;
192
193     entry = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
194     for (i = 0; i < dir->NumberOfNamedEntries + dir->NumberOfIdEntries; i++, entry++)
195     {
196         void *ptr = root + entry->u2.s3.OffsetToDirectory;
197         if (entry->u2.s3.DataIsDirectory) fixup_resources( ptr, root, base );
198         else
199         {
200             IMAGE_RESOURCE_DATA_ENTRY *data = ptr;
201             fixup_rva_ptrs( &data->OffsetToData, base, 1 );
202         }
203     }
204 }
205
206
207 /* map a builtin dll in memory and fixup RVAs */
208 static void *map_dll( const IMAGE_NT_HEADERS *nt_descr )
209 {
210 #ifdef HAVE_MMAP
211     IMAGE_DATA_DIRECTORY *dir;
212     IMAGE_DOS_HEADER *dos;
213     IMAGE_NT_HEADERS *nt;
214     IMAGE_SECTION_HEADER *sec;
215     BYTE *addr, *code_start, *data_start;
216     size_t page_size = getpagesize();
217     int nb_sections = 2;  /* code + data */
218
219     size_t size = (sizeof(IMAGE_DOS_HEADER)
220                    + sizeof(IMAGE_NT_HEADERS)
221                    + nb_sections * sizeof(IMAGE_SECTION_HEADER));
222
223     assert( size <= page_size );
224
225     /* module address must be aligned on 64K boundary */
226     addr = (BYTE *)((nt_descr->OptionalHeader.ImageBase + 0xffff) & ~0xffff);
227     if (wine_anon_mmap( addr, page_size, PROT_READ|PROT_WRITE, MAP_FIXED ) != addr) return NULL;
228
229     dos    = (IMAGE_DOS_HEADER *)addr;
230     nt     = (IMAGE_NT_HEADERS *)(dos + 1);
231     sec    = (IMAGE_SECTION_HEADER *)(nt + 1);
232     code_start = addr + page_size;
233
234     /* HACK! */
235     data_start = code_start + page_size;
236
237     /* Build the DOS and NT headers */
238
239     dos->e_magic  = IMAGE_DOS_SIGNATURE;
240     dos->e_lfanew = sizeof(*dos);
241
242     *nt = *nt_descr;
243
244     nt->FileHeader.NumberOfSections                = nb_sections;
245     nt->OptionalHeader.SizeOfCode                  = data_start - code_start;
246     nt->OptionalHeader.SizeOfInitializedData       = 0;
247     nt->OptionalHeader.SizeOfUninitializedData     = 0;
248     nt->OptionalHeader.ImageBase                   = (DWORD)addr;
249
250     fixup_rva_ptrs( &nt->OptionalHeader.AddressOfEntryPoint, addr, 1 );
251
252     /* Build the code section */
253
254     strcpy( sec->Name, ".text" );
255     sec->SizeOfRawData = data_start - code_start;
256     sec->Misc.VirtualSize = sec->SizeOfRawData;
257     sec->VirtualAddress   = code_start - addr;
258     sec->PointerToRawData = code_start - addr;
259     sec->Characteristics  = (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ);
260     sec++;
261
262     /* Build the data section */
263
264     strcpy( sec->Name, ".data" );
265     sec->SizeOfRawData = 0;
266     sec->Misc.VirtualSize = sec->SizeOfRawData;
267     sec->VirtualAddress   = data_start - addr;
268     sec->PointerToRawData = data_start - addr;
269     sec->Characteristics  = (IMAGE_SCN_CNT_INITIALIZED_DATA |
270                              IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ);
271     sec++;
272
273     /* Build the import directory */
274
275     dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_IMPORT_DIRECTORY];
276     if (dir->Size)
277     {
278         IMAGE_IMPORT_DESCRIPTOR *imports = (void *)dir->VirtualAddress;
279         fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
280         fixup_imports( imports, dir->Size, addr );
281     }
282
283     /* Build the resource directory */
284
285     dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_RESOURCE_DIRECTORY];
286     if (dir->Size)
287     {
288         void *ptr = (void *)dir->VirtualAddress;
289         fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
290         fixup_resources( ptr, ptr, addr );
291     }
292
293     /* Build the export directory */
294
295     dir = &nt->OptionalHeader.DataDirectory[IMAGE_FILE_EXPORT_DIRECTORY];
296     if (dir->Size)
297     {
298         IMAGE_EXPORT_DIRECTORY *exports = (void *)dir->VirtualAddress;
299         fixup_rva_ptrs( &dir->VirtualAddress, addr, 1 );
300         fixup_rva_ptrs( (void *)exports->AddressOfFunctions, addr, exports->NumberOfFunctions );
301         fixup_rva_ptrs( (void *)exports->AddressOfNames, addr, exports->NumberOfNames );
302         fixup_rva_ptrs( &exports->Name, addr, 1 );
303         fixup_rva_ptrs( &exports->AddressOfFunctions, addr, 1 );
304         fixup_rva_ptrs( &exports->AddressOfNames, addr, 1 );
305         fixup_rva_ptrs( &exports->AddressOfNameOrdinals, addr, 1 );
306     }
307     return addr;
308 #else  /* HAVE_MMAP */
309     return NULL;
310 #endif  /* HAVE_MMAP */
311 }
312
313
314 /***********************************************************************
315  *           __wine_dll_register
316  *
317  * Register a built-in DLL descriptor.
318  */
319 void __wine_dll_register( const IMAGE_NT_HEADERS *header, const char *filename )
320 {
321     if (load_dll_callback) load_dll_callback( map_dll(header), filename );
322     else
323     {
324         if (!(header->FileHeader.Characteristics & IMAGE_FILE_DLL))
325             main_exe = header;
326         else
327         {
328             assert( nb_dlls < MAX_DLLS );
329             builtin_dlls[nb_dlls].nt = header;
330             builtin_dlls[nb_dlls].filename = filename;
331             nb_dlls++;
332         }
333     }
334 }
335
336
337 /***********************************************************************
338  *           wine_dll_set_callback
339  *
340  * Set the callback function for dll loading, and call it
341  * for all dlls that were implicitly loaded already.
342  */
343 void wine_dll_set_callback( load_dll_callback_t load )
344 {
345     int i;
346     load_dll_callback = load;
347     for (i = 0; i < nb_dlls; i++)
348     {
349         const IMAGE_NT_HEADERS *nt = builtin_dlls[i].nt;
350         if (!nt) continue;
351         builtin_dlls[i].nt = NULL;
352         load_dll_callback( map_dll(nt), builtin_dlls[i].filename );
353     }
354     nb_dlls = 0;
355     if (main_exe) load_dll_callback( map_dll(main_exe), "" );
356 }
357
358
359 /***********************************************************************
360  *           wine_dll_load
361  *
362  * Load a builtin dll.
363  */
364 void *wine_dll_load( const char *filename, char *error, int errorsize, int *file_exists )
365 {
366     int i;
367
368     /* callback must have been set already */
369     assert( load_dll_callback );
370
371     /* check if we have it in the list */
372     /* this can happen when initializing pre-loaded dlls in wine_dll_set_callback */
373     for (i = 0; i < nb_dlls; i++)
374     {
375         if (!builtin_dlls[i].nt) continue;
376         if (!strcmp( builtin_dlls[i].filename, filename ))
377         {
378             const IMAGE_NT_HEADERS *nt = builtin_dlls[i].nt;
379             builtin_dlls[i].nt = NULL;
380             load_dll_callback( map_dll(nt), builtin_dlls[i].filename );
381             *file_exists = 1;
382             return (void *)1;
383         }
384     }
385     return dlopen_dll( filename, error, errorsize, 0, file_exists );
386 }
387
388
389 /***********************************************************************
390  *           wine_dll_unload
391  *
392  * Unload a builtin dll.
393  */
394 void wine_dll_unload( void *handle )
395 {
396     if (handle != (void *)1)
397         wine_dlclose( handle, NULL, 0 );
398 }
399
400
401 /***********************************************************************
402  *           wine_dll_load_main_exe
403  *
404  * Try to load the .so for the main exe.
405  */
406 void *wine_dll_load_main_exe( const char *name, char *error, int errorsize,
407                               int test_only, int *file_exists )
408 {
409     return dlopen_dll( name, error, errorsize, test_only, file_exists );
410 }
411
412
413 /***********************************************************************
414  *           wine_init
415  *
416  * Main Wine initialisation.
417  */
418 void wine_init( int argc, char *argv[], char *error, int error_size )
419 {
420     int file_exists;
421     void *kernel;
422     void (*init_func)(int, char **);
423
424     if (!dlopen_dll( "ntdll.dll", error, error_size, 0, &file_exists )) return;
425     /* make sure kernel32 is loaded too */
426     if (!(kernel = dlopen_dll( "kernel32.dll", error, error_size, 0, &file_exists ))) return;
427     if (!(init_func = wine_dlsym( kernel, "__wine_process_init", error, error_size ))) return;
428     init_func( argc, argv );
429 }
430
431
432 /*
433  * These functions provide wrappers around dlopen() and associated
434  * functions.  They work around a bug in glibc 2.1.x where calling
435  * a dl*() function after a previous dl*() function has failed
436  * without a dlerror() call between the two will cause a crash.
437  * They all take a pointer to a buffer that
438  * will receive the error description (from dlerror()).  This
439  * parameter may be NULL if the error description is not required.
440  */
441
442 /***********************************************************************
443  *              wine_dlopen
444  */
445 void *wine_dlopen( const char *filename, int flag, char *error, int errorsize )
446 {
447 #ifdef HAVE_DLOPEN
448     void *ret;
449     const char *s;
450     dlerror(); dlerror();
451     ret = dlopen( filename, flag );
452     s = dlerror();
453     if (error)
454     {
455         strncpy( error, s ? s : "", errorsize );
456         error[errorsize - 1] = '\0';
457     }
458     dlerror();
459     return ret;
460 #else
461     if (error)
462     {
463         strncpy( error, "dlopen interface not detected by configure", errorsize );
464         error[errorsize - 1] = '\0';
465     }
466     return NULL;
467 #endif
468 }
469
470 /***********************************************************************
471  *              wine_dlsym
472  */
473 void *wine_dlsym( void *handle, const char *symbol, char *error, int errorsize )
474 {
475 #ifdef HAVE_DLOPEN
476     void *ret;
477     const char *s;
478     dlerror(); dlerror();
479     ret = dlsym( handle, symbol );
480     s = dlerror();
481     if (error)
482     {
483         strncpy( error, s ? s : "", errorsize );
484         error[errorsize - 1] = '\0';
485     }
486     dlerror();
487     return ret;
488 #else
489     if (error)
490     {
491         strncpy( error, "dlopen interface not detected by configure", errorsize );
492         error[errorsize - 1] = '\0';
493     }
494     return NULL;
495 #endif
496 }
497
498 /***********************************************************************
499  *              wine_dlclose
500  */
501 int wine_dlclose( void *handle, char *error, int errorsize )
502 {
503 #ifdef HAVE_DLOPEN
504     int ret;
505     const char *s;
506     dlerror(); dlerror();
507     ret = dlclose( handle );
508     s = dlerror();
509     if (error)
510     {
511         strncpy( error, s ? s : "", errorsize );
512         error[errorsize - 1] = '\0';
513     }
514     dlerror();
515     return ret;
516 #else
517     if (error)
518     {
519         strncpy( error, "dlopen interface not detected by configure", errorsize );
520         error[errorsize - 1] = '\0';
521     }
522     return 1;
523 #endif
524 }