diff options
-rw-r--r-- | winsup/cygwin/ChangeLog | 9 | ||||
-rw-r--r-- | winsup/cygwin/dll_init.cc | 26 | ||||
-rw-r--r-- | winsup/cygwin/dll_init.h | 19 |
3 files changed, 48 insertions, 6 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 1670f7f8f..3edbad158 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,12 @@ +2011-05-28 Ryan Johnson <ryan.johnson@cs.utoronto.ca> + + * dll_init.cc (dll_list::alloc): Initialize dll::image_size. + (reserve_at): Don't reserve space needed by the target dll if the + latter overlaps the free region to be blocked. + (dll_list::load_after_fork): Use new version of reserve_at. + * dll_init.h (dll::image_size): New member. + (pefile): New struct. + 2011-05-28 Christopher Faylor <me.cygwin2011@cgf.cx> Ryan Johnson <ryan.johnson@cs.utoronto.ca> diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc index 68a974b7b..060ff497e 100644 --- a/winsup/cygwin/dll_init.cc +++ b/winsup/cygwin/dll_init.cc @@ -161,6 +161,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->type = type; if (end == NULL) end = &start; /* Point to "end" of dll chain. */ @@ -292,21 +293,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); @@ -384,7 +397,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 d14cc6cb9..dc5c57038 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; WCHAR name[1]; void detach (); int init (); @@ -109,6 +110,24 @@ public: dll_list () { protect.init ("dll_list"); } }; +/* References: + http://msdn.microsoft.com/en-us/windows/hardware/gg463125 + http://msdn.microsoft.com/en-us/library/ms809762.aspx +*/ +struct pefile +{ + IMAGE_DOS_HEADER dos_hdr; + + char* rva (long offset) { return (char*) this + offset; } + PIMAGE_NT_HEADERS32 pe_hdr () { return (PIMAGE_NT_HEADERS32) rva (dos_hdr.e_lfanew); } + PIMAGE_OPTIONAL_HEADER32 optional_hdr () { return &pe_hdr ()->OptionalHeader; } + PIMAGE_DATA_DIRECTORY idata_dir (DWORD which) + { + PIMAGE_OPTIONAL_HEADER32 oh = optional_hdr (); + return (which < oh->NumberOfRvaAndSizes)? oh->DataDirectory + which : 0; + } +}; + extern dll_list dlls; void dll_global_dtors (); |