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
22 #include "wine/port.h"
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_MMAN_H
37 #define NONAMELESSUNION
38 #define NONAMELESSSTRUCT
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
;
51 const IMAGE_NT_HEADERS
*nt
; /* NT header */
52 const char *filename
; /* DLL file name */
53 } builtin_dlls
[MAX_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
;
67 /* build the dll load path from the WINEDLLPATH variable */
68 static void build_dll_path(void)
70 static const char * const dlldir
= DLLDIR
;
72 char *p
, *path
= getenv( "WINEDLLPATH" );
78 /* count how many path elements we need */
83 while (*p
== ':') p
++;
86 while (*p
&& *p
!= ':') p
++;
90 dll_paths
= malloc( (count
+1) * sizeof(*dll_paths
) );
98 while (*p
== ':') *p
++ = 0;
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
];
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
);
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
);
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
;
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;
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 */
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
;
168 if (*ptr
) *ptr
= (void *)((char *)*ptr
- (char *)base
);
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 */
183 if (*ptr
>= (void *)0x10000) *ptr
= (void *)((char *)*ptr
- (char *)base
);
184 else if (*ptr
) *ptr
= (void *)(0x80000000 | (unsigned int)*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
;
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
);
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
)
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
;
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
);
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
);
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
);
276 /* Build the import directory */
278 dir
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_FILE_IMPORT_DIRECTORY
];
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
];
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
];
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 );
311 #else /* HAVE_MMAP */
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
);
327 if (!(header
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
))
331 assert( nb_dlls
< MAX_DLLS
);
332 builtin_dlls
[nb_dlls
].nt
= header
;
333 builtin_dlls
[nb_dlls
].filename
= filename
;
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
)
349 load_dll_callback
= load
;
350 for (i
= 0; i
< nb_dlls
; i
++)
352 const IMAGE_NT_HEADERS
*nt
= builtin_dlls
[i
].nt
;
354 builtin_dlls
[i
].nt
= NULL
;
355 load_dll_callback( map_dll(nt
), builtin_dlls
[i
].filename
);
358 if (main_exe
) load_dll_callback( map_dll(main_exe
), "" );
362 /***********************************************************************
365 * Load a builtin dll.
367 void *wine_dll_load( const char *filename
, char *error
, int errorsize
)
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
);
387 return dlopen_dll( filename
, error
, errorsize
, 0 );
391 /***********************************************************************
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 /***********************************************************************
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();
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. */
446 if ( (uintptr_t)addr
& (pagesize
-1) )
448 if ( flags
& MAP_FIXED
)
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");
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 )
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
)
481 if ( result
!= (void *) -1 ) /* This should never happen ... */
482 munmap( result
, len
);
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 /***********************************************************************
499 * Portable wrapper for anonymous mmaps
501 void *wine_anon_mmap( void *start
, size_t size
, int prot
, int flags
)
504 static int fdzero
= -1;
511 if ((fdzero
= open( "/dev/zero", O_RDONLY
)) == -1)
513 perror( "/dev/zero: open" );
517 #endif /* MAP_ANON */
520 flags
&= ~MAP_SHARED
;
523 /* Linux EINVAL's on us if we don't pass MAP_PRIVATE to an anon mmap */
525 flags
|= MAP_PRIVATE
;
528 #if defined(__svr4__) || defined(__NetBSD__)
529 if ( try_mmap_fixed( start
, size
, prot
, flags
, fdzero
, 0 ) )
533 return mmap( start
, size
, prot
, flags
, fdzero
, 0 );
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 /***********************************************************************
553 void *wine_dlopen( const char *filename
, int flag
, char *error
, int errorsize
)
558 dlerror(); dlerror();
559 ret
= dlopen( filename
, flag
);
563 strncpy( error
, s
? s
: "", errorsize
);
564 error
[errorsize
- 1] = '\0';
571 strncpy( error
, "dlopen interface not detected by configure", errorsize
);
572 error
[errorsize
- 1] = '\0';
578 /***********************************************************************
581 void *wine_dlsym( void *handle
, const char *symbol
, char *error
, int errorsize
)
586 dlerror(); dlerror();
587 ret
= dlsym( handle
, symbol
);
591 strncpy( error
, s
? s
: "", errorsize
);
592 error
[errorsize
- 1] = '\0';
599 strncpy( error
, "dlopen interface not detected by configure", errorsize
);
600 error
[errorsize
- 1] = '\0';
606 /***********************************************************************
609 int wine_dlclose( void *handle
, char *error
, int errorsize
)
614 dlerror(); dlerror();
615 ret
= dlclose( handle
);
619 strncpy( error
, s
? s
: "", errorsize
);
620 error
[errorsize
- 1] = '\0';
627 strncpy( error
, "dlopen interface not detected by configure", errorsize
);
628 error
[errorsize
- 1] = '\0';