3 Copyright (c) 2005 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
27 #include "PeCoffLoaderEx.h"
29 #ifdef EFI_NT_EMULATOR
31 #include "EfiHobLib.h"
32 #include EFI_PPI_DEFINITION (NtLoadAsDll)
37 PeCoffLoaderGetPeHeader (
38 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
39 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
44 PeCoffLoaderImageAddress (
45 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
51 PeCoffLoaderGetImageInfo (
52 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
53 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
58 PeCoffLoaderRelocateImage (
59 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
60 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
65 PeCoffLoaderLoadImage (
66 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
67 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
72 PeCoffLoaderUnloadImage (
73 IN EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
76 #if defined (EFI_DEBUG_ITP_BREAK) && !defined (_CONSOLE)
78 AsmEfiSetBreakSupport (
83 EFI_PEI_PE_COFF_LOADER_PROTOCOL mPeCoffLoader
= {
84 PeCoffLoaderGetImageInfo
,
85 PeCoffLoaderLoadImage
,
86 PeCoffLoaderRelocateImage
,
87 PeCoffLoaderUnloadImage
90 #ifdef EFI_NT_EMULATOR
91 EFI_NT_LOAD_AS_DLL_PPI
*mPeCoffLoaderWinNtLoadAsDll
= NULL
;
95 InstallEfiPeiPeCoffLoader (
96 IN EFI_PEI_SERVICES
**PeiServices
,
97 IN OUT EFI_PEI_PE_COFF_LOADER_PROTOCOL
**This
,
98 IN EFI_PEI_PPI_DESCRIPTOR
*ThisPpi
104 Install PE/COFF loader PPI
108 PeiServices - General purpose services available to every PEIM
110 This - Pointer to get Pei PE coff loader protocol as output
112 ThisPpi - Passed in as EFI_NT_LOAD_AS_DLL_PPI on NT_EMULATOR platform
122 Status
= EFI_SUCCESS
;
124 #ifdef EFI_NT_EMULATOR
126 // For use by PEI Core and Modules
128 if (NULL
!= PeiServices
) {
129 Status
= (**PeiServices
).LocatePpi (
131 &gEfiNtLoadAsDllPpiGuid
,
134 &mPeCoffLoaderWinNtLoadAsDll
138 // Now in SecMain or ERM usage, bind appropriately
140 PEI_ASSERT (PeiServices
, (NULL
!= ThisPpi
));
142 mPeCoffLoaderWinNtLoadAsDll
= (EFI_NT_LOAD_AS_DLL_PPI
*) ThisPpi
;
143 PEI_ASSERT (PeiServices
, (NULL
!= mPeCoffLoaderWinNtLoadAsDll
));
148 *This
= &mPeCoffLoader
;
156 PeCoffLoaderGetPeHeader (
157 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
158 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
164 Retrieves the PE or TE Header from a PE/COFF or TE image
168 ImageContext - The context of the image being loaded
170 PeHdr - The buffer in which to return the PE32, PE32+, or TE header
174 EFI_SUCCESS if the PE or TE Header is read,
175 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
180 EFI_IMAGE_DOS_HEADER DosHdr
;
185 // Read the DOS image header to check for it's existance
187 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
188 Status
= ImageContext
->ImageRead (
189 ImageContext
->Handle
,
194 if (EFI_ERROR (Status
)) {
195 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
199 ImageContext
->PeCoffHeaderOffset
= 0;
200 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
202 // DOS image header is present, so read the PE header after the DOS image
205 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
209 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
210 // data, but that should not hurt anythine. Hdr.Pe32->OptionalHeader.Magic
211 // determins if this is a PE32 or PE32+ image. The magic is in the same
212 // location in both images.
214 Size
= sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
);
215 Status
= ImageContext
->ImageRead (
216 ImageContext
->Handle
,
217 ImageContext
->PeCoffHeaderOffset
,
221 if (EFI_ERROR (Status
)) {
222 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
227 // Use Signature to figure out if we understand the image format
229 if (Hdr
.Te
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
230 ImageContext
->IsTeImage
= TRUE
;
231 ImageContext
->Machine
= Hdr
.Te
->Machine
;
232 ImageContext
->ImageType
= (UINT16
)(Hdr
.Te
->Subsystem
);
233 ImageContext
->ImageSize
= 0;
234 ImageContext
->SectionAlignment
= 4096;
235 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
)Hdr
.Te
->BaseOfCode
- (UINTN
)Hdr
.Te
->StrippedSize
;
237 } else if (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
) {
238 ImageContext
->IsTeImage
= FALSE
;
239 ImageContext
->Machine
= Hdr
.Pe32
->FileHeader
.Machine
;
242 // NOTE: We use Machine to identify PE32/PE32+, instead of Magic.
243 // It is for backward-compatibility consideration, because
244 // some system will generate PE32+ image with PE32 Magic.
246 if (Hdr
.Pe32
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA32
) {
247 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
248 } else if (Hdr
.Pe32
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA64
) {
249 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
250 } else if (Hdr
.Pe32
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_X64
) {
251 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
253 Magic
= Hdr
.Pe32
->OptionalHeader
.Magic
;
256 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
||
257 Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
259 // PE32 and PE32+ have the same offset for these fields.
260 // We use PE32 for both PE32 and PE32+ headers here.
262 ImageContext
->ImageType
= Hdr
.Pe32
->OptionalHeader
.Subsystem
;
263 ImageContext
->ImageSize
= (UINT64
)Hdr
.Pe32
->OptionalHeader
.SizeOfImage
;
264 ImageContext
->SectionAlignment
= Hdr
.Pe32
->OptionalHeader
.SectionAlignment
;
265 ImageContext
->SizeOfHeaders
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
;
268 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_MACHINE_TYPE
;
269 return EFI_UNSUPPORTED
;
272 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_MACHINE_TYPE
;
273 return EFI_UNSUPPORTED
;
276 if (!PeCoffLoaderImageFormatSupported (ImageContext
->Machine
)) {
278 // If the PE/COFF loader does not support the image type return
279 // unsupported. This library can suport lots of types of images
280 // this does not mean the user of this library can call the entry
281 // point of the image.
283 return EFI_UNSUPPORTED
;
291 PeCoffLoaderCheckImageType (
292 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
298 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
302 ImageContext - The context of the image being loaded
306 EFI_SUCCESS if the PE/COFF or TE image is supported
307 EFI_UNSUPPORTED of the PE/COFF or TE image is not supported.
311 switch (ImageContext
->ImageType
) {
313 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
:
314 ImageContext
->ImageCodeMemoryType
= EfiLoaderCode
;
315 ImageContext
->ImageDataMemoryType
= EfiLoaderData
;
318 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
:
319 ImageContext
->ImageCodeMemoryType
= EfiBootServicesCode
;
320 ImageContext
->ImageDataMemoryType
= EfiBootServicesData
;
323 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
324 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
:
325 ImageContext
->ImageCodeMemoryType
= EfiRuntimeServicesCode
;
326 ImageContext
->ImageDataMemoryType
= EfiRuntimeServicesData
;
330 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_SUBSYSTEM
;
331 return EFI_UNSUPPORTED
;
339 PeCoffLoaderGetImageInfo (
340 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
341 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
347 Retrieves information on a PE/COFF image
351 This - Calling context
353 ImageContext - The context of the image being loaded
357 EFI_SUCCESS if the information on the PE/COFF image was collected.
358 EFI_UNSUPPORTED of the PE/COFF image is not supported.
359 Otherwise, the error status from reading the PE/COFF image using the
360 ImageContext->ImageRead() function
362 EFI_INVALID_PARAMETER - ImageContext is NULL.
367 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
368 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
369 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
372 UINTN DebugDirectoryEntryRva
;
373 UINTN DebugDirectoryEntryFileOffset
;
374 UINTN SectionHeaderOffset
;
375 EFI_IMAGE_SECTION_HEADER SectionHeader
;
376 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
377 UINT32 NumberOfRvaAndSizes
;
380 if (NULL
== ImageContext
) {
381 return EFI_INVALID_PARAMETER
;
387 ImageContext
->ImageError
= EFI_IMAGE_ERROR_SUCCESS
;
389 Hdr
.Union
= &HdrData
;
390 Status
= PeCoffLoaderGetPeHeader (ImageContext
, Hdr
);
391 if (EFI_ERROR (Status
)) {
396 // Verify machine type
398 Status
= PeCoffLoaderCheckImageType (ImageContext
);
399 if (EFI_ERROR (Status
)) {
403 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
406 // Retrieve the base address of the image
408 if (!(ImageContext
->IsTeImage
)) {
411 // NOTE: We use Machine to identify PE32/PE32+, instead of Magic.
412 // It is for backward-compatibility consideration, because
413 // some system will generate PE32+ image with PE32 Magic.
415 if (Hdr
.Pe32
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA32
) {
416 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
417 } else if (Hdr
.Pe32
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA64
) {
418 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
419 } else if (Hdr
.Pe32
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_X64
) {
420 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
422 Magic
= Hdr
.Pe32
->OptionalHeader
.Magic
;
425 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
429 ImageContext
->ImageAddress
= Hdr
.Pe32
->OptionalHeader
.ImageBase
;
434 ImageContext
->ImageAddress
= Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
437 ImageContext
->ImageAddress
= (EFI_PHYSICAL_ADDRESS
)(Hdr
.Te
->ImageBase
);
441 // Initialize the alternate destination address to 0 indicating that it
442 // should not be used.
444 ImageContext
->DestinationAddress
= 0;
447 // Initialize the codeview pointer.
449 ImageContext
->CodeView
= NULL
;
450 ImageContext
->PdbPointer
= NULL
;
453 // Three cases with regards to relocations:
454 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
455 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
456 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
457 // has no base relocs to apply
458 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
460 // Look at the file header to determine if relocations have been stripped, and
461 // save this info in the image context for later use.
463 if ((!(ImageContext
->IsTeImage
)) && ((Hdr
.Pe32
->FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
464 ImageContext
->RelocationsStripped
= TRUE
;
466 ImageContext
->RelocationsStripped
= FALSE
;
469 if (!(ImageContext
->IsTeImage
)) {
471 // Use PE32 to access fields that have same offset in PE32 and PE32+
473 ImageContext
->ImageSize
= (UINT64
) Hdr
.Pe32
->OptionalHeader
.SizeOfImage
;
474 ImageContext
->SectionAlignment
= Hdr
.Pe32
->OptionalHeader
.SectionAlignment
;
475 ImageContext
->SizeOfHeaders
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
;
476 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
480 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
481 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
486 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
487 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
490 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
492 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
495 // Determine the file offset of the debug directory... This means we walk
496 // the sections to find which section contains the RVA of the debug
499 DebugDirectoryEntryFileOffset
= 0;
501 SectionHeaderOffset
= (UINTN
)(
502 ImageContext
->PeCoffHeaderOffset
+
504 sizeof (EFI_IMAGE_FILE_HEADER
) +
505 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
508 for (Index
= 0; Index
< Hdr
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
510 // Read section header from file
512 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
513 Status
= ImageContext
->ImageRead (
514 ImageContext
->Handle
,
519 if (EFI_ERROR (Status
)) {
520 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
524 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
525 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
527 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
531 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
534 if (DebugDirectoryEntryFileOffset
!= 0) {
535 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
++) {
537 // Read next debug directory entry
539 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
540 Status
= ImageContext
->ImageRead (
541 ImageContext
->Handle
,
542 DebugDirectoryEntryFileOffset
,
546 if (EFI_ERROR (Status
)) {
547 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
551 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
552 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
));
553 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
554 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
564 // Because Te image only extracts base relocations and debug directory entries from
565 // Pe image and in Te image header there is not a field to describe the imagesize,
566 // we use the largest VirtualAddress plus Size in each directory entry to describe the imagesize
568 ImageContext
->ImageSize
= (UINT64
) (Hdr
.Te
->DataDirectory
[0].VirtualAddress
+ Hdr
.Te
->DataDirectory
[0].Size
);
569 ImageContext
->SectionAlignment
= 4096;
570 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
) Hdr
.Te
->BaseOfCode
- (UINTN
) Hdr
.Te
->StrippedSize
;
572 DebugDirectoryEntry
= &Hdr
.Te
->DataDirectory
[1];
573 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
574 SectionHeaderOffset
= (UINTN
)(sizeof (EFI_TE_IMAGE_HEADER
));
576 DebugDirectoryEntryFileOffset
= 0;
578 for (Index
= 0; Index
< Hdr
.Te
->NumberOfSections
; Index
++) {
580 // Read section header from file
582 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
583 Status
= ImageContext
->ImageRead (
584 ImageContext
->Handle
,
589 if (EFI_ERROR (Status
)) {
590 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
594 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
595 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
596 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
597 SectionHeader
.VirtualAddress
+
598 SectionHeader
.PointerToRawData
+
599 sizeof (EFI_TE_IMAGE_HEADER
) -
600 Hdr
.Te
->StrippedSize
;
604 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
607 if (DebugDirectoryEntryFileOffset
!= 0) {
608 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
++) {
610 // Read next debug directory entry
612 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
613 Status
= ImageContext
->ImageRead (
614 ImageContext
->Handle
,
615 DebugDirectoryEntryFileOffset
,
619 if (EFI_ERROR (Status
)) {
620 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
624 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
625 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
));
637 PeCoffLoaderImageAddress (
638 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
645 Converts an image address to the loaded address
649 ImageContext - The context of the image being loaded
651 Address - The address to be converted to the loaded address
655 NULL if the address can not be converted, otherwise, the converted address
659 if (Address
>= ImageContext
->ImageSize
) {
660 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
664 return (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
+ Address
);
669 PeCoffLoaderRelocateImage (
670 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
671 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
677 Relocates a PE/COFF image in memory
681 This - Calling context
683 ImageContext - Contains information on the loaded image to relocate
687 EFI_SUCCESS if the PE/COFF image was relocated
688 EFI_LOAD_ERROR if the image is not a valid PE/COFF image
689 EFI_UNSUPPORTED not support
694 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
695 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
697 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
698 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
707 EFI_PHYSICAL_ADDRESS BaseAddress
;
708 UINT32 NumberOfRvaAndSizes
;
710 #ifdef EFI_NT_EMULATOR
717 if (NULL
== ImageContext
) {
718 return EFI_INVALID_PARAMETER
;
724 ImageContext
->ImageError
= EFI_IMAGE_ERROR_SUCCESS
;
727 // If there are no relocation entries, then we are done
729 if (ImageContext
->RelocationsStripped
) {
734 // If the destination address is not 0, use that rather than the
735 // image address as the relocation target.
737 if (ImageContext
->DestinationAddress
!= 0) {
738 BaseAddress
= ImageContext
->DestinationAddress
;
740 BaseAddress
= ImageContext
->ImageAddress
;
743 if (!(ImageContext
->IsTeImage
)) {
744 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
747 // NOTE: We use Machine to identify PE32/PE32+, instead of Magic.
748 // It is for backward-compatibility consideration, because
749 // some system will generate PE32+ image with PE32 Magic.
751 if (Hdr
.Pe32
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA32
) {
752 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
753 } else if (Hdr
.Pe32
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA64
) {
754 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
755 } else if (Hdr
.Pe32
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_X64
) {
756 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
758 Magic
= Hdr
.Pe32
->OptionalHeader
.Magic
;
761 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
765 Adjust
= (UINT64
)BaseAddress
- Hdr
.Pe32
->OptionalHeader
.ImageBase
;
766 Hdr
.Pe32
->OptionalHeader
.ImageBase
= (UINT32
)BaseAddress
;
768 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
769 RelocDir
= &Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
774 Adjust
= (UINT64
) BaseAddress
- Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
775 Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
= (UINT64
)BaseAddress
;
777 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
778 RelocDir
= &Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
782 // Find the relocation block
783 // Per the PE/COFF spec, you can't assume that a given data directory
784 // is present in the image. You have to check the NumberOfRvaAndSizes in
785 // the optional header to verify a desired directory entry is there.
788 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
789 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
790 RelocBaseEnd
= PeCoffLoaderImageAddress (
792 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
796 // Set base and end to bypass processing below.
798 RelocBase
= RelocBaseEnd
= 0;
801 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
802 Adjust
= (UINT64
) (BaseAddress
- Hdr
.Te
->ImageBase
);
803 Hdr
.Te
->ImageBase
= (UINT64
) (BaseAddress
);
806 // Find the relocation block
808 RelocDir
= &Hdr
.Te
->DataDirectory
[0];
809 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(
810 ImageContext
->ImageAddress
+
811 RelocDir
->VirtualAddress
+
812 sizeof(EFI_TE_IMAGE_HEADER
) -
815 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) ((UINTN
) RelocBase
+ (UINTN
) RelocDir
->Size
- 1);
819 // Run the relocation information and apply the fixups
821 FixupData
= ImageContext
->FixupData
;
822 while (RelocBase
< RelocBaseEnd
) {
824 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
825 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
826 if (!(ImageContext
->IsTeImage
)) {
827 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
);
829 FixupBase
= (CHAR8
*)(UINTN
)(ImageContext
->ImageAddress
+
830 RelocBase
->VirtualAddress
+
831 sizeof(EFI_TE_IMAGE_HEADER
) -
836 if ((CHAR8
*) RelocEnd
< (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
) ||
837 (CHAR8
*) RelocEnd
> (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+
838 (UINTN
)ImageContext
->ImageSize
)) {
839 ImageContext
->ImageError
= EFI_IMAGE_ERROR_FAILED_RELOCATION
;
840 return EFI_LOAD_ERROR
;
844 // Run this relocation record
846 while (Reloc
< RelocEnd
) {
848 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
849 switch ((*Reloc
) >> 12) {
850 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
853 case EFI_IMAGE_REL_BASED_HIGH
:
854 F16
= (UINT16
*) Fixup
;
855 *F16
= (UINT16
) (*F16
+ (UINT16
)(((UINT32
)Adjust
) >> 16));
856 if (FixupData
!= NULL
) {
857 *(UINT16
*) FixupData
= *F16
;
858 FixupData
= FixupData
+ sizeof (UINT16
);
862 case EFI_IMAGE_REL_BASED_LOW
:
863 F16
= (UINT16
*) Fixup
;
864 *F16
= (UINT16
) (*F16
+ (UINT16
) Adjust
);
865 if (FixupData
!= NULL
) {
866 *(UINT16
*) FixupData
= *F16
;
867 FixupData
= FixupData
+ sizeof (UINT16
);
871 case EFI_IMAGE_REL_BASED_HIGHLOW
:
872 F32
= (UINT32
*) Fixup
;
873 *F32
= *F32
+ (UINT32
) Adjust
;
874 if (FixupData
!= NULL
) {
875 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
876 *(UINT32
*) FixupData
= *F32
;
877 FixupData
= FixupData
+ sizeof (UINT32
);
881 case EFI_IMAGE_REL_BASED_DIR64
:
885 F64
= (UINT64
*) Fixup
;
886 *F64
= *F64
+ (UINT64
) Adjust
;
887 if (FixupData
!= NULL
) {
888 FixupData
= ALIGN_POINTER (FixupData
, sizeof(UINT64
));
889 *(UINT64
*)(FixupData
) = *F64
;
890 FixupData
= FixupData
+ sizeof(UINT64
);
894 case EFI_IMAGE_REL_BASED_HIGHADJ
:
896 // Return the same EFI_UNSUPPORTED return code as
897 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
898 // the relocation type.
900 ImageContext
->ImageError
= EFI_IMAGE_ERROR_FAILED_RELOCATION
;
901 return EFI_UNSUPPORTED
;
905 // The common code does not handle some of the stranger IPF relocations
906 // PeCoffLoaderRelocateImageEx () addes support for these complex fixups
907 // on IPF and is a No-Op on other archtiectures.
909 Status
= PeCoffLoaderRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
910 if (EFI_ERROR (Status
)) {
911 ImageContext
->ImageError
= EFI_IMAGE_ERROR_FAILED_RELOCATION
;
917 // Next relocation record
925 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
928 #ifdef EFI_NT_EMULATOR
929 DllEntryPoint
= NULL
;
930 ImageContext
->ModHandle
= NULL
;
932 // Load the DLL if it's not an EBC image.
934 if ((ImageContext
->PdbPointer
!= NULL
) &&
935 (ImageContext
->Machine
!= EFI_IMAGE_MACHINE_EBC
)) {
936 Status
= mPeCoffLoaderWinNtLoadAsDll
->Entry (
937 ImageContext
->PdbPointer
,
942 if (!EFI_ERROR (Status
) && DllEntryPoint
!= NULL
) {
943 ImageContext
->EntryPoint
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) DllEntryPoint
;
944 ImageContext
->ModHandle
= ModHandle
;
954 PeCoffLoaderLoadImage (
955 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
956 IN OUT EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
962 Loads a PE/COFF image into memory
966 This - Calling context
968 ImageContext - Contains information on image to load into memory
972 EFI_SUCCESS if the PE/COFF image was loaded
973 EFI_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
974 EFI_LOAD_ERROR if the image is a runtime driver with no relocations
975 EFI_INVALID_PARAMETER if the image address is invalid
980 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
981 EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
982 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
983 EFI_IMAGE_SECTION_HEADER
*Section
;
984 UINTN NumberOfSections
;
989 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
990 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
992 UINT32 TempDebugEntryRva
;
993 UINT32 NumberOfRvaAndSizes
;
996 if (NULL
== ImageContext
) {
997 return EFI_INVALID_PARAMETER
;
1003 ImageContext
->ImageError
= EFI_IMAGE_ERROR_SUCCESS
;
1006 // Copy the provided context info into our local version, get what we
1007 // can from the original image, and then use that to make sure everything
1010 CopyMem (&CheckContext
, ImageContext
, sizeof (EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
));
1012 Status
= PeCoffLoaderGetImageInfo (This
, &CheckContext
);
1013 if (EFI_ERROR (Status
)) {
1018 // Make sure there is enough allocated space for the image being loaded
1020 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
1021 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_IMAGE_SIZE
;
1022 return EFI_BUFFER_TOO_SMALL
;
1024 if (ImageContext
->ImageAddress
== 0) {
1026 // Image cannot be loaded into 0 address.
1028 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1029 return EFI_INVALID_PARAMETER
;
1032 // If there's no relocations, then make sure it's not a runtime driver,
1033 // and that it's being loaded at the linked address.
1035 if (CheckContext
.RelocationsStripped
) {
1037 // If the image does not contain relocations and it is a runtime driver
1038 // then return an error.
1040 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
1041 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_SUBSYSTEM
;
1042 return EFI_LOAD_ERROR
;
1045 // If the image does not contain relocations, and the requested load address
1046 // is not the linked address, then return an error.
1048 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
1049 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1050 return EFI_INVALID_PARAMETER
;
1054 // Make sure the allocated space has the proper section alignment
1056 if (!(ImageContext
->IsTeImage
)) {
1057 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
1058 ImageContext
->ImageError
= EFI_IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
1059 return EFI_INVALID_PARAMETER
;
1063 // Read the entire PE/COFF or TE header into memory
1065 if (!(ImageContext
->IsTeImage
)) {
1066 Status
= ImageContext
->ImageRead (
1067 ImageContext
->Handle
,
1069 &ImageContext
->SizeOfHeaders
,
1070 (VOID
*) (UINTN
) ImageContext
->ImageAddress
1073 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
1075 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
1076 (UINTN
)ImageContext
->ImageAddress
+
1077 ImageContext
->PeCoffHeaderOffset
+
1079 sizeof(EFI_IMAGE_FILE_HEADER
) +
1080 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
1082 NumberOfSections
= (UINTN
) (Hdr
.Pe32
->FileHeader
.NumberOfSections
);
1084 Status
= ImageContext
->ImageRead (
1085 ImageContext
->Handle
,
1087 &ImageContext
->SizeOfHeaders
,
1088 (VOID
*)(UINTN
)ImageContext
->ImageAddress
1091 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
1093 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
1094 (UINTN
)ImageContext
->ImageAddress
+
1095 sizeof(EFI_TE_IMAGE_HEADER
)
1097 NumberOfSections
= (UINTN
) (Hdr
.Te
->NumberOfSections
);
1101 if (EFI_ERROR (Status
)) {
1102 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
1103 return EFI_LOAD_ERROR
;
1107 // Load each section of the image
1109 Section
= FirstSection
;
1110 for (Index
= 0, MaxEnd
= NULL
; Index
< NumberOfSections
; Index
++) {
1113 // Compute sections address
1115 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
);
1116 End
= PeCoffLoaderImageAddress (
1118 Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1
1120 if (ImageContext
->IsTeImage
) {
1121 Base
= (CHAR8
*)((UINTN
) Base
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
)Hdr
.Te
->StrippedSize
);
1122 End
= (CHAR8
*)((UINTN
) End
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
)Hdr
.Te
->StrippedSize
);
1129 // If the base start or end address resolved to 0, then fail.
1131 if ((Base
== NULL
) || (End
== NULL
)) {
1132 ImageContext
->ImageError
= EFI_IMAGE_ERROR_SECTION_NOT_LOADED
;
1133 return EFI_LOAD_ERROR
;
1139 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
1140 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
1141 Size
= (UINTN
) Section
->SizeOfRawData
;
1144 if (Section
->SizeOfRawData
) {
1145 if (!(ImageContext
->IsTeImage
)) {
1146 Status
= ImageContext
->ImageRead (
1147 ImageContext
->Handle
,
1148 Section
->PointerToRawData
,
1153 Status
= ImageContext
->ImageRead (
1154 ImageContext
->Handle
,
1155 Section
->PointerToRawData
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
)Hdr
.Te
->StrippedSize
,
1161 if (EFI_ERROR (Status
)) {
1162 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
1168 // If raw size is less then virt size, zero fill the remaining
1171 if (Size
< Section
->Misc
.VirtualSize
) {
1172 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
1181 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
1184 // Get image's entry point
1186 if (!(ImageContext
->IsTeImage
)) {
1189 // NOTE: We use Machine to identify PE32/PE32+, instead of Magic.
1190 // It is for backward-compatibility consideration, because
1191 // some system will generate PE32+ image with PE32 Magic.
1193 if (Hdr
.Pe32
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA32
) {
1194 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
1195 } else if (Hdr
.Pe32
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_IA64
) {
1196 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
1197 } else if (Hdr
.Pe32
->FileHeader
.Machine
== EFI_IMAGE_MACHINE_X64
) {
1198 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
1200 Magic
= Hdr
.Pe32
->OptionalHeader
.Magic
;
1204 // Sizes of AddressOfEntryPoint are different so we need to do this safely
1206 ImageContext
->EntryPoint
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1208 (UINTN
)Hdr
.Pe32
->OptionalHeader
.AddressOfEntryPoint
1212 ImageContext
->EntryPoint
= (EFI_PHYSICAL_ADDRESS
) (
1213 (UINTN
)ImageContext
->ImageAddress
+
1214 (UINTN
)Hdr
.Te
->AddressOfEntryPoint
+
1215 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1216 (UINTN
)Hdr
.Te
->StrippedSize
1221 // Determine the size of the fixup data
1223 // Per the PE/COFF spec, you can't assume that a given data directory
1224 // is present in the image. You have to check the NumberOfRvaAndSizes in
1225 // the optional header to verify a desired directory entry is there.
1227 if (!(ImageContext
->IsTeImage
)) {
1228 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1232 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1233 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1238 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1239 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1242 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1243 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1245 ImageContext
->FixupDataSize
= 0;
1248 DirectoryEntry
= &Hdr
.Te
->DataDirectory
[0];
1249 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1252 // Consumer must allocate a buffer for the relocation fixup log.
1253 // Only used for runtime drivers.
1255 ImageContext
->FixupData
= NULL
;
1258 // Load the Codeview info if present
1260 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
1261 if (!(ImageContext
->IsTeImage
)) {
1262 DebugEntry
= PeCoffLoaderImageAddress (
1264 ImageContext
->DebugDirectoryEntryRva
1267 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(UINTN
)(
1268 ImageContext
->ImageAddress
+
1269 ImageContext
->DebugDirectoryEntryRva
+
1270 sizeof(EFI_TE_IMAGE_HEADER
) -
1271 Hdr
.Te
->StrippedSize
1275 if (DebugEntry
!= NULL
) {
1276 TempDebugEntryRva
= DebugEntry
->RVA
;
1277 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
1279 if ((UINTN
)Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
1280 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
1282 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
1286 if (TempDebugEntryRva
!= 0) {
1287 if (!(ImageContext
->IsTeImage
)) {
1288 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
);
1290 ImageContext
->CodeView
= (VOID
*)(
1291 (UINTN
)ImageContext
->ImageAddress
+
1292 (UINTN
)TempDebugEntryRva
+
1293 (UINTN
)sizeof (EFI_TE_IMAGE_HEADER
) -
1294 (UINTN
) Hdr
.Te
->StrippedSize
1298 if (ImageContext
->CodeView
== NULL
) {
1299 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
1300 return EFI_LOAD_ERROR
;
1303 if (DebugEntry
->RVA
== 0) {
1304 Size
= DebugEntry
->SizeOfData
;
1305 if (!(ImageContext
->IsTeImage
)) {
1306 Status
= ImageContext
->ImageRead (
1307 ImageContext
->Handle
,
1308 DebugEntry
->FileOffset
,
1310 ImageContext
->CodeView
1313 Status
= ImageContext
->ImageRead (
1314 ImageContext
->Handle
,
1315 DebugEntry
->FileOffset
+ sizeof (EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->StrippedSize
,
1317 ImageContext
->CodeView
1320 // Should we apply fix up to this field according to the size difference between PE and TE?
1321 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1322 // in original PE image.
1326 if (EFI_ERROR (Status
)) {
1327 ImageContext
->ImageError
= EFI_IMAGE_ERROR_IMAGE_READ
;
1328 return EFI_LOAD_ERROR
;
1331 DebugEntry
->RVA
= TempDebugEntryRva
;
1334 switch (*(UINT32
*) ImageContext
->CodeView
) {
1335 case CODEVIEW_SIGNATURE_NB10
:
1336 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1339 case CODEVIEW_SIGNATURE_RSDS
:
1340 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
1350 #if defined (EFI_DEBUG_ITP_BREAK) && !defined (_CONSOLE)
1351 AsmEfiSetBreakSupport ((UINTN
)(ImageContext
->ImageAddress
));
1359 PeCoffLoaderUnloadImage (
1360 IN EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1364 Routine Description:
1366 Unload a PE/COFF image from memory
1370 ImageContext - Contains information on image to load into memory
1378 #ifdef EFI_NT_EMULATOR
1380 // Calling Win32 API free library
1382 mPeCoffLoaderWinNtLoadAsDll
->FreeLibrary (ImageContext
->ModHandle
);