* 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, | ||||
| 	     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); | ||||
| 	  if (d) | ||||
| #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