]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/dll_init.cc
Remove unneeded header files from source files throughout.
[newlib-cygwin.git] / winsup / cygwin / dll_init.cc
CommitLineData
1fd5e000
CF
1/* dll_init.cc
2
9aca6a48 3 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
1fd5e000
CF
4
5This software is a copyrighted work licensed under the terms of the
6Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7details. */
8
1fd5e000 9#include "winsup.h"
9e2baf8d 10#include "cygerrno.h"
f0338f54
CF
11#include "perprocess.h"
12#include "dll_init.h"
13#include "environ.h"
1ff9f4b9 14#include "security.h"
47063f00 15#include "path.h"
7ac61736 16#include "fhandler.h"
1ff9f4b9
CF
17#include "dtable.h"
18#include "cygheap.h"
6b7cd251 19#include "pinfo.h"
9aca6a48 20#include "cygtls.h"
1fd5e000
CF
21
22extern void __stdcall check_sanity_and_sync (per_process *);
23
2eb392bd 24dll_list NO_COPY dlls;
1fd5e000 25
dda06573 26static bool dll_global_dtors_recorded;
1fd5e000 27
2eb392bd 28/* Run destructors for all DLLs on exit. */
dda06573 29void
f0227ea3 30dll_global_dtors ()
1fd5e000 31{
dda06573
CF
32 int recorded = dll_global_dtors_recorded;
33 dll_global_dtors_recorded = false;
34 if (recorded)
35 for (dll *d = dlls.istart (DLL_ANY); d; d = dlls.inext ())
36 d->p.run_dtors ();
1fd5e000
CF
37}
38
2eb392bd
CF
39/* Run all constructors associated with a dll */
40void
41per_module::run_ctors ()
1fd5e000 42{
2eb392bd 43 void (**pfunc)() = ctors;
1fd5e000
CF
44
45 /* Run ctors backwards, so skip the first entry and find how many
46 there are, then run them. */
47
48 if (pfunc)
49 {
50 int i;
51 for (i = 1; pfunc[i]; i++);
52
f7632549 53 for (int j = i - 1; j > 0; j--)
1fd5e000
CF
54 (pfunc[j]) ();
55 }
56}
57
2eb392bd
CF
58/* Run all destructors associated with a dll */
59void
60per_module::run_dtors ()
1fd5e000 61{
2eb392bd 62 void (**pfunc)() = dtors;
1fd5e000
CF
63 for (int i = 1; pfunc[i]; i++)
64 (pfunc[i]) ();
65}
66
2eb392bd
CF
67/* Initialize an individual DLL */
68int
69dll::init ()
1fd5e000 70{
2eb392bd 71 int ret = 1;
1fd5e000 72
2eb392bd
CF
73 /* Why didn't we just import this variable? */
74 *(p.envptr) = __cygwin_environ;
1fd5e000 75
2eb392bd
CF
76 /* Don't run constructors or the "main" if we've forked. */
77 if (!in_forkee)
1fd5e000
CF
78 {
79 /* global contructors */
2eb392bd 80 p.run_ctors ();
1fd5e000
CF
81
82 /* entry point of dll (use main of per_process with null args...) */
2eb392bd
CF
83 if (p.main)
84 ret = (*(p.main)) (0, 0, 0);
1fd5e000
CF
85 }
86
87 return ret;
88}
89
2eb392bd
CF
90/* Look for a dll based on name */
91dll *
92dll_list::operator[] (const char *name)
1fd5e000 93{
2eb392bd
CF
94 dll *d = &start;
95 while ((d = d->next) != NULL)
96 if (strcasematch (name, d->name))
97 return d;
1fd5e000 98
2eb392bd 99 return NULL;
1fd5e000
CF
100}
101
c43c5c16 102#define RETRIES 1000
2eb392bd 103
c77c4419 104/* Allocate space for a dll struct contiguous with the just-loaded dll. */
2eb392bd
CF
105dll *
106dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
1fd5e000 107{
7b4b41ab 108 char name[NT_MAX_PATH];
2eb392bd 109 DWORD namelen = GetModuleFileName (h, name, sizeof (name));
1fd5e000 110
2eb392bd
CF
111 /* Already loaded? */
112 dll *d = dlls[name];
113 if (d)
1fd5e000 114 {
2eb392bd
CF
115 d->count++; /* Yes. Bump the usage count. */
116 return d; /* Return previously allocated pointer. */
1fd5e000
CF
117 }
118
5bc584ba
CF
119 SYSTEM_INFO s1;
120 GetSystemInfo (&s1);
121
2eb392bd
CF
122 int i;
123 void *s = p->bss_end;
5bc584ba 124 DWORD n;
2eb392bd
CF
125 MEMORY_BASIC_INFORMATION m;
126 /* Search for space after the DLL */
5bc584ba 127 for (i = 0; i <= RETRIES; i++, s = (char *) m.BaseAddress + m.RegionSize)
1fd5e000 128 {
2eb392bd
CF
129 if (!VirtualQuery (s, &m, sizeof (m)))
130 return NULL; /* Can't do it. */
131 if (m.State == MEM_FREE)
5bc584ba
CF
132 {
133 /* Couldn't find any. Uh oh. FIXME: Issue an error? */
134 if (i == RETRIES)
135 return NULL; /* Oh well. Couldn't locate free space. */
136
137 /* Ensure that this is rounded to the nearest page boundary.
138 FIXME: Should this be ensured by VirtualQuery? */
139 n = (DWORD) m.BaseAddress;
140 DWORD r = n % s1.dwAllocationGranularity;
141
142 if (r)
143 n = ((n - r) + s1.dwAllocationGranularity);
144
145 /* First reserve the area of memory, then commit it. */
146 if (VirtualAlloc ((void *) n, sizeof (dll), MEM_RESERVE, PAGE_READWRITE))
147 d = (dll *) VirtualAlloc ((void *) n, sizeof (dll), MEM_COMMIT,
148 PAGE_READWRITE);
149 if (d)
150 break;
151 }
1fd5e000
CF
152 }
153
c77c4419 154 /* Did we succeed? */
92e30b75 155 if (d == NULL)
c77c4419 156 { /* Nope. */
92e30b75 157#ifdef DEBUGGING
49a16134 158 system_printf ("VirtualAlloc failed, %E");
92e30b75
CF
159#endif
160 __seterrno ();
161 return NULL;
162 }
2eb392bd
CF
163
164 /* Now we've allocated a block of information. Fill it in with the supplied
165 info about this DLL. */
166 d->count = 1;
167 d->namelen = namelen;
168 strcpy (d->name, name);
169 d->handle = h;
170 d->p = p;
171 d->type = type;
172 if (end == NULL)
173 end = &start; /* Point to "end" of dll chain. */
174 end->next = d; /* Standard linked list stuff. */
175 d->next = NULL;
176 d->prev = end;
177 end = d;
178 tot++;
179 if (type == DLL_LOAD)
180 loaded_dlls++;
181 return d;
1fd5e000
CF
182}
183
2eb392bd 184/* Detach a DLL from the chain. */
1fd5e000 185void
052990e6 186dll_list::detach (void *retaddr)
1fd5e000 187{
edc4f86a 188 if (!myself || exit_state)
6b7cd251 189 return;
052990e6
CF
190 MEMORY_BASIC_INFORMATION m;
191 if (!VirtualQuery (retaddr, &m, sizeof m))
192 return;
193 HMODULE h = (HMODULE) m.AllocationBase;
6b7cd251 194
052990e6
CF
195 dll *d = &start;
196 while ((d = d->next))
197 if (d->handle != h)
198 continue;
199 else if (d->count <= 0)
2d1d1eb1 200 system_printf ("WARNING: trying to detach an already detached dll ...");
052990e6
CF
201 else if (--d->count == 0)
202 {
203 d->p.run_dtors ();
204 d->prev->next = d->next;
205 if (d->next)
206 d->next->prev = d->prev;
207 if (d->type == DLL_LOAD)
208 loaded_dlls--;
209 if (end == d)
210 end = d->prev;
211 VirtualFree (d, 0, MEM_RELEASE);
212 break;
213 }
1fd5e000
CF
214}
215
c77c4419 216/* Initialization for all linked DLLs, called by dll_crt0_1. */
1fd5e000 217void
2eb392bd 218dll_list::init ()
1fd5e000 219{
dda06573 220 dll_global_dtors_recorded = true;
1fd5e000 221
2eb392bd
CF
222 /* Walk the dll chain, initializing each dll */
223 dll *d = &start;
224 while ((d = d->next))
225 d->init ();
1fd5e000
CF
226}
227
228#define A64K (64 * 1024)
229
230/* Mark every memory address up to "here" as reserved. This may force
231 Windows NT to load a DLL in the next available, lowest slot. */
2eb392bd 232static void
1fd5e000
CF
233reserve_upto (const char *name, DWORD here)
234{
235 DWORD size;
236 MEMORY_BASIC_INFORMATION mb;
237 for (DWORD start = 0x10000; start < here; start += size)
238 if (!VirtualQuery ((void *) start, &mb, sizeof (mb)))
54030e21 239 size = A64K;
1fd5e000
CF
240 else
241 {
242 size = A64K * ((mb.RegionSize + A64K - 1) / A64K);
243 start = A64K * (((DWORD) mb.BaseAddress + A64K - 1) / A64K);
244
245 if (start + size > here)
246 size = here - start;
247 if (mb.State == MEM_FREE &&
248 !VirtualAlloc ((void *) start, size, MEM_RESERVE, PAGE_NOACCESS))
249 api_fatal ("couldn't allocate memory %p(%d) for '%s' alignment, %E\n",
250 start, size, name);
251 }
252}
253
254/* Release all of the memory previously allocated by "upto" above.
255 Note that this may also free otherwise reserved memory. If that becomes
256 a problem, we'll have to keep track of the memory that we reserve above. */
2eb392bd 257static void
1fd5e000
CF
258release_upto (const char *name, DWORD here)
259{
260 DWORD size;
261 MEMORY_BASIC_INFORMATION mb;
262 for (DWORD start = 0x10000; start < here; start += size)
263 if (!VirtualQuery ((void *) start, &mb, sizeof (mb)))
264 size = 64 * 1024;
265 else
266 {
267 size = mb.RegionSize;
268 if (!(mb.State == MEM_RESERVE && mb.AllocationProtect == PAGE_NOACCESS &&
1cc651ec
CF
269 (((void *) start < cygheap->user_heap.base
270 || (void *) start > cygheap->user_heap.top) &&
3593c187 271 ((void *) start < (void *) cygheap
1cc651ec 272 | (void *) start > (void *) ((char *) cygheap + CYGHEAPSIZE)))))
1fd5e000
CF
273 continue;
274 if (!VirtualFree ((void *) start, 0, MEM_RELEASE))
275 api_fatal ("couldn't release memory %p(%d) for '%s' alignment, %E\n",
276 start, size, name);
277 }
278}
279
280/* Reload DLLs after a fork. Iterates over the list of dynamically loaded DLLs
281 and attempts to load them in the same place as they were loaded in the parent. */
282void
2eb392bd 283dll_list::load_after_fork (HANDLE parent, dll *first)
1fd5e000 284{
1fd5e000 285 int try2 = 0;
2eb392bd 286 dll d;
1fd5e000 287
75a57bf0 288 void *next = first;
2eb392bd
CF
289 while (next)
290 {
291 DWORD nb;
292 /* Read the dll structure from the parent. */
c77c4419
CF
293 if (!ReadProcessMemory (parent, next, &d, sizeof (dll), &nb) ||
294 nb != sizeof (dll))
2eb392bd 295 return;
c77c4419 296
2eb392bd
CF
297 /* We're only interested in dynamically loaded dlls.
298 Hopefully, this function wouldn't even have been called unless
299 the parent had some of those. */
300 if (d.type == DLL_LOAD)
301 {
005c3065 302 bool unload = true;
2eb392bd
CF
303 HMODULE h = LoadLibraryEx (d.name, NULL, DONT_RESOLVE_DLL_REFERENCES);
304
005c3065
CF
305 if (!h)
306 system_printf ("can't reload %s", d.name);
2eb392bd
CF
307 /* See if DLL will load in proper place. If so, free it and reload
308 it the right way.
309 It sort of stinks that we can't invert the order of the FreeLibrary
310 and LoadLibrary since Microsoft documentation seems to imply that that
311 should do what we want. However, since the library was loaded above,
c77c4419 312 the second LoadLibrary does not execute it's startup code unless it
2eb392bd 313 is first unloaded. */
005c3065 314 else if (h == d.handle)
2eb392bd 315 {
005c3065
CF
316 if (unload)
317 {
318 FreeLibrary (h);
319 LoadLibrary (d.name);
320 }
2eb392bd
CF
321 }
322 else if (try2)
54030e21
CF
323 api_fatal ("unable to remap %s to same address as parent(%p) != %p",
324 d.name, d.handle, h);
2eb392bd
CF
325 else
326 {
327 /* It loaded in the wrong place. Dunno why this happens but it always
328 seems to happen when there are multiple DLLs attempting to load into
329 the same address space. In the "forked" process, the second DLL always
330 loads into a different location. */
331 FreeLibrary (h);
332 /* Block all of the memory up to the new load address. */
333 reserve_upto (d.name, (DWORD) d.handle);
334 try2 = 1; /* And try */
335 continue; /* again. */
336 }
337 /* If we reached here, and try2 is set, then there is a lot of memory to
338 release. */
339 if (try2)
340 {
341 release_upto (d.name, (DWORD) d.handle);
342 try2 = 0;
343 }
344 }
345 next = d.next; /* Get the address of the next DLL. */
346 }
5d970405 347 in_forkee = false;
1fd5e000
CF
348}
349
2346864a
CF
350struct dllcrt0_info
351{
352 HMODULE h;
353 per_process *p;
354 int res;
355 dllcrt0_info (HMODULE h0, per_process *p0): h(h0), p(p0) {}
356};
357
5f931698 358extern "C" int
1fd5e000
CF
359dll_dllcrt0 (HMODULE h, per_process *p)
360{
2346864a
CF
361 dllcrt0_info x (h, p);
362
363 if (_my_tls.isinitialized ())
364 dll_dllcrt0_1 (&x);
365 else
366 _my_tls.call ((DWORD (*) (void *, void *)) dll_dllcrt0_1, &x);
367 return x.res;
368}
369
370void
371dll_dllcrt0_1 (VOID *x)
372{
373 HMODULE& h = ((dllcrt0_info *)x)->h;
374 per_process*& p = ((dllcrt0_info *)x)->p;
375 int& res = ((dllcrt0_info *)x)->res;
376
939f16ac
CF
377 /* Windows apparently installs a bunch of exception handlers prior to
378 this function getting called and one of them may trip before cygwin
379 gets to it. So, install our own exception handler only.
380 FIXME: It is possible that we may have to save state of the
381 previous exception handler chain and restore it, if problems
382 are noted. */
2346864a 383 _my_tls.init_exception_handler (_cygtls::handle_exceptions);
344be4a7 384
737a86d3
CF
385 if (p == NULL)
386 p = &__cygwin_user_data;
387 else
5f931698 388 *(p->impure_ptr_ptr) = __cygwin_user_data.impure_ptr;
737a86d3 389
2346864a 390 bool linked = !in_forkee && !cygwin_finished_initializing;
29d1e62e 391
1fd5e000 392 /* Partially initialize Cygwin guts for non-cygwin apps. */
737a86d3
CF
393 if (dynamically_loaded && user_data->magic_biscuit == 0)
394 dll_crt0 (p);
5bc584ba 395 else
2eb392bd
CF
396 check_sanity_and_sync (p);
397
398 dll_type type;
399
400 /* If this function is called before cygwin has finished
401 initializing, then the DLL must be a cygwin-aware DLL
402 that was explicitly linked into the program rather than
403 a dlopened DLL. */
2346864a 404 if (linked)
2eb392bd
CF
405 type = DLL_LINK;
406 else
407 {
408 type = DLL_LOAD;
409 dlls.reload_on_fork = 1;
410 }
411
412 /* Allocate and initialize space for the DLL. */
413 dll *d = dlls.alloc (h, p, type);
414
415 /* If d == NULL, then something is broken.
416 Otherwise, if we've finished initializing, it's ok to
417 initialize the DLL. If we haven't finished initializing,
418 it may not be safe to call the dll's "main" since not
419 all of cygwin's internal structures may have been set up. */
2346864a
CF
420 if (!d || (!linked && !d->init ()))
421 res = -1;
422 else
423 res = (DWORD) d;
1fd5e000
CF
424}
425
426/* OBSOLETE: This function is obsolescent and will go away in the
427 future. Cygwin can now handle being loaded from a noncygwin app
428 using the same entry point. */
429
2eb392bd 430extern "C" int
1fd5e000
CF
431dll_noncygwin_dllcrt0 (HMODULE h, per_process *p)
432{
433 return dll_dllcrt0 (h, p);
434}
435
2eb392bd 436extern "C" void
052990e6 437cygwin_detach_dll (dll *)
1fd5e000 438{
51f90b2f
CF
439 HANDLE retaddr;
440 if (_my_tls.isinitialized ())
441 retaddr = (HANDLE) _my_tls.retaddr ();
442 else
443 retaddr = __builtin_return_address (0);
444 dlls.detach (retaddr);
1fd5e000
CF
445}
446
2eb392bd 447extern "C" void
1fd5e000
CF
448dlfork (int val)
449{
2eb392bd 450 dlls.reload_on_fork = val;
1fd5e000
CF
451}
452
2eb392bd
CF
453/* Called from various places to update all of the individual
454 ideas of the environ block. Explain to me again why we didn't
455 just import __cygwin_environ? */
456void __stdcall
457update_envptrs ()
458{
2eb392bd 459 for (dll *d = dlls.istart (DLL_ANY); d; d = dlls.inext ())
9aca6a48 460 *(d->p.envptr) = __cygwin_environ;
2eb392bd
CF
461 *main_environ = __cygwin_environ;
462}
This page took 0.303206 seconds and 5 git commands to generate.