* 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>
|
2009-06-06 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
* mmap.cc: Use NtUnmapViewOfSection instead of UnmapViewOfFile
|
* mmap.cc: Use NtUnmapViewOfSection instead of UnmapViewOfFile
|
||||||
|
|
|
@ -21,6 +21,9 @@ details. */
|
||||||
#include "cygtls.h"
|
#include "cygtls.h"
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <alloca.h>
|
#include <alloca.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include "ntdll.h"
|
||||||
|
|
||||||
extern void __stdcall check_sanity_and_sync (per_process *);
|
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];
|
WCHAR name[NT_MAX_PATH];
|
||||||
DWORD namelen = GetModuleFileNameW (h, name, sizeof (name));
|
DWORD namelen = GetModuleFileNameW (h, name, sizeof (name));
|
||||||
size_t d_size = sizeof (dll) + namelen * sizeof (WCHAR);
|
|
||||||
|
|
||||||
/* Already loaded? */
|
/* Already loaded? */
|
||||||
dll *d = dlls[name];
|
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. */
|
return d; /* Return previously allocated pointer. */
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSTEM_INFO s1;
|
|
||||||
GetSystemInfo (&s1);
|
|
||||||
|
|
||||||
int i;
|
|
||||||
void *s = p->bss_end;
|
void *s = p->bss_end;
|
||||||
DWORD n;
|
size_t d_size = sizeof (dll) + namelen * sizeof (WCHAR);
|
||||||
|
|
||||||
MEMORY_BASIC_INFORMATION m;
|
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 */
|
/* 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)))
|
if (!VirtualQuery (s, &m, sizeof (m)))
|
||||||
return NULL; /* Can't do it. */
|
return NULL; /* Can't do it. */
|
||||||
|
@ -138,30 +143,64 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
|
||||||
if (i == RETRIES)
|
if (i == RETRIES)
|
||||||
return NULL; /* Oh well. Couldn't locate free space. */
|
return NULL; /* Oh well. Couldn't locate free space. */
|
||||||
|
|
||||||
/* Ensure that this is rounded to the nearest page boundary.
|
d = (dll *) m.BaseAddress;
|
||||||
FIXME: Should this be ensured by VirtualQuery? */
|
/* Instead of calling VirtualAlloc, which always allocates memory
|
||||||
n = (DWORD) m.BaseAddress;
|
on a 64K boundary, we allocate the memory using a section
|
||||||
DWORD r = n % s1.dwAllocationGranularity;
|
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)
|
On x86, using a section object allows us to allocate the struct
|
||||||
n = ((n - r) + s1.dwAllocationGranularity);
|
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. */
|
Of course, this doesn't help if the DLL needs all of the 64K
|
||||||
if (VirtualAlloc ((void *) n, d_size, MEM_RESERVE, PAGE_READWRITE))
|
memory slot but there's only a 1 in 16 chance for that.
|
||||||
d = (dll *) VirtualAlloc ((void *) n, d_size, MEM_COMMIT,
|
|
||||||
PAGE_READWRITE);
|
And, alas, it won't work on 64 bit systems because the
|
||||||
if (d)
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Did we succeed? */
|
/* Did we succeed? */
|
||||||
if (d == NULL)
|
if (!NT_SUCCESS (status))
|
||||||
{ /* Nope. */
|
{ /* Nope. */
|
||||||
#ifdef DEBUGGING
|
__seterrno_from_nt_status (status);
|
||||||
system_printf ("VirtualAlloc failed, %E");
|
|
||||||
#endif
|
|
||||||
__seterrno ();
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +251,7 @@ dll_list::detach (void *retaddr)
|
||||||
loaded_dlls--;
|
loaded_dlls--;
|
||||||
if (end == d)
|
if (end == d)
|
||||||
end = d->prev;
|
end = d->prev;
|
||||||
VirtualFree (d, 0, MEM_RELEASE);
|
NtUnmapViewOfSection (GetCurrentProcess (), d);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue