diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index aba346b9e..82851aa4a 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,16 @@ +2011-05-28 Christopher Faylor + + * dll_init.cc (reserve_upto): Remove. + (release_upto): Ditto. + (dll_list::reserve_space): New function to reserve space needed by + DLL_LOAD dlls early in the fork process. + (dll_list::load_after_fork): Rewrite to use recursion for tracking + reservations made while trying to make dlls land where they belong. + (dll_list::load_after_fork_impl): Ditto. + (dll_list::alloc): Initialize image base field. + * dll_init.h (struct dll_list): declare new functions. + (dll::image_size): New member. + 2011-05-28 Ryan Johnson * dll_init.cc (dll_list::find_by_modname): New function to search the diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc index 6fc117c0a..7882ed65f 100644 --- a/winsup/cygwin/dll_init.cc +++ b/winsup/cygwin/dll_init.cc @@ -173,6 +173,7 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type) d->handle = h; d->has_dtors = true; d->p = p; + d->image_size = ((pefile*)h)->optional_hdr ()->SizeOfImage; d->ndeps = 0; d->deps = NULL; d->modname = wcsrchr (d->name, L'\\'); @@ -416,21 +417,33 @@ release_upto (const PWCHAR name, DWORD here) } } -/* Mark one page at "here" as reserved. This may force - Windows NT to load a DLL elsewhere. */ +/* Reserve the chunk of free address space starting _here_ and (usually) + covering at least _dll_size_ bytes. However, we must take care not + to clobber the dll's target address range because it often overlaps. + */ static DWORD -reserve_at (const PWCHAR name, DWORD here) +reserve_at (const PWCHAR name, DWORD here, DWORD dll_base, DWORD dll_size) { DWORD size; MEMORY_BASIC_INFORMATION mb; if (!VirtualQuery ((void *) here, &mb, sizeof (mb))) - size = 64 * 1024; - + api_fatal ("couldn't examine memory at %08lx while mapping %W, %E", + here, name); if (mb.State != MEM_FREE) return 0; size = mb.RegionSize; + + // don't clobber the space where we want the dll to land + DWORD end = here + size; + DWORD dll_end = dll_base + dll_size; + if (dll_base < here && dll_end > here) + here = dll_end; // the dll straddles our left edge + else if (dll_base >= here && dll_base < end) + end = dll_base; // the dll overlaps partly or fully to our right + + size = end - here; if (!VirtualAlloc ((void *) here, size, MEM_RESERVE, PAGE_NOACCESS)) api_fatal ("couldn't allocate memory %p(%d) for '%W' alignment, %E\n", here, size, name); @@ -508,7 +521,8 @@ dll_list::load_after_fork (HANDLE parent) can in the child, due to differences in the load ordering. Block memory at it's preferred address and try again. */ if ((DWORD) h > (DWORD) d->handle) - preferred_block = reserve_at (d->name, (DWORD) h); + preferred_block = reserve_at (d->name, (DWORD) h, + (DWORD) d->handle, d->image_size); } } diff --git a/winsup/cygwin/dll_init.h b/winsup/cygwin/dll_init.h index 3a9a5c4f0..3fbe8760f 100644 --- a/winsup/cygwin/dll_init.h +++ b/winsup/cygwin/dll_init.h @@ -52,6 +52,7 @@ struct dll int count; bool has_dtors; dll_type type; + DWORD image_size; long ndeps; dll** deps; PWCHAR modname;