2 * Win32 builtin dlls support
4 * Copyright 2000 Alexandre Julliard
13 #include <sys/types.h>
15 #ifdef HAVE_SYS_MMAN_H
23 #include "wine/library.h"
24 #include "wine/port.h"
30 const IMAGE_NT_HEADERS
*nt
; /* NT header */
31 const char *filename
; /* DLL file name */
32 } builtin_dlls
[MAX_DLLS
];
36 static const IMAGE_NT_HEADERS
*main_exe
;
38 static load_dll_callback_t load_dll_callback
;
40 static char **dll_paths
;
41 static int nb_dll_paths
;
42 static int dll_path_maxlen
;
46 /* build the dll load path from the WINEDLLPATH variable */
47 static void build_dll_path(void)
50 char *p
, *path
= getenv( "WINEDLLPATH" );
58 while (*p
== ':') p
++;
61 while (*p
&& *p
!= ':') p
++;
64 dll_paths
= malloc( count
* sizeof(*dll_paths
) );
69 while (*p
== ':') *p
++ = 0;
71 dll_paths
[nb_dll_paths
] = p
;
72 while (*p
&& *p
!= ':') p
++;
73 if (p
- dll_paths
[nb_dll_paths
] > dll_path_maxlen
)
74 dll_path_maxlen
= p
- dll_paths
[nb_dll_paths
];
80 /* open a library for a given dll, searching in the dll path
81 * 'name' must be the Windows dll name (e.g. "kernel32.dll") */
82 static void *dlopen_dll( const char *name
)
85 int i
, namelen
= strlen(name
);
89 if (!init_done
) build_dll_path();
91 /* check for .dll or .exe extension to remove */
92 if ((p
= strrchr( name
, '.' )))
94 if (!strcasecmp( p
, ".dll" ) || !strcasecmp( p
, ".exe" )) namelen
-= 4;
97 buffer
= malloc( dll_path_maxlen
+ namelen
+ 8 );
99 /* store the name at the end of the buffer, prefixed by /lib and followed by .so */
100 p
= buffer
+ dll_path_maxlen
;
101 memcpy( p
, "/lib", 4 );
102 for (i
= 0, p
+= 4; i
< namelen
; i
++, p
++) *p
= tolower(name
[i
]);
103 memcpy( p
, ".so", 4 );
105 for (i
= 0; i
< nb_dll_paths
; i
++)
107 int len
= strlen(dll_paths
[i
]);
108 char *p
= buffer
+ dll_path_maxlen
- len
;
109 memcpy( p
, dll_paths
[i
], len
);
110 if ((ret
= dlopen( p
, RTLD_NOW
))) break;
113 /* now try the default dlopen search path */
114 if (!ret
) ret
= dlopen( buffer
+ dll_path_maxlen
+ 1, RTLD_NOW
);
123 /* adjust an array of pointers to make them into RVAs */
124 static inline void fixup_rva_ptrs( void *array
, void *base
, int count
)
126 void **ptr
= (void **)array
;
129 if (*ptr
) *ptr
= (void *)((char *)*ptr
- (char *)base
);
135 /* fixup RVAs in the resource directory */
136 static void fixup_resources( IMAGE_RESOURCE_DIRECTORY
*dir
, char *root
, void *base
)
138 IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
141 entry
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
142 for (i
= 0; i
< dir
->NumberOfNamedEntries
+ dir
->NumberOfIdEntries
; i
++, entry
++)
144 void *ptr
= root
+ entry
->u2
.s
.OffsetToDirectory
;
145 if (entry
->u2
.s
.DataIsDirectory
) fixup_resources( ptr
, root
, base
);
148 IMAGE_RESOURCE_DATA_ENTRY
*data
= ptr
;
149 fixup_rva_ptrs( &data
->OffsetToData
, base
, 1 );
155 /* map a builtin dll in memory and fixup RVAs */
156 static void *map_dll( const IMAGE_NT_HEADERS
*nt_descr
)
158 IMAGE_DATA_DIRECTORY
*dir
;
159 IMAGE_DOS_HEADER
*dos
;
160 IMAGE_NT_HEADERS
*nt
;
161 IMAGE_SECTION_HEADER
*sec
;
162 BYTE
*addr
, *code_start
, *data_start
;
163 size_t page_size
= getpagesize();
164 int nb_sections
= 2; /* code + data */
166 size_t size
= (sizeof(IMAGE_DOS_HEADER
)
167 + sizeof(IMAGE_NT_HEADERS
)
168 + nb_sections
* sizeof(IMAGE_SECTION_HEADER
));
170 assert( size
<= page_size
);
172 if (nt_descr
->OptionalHeader
.ImageBase
)
174 addr
= wine_anon_mmap( (void *)nt_descr
->OptionalHeader
.ImageBase
,
175 page_size
, PROT_READ
|PROT_WRITE
, MAP_FIXED
);
176 if (addr
!= (BYTE
*)nt_descr
->OptionalHeader
.ImageBase
) return NULL
;
180 /* this will leak memory; but it should never happen */
181 addr
= wine_anon_mmap( NULL
, page_size
, PROT_READ
|PROT_WRITE
, 0 );
182 if (addr
== (BYTE
*)-1) return NULL
;
185 dos
= (IMAGE_DOS_HEADER
*)addr
;
186 nt
= (IMAGE_NT_HEADERS
*)(dos
+ 1);
187 sec
= (IMAGE_SECTION_HEADER
*)(nt
+ 1);
188 code_start
= addr
+ page_size
;
191 data_start
= code_start
+ page_size
;
193 /* Build the DOS and NT headers */
195 dos
->e_magic
= IMAGE_DOS_SIGNATURE
;
196 dos
->e_lfanew
= sizeof(*dos
);
200 nt
->FileHeader
.NumberOfSections
= nb_sections
;
201 nt
->OptionalHeader
.SizeOfCode
= data_start
- code_start
;
202 nt
->OptionalHeader
.SizeOfInitializedData
= 0;
203 nt
->OptionalHeader
.SizeOfUninitializedData
= 0;
204 nt
->OptionalHeader
.ImageBase
= (DWORD
)addr
;
206 fixup_rva_ptrs( &nt
->OptionalHeader
.AddressOfEntryPoint
, addr
, 1 );
208 /* Build the code section */
210 strcpy( sec
->Name
, ".text" );
211 sec
->SizeOfRawData
= data_start
- code_start
;
212 sec
->Misc
.VirtualSize
= sec
->SizeOfRawData
;
213 sec
->VirtualAddress
= code_start
- addr
;
214 sec
->PointerToRawData
= code_start
- addr
;
215 sec
->Characteristics
= (IMAGE_SCN_CNT_CODE
| IMAGE_SCN_MEM_EXECUTE
| IMAGE_SCN_MEM_READ
);
218 /* Build the data section */
220 strcpy( sec
->Name
, ".data" );
221 sec
->SizeOfRawData
= 0;
222 sec
->Misc
.VirtualSize
= sec
->SizeOfRawData
;
223 sec
->VirtualAddress
= data_start
- addr
;
224 sec
->PointerToRawData
= data_start
- addr
;
225 sec
->Characteristics
= (IMAGE_SCN_CNT_INITIALIZED_DATA
|
226 IMAGE_SCN_MEM_WRITE
| IMAGE_SCN_MEM_READ
);
229 /* Build the import directory */
231 dir
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_FILE_IMPORT_DIRECTORY
];
234 IMAGE_IMPORT_DESCRIPTOR
*imports
= (void *)dir
->VirtualAddress
;
235 fixup_rva_ptrs( &dir
->VirtualAddress
, addr
, 1 );
236 /* we can fixup everything at once since we only have pointers and 0 values */
237 fixup_rva_ptrs( imports
, addr
, dir
->Size
/ sizeof(void*) );
240 /* Build the resource directory */
242 dir
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_FILE_RESOURCE_DIRECTORY
];
245 void *ptr
= (void *)dir
->VirtualAddress
;
246 fixup_rva_ptrs( &dir
->VirtualAddress
, addr
, 1 );
247 fixup_resources( ptr
, ptr
, addr
);
250 /* Build the export directory */
252 dir
= &nt
->OptionalHeader
.DataDirectory
[IMAGE_FILE_EXPORT_DIRECTORY
];
255 IMAGE_EXPORT_DIRECTORY
*exports
= (void *)dir
->VirtualAddress
;
256 fixup_rva_ptrs( &dir
->VirtualAddress
, addr
, 1 );
257 fixup_rva_ptrs( (void *)exports
->AddressOfFunctions
, addr
, exports
->NumberOfFunctions
);
258 fixup_rva_ptrs( (void *)exports
->AddressOfNames
, addr
, exports
->NumberOfNames
);
259 fixup_rva_ptrs( &exports
->Name
, addr
, 1 );
260 fixup_rva_ptrs( &exports
->AddressOfFunctions
, addr
, 1 );
261 fixup_rva_ptrs( &exports
->AddressOfNames
, addr
, 1 );
262 fixup_rva_ptrs( &exports
->AddressOfNameOrdinals
, addr
, 1 );
268 /***********************************************************************
269 * __wine_dll_register
271 * Register a built-in DLL descriptor.
273 void __wine_dll_register( const IMAGE_NT_HEADERS
*header
, const char *filename
)
275 if (load_dll_callback
) load_dll_callback( map_dll(header
), filename
);
278 if (!(header
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
))
282 assert( nb_dlls
< MAX_DLLS
);
283 builtin_dlls
[nb_dlls
].nt
= header
;
284 builtin_dlls
[nb_dlls
].filename
= filename
;
291 /***********************************************************************
292 * wine_dll_set_callback
294 * Set the callback function for dll loading, and call it
295 * for all dlls that were implicitly loaded already.
297 void wine_dll_set_callback( load_dll_callback_t load
)
300 load_dll_callback
= load
;
301 for (i
= 0; i
< nb_dlls
; i
++)
303 const IMAGE_NT_HEADERS
*nt
= builtin_dlls
[i
].nt
;
305 builtin_dlls
[i
].nt
= NULL
;
306 load_dll_callback( map_dll(nt
), builtin_dlls
[i
].filename
);
309 if (main_exe
) load_dll_callback( map_dll(main_exe
), "" );
313 /***********************************************************************
316 * Load a builtin dll.
318 void *wine_dll_load( const char *filename
)
322 /* callback must have been set already */
323 assert( load_dll_callback
);
325 /* check if we have it in the list */
326 /* this can happen when initializing pre-loaded dlls in wine_dll_set_callback */
327 for (i
= 0; i
< nb_dlls
; i
++)
329 if (!builtin_dlls
[i
].nt
) continue;
330 if (!strcasecmp( builtin_dlls
[i
].filename
, filename
))
332 const IMAGE_NT_HEADERS
*nt
= builtin_dlls
[i
].nt
;
333 builtin_dlls
[i
].nt
= NULL
;
334 load_dll_callback( map_dll(nt
), builtin_dlls
[i
].filename
);
338 return dlopen_dll( filename
);
342 /***********************************************************************
345 * Unload a builtin dll.
347 void wine_dll_unload( void *handle
)
350 if (handle
!= (void *)1) dlclose( handle
);