* dll_init.cc (dll_list::alloc): Allocate memory using a section
object. Explain why. Drop call to GetSystemInfo, rather call getpagesize to get allocation granularity. Only align to allocation granularity under WOW64. Use roundup2 to align. (dll_list::detach): Call NtUnmapViewOfSection instead of VirtualFree.
This commit is contained in:
parent
f985cc1c53
commit
cf2e7e9cbc
|
@ -1,3 +1,11 @@
|
|||
2009-06-06 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* dll_init.cc (dll_list::alloc): Allocate memory using a section
|
||||
object. Explain why. Drop call to GetSystemInfo, rather call
|
||||
getpagesize to get allocation granularity. Only align to allocation
|
||||
granularity under WOW64. Use roundup2 to align.
|
||||
(dll_list::detach): Call NtUnmapViewOfSection instead of VirtualFree.
|
||||
|
||||
2009-06-06 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* mmap.cc: Use NtUnmapViewOfSection instead of UnmapViewOfFile
|
||||
|
|
|
@ -21,6 +21,9 @@ details. */
|
|||
#include "cygtls.h"
|
||||
#include <wchar.h>
|
||||
#include <alloca.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include "ntdll.h"
|
||||
|
||||
extern void __stdcall check_sanity_and_sync (per_process *);
|
||||
|
||||
|
@ -110,7 +113,6 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
|
|||
{
|
||||
WCHAR name[NT_MAX_PATH];
|
||||
DWORD namelen = GetModuleFileNameW (h, name, sizeof (name));
|
||||
size_t d_size = sizeof (dll) + namelen * sizeof (WCHAR);
|
||||
|
||||
/* Already loaded? */
|
||||
dll *d = dlls[name];
|
||||
|
@ -120,15 +122,18 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
|
|||
return d; /* Return previously allocated pointer. */
|
||||
}
|
||||
|
||||
SYSTEM_INFO s1;
|
||||
GetSystemInfo (&s1);
|
||||
|
||||
int i;
|
||||
void *s = p->bss_end;
|
||||
DWORD n;
|
||||
size_t d_size = sizeof (dll) + namelen * sizeof (WCHAR);
|
||||
|
||||
MEMORY_BASIC_INFORMATION m;
|
||||
NTSTATUS status = 0;
|
||||
HANDLE sect_h;
|
||||
OBJECT_ATTRIBUTES oa;
|
||||
InitializeObjectAttributes (&oa, NULL, 0, NULL,
|
||||
sec_none.lpSecurityDescriptor);
|
||||
|
||||
/* Search for space after the DLL */
|
||||
for (i = 0; i <= RETRIES; i++, s = (char *) m.BaseAddress + m.RegionSize)
|
||||
for (int i = 0; i <= RETRIES; i++, s = (char *) m.BaseAddress + m.RegionSize)
|
||||
{
|
||||
if (!VirtualQuery (s, &m, sizeof (m)))
|
||||
return NULL; /* Can't do it. */
|
||||
|
@ -138,30 +143,64 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
|
|||
if (i == RETRIES)
|
||||
return NULL; /* Oh well. Couldn't locate free space. */
|
||||
|
||||
/* Ensure that this is rounded to the nearest page boundary.
|
||||
FIXME: Should this be ensured by VirtualQuery? */
|
||||
n = (DWORD) m.BaseAddress;
|
||||
DWORD r = n % s1.dwAllocationGranularity;
|
||||
d = (dll *) m.BaseAddress;
|
||||
/* Instead of calling VirtualAlloc, which always allocates memory
|
||||
on a 64K boundary, we allocate the memory using a section
|
||||
object. The disadvantage of the 64K boundary in this case is
|
||||
the fact that that boundary could be easily the start address
|
||||
of another DLL yet to load into memory.
|
||||
|
||||
if (r)
|
||||
n = ((n - r) + s1.dwAllocationGranularity);
|
||||
On x86, using a section object allows us to allocate the struct
|
||||
dll into a memory slot in the remainder of the last 64K slot of
|
||||
the DLL. This memory slot will never be used for anything
|
||||
else. Given that the struct dll will fit into a single page
|
||||
99.99% of the time anyway, this is a neat way to avoid DLL load
|
||||
address collisions in most cases.
|
||||
|
||||
/* First reserve the area of memory, then commit it. */
|
||||
if (VirtualAlloc ((void *) n, d_size, MEM_RESERVE, PAGE_READWRITE))
|
||||
d = (dll *) VirtualAlloc ((void *) n, d_size, MEM_COMMIT,
|
||||
PAGE_READWRITE);
|
||||
if (d)
|
||||
Of course, this doesn't help if the DLL needs all of the 64K
|
||||
memory slot but there's only a 1 in 16 chance for that.
|
||||
|
||||
And, alas, it won't work on 64 bit systems because the
|
||||
AT_ROUND_TO_PAGE flag required to make a page-aligned allocation
|
||||
isn't supported under WOW64. So, as with VirtualAlloc, ensure
|
||||
that address is rounded up to next 64K allocation boundary if
|
||||
running under WOW64. */
|
||||
if (wincap.is_wow64 ())
|
||||
d = (dll *) roundup2 ((uintptr_t) d, getpagesize ());
|
||||
|
||||
LARGE_INTEGER so = { QuadPart: d_size };
|
||||
status = NtCreateSection (§_h, SECTION_ALL_ACCESS, &oa, &so,
|
||||
PAGE_READWRITE, SEC_COMMIT, NULL);
|
||||
if (NT_SUCCESS (status))
|
||||
{
|
||||
ULONG viewsize = 0;
|
||||
so.QuadPart = 0;
|
||||
status = NtMapViewOfSection (sect_h, GetCurrentProcess (),
|
||||
(void **) &d, 0, d_size, &so,
|
||||
&viewsize, ViewUnmap,
|
||||
wincap.is_wow64 ()
|
||||
? 0 : AT_ROUND_TO_PAGE,
|
||||
PAGE_READWRITE);
|
||||
#ifdef DEBUGGING
|
||||
if (!NT_SUCCESS (status))
|
||||
system_printf ("NtMapViewOfSection failed, %p", status);
|
||||
#endif
|
||||
NtClose (sect_h);
|
||||
}
|
||||
#ifdef DEBUGGING
|
||||
else
|
||||
system_printf ("NtCreateSection failed, %p", status);
|
||||
#endif
|
||||
|
||||
if (NT_SUCCESS (status))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Did we succeed? */
|
||||
if (d == NULL)
|
||||
if (!NT_SUCCESS (status))
|
||||
{ /* Nope. */
|
||||
#ifdef DEBUGGING
|
||||
system_printf ("VirtualAlloc failed, %E");
|
||||
#endif
|
||||
__seterrno ();
|
||||
__seterrno_from_nt_status (status);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -212,7 +251,7 @@ dll_list::detach (void *retaddr)
|
|||
loaded_dlls--;
|
||||
if (end == d)
|
||||
end = d->prev;
|
||||
VirtualFree (d, 0, MEM_RELEASE);
|
||||
NtUnmapViewOfSection (GetCurrentProcess (), d);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue