# HG changeset patch # Parent 455fc9f558beecf89ca7bb44f1ec044a38e6acf6 diff --git a/dll_init.cc b/dll_init.cc --- a/dll_init.cc +++ b/dll_init.cc @@ -154,6 +154,8 @@ d->handle = h; d->has_dtors = true; d->p = p; + d->image_size = ((pefile*)h)->optional_hdr ()->SizeOfImage; + d->preferred_base = (void*) ((pefile*)h)->optional_hdr ()->ImageBase; d->ndeps = 0; d->deps = NULL; d->modname = wcsrchr (d->name, L'\\'); @@ -388,21 +390,33 @@ } } -/* 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 < here) + 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); @@ -480,7 +494,8 @@ 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/dll_init.h b/dll_init.h --- a/dll_init.h +++ b/dll_init.h @@ -52,6 +52,8 @@ int count; bool has_dtors; dll_type type; + DWORD image_size; + void* preferred_base; long ndeps; dll** deps; PWCHAR modname;