aboutsummaryrefslogtreecommitdiff
path: root/winsup/cygwin/dll_init.cc
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2009-06-07 07:26:07 +0000
committerCorinna Vinschen <corinna@vinschen.de>2009-06-07 07:26:07 +0000
commitcf2e7e9cbcda91783b81de4ecec07116e8c2e641 (patch)
tree3c1f123047ed93bbefad90ef12db8ae943f5926e /winsup/cygwin/dll_init.cc
parentf985cc1c535516836e4bb323b0498255ce7a8b6b (diff)
downloadnewlib-cf2e7e9cbcda91783b81de4ecec07116e8c2e641.zip
newlib-cf2e7e9cbcda91783b81de4ecec07116e8c2e641.tar.gz
newlib-cf2e7e9cbcda91783b81de4ecec07116e8c2e641.tar.bz2
* 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.
Diffstat (limited to 'winsup/cygwin/dll_init.cc')
-rw-r--r--winsup/cygwin/dll_init.cc89
1 files changed, 64 insertions, 25 deletions
diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc
index e42718d..5b026c7 100644
--- a/winsup/cygwin/dll_init.cc
+++ b/winsup/cygwin/dll_init.cc
@@ -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;
-
- if (r)
- n = ((n - r) + 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.
+
+ 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.
+
+ 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
- /* 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)
+ 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;
}
}