* 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:
Corinna Vinschen 2009-06-07 07:26:07 +00:00
parent f985cc1c53
commit cf2e7e9cbc
2 changed files with 71 additions and 24 deletions

View File

@ -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

View File

@ -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 (&sect_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;
}
}