]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/dll_init.cc
* Merge in cygwin-64bit-branch.
[newlib-cygwin.git] / winsup / cygwin / dll_init.cc
CommitLineData
1fd5e000
CF
1/* dll_init.cc
2
bc837d22 3 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
61522196 4 2009, 2010, 2011, 2012, 2013 Red Hat, Inc.
1fd5e000
CF
5
6This software is a copyrighted work licensed under the terms of the
7Cygwin license. Please consult the file "CYGWIN_LICENSE" for
8details. */
9
1fd5e000 10#include "winsup.h"
9e2baf8d 11#include "cygerrno.h"
f0338f54 12#include "perprocess.h"
71c17c54 13#include "sync.h"
f0338f54
CF
14#include "dll_init.h"
15#include "environ.h"
1ff9f4b9 16#include "security.h"
47063f00 17#include "path.h"
7ac61736 18#include "fhandler.h"
1ff9f4b9
CF
19#include "dtable.h"
20#include "cygheap.h"
6b7cd251 21#include "pinfo.h"
44d2fc0a 22#include "child_info.h"
9aca6a48 23#include "cygtls.h"
98a97ac6 24#include "exception.h"
69d704be 25#include <wchar.h>
d5c4cd3f 26#include <sys/reent.h>
73bcd49b 27#include <assert.h>
1fd5e000
CF
28
29extern void __stdcall check_sanity_and_sync (per_process *);
30
29649132
CF
31#define fabort fork_info->abort
32
71f53a2f 33dll_list dlls;
1fd5e000 34
71c17c54
CF
35muto dll_list::protect;
36
dda06573 37static bool dll_global_dtors_recorded;
1fd5e000 38
2eb392bd 39/* Run destructors for all DLLs on exit. */
dda06573 40void
f0227ea3 41dll_global_dtors ()
1fd5e000 42{
3521d504
CF
43 /* Don't attempt to call destructors if we're still in fork processing
44 since that likely means fork is failing and everything will not have been
45 set up. */
46 if (in_forkee)
47 return;
dda06573
CF
48 int recorded = dll_global_dtors_recorded;
49 dll_global_dtors_recorded = false;
53364a1f 50 if (recorded && dlls.start.next)
bee18f45 51 for (dll *d = dlls.end; d != &dlls.start; d = d->prev)
6282fe16 52 d->run_dtors ();
1fd5e000
CF
53}
54
2eb392bd
CF
55/* Run all constructors associated with a dll */
56void
57per_module::run_ctors ()
1fd5e000 58{
2eb392bd 59 void (**pfunc)() = ctors;
1fd5e000
CF
60
61 /* Run ctors backwards, so skip the first entry and find how many
62 there are, then run them. */
63
64 if (pfunc)
65 {
66 int i;
67 for (i = 1; pfunc[i]; i++);
68
f7632549 69 for (int j = i - 1; j > 0; j--)
1fd5e000
CF
70 (pfunc[j]) ();
71 }
72}
73
2eb392bd
CF
74/* Run all destructors associated with a dll */
75void
76per_module::run_dtors ()
1fd5e000 77{
2eb392bd 78 void (**pfunc)() = dtors;
e7fd0883
CF
79 while (*++pfunc)
80 (*pfunc) ();
1fd5e000
CF
81}
82
2eb392bd
CF
83/* Initialize an individual DLL */
84int
85dll::init ()
1fd5e000 86{
2eb392bd 87 int ret = 1;
1fd5e000 88
61522196 89#ifndef __x86_64__
27f564e9 90 /* This should be a no-op. Why didn't we just import this variable? */
f3e3e0e7
CF
91 if (!p.envptr)
92 p.envptr = &__cygwin_environ;
8d777a13 93 else if (*(p.envptr) != __cygwin_environ)
f3e3e0e7 94 *(p.envptr) = __cygwin_environ;
61522196 95#endif
1fd5e000 96
2eb392bd
CF
97 /* Don't run constructors or the "main" if we've forked. */
98 if (!in_forkee)
1fd5e000
CF
99 {
100 /* global contructors */
2eb392bd 101 p.run_ctors ();
1fd5e000
CF
102
103 /* entry point of dll (use main of per_process with null args...) */
2eb392bd 104 if (p.main)
27f564e9 105 ret = p.main (0, 0, 0);
1fd5e000
CF
106 }
107
108 return ret;
109}
110
50124fc0
CV
111/* Look for a dll based on the full path.
112
113 CV, 2012-03-04: Per MSDN, If a DLL with the same module name is already
114 loaded in memory, the system uses the loaded DLL, no matter which directory
115 it is in. The system does not search for the DLL. See
116 http://msdn.microsoft.com/en-us/library/ms682586%28v=vs.85%29.aspx
117
118 On 2012-02-08 I interpreted "module name" as "basename". So the assumption
119 was that the Windows Loader does not load another DLL with the same basename,
120 if one such DLL is already loaded. Consequentially I changed the code so
121 that DLLs are only compared by basename.
122
123 This assumption was obviously wrong, as the perl dynaloader proves. It
124 loads multiple DLLs with the same basename into memory, just from different
125 locations. This mechanism is broken when only comparing basenames in the
126 below code.
127
128 However, the original problem reported on 2012-02-07 was a result of
129 a subtil difference between the paths returned by different calls to
130 GetModuleFileNameW: Sometimes the path is a plain DOS path, sometimes
131 it's preceeded by the long pathname prefix "\\?\".
132
133 So I reverted the original change from 2012-02-08 and only applied the
134 following fix: Check if the path is preceeded by a long pathname prefix,
135 and, if so, drop it forthwith so that subsequent full path comparisons
75effa37 136 work as expected.
46f5dd59 137
75effa37
CV
138 At least that was the original idea. In fact there are two case, linked
139 and runtime loaded DLLs, which have to be distinguished:
46f5dd59 140
75effa37
CV
141 - Linked DLLs are loaded by only specifying the basename of the DLL and
142 searching it using the system DLL search order as given in the
143 aforementioned MSDN URL.
144
145 - Runtime loaded DLLs are specified with the full path since that's how
146 dlopen works.
147
148 In effect, we have to be careful not to mix linked and loaded DLLs.
149 For more info how this gets accomplished, see the comments at the start
150 of dll_list::alloc, as well as the comment preceeding the definition of
151 the in_load_after_fork bool later in the file. */
2eb392bd 152dll *
50124fc0
CV
153dll_list::operator[] (const PWCHAR name)
154{
155 dll *d = &start;
156 while ((d = d->next) != NULL)
157 if (!wcscasecmp (name, d->name))
158 return d;
159
160 return NULL;
161}
162
163/* Look for a dll based on the basename. */
164dll *
165dll_list::find_by_modname (const PWCHAR modname)
1fd5e000 166{
2eb392bd
CF
167 dll *d = &start;
168 while ((d = d->next) != NULL)
9eba4de2 169 if (!wcscasecmp (modname, d->modname))
2eb392bd 170 return d;
1fd5e000 171
2eb392bd 172 return NULL;
1fd5e000
CF
173}
174
c43c5c16 175#define RETRIES 1000
2eb392bd 176
71f53a2f 177/* Allocate space for a dll struct. */
2eb392bd
CF
178dll *
179dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
1fd5e000 180{
50124fc0
CV
181 WCHAR buf[NT_MAX_PATH];
182 GetModuleFileNameW (h, buf, sizeof (buf));
183 PWCHAR name = buf;
184 if (!wcsncmp (name, L"\\\\?\\", 4))
26e60345
CV
185 {
186 name += 4;
187 if (!wcsncmp (name, L"UNC\\", 4))
188 {
189 name += 2;
190 *name = L'\\';
191 }
192 }
8f4ea5f0 193 DWORD namelen = wcslen (name);
f5b0d9d4 194 PWCHAR modname = wcsrchr (name, L'\\') + 1;
1fd5e000 195
71c17c54 196 guard (true);
f5b0d9d4
CV
197 /* Already loaded? For linked DLLs, only compare the basenames. Linked
198 DLLs are loaded using just the basename and the default DLL search path.
199 The Windows loader picks up the first one it finds. */
200 dll *d = (type == DLL_LINK) ? dlls.find_by_modname (modname) : dlls[name];
2eb392bd 201 if (d)
1fd5e000 202 {
71f53a2f
CF
203 if (!in_forkee)
204 d->count++; /* Yes. Bump the usage count. */
8f4ea5f0
CV
205 else if (d->handle != h)
206 fabort ("%W: Loaded to different address: parent(%p) != child(%p)",
50124fc0 207 name, d->handle, h);
f5b0d9d4
CV
208 /* If this DLL has been linked against, and the full path differs, try
209 to sanity check if this is the same DLL, just in another path. */
210 else if (type == DLL_LINK && wcscasecmp (name, d->name)
211 && (d->p.data_start != p->data_start
212 || d->p.data_start != p->data_start
213 || d->p.bss_start != p->bss_start
214 || d->p.bss_end != p->bss_end
215 || d->p.ctors != p->ctors
216 || d->p.dtors != p->dtors))
217 fabort ("\nLoaded different DLL with same basename in forked child,\n"
218 "parent loaded: %W\n"
219 " child loaded: %W\n"
220 "The DLLs differ, so it's not safe to run the forked child.\n"
221 "Make sure to remove the offending DLL before trying again.",
222 d->name, name);
8978381c 223 d->p = p;
1fd5e000 224 }
73bcd49b
CF
225 else
226 {
227 /* FIXME: Change this to new at some point. */
228 d = (dll *) cmalloc (HEAP_2_DLL, sizeof (*d) + (namelen * sizeof (*name)));
229
8f4ea5f0
CV
230 /* Now we've allocated a block of information. Fill it in with the
231 supplied info about this DLL. */
73bcd49b
CF
232 d->count = 1;
233 wcscpy (d->name, name);
f5b0d9d4 234 d->modname = d->name + (modname - name);
73bcd49b
CF
235 d->handle = h;
236 d->has_dtors = true;
237 d->p = p;
977ad543
CF
238 d->ndeps = 0;
239 d->deps = NULL;
6cd2e185 240 d->image_size = ((pefile*)h)->optional_hdr ()->SizeOfImage;
6642f7da 241 d->preferred_base = (void*) ((pefile*)h)->optional_hdr()->ImageBase;
73bcd49b 242 d->type = type;
977ad543 243 append (d);
73bcd49b
CF
244 if (type == DLL_LOAD)
245 loaded_dlls++;
246 }
71c17c54 247 guard (false);
61522196 248#ifndef __x86_64__
73bcd49b 249 assert (p->envptr != NULL);
61522196 250#endif
2eb392bd 251 return d;
1fd5e000
CF
252}
253
977ad543
CF
254void
255dll_list::append (dll* d)
256{
257 if (end == NULL)
258 end = &start; /* Point to "end" of dll chain. */
259 end->next = d; /* Standard linked list stuff. */
260 d->next = NULL;
261 d->prev = end;
262 end = d;
977ad543
CF
263}
264
265void dll_list::populate_deps (dll* d)
266{
267 WCHAR wmodname[NT_MAX_PATH];
268 pefile* pef = (pefile*) d->handle;
269 PIMAGE_DATA_DIRECTORY dd = pef->idata_dir (IMAGE_DIRECTORY_ENTRY_IMPORT);
270 /* Annoyance: calling crealloc with a NULL pointer will use the
271 wrong heap and crash, so we have to replicate some code */
272 long maxdeps = 4;
273 d->deps = (dll**) cmalloc (HEAP_2_DLL, maxdeps*sizeof (dll*));
274 d->ndeps = 0;
275 for (PIMAGE_IMPORT_DESCRIPTOR id=
276 (PIMAGE_IMPORT_DESCRIPTOR) pef->rva (dd->VirtualAddress);
277 dd->Size && id->Name;
278 id++)
279 {
280 char* modname = pef->rva (id->Name);
281 sys_mbstowcs (wmodname, NT_MAX_PATH, modname);
50124fc0 282 if (dll* dep = find_by_modname (wmodname))
977ad543
CF
283 {
284 if (d->ndeps >= maxdeps)
285 {
286 maxdeps = 2*(1+maxdeps);
287 d->deps = (dll**) crealloc (d->deps, maxdeps*sizeof (dll*));
288 }
289 d->deps[d->ndeps++] = dep;
290 }
291 }
6642f7da 292
977ad543
CF
293 /* add one to differentiate no deps from unknown */
294 d->ndeps++;
295}
296
297
298void
299dll_list::topsort ()
300{
301 /* Anything to do? */
302 if (!end)
303 return;
6642f7da 304
977ad543
CF
305 /* make sure we have all the deps available */
306 dll* d = &start;
307 while ((d = d->next))
308 if (!d->ndeps)
309 populate_deps (d);
6642f7da 310
977ad543
CF
311 /* unlink head and tail pointers so the sort can rebuild the list */
312 d = start.next;
313 start.next = end = NULL;
314 topsort_visit (d, true);
315
316 /* clear node markings made by the sort */
317 d = &start;
318 while ((d = d->next))
319 {
29649132 320#ifdef DEBUGGING
9eba4de2 321 paranoid_printf ("%W", d->modname);
29649132 322 for (int i = 1; i < -d->ndeps; i++)
9eba4de2 323 paranoid_printf ("-> %W", d->deps[i - 1]->modname);
29649132 324#endif
977ad543
CF
325
326 /* It would be really nice to be able to keep this information
327 around for next time, but we don't have an easy way to
328 invalidate cached dependencies when a module unloads. */
329 d->ndeps = 0;
330 cfree (d->deps);
331 d->deps = NULL;
332 }
333}
334
335/* A recursive in-place topological sort. The result is ordered so that
336 dependencies of a dll appear before it in the list.
337
338 NOTE: this algorithm is guaranteed to terminate with a "partial
339 order" of dlls but does not do anything smart about cycles: an
340 arbitrary dependent dll will necessarily appear first. Perhaps not
341 surprisingly, Windows ships several dlls containing dependency
342 cycles, including SspiCli/RPCRT4.dll and a lovely tangle involving
343 USP10/LPK/GDI32/USER32.dll). Fortunately, we don't care about
344 Windows DLLs here, and cygwin dlls should behave better */
345void
346dll_list::topsort_visit (dll* d, bool seek_tail)
347{
348 /* Recurse to the end of the dll chain, then visit nodes as we
349 unwind. We do this because once we start visiting nodes we can no
350 longer trust any _next_ pointers.
351
352 We "mark" visited nodes (to avoid revisiting them) by negating
353 ndeps (undone once the sort completes). */
354 if (seek_tail && d->next)
355 topsort_visit (d->next, true);
6642f7da 356
977ad543
CF
357 if (d->ndeps > 0)
358 {
359 d->ndeps = -d->ndeps;
29649132
CF
360 for (long i = 1; i < -d->ndeps; i++)
361 topsort_visit (d->deps[i - 1], false);
977ad543
CF
362
363 append (d);
364 }
365}
366
367
fc6a0dc8
CF
368dll *
369dll_list::find (void *retaddr)
d5c4cd3f 370{
fc6a0dc8
CF
371 MEMORY_BASIC_INFORMATION m;
372 if (!VirtualQuery (retaddr, &m, sizeof m))
373 return NULL;
374 HMODULE h = (HMODULE) m.AllocationBase;
375
376 dll *d = &start;
377 while ((d = d->next))
378 if (d->handle == h)
379 break;
380 return d;
d5c4cd3f
CF
381}
382
2eb392bd 383/* Detach a DLL from the chain. */
1fd5e000 384void
052990e6 385dll_list::detach (void *retaddr)
1fd5e000 386{
fc6a0dc8 387 dll *d;
97575769
CF
388 /* Don't attempt to call destructors if we're still in fork processing
389 since that likely means fork is failing and everything will not have been
390 set up. */
391 if (!myself || in_forkee)
052990e6 392 return;
71c17c54
CF
393 guard (true);
394 if ((d = find (retaddr)))
fc6a0dc8 395 {
71c17c54
CF
396 if (d->count <= 0)
397 system_printf ("WARNING: trying to detach an already detached dll ...");
398 if (--d->count == 0)
399 {
400 /* Ensure our exception handler is enabled for destructors */
401 exception protect;
402 /* Call finalize function if we are not already exiting */
403 if (!exit_state)
404 __cxa_finalize (d);
405 d->run_dtors ();
406 d->prev->next = d->next;
407 if (d->next)
408 d->next->prev = d->prev;
409 if (d->type == DLL_LOAD)
410 loaded_dlls--;
411 if (end == d)
412 end = d->prev;
413 cfree (d);
414 }
fc6a0dc8 415 }
71c17c54 416 guard (false);
1fd5e000
CF
417}
418
c77c4419 419/* Initialization for all linked DLLs, called by dll_crt0_1. */
1fd5e000 420void
2eb392bd 421dll_list::init ()
1fd5e000 422{
2eb392bd
CF
423 /* Walk the dll chain, initializing each dll */
424 dll *d = &start;
53364a1f 425 dll_global_dtors_recorded = d->next != NULL;
2eb392bd
CF
426 while ((d = d->next))
427 d->init ();
1fd5e000
CF
428}
429
430#define A64K (64 * 1024)
431
1fd5e000 432
6cd2e185
CF
433/* Reserve the chunk of free address space starting _here_ and (usually)
434 covering at least _dll_size_ bytes. However, we must take care not
435 to clobber the dll's target address range because it often overlaps.
436 */
61522196
CV
437static PVOID
438reserve_at (const PWCHAR name, PVOID here, PVOID dll_base, DWORD dll_size)
8d777a13
CF
439{
440 DWORD size;
441 MEMORY_BASIC_INFORMATION mb;
442
61522196
CV
443 if (!VirtualQuery (here, &mb, sizeof (mb)))
444 fabort ("couldn't examine memory at %p while mapping %W, %E", here, name);
8d777a13
CF
445 if (mb.State != MEM_FREE)
446 return 0;
447
448 size = mb.RegionSize;
6642f7da 449
6cd2e185 450 // don't clobber the space where we want the dll to land
61522196
CV
451 caddr_t end = (caddr_t) here + size;
452 caddr_t dll_end = (caddr_t) dll_base + dll_size;
453 if (dll_base < here && dll_end > (caddr_t) here)
454 here = (PVOID) dll_end; // the dll straddles our left edge
455 else if (dll_base >= here && (caddr_t) dll_base < end)
456 end = (caddr_t) dll_base; // the dll overlaps partly or fully to our right
457
458 size = end - (caddr_t) here;
459 if (!VirtualAlloc (here, size, MEM_RESERVE, PAGE_NOACCESS))
29649132
CF
460 fabort ("couldn't allocate memory %p(%d) for '%W' alignment, %E\n",
461 here, size, name);
8d777a13
CF
462 return here;
463}
464
465/* Release the memory previously allocated by "reserve_at" above. */
466static void
61522196 467release_at (const PWCHAR name, PVOID here)
8d777a13 468{
61522196 469 if (!VirtualFree (here, 0, MEM_RELEASE))
29649132
CF
470 fabort ("couldn't release memory %p for '%W' alignment, %E\n",
471 here, name);
8d777a13
CF
472}
473
6642f7da
CF
474/* Step 1: Reserve memory for all DLL_LOAD dlls. This is to prevent
475 anything else from taking their spot as we compensate for Windows
476 randomly relocating things.
477
478 NOTE: because we can't depend on LoadLibraryExW to do the right
479 thing, we have to do a vanilla VirtualAlloc instead. One possible
480 optimization might attempt a LoadLibraryExW first, in case it lands
481 in the right place, but then we have to find a way of tracking
482 which dlls ended up needing VirtualAlloc after all. */
483void
484dll_list::reserve_space ()
485{
486 for (dll* d = dlls.istart (DLL_LOAD); d; d = dlls.inext ())
487 if (!VirtualAlloc (d->handle, d->image_size, MEM_RESERVE, PAGE_NOACCESS))
6a288492 488 fabort ("address space needed by '%W' (%p) is already occupied",
9eba4de2 489 d->modname, d->handle);
6642f7da
CF
490}
491
f5b0d9d4
CV
492/* We need the in_load_after_fork flag so dll_dllcrt0_1 can decide at fork
493 time if this is a linked DLL or a dynamically loaded DLL. In either case,
494 both, cygwin_finished_initializing and in_forkee are true, so they are not
495 sufficient to discern the situation. */
496static bool NO_COPY in_load_after_fork;
497
1d95e198 498/* Reload DLLs after a fork. Iterates over the list of dynamically loaded
71f53a2f
CF
499 DLLs and attempts to load them in the same place as they were loaded in the
500 parent. */
1fd5e000 501void
71f53a2f 502dll_list::load_after_fork (HANDLE parent)
1fd5e000 503{
6642f7da
CF
504 // moved to frok::child for performance reasons:
505 // dll_list::reserve_space();
8d777a13 506
f5b0d9d4 507 in_load_after_fork = true;
6642f7da 508 load_after_fork_impl (parent, dlls.istart (DLL_LOAD), 0);
f5b0d9d4 509 in_load_after_fork = false;
6642f7da 510}
8d777a13 511
6642f7da
CF
512static int const DLL_RETRY_MAX = 6;
513void dll_list::load_after_fork_impl (HANDLE parent, dll* d, int retries)
514{
515 /* Step 2: For each dll which did not map at its preferred base
516 address in the parent, try to coerce it to land at the same spot
517 as before. If not, unload it, reserve the memory around it, and
518 try again. Use recursion to remember blocked regions address
519 space so we can release them later.
520
521 We DONT_RESOLVE_DLL_REFERENCES at first in case the DLL lands in
522 the wrong spot;
523
524 NOTE: This step skips DLLs which loaded at their preferred
525 address in the parent because they should behave (we already
526 verified that their preferred address in the child is
527 available). However, this may fail on a Vista/Win7 machine with
528 ASLR active, because the ASLR base address will usually not equal
529 the preferred base recorded in the dll. In this case, we should
530 make the LoadLibraryExW call unconditional.
531 */
532 for ( ; d; d = dlls.inext ())
533 if (d->handle != d->preferred_base)
534 {
535 /* See if the DLL will load in proper place. If not, unload it,
536 reserve the memory around it, and try again.
537
538 If this is the first attempt, we need to release the
539 dll's protective reservation from step 1
540 */
541 if (!retries && !VirtualFree (d->handle, 0, MEM_RELEASE))
61522196 542 fabort ("unable to release protective reservation for %W (%p), %E",
9eba4de2 543 d->modname, d->handle);
b86f999a 544
6642f7da
CF
545 HMODULE h = LoadLibraryExW (d->name, NULL, DONT_RESOLVE_DLL_REFERENCES);
546 if (!h)
9eba4de2 547 fabort ("unable to create interim mapping for %W, %E", d->name);
6642f7da
CF
548 if (h != d->handle)
549 {
61522196 550 sigproc_printf ("%W loaded in wrong place: %p != %p",
9eba4de2 551 d->modname, h, d->handle);
6642f7da 552 FreeLibrary (h);
61522196
CV
553 PVOID reservation = reserve_at (d->modname, h,
554 d->handle, d->image_size);
6642f7da 555 if (!reservation)
29649132 556 fabort ("unable to block off %p to prevent %W from loading there",
9eba4de2 557 h, d->modname);
6642f7da
CF
558
559 if (retries < DLL_RETRY_MAX)
560 load_after_fork_impl (parent, d, retries+1);
561 else
61522196 562 fabort ("unable to remap %W to same address as parent (%p) - try running rebaseall",
9eba4de2 563 d->modname, d->handle);
6642f7da
CF
564
565 /* once the above returns all the dlls are mapped; release
566 the reservation and continue unwinding */
61522196 567 sigproc_printf ("releasing blocked space at %p", reservation);
9eba4de2 568 release_at (d->modname, reservation);
6642f7da
CF
569 return;
570 }
571 }
8d777a13 572
6642f7da
CF
573 /* Step 3: try to load each dll for real after either releasing the
574 protective reservation (for well-behaved dlls) or unloading the
575 interim mapping (for rebased dlls) . The dll list is sorted in
576 dependency order, so we shouldn't pull in any additional dlls
29649132 577 outside our control. */
6642f7da
CF
578 for (dll *d = dlls.istart (DLL_LOAD); d; d = dlls.inext ())
579 {
580 if (d->handle == d->preferred_base)
581 {
582 if (!VirtualFree (d->handle, 0, MEM_RELEASE))
61522196 583 fabort ("unable to release protective reservation for %W (%p), %E",
9eba4de2 584 d->modname, d->handle);
2eb392bd 585 }
6642f7da
CF
586 else
587 {
588 /* Free the library using our parent's handle: it's identical
29649132 589 to ours or we wouldn't have gotten this far */
6642f7da 590 if (!FreeLibrary (d->handle))
29649132 591 fabort ("unable to unload interim mapping of %W, %E",
9eba4de2 592 d->modname);
6642f7da
CF
593 }
594 HMODULE h = LoadLibraryW (d->name);
595 if (!h)
29649132 596 fabort ("unable to map %W, %E", d->name);
6642f7da 597 if (h != d->handle)
29649132 598 fabort ("unable to map %W to same address as parent: %p != %p",
9eba4de2 599 d->modname, d->handle, h);
6642f7da 600 }
1fd5e000
CF
601}
602
2346864a
CF
603struct dllcrt0_info
604{
605 HMODULE h;
606 per_process *p;
61522196 607 PVOID res;
8d777a13 608 dllcrt0_info (HMODULE h0, per_process *p0): h (h0), p (p0) {}
2346864a
CF
609};
610
61522196 611extern "C" PVOID
1fd5e000
CF
612dll_dllcrt0 (HMODULE h, per_process *p)
613{
5025bf33 614 if (dynamically_loaded)
61522196 615 return (PVOID) 1;
2346864a 616 dllcrt0_info x (h, p);
5025bf33 617 dll_dllcrt0_1 (&x);
2346864a
CF
618 return x.res;
619}
620
621void
622dll_dllcrt0_1 (VOID *x)
623{
8d777a13
CF
624 HMODULE& h = ((dllcrt0_info *) x)->h;
625 per_process*& p = ((dllcrt0_info *) x)->p;
61522196 626 PVOID& res = ((dllcrt0_info *) x)->res;
2346864a 627
737a86d3
CF
628 if (p == NULL)
629 p = &__cygwin_user_data;
630 else
27f564e9
CF
631 {
632 *(p->impure_ptr_ptr) = __cygwin_user_data.impure_ptr;
633 _pei386_runtime_relocator (p);
634 }
737a86d3 635
f5b0d9d4 636 bool linked = !cygwin_finished_initializing && !in_load_after_fork;
29d1e62e 637
ce5eb135
CV
638 /* Broken DLLs built against Cygwin versions 1.7.0-49 up to 1.7.0-57
639 override the cxx_malloc pointer in their DLL initialization code,
640 when loaded either statically or dynamically. Because this leaves
641 a stale pointer into demapped memory space if the DLL is unloaded
642 by a call to dlclose, we prevent this happening for dynamically
643 loaded DLLS in dlopen by saving and restoring cxx_malloc around
644 the call to LoadLibrary, which invokes the DLL's startup sequence.
645 Modern DLLs won't even attempt to override the pointer when loaded
646 statically, but will write their overrides directly into the
647 struct it points to. With all modern DLLs, this will remain the
648 default_cygwin_cxx_malloc struct in cxx.cc, but if any broken DLLs
649 are in the mix they will have overridden the pointer and subsequent
650 overrides will go into their embedded cxx_malloc structs. This is
651 almost certainly not a problem as they can never be unloaded, but
652 if we ever did want to do anything about it, we could check here to
653 see if the pointer had been altered in the early parts of the DLL's
654 startup, and if so copy back the new overrides and reset it here.
655 However, that's just a note for the record; at the moment, we can't
656 see any need to worry about this happening. */
657
5025bf33 658 check_sanity_and_sync (p);
2eb392bd
CF
659
660 dll_type type;
661
662 /* If this function is called before cygwin has finished
663 initializing, then the DLL must be a cygwin-aware DLL
664 that was explicitly linked into the program rather than
665 a dlopened DLL. */
2346864a 666 if (linked)
2eb392bd
CF
667 type = DLL_LINK;
668 else
669 {
670 type = DLL_LOAD;
671 dlls.reload_on_fork = 1;
672 }
673
674 /* Allocate and initialize space for the DLL. */
675 dll *d = dlls.alloc (h, p, type);
676
677 /* If d == NULL, then something is broken.
678 Otherwise, if we've finished initializing, it's ok to
679 initialize the DLL. If we haven't finished initializing,
680 it may not be safe to call the dll's "main" since not
681 all of cygwin's internal structures may have been set up. */
2346864a 682 if (!d || (!linked && !d->init ()))
61522196 683 res = (PVOID) -1;
2346864a 684 else
61522196 685 res = (PVOID) d;
1fd5e000
CF
686}
687
61522196 688#ifndef __x86_64__
2b37c431 689/* OBSOLETE: This function is obsolete and will go away in the
1fd5e000
CF
690 future. Cygwin can now handle being loaded from a noncygwin app
691 using the same entry point. */
2eb392bd 692extern "C" int
1fd5e000
CF
693dll_noncygwin_dllcrt0 (HMODULE h, per_process *p)
694{
61522196 695 return (int) dll_dllcrt0 (h, p);
1fd5e000 696}
61522196 697#endif /* !__x86_64__ */
1fd5e000 698
2eb392bd 699extern "C" void
052990e6 700cygwin_detach_dll (dll *)
1fd5e000 701{
51f90b2f
CF
702 HANDLE retaddr;
703 if (_my_tls.isinitialized ())
fc6a0dc8 704 retaddr = (void *) _my_tls.retaddr ();
51f90b2f
CF
705 else
706 retaddr = __builtin_return_address (0);
707 dlls.detach (retaddr);
1fd5e000
CF
708}
709
2eb392bd 710extern "C" void
1fd5e000
CF
711dlfork (int val)
712{
2eb392bd 713 dlls.reload_on_fork = val;
1fd5e000
CF
714}
715
61522196 716#ifndef __x86_64__
2eb392bd
CF
717/* Called from various places to update all of the individual
718 ideas of the environ block. Explain to me again why we didn't
719 just import __cygwin_environ? */
720void __stdcall
721update_envptrs ()
722{
2eb392bd 723 for (dll *d = dlls.istart (DLL_ANY); d; d = dlls.inext ())
8d777a13
CF
724 if (*(d->p.envptr) != __cygwin_environ)
725 *(d->p.envptr) = __cygwin_environ;
2eb392bd
CF
726 *main_environ = __cygwin_environ;
727}
61522196 728#endif
This page took 0.441768 seconds and 5 git commands to generate.