3 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
12 #include "perprocess.h"
22 extern void __stdcall check_sanity_and_sync (per_process *);
24 dll_list NO_COPY dlls;
26 static int NO_COPY in_forkee;
27 static bool dll_global_dtors_recorded;
29 /* Run destructors for all DLLs on exit. */
33 int recorded = dll_global_dtors_recorded;
34 dll_global_dtors_recorded = false;
36 for (dll *d = dlls.istart (DLL_ANY); d; d = dlls.inext ())
40 /* Run all constructors associated with a dll */
42 per_module::run_ctors ()
44 void (**pfunc)() = ctors;
46 /* Run ctors backwards, so skip the first entry and find how many
47 there are, then run them. */
52 for (i = 1; pfunc[i]; i++);
54 for (int j = i - 1; j > 0; j--)
59 /* Run all destructors associated with a dll */
61 per_module::run_dtors ()
63 void (**pfunc)() = dtors;
64 for (int i = 1; pfunc[i]; i++)
68 /* Initialize an individual DLL */
74 /* Why didn't we just import this variable? */
75 *(p.envptr) = __cygwin_environ;
77 /* Don't run constructors or the "main" if we've forked. */
80 /* global contructors */
83 /* entry point of dll (use main of per_process with null args...) */
85 ret = (*(p.main)) (0, 0, 0);
91 /* Look for a dll based on name */
93 dll_list::operator[] (const char *name)
96 while ((d = d->next) != NULL)
97 if (strcasematch (name, d->name))
105 /* Allocate space for a dll struct contiguous with the just-loaded dll. */
107 dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
109 char name[CYG_MAX_PATH];
110 DWORD namelen = GetModuleFileName (h, name, sizeof (name));
112 /* Already loaded? */
116 d->count++; /* Yes. Bump the usage count. */
117 return d; /* Return previously allocated pointer. */
124 void *s = p->bss_end;
126 MEMORY_BASIC_INFORMATION m;
127 /* Search for space after the DLL */
128 for (i = 0; i <= RETRIES; i++, s = (char *) m.BaseAddress + m.RegionSize)
130 if (!VirtualQuery (s, &m, sizeof (m)))
131 return NULL; /* Can't do it. */
132 if (m.State == MEM_FREE)
134 /* Couldn't find any. Uh oh. FIXME: Issue an error? */
136 return NULL; /* Oh well. Couldn't locate free space. */
138 /* Ensure that this is rounded to the nearest page boundary.
139 FIXME: Should this be ensured by VirtualQuery? */
140 n = (DWORD) m.BaseAddress;
141 DWORD r = n % s1.dwAllocationGranularity;
144 n = ((n - r) + s1.dwAllocationGranularity);
146 /* First reserve the area of memory, then commit it. */
147 if (VirtualAlloc ((void *) n, sizeof (dll), MEM_RESERVE, PAGE_READWRITE))
148 d = (dll *) VirtualAlloc ((void *) n, sizeof (dll), MEM_COMMIT,
155 /* Did we succeed? */
159 system_printf ("VirtualAlloc failed, %E");
165 /* Now we've allocated a block of information. Fill it in with the supplied
166 info about this DLL. */
168 d->namelen = namelen;
169 strcpy (d->name, name);
174 end = &start; /* Point to "end" of dll chain. */
175 end->next = d; /* Standard linked list stuff. */
180 if (type == DLL_LOAD)
185 /* Detach a DLL from the chain. */
187 dll_list::detach (void *retaddr)
189 if (!myself || exit_state)
191 MEMORY_BASIC_INFORMATION m;
192 if (!VirtualQuery (retaddr, &m, sizeof m))
194 HMODULE h = (HMODULE) m.AllocationBase;
197 while ((d = d->next))
200 else if (d->count <= 0)
201 system_printf ("WARNING: trying to detach an already detached dll ...");
202 else if (--d->count == 0)
205 d->prev->next = d->next;
207 d->next->prev = d->prev;
208 if (d->type == DLL_LOAD)
212 VirtualFree (d, 0, MEM_RELEASE);
217 /* Initialization for all linked DLLs, called by dll_crt0_1. */
221 dll_global_dtors_recorded = true;
223 /* Walk the dll chain, initializing each dll */
225 while ((d = d->next))
229 #define A64K (64 * 1024)
231 /* Mark every memory address up to "here" as reserved. This may force
232 Windows NT to load a DLL in the next available, lowest slot. */
234 reserve_upto (const char *name, DWORD here)
237 MEMORY_BASIC_INFORMATION mb;
238 for (DWORD start = 0x10000; start < here; start += size)
239 if (!VirtualQuery ((void *) start, &mb, sizeof (mb)))
243 size = A64K * ((mb.RegionSize + A64K - 1) / A64K);
244 start = A64K * (((DWORD) mb.BaseAddress + A64K - 1) / A64K);
246 if (start + size > here)
248 if (mb.State == MEM_FREE &&
249 !VirtualAlloc ((void *) start, size, MEM_RESERVE, PAGE_NOACCESS))
250 api_fatal ("couldn't allocate memory %p(%d) for '%s' alignment, %E\n",
255 /* Release all of the memory previously allocated by "upto" above.
256 Note that this may also free otherwise reserved memory. If that becomes
257 a problem, we'll have to keep track of the memory that we reserve above. */
259 release_upto (const char *name, DWORD here)
262 MEMORY_BASIC_INFORMATION mb;
263 for (DWORD start = 0x10000; start < here; start += size)
264 if (!VirtualQuery ((void *) start, &mb, sizeof (mb)))
268 size = mb.RegionSize;
269 if (!(mb.State == MEM_RESERVE && mb.AllocationProtect == PAGE_NOACCESS &&
270 (((void *) start < cygheap->user_heap.base
271 || (void *) start > cygheap->user_heap.top) &&
272 ((void *) start < (void *) cygheap
273 | (void *) start > (void *) ((char *) cygheap + CYGHEAPSIZE)))))
275 if (!VirtualFree ((void *) start, 0, MEM_RELEASE))
276 api_fatal ("couldn't release memory %p(%d) for '%s' alignment, %E\n",
281 /* Reload DLLs after a fork. Iterates over the list of dynamically loaded DLLs
282 and attempts to load them in the same place as they were loaded in the parent. */
284 dll_list::load_after_fork (HANDLE parent, dll *first)
294 /* Read the dll structure from the parent. */
295 if (!ReadProcessMemory (parent, next, &d, sizeof (dll), &nb) ||
299 /* We're only interested in dynamically loaded dlls.
300 Hopefully, this function wouldn't even have been called unless
301 the parent had some of those. */
302 if (d.type == DLL_LOAD)
305 HMODULE h = LoadLibraryEx (d.name, NULL, DONT_RESOLVE_DLL_REFERENCES);
308 system_printf ("can't reload %s", d.name);
309 /* See if DLL will load in proper place. If so, free it and reload
311 It sort of stinks that we can't invert the order of the FreeLibrary
312 and LoadLibrary since Microsoft documentation seems to imply that that
313 should do what we want. However, since the library was loaded above,
314 the second LoadLibrary does not execute it's startup code unless it
315 is first unloaded. */
316 else if (h == d.handle)
321 LoadLibrary (d.name);
325 api_fatal ("unable to remap %s to same address as parent(%p) != %p",
326 d.name, d.handle, h);
329 /* It loaded in the wrong place. Dunno why this happens but it always
330 seems to happen when there are multiple DLLs attempting to load into
331 the same address space. In the "forked" process, the second DLL always
332 loads into a different location. */
334 /* Block all of the memory up to the new load address. */
335 reserve_upto (d.name, (DWORD) d.handle);
336 try2 = 1; /* And try */
337 continue; /* again. */
339 /* If we reached here, and try2 is set, then there is a lot of memory to
343 release_upto (d.name, (DWORD) d.handle);
347 next = d.next; /* Get the address of the next DLL. */
353 dll_dllcrt0 (HMODULE h, per_process *p)
356 p = &__cygwin_user_data;
358 *(p->impure_ptr_ptr) = __cygwin_user_data.impure_ptr;
359 bool initializing = in_forkee || cygwin_finished_initializing;
361 /* Partially initialize Cygwin guts for non-cygwin apps. */
362 if (dynamically_loaded && user_data->magic_biscuit == 0)
365 check_sanity_and_sync (p);
369 /* If this function is called before cygwin has finished
370 initializing, then the DLL must be a cygwin-aware DLL
371 that was explicitly linked into the program rather than
378 dlls.reload_on_fork = 1;
381 /* Allocate and initialize space for the DLL. */
382 dll *d = dlls.alloc (h, p, type);
384 /* If d == NULL, then something is broken.
385 Otherwise, if we've finished initializing, it's ok to
386 initialize the DLL. If we haven't finished initializing,
387 it may not be safe to call the dll's "main" since not
388 all of cygwin's internal structures may have been set up. */
389 if (!d || (initializing && !d->init ()))
395 /* OBSOLETE: This function is obsolescent and will go away in the
396 future. Cygwin can now handle being loaded from a noncygwin app
397 using the same entry point. */
400 dll_noncygwin_dllcrt0 (HMODULE h, per_process *p)
402 return dll_dllcrt0 (h, p);
406 cygwin_detach_dll (dll *)
408 dlls.detach (__builtin_return_address (0));
414 dlls.reload_on_fork = val;
417 /* Called from various places to update all of the individual
418 ideas of the environ block. Explain to me again why we didn't
419 just import __cygwin_environ? */
423 extern char ***main_environ;
424 for (dll *d = dlls.istart (DLL_ANY); d; d = dlls.inext ())
426 *(d->p.envptr) = __cygwin_environ;
428 *main_environ = __cygwin_environ;