1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5
6//
7
8#include "common.h"
9#include "peimagelayout.h"
10#include "peimagelayout.inl"
11
12#ifndef DACCESS_COMPILE
13PEImageLayout* PEImageLayout::CreateFlat(const void *flat, COUNT_T size,PEImage* pOwner)
14{
15 STANDARD_VM_CONTRACT;
16 return new RawImageLayout(flat,size,pOwner);
17}
18
19
20PEImageLayout* PEImageLayout::CreateFromHMODULE(HMODULE hModule,PEImage* pOwner, BOOL bTakeOwnership)
21{
22 CONTRACTL
23 {
24 THROWS;
25 GC_TRIGGERS;
26 MODE_ANY;
27 }
28 CONTRACTL_END;
29 return new RawImageLayout(hModule,pOwner,bTakeOwnership,TRUE);
30}
31
32PEImageLayout* PEImageLayout::LoadFromFlat(PEImageLayout* pflatimage)
33{
34 STANDARD_VM_CONTRACT;
35 return new ConvertedImageLayout(pflatimage);
36}
37
38PEImageLayout* PEImageLayout::Load(PEImage* pOwner, BOOL bNTSafeLoad, BOOL bThrowOnError)
39{
40 STANDARD_VM_CONTRACT;
41
42#if defined(CROSSGEN_COMPILE) || defined(FEATURE_PAL)
43 return PEImageLayout::Map(pOwner->GetFileHandle(), pOwner);
44#else
45 PEImageLayoutHolder pAlloc(new LoadedImageLayout(pOwner,bNTSafeLoad,bThrowOnError));
46 if (pAlloc->GetBase()==NULL)
47 return NULL;
48 return pAlloc.Extract();
49#endif
50}
51
52PEImageLayout* PEImageLayout::LoadFlat(HANDLE hFile,PEImage* pOwner)
53{
54 STANDARD_VM_CONTRACT;
55 return new FlatImageLayout(hFile,pOwner);
56}
57
58PEImageLayout* PEImageLayout::Map(HANDLE hFile, PEImage* pOwner)
59{
60 CONTRACT(PEImageLayout*)
61 {
62 THROWS;
63 GC_TRIGGERS;
64 MODE_ANY;
65 PRECONDITION(CheckPointer(pOwner));
66 POSTCONDITION(CheckPointer(RETVAL));
67 POSTCONDITION(RETVAL->CheckFormat());
68 }
69 CONTRACT_END;
70
71 PEImageLayoutHolder pAlloc(new MappedImageLayout(hFile,pOwner));
72 if (pAlloc->GetBase()==NULL)
73 {
74 //cross-platform or a bad image
75 PEImageLayoutHolder pFlat(new FlatImageLayout(hFile, pOwner));
76 if (!pFlat->CheckFormat())
77 ThrowHR(COR_E_BADIMAGEFORMAT);
78
79 pAlloc=new ConvertedImageLayout(pFlat);
80 }
81 else
82 if(!pAlloc->CheckFormat())
83 ThrowHR(COR_E_BADIMAGEFORMAT);
84 RETURN pAlloc.Extract();
85}
86
87#ifdef FEATURE_PREJIT
88
89#ifdef FEATURE_PAL
90DWORD SectionCharacteristicsToPageProtection(UINT characteristics)
91{
92 _ASSERTE((characteristics & VAL32(IMAGE_SCN_MEM_READ)) != 0);
93 DWORD pageProtection;
94
95 if ((characteristics & VAL32(IMAGE_SCN_MEM_WRITE)) != 0)
96 {
97 if ((characteristics & VAL32(IMAGE_SCN_MEM_EXECUTE)) != 0)
98 {
99 pageProtection = PAGE_EXECUTE_READWRITE;
100 }
101 else
102 {
103 pageProtection = PAGE_READWRITE;
104 }
105 }
106 else
107 {
108 if ((characteristics & VAL32(IMAGE_SCN_MEM_EXECUTE)) != 0)
109 {
110 pageProtection = PAGE_EXECUTE_READ;
111 }
112 else
113 {
114 pageProtection = PAGE_READONLY;
115 }
116 }
117
118 return pageProtection;
119}
120#endif // FEATURE_PAL
121
122//To force base relocation on Vista (which uses ASLR), unmask IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
123//(0x40) for OptionalHeader.DllCharacteristics
124void PEImageLayout::ApplyBaseRelocations()
125{
126 STANDARD_VM_CONTRACT;
127
128 SetRelocated();
129
130 //
131 // Note that this is not a univeral routine for applying relocations. It handles only the subset
132 // required by NGen images. Also, it assumes that the image format is valid.
133 //
134
135 SSIZE_T delta = (SIZE_T) GetBase() - (SIZE_T) GetPreferredBase();
136
137 // Nothing to do - image is loaded at preferred base
138 if (delta == 0)
139 return;
140
141 LOG((LF_LOADER, LL_INFO100, "PEImage: Applying base relocations (preferred: %x, actual: %x)\n",
142 GetPreferredBase(), GetBase()));
143
144 COUNT_T dirSize;
145 TADDR dir = GetDirectoryEntryData(IMAGE_DIRECTORY_ENTRY_BASERELOC, &dirSize);
146
147 // Minimize number of calls to VirtualProtect by keeping a whole section unprotected at a time.
148 BYTE * pWriteableRegion = NULL;
149 SIZE_T cbWriteableRegion = 0;
150 DWORD dwOldProtection = 0;
151
152 BYTE * pFlushRegion = NULL;
153 SIZE_T cbFlushRegion = 0;
154 // The page size of PE file relocs is always 4096 bytes
155 const SIZE_T cbPageSize = 4096;
156
157 COUNT_T dirPos = 0;
158 while (dirPos < dirSize)
159 {
160 PIMAGE_BASE_RELOCATION r = (PIMAGE_BASE_RELOCATION)(dir + dirPos);
161
162 COUNT_T fixupsSize = VAL32(r->SizeOfBlock);
163
164 USHORT *fixups = (USHORT *) (r + 1);
165
166 _ASSERTE(fixupsSize > sizeof(IMAGE_BASE_RELOCATION));
167 _ASSERTE((fixupsSize - sizeof(IMAGE_BASE_RELOCATION)) % 2 == 0);
168
169 COUNT_T fixupsCount = (fixupsSize - sizeof(IMAGE_BASE_RELOCATION)) / 2;
170
171 _ASSERTE((BYTE *)(fixups + fixupsCount) <= (BYTE *)(dir + dirSize));
172
173 DWORD rva = VAL32(r->VirtualAddress);
174
175 BYTE * pageAddress = (BYTE *)GetBase() + rva;
176
177 // Check whether the page is outside the unprotected region
178 if ((SIZE_T)(pageAddress - pWriteableRegion) >= cbWriteableRegion)
179 {
180 // Restore the protection
181 if (dwOldProtection != 0)
182 {
183 BOOL bExecRegion = (dwOldProtection & (PAGE_EXECUTE | PAGE_EXECUTE_READ |
184 PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0;
185
186 if (!ClrVirtualProtect(pWriteableRegion, cbWriteableRegion,
187 dwOldProtection, &dwOldProtection))
188 ThrowLastError();
189
190 dwOldProtection = 0;
191 }
192
193 USHORT fixup = VAL16(fixups[0]);
194
195 IMAGE_SECTION_HEADER *pSection = RvaToSection(rva + (fixup & 0xfff));
196 PREFIX_ASSUME(pSection != NULL);
197
198 pWriteableRegion = (BYTE*)GetRvaData(VAL32(pSection->VirtualAddress));
199 cbWriteableRegion = VAL32(pSection->SizeOfRawData);
200
201 // Unprotect the section if it is not writable
202 if (((pSection->Characteristics & VAL32(IMAGE_SCN_MEM_WRITE)) == 0))
203 {
204 DWORD dwNewProtection = PAGE_READWRITE;
205#if defined(FEATURE_PAL) && !defined(CROSSGEN_COMPILE)
206 if (((pSection->Characteristics & VAL32(IMAGE_SCN_MEM_EXECUTE)) != 0))
207 {
208 // On SELinux, we cannot change protection that doesn't have execute access rights
209 // to one that has it, so we need to set the protection to RWX instead of RW
210 dwNewProtection = PAGE_EXECUTE_READWRITE;
211 }
212#endif // FEATURE_PAL && !CROSSGEN_COMPILE
213 if (!ClrVirtualProtect(pWriteableRegion, cbWriteableRegion,
214 dwNewProtection, &dwOldProtection))
215 ThrowLastError();
216#ifdef FEATURE_PAL
217 dwOldProtection = SectionCharacteristicsToPageProtection(pSection->Characteristics);
218#endif // FEATURE_PAL
219 }
220 }
221
222 BYTE* pEndAddressToFlush = NULL;
223 for (COUNT_T fixupIndex = 0; fixupIndex < fixupsCount; fixupIndex++)
224 {
225 USHORT fixup = VAL16(fixups[fixupIndex]);
226
227 BYTE * address = pageAddress + (fixup & 0xfff);
228
229 switch (fixup>>12)
230 {
231 case IMAGE_REL_BASED_PTR:
232 *(TADDR *)address += delta;
233 pEndAddressToFlush = max(pEndAddressToFlush, address + sizeof(TADDR));
234 break;
235
236#ifdef _TARGET_ARM_
237 case IMAGE_REL_BASED_THUMB_MOV32:
238 PutThumb2Mov32((UINT16 *)address, GetThumb2Mov32((UINT16 *)address) + (INT32)delta);
239 pEndAddressToFlush = max(pEndAddressToFlush, address + 8);
240 break;
241#endif
242
243 case IMAGE_REL_BASED_ABSOLUTE:
244 //no adjustment
245 break;
246
247 default:
248 _ASSERTE(!"Unhandled reloc type!");
249 }
250 }
251
252 BOOL bExecRegion = (dwOldProtection & (PAGE_EXECUTE | PAGE_EXECUTE_READ |
253 PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0;
254
255 if (bExecRegion && pEndAddressToFlush != NULL)
256 {
257 // If the current page is not next to the pending region to flush, flush the current pending region and start a new one
258 if (pageAddress >= pFlushRegion + cbFlushRegion + cbPageSize || pageAddress < pFlushRegion)
259 {
260 if (pFlushRegion != NULL)
261 {
262 ClrFlushInstructionCache(pFlushRegion, cbFlushRegion);
263 }
264 pFlushRegion = pageAddress;
265 }
266
267 cbFlushRegion = pEndAddressToFlush - pFlushRegion;
268 }
269
270 dirPos += fixupsSize;
271 }
272 _ASSERTE(dirSize == dirPos);
273
274#ifndef CROSSGEN_COMPILE
275 if (dwOldProtection != 0)
276 {
277 BOOL bExecRegion = (dwOldProtection & (PAGE_EXECUTE | PAGE_EXECUTE_READ |
278 PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0;
279
280 // Restore the protection
281 if (!ClrVirtualProtect(pWriteableRegion, cbWriteableRegion,
282 dwOldProtection, &dwOldProtection))
283 ThrowLastError();
284 }
285#endif // CROSSGEN_COMPILE
286
287 if (pFlushRegion != NULL)
288 {
289 ClrFlushInstructionCache(pFlushRegion, cbFlushRegion);
290 }
291}
292#endif // FEATURE_PREJIT
293
294
295RawImageLayout::RawImageLayout(const void *flat, COUNT_T size,PEImage* pOwner)
296{
297 CONTRACTL
298 {
299 CONSTRUCTOR_CHECK;
300 THROWS;
301 GC_TRIGGERS;
302 MODE_ANY;
303 INJECT_FAULT(COMPlusThrowOM(););
304 }
305 CONTRACTL_END;
306 m_pOwner=pOwner;
307 m_Layout=LAYOUT_FLAT;
308
309 if (size)
310 {
311 HandleHolder mapping(WszCreateFileMapping(INVALID_HANDLE_VALUE, NULL,
312 PAGE_READWRITE, 0,
313 size, NULL));
314 if (mapping==NULL)
315 ThrowLastError();
316 m_DataCopy.Assign(CLRMapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 0));
317 if(m_DataCopy==NULL)
318 ThrowLastError();
319 memcpy(m_DataCopy,flat,size);
320 flat=m_DataCopy;
321 }
322 TESTHOOKCALL(ImageMapped(GetPath(),flat,IM_FLAT));
323 Init((void*)flat,size);
324}
325RawImageLayout::RawImageLayout(const void *mapped, PEImage* pOwner, BOOL bTakeOwnership, BOOL bFixedUp)
326{
327 CONTRACTL
328 {
329 CONSTRUCTOR_CHECK;
330 THROWS;
331 GC_TRIGGERS;
332 MODE_ANY;
333 INJECT_FAULT(COMPlusThrowOM(););
334 }
335 CONTRACTL_END;
336 m_pOwner=pOwner;
337 m_Layout=LAYOUT_MAPPED;
338
339 if (bTakeOwnership)
340 {
341#ifndef FEATURE_PAL
342 PathString wszDllName;
343 WszGetModuleFileName((HMODULE)mapped, wszDllName);
344
345 m_LibraryHolder=CLRLoadLibraryEx(wszDllName,NULL,GetLoadWithAlteredSearchPathFlag());
346#else // !FEATURE_PAL
347 _ASSERTE(!"bTakeOwnership Should not be used on FEATURE_PAL");
348#endif // !FEATURE_PAL
349 }
350
351 TESTHOOKCALL(ImageMapped(GetPath(),mapped,bFixedUp?IM_IMAGEMAP|IM_FIXEDUP:IM_IMAGEMAP));
352 IfFailThrow(Init((void*)mapped,(bool)(bFixedUp!=FALSE)));
353}
354
355ConvertedImageLayout::ConvertedImageLayout(PEImageLayout* source)
356{
357 CONTRACTL
358 {
359 CONSTRUCTOR_CHECK;
360 STANDARD_VM_CHECK;
361 }
362 CONTRACTL_END;
363 m_Layout=LAYOUT_LOADED;
364 m_pOwner=source->m_pOwner;
365 _ASSERTE(!source->IsMapped());
366
367 if (!source->HasNTHeaders())
368 EEFileLoadException::Throw(GetPath(), COR_E_BADIMAGEFORMAT);
369 LOG((LF_LOADER, LL_INFO100, "PEImage: Opening manually mapped stream\n"));
370
371
372 m_FileMap.Assign(WszCreateFileMapping(INVALID_HANDLE_VALUE, NULL,
373 PAGE_READWRITE, 0,
374 source->GetVirtualSize(), NULL));
375 if (m_FileMap == NULL)
376 ThrowLastError();
377
378
379 m_FileView.Assign(CLRMapViewOfFileEx(m_FileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0,
380 (void *) source->GetPreferredBase()));
381 if (m_FileView == NULL)
382 m_FileView.Assign(CLRMapViewOfFile(m_FileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0));
383
384 if (m_FileView == NULL)
385 ThrowLastError();
386
387 source->LayoutILOnly(m_FileView, TRUE); //@TODO should be false for streams
388 TESTHOOKCALL(ImageMapped(GetPath(),m_FileView,IM_IMAGEMAP));
389 IfFailThrow(Init(m_FileView));
390
391#ifdef CROSSGEN_COMPILE
392 if (HasNativeHeader())
393 ApplyBaseRelocations();
394#endif
395}
396
397MappedImageLayout::MappedImageLayout(HANDLE hFile, PEImage* pOwner)
398{
399 CONTRACTL
400 {
401 CONSTRUCTOR_CHECK;
402 STANDARD_VM_CHECK;
403 }
404 CONTRACTL_END;
405 m_Layout=LAYOUT_MAPPED;
406 m_pOwner=pOwner;
407
408 // If mapping was requested, try to do SEC_IMAGE mapping
409 LOG((LF_LOADER, LL_INFO100, "PEImage: Opening OS mapped %S (hFile %p)\n", (LPCWSTR) GetPath(), hFile));
410
411#ifndef FEATURE_PAL
412
413
414 // Let OS map file for us
415
416 // This may fail on e.g. cross-platform (32/64) loads.
417 m_FileMap.Assign(WszCreateFileMapping(hFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL));
418 if (m_FileMap == NULL)
419 {
420#ifndef CROSSGEN_COMPILE
421
422 // Capture last error as it may get reset below.
423
424 DWORD dwLastError = GetLastError();
425 // There is no reflection-only load on CoreCLR and so we can always throw an error here.
426 // It is important on Windows Phone. All assemblies that we load must have SEC_IMAGE set
427 // so that the OS can perform signature verification.
428 if (pOwner->IsFile())
429 {
430 EEFileLoadException::Throw(pOwner->GetPathForErrorMessages(), HRESULT_FROM_WIN32(dwLastError));
431 }
432 else
433 {
434 // Throw generic exception.
435 ThrowWin32(dwLastError);
436 }
437
438#endif // CROSSGEN_COMPILE
439
440 return;
441 }
442
443#ifdef _DEBUG
444 // Force relocs by occuping the preferred base while the actual mapping is performed
445 CLRMapViewHolder forceRelocs;
446 if (PEDecoder::GetForceRelocs())
447 {
448 forceRelocs.Assign(CLRMapViewOfFile(m_FileMap, 0, 0, 0, 0));
449 }
450#endif // _DEBUG
451
452 m_FileView.Assign(CLRMapViewOfFile(m_FileMap, 0, 0, 0, 0));
453 if (m_FileView == NULL)
454 ThrowLastError();
455 TESTHOOKCALL(ImageMapped(GetPath(),m_FileView,IM_IMAGEMAP));
456 IfFailThrow(Init((void *) m_FileView));
457
458#ifdef CROSSGEN_COMPILE
459 //Do base relocation for PE. Unlike LoadLibrary, MapViewOfFile will not do that for us even with SEC_IMAGE
460 if (pOwner->IsTrustedNativeImage())
461 {
462 // This should never happen in correctly setup system, but do a quick check right anyway to
463 // avoid running too far with bogus data
464
465 if (!HasCorHeader())
466 ThrowHR(COR_E_BADIMAGEFORMAT);
467
468 // For phone, we need to be permissive of MSIL assemblies pretending to be native images,
469 // to support forced fall back to JIT
470 // if (!HasNativeHeader())
471 // ThrowHR(COR_E_BADIMAGEFORMAT);
472
473 if (HasNativeHeader() && g_fAllowNativeImages)
474 {
475 if (!IsNativeMachineFormat())
476 ThrowHR(COR_E_BADIMAGEFORMAT);
477
478 ApplyBaseRelocations();
479 }
480 }
481 else
482#endif
483 if (!IsNativeMachineFormat() && !IsI386())
484 {
485 //can't rely on the image
486 Reset();
487 return;
488 }
489
490#ifdef _DEBUG
491 if (forceRelocs != NULL)
492 {
493 forceRelocs.Release();
494
495 if (CheckNTHeaders()) {
496 // Reserve the space so nobody can use it. A potential bug is likely to
497 // result in a plain AV this way. It is not a good idea to use the original
498 // mapping for the reservation since since it would lock the file on the disk.
499
500 // ignore any errors
501 ClrVirtualAlloc((void*)GetPreferredBase(), GetVirtualSize(), MEM_RESERVE, PAGE_NOACCESS);
502 }
503 }
504#endif // _DEBUG
505
506#else //!FEATURE_PAL
507
508#ifndef CROSSGEN_COMPILE
509 m_LoadedFile = PAL_LOADLoadPEFile(hFile);
510
511 if (m_LoadedFile == NULL)
512 {
513 // For CoreCLR, try to load all files via LoadLibrary first. If LoadLibrary did not work, retry using
514 // regular mapping - but not for native images.
515 if (pOwner->IsTrustedNativeImage())
516 ThrowHR(E_FAIL); // we don't have any indication of what kind of failure. Possibly a corrupt image.
517 return;
518 }
519
520 LOG((LF_LOADER, LL_INFO1000, "PEImage: image %S (hFile %p) mapped @ %p\n",
521 (LPCWSTR) GetPath(), hFile, (void*)m_LoadedFile));
522
523 TESTHOOKCALL(ImageMapped(GetPath(),m_LoadedFile,IM_IMAGEMAP));
524 IfFailThrow(Init((void *) m_LoadedFile));
525
526 if (!HasCorHeader())
527 ThrowHR(COR_E_BADIMAGEFORMAT);
528
529 if ((HasNativeHeader() || HasReadyToRunHeader()) && g_fAllowNativeImages)
530 {
531 //Do base relocation for PE, if necessary.
532 if (!IsNativeMachineFormat())
533 ThrowHR(COR_E_BADIMAGEFORMAT);
534
535 ApplyBaseRelocations();
536 SetRelocated();
537 }
538
539#else // !CROSSGEN_COMPILE
540 m_LoadedFile = NULL;
541#endif // !CROSSGEN_COMPILE
542
543#endif // !FEATURE_PAL
544}
545
546#if !defined(CROSSGEN_COMPILE) && !defined(FEATURE_PAL)
547LoadedImageLayout::LoadedImageLayout(PEImage* pOwner, BOOL bNTSafeLoad, BOOL bThrowOnError)
548{
549 CONTRACTL
550 {
551 CONSTRUCTOR_CHECK;
552 STANDARD_VM_CHECK;
553 PRECONDITION(CheckPointer(pOwner));
554 }
555 CONTRACTL_END;
556
557 m_Layout=LAYOUT_LOADED;
558 m_pOwner=pOwner;
559
560 DWORD dwFlags = GetLoadWithAlteredSearchPathFlag();
561 if (bNTSafeLoad)
562 dwFlags|=DONT_RESOLVE_DLL_REFERENCES;
563
564 m_Module = CLRLoadLibraryEx(pOwner->GetPath(), NULL, dwFlags);
565 if (m_Module == NULL)
566 {
567 if (!bThrowOnError)
568 return;
569
570 // Fetch the HRESULT upfront before anybody gets a chance to corrupt it
571 HRESULT hr = HRESULT_FROM_GetLastError();
572 EEFileLoadException::Throw(pOwner->GetPath(), hr, NULL);
573 }
574 TESTHOOKCALL(ImageMapped(GetPath(),m_Module,IM_LOADLIBRARY));
575 IfFailThrow(Init(m_Module,true));
576
577 LOG((LF_LOADER, LL_INFO1000, "PEImage: Opened HMODULE %S\n", (LPCWSTR) GetPath()));
578}
579#endif // !CROSSGEN_COMPILE && !FEATURE_PAL
580
581FlatImageLayout::FlatImageLayout(HANDLE hFile, PEImage* pOwner)
582{
583 CONTRACTL
584 {
585 CONSTRUCTOR_CHECK;
586 STANDARD_VM_CHECK;
587 PRECONDITION(CheckPointer(pOwner));
588 }
589 CONTRACTL_END;
590 m_Layout=LAYOUT_FLAT;
591 m_pOwner=pOwner;
592 LOG((LF_LOADER, LL_INFO100, "PEImage: Opening flat %S\n", (LPCWSTR) GetPath()));
593
594 COUNT_T size = SafeGetFileSize(hFile, NULL);
595 if (size == 0xffffffff && GetLastError() != NOERROR)
596 {
597 ThrowLastError();
598 }
599
600 // It's okay if resource files are length zero
601 if (size > 0)
602 {
603 m_FileMap.Assign(WszCreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL));
604 if (m_FileMap == NULL)
605 ThrowLastError();
606
607 m_FileView.Assign(CLRMapViewOfFile(m_FileMap, FILE_MAP_READ, 0, 0, 0));
608 if (m_FileView == NULL)
609 ThrowLastError();
610 }
611 TESTHOOKCALL(ImageMapped(GetPath(),m_FileView,IM_FLAT));
612 Init(m_FileView, size);
613}
614
615
616#endif // !DACESS_COMPILE
617
618
619
620#ifdef DACCESS_COMPILE
621void
622PEImageLayout::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
623{
624 WRAPPER_NO_CONTRACT;
625 DAC_ENUM_VTHIS();
626 EMEM_OUT(("MEM: %p PEFile\n", dac_cast<TADDR>(this)));
627 PEDecoder::EnumMemoryRegions(flags,false);
628}
629#endif //DACCESS_COMPILE
630