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 |
13 | PEImageLayout* 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 | |
20 | PEImageLayout* 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 | |
32 | PEImageLayout* PEImageLayout::LoadFromFlat(PEImageLayout* pflatimage) |
33 | { |
34 | STANDARD_VM_CONTRACT; |
35 | return new ConvertedImageLayout(pflatimage); |
36 | } |
37 | |
38 | PEImageLayout* 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 | |
52 | PEImageLayout* PEImageLayout::LoadFlat(HANDLE hFile,PEImage* pOwner) |
53 | { |
54 | STANDARD_VM_CONTRACT; |
55 | return new FlatImageLayout(hFile,pOwner); |
56 | } |
57 | |
58 | PEImageLayout* 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 |
90 | DWORD 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 |
124 | void 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 | |
295 | RawImageLayout::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 | } |
325 | RawImageLayout::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 | |
355 | ConvertedImageLayout::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 | |
397 | MappedImageLayout::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) |
547 | LoadedImageLayout::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 | |
581 | FlatImageLayout::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 |
621 | void |
622 | PEImageLayout::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 | |