* 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