3 Functions to get info and load PE/COFF image.
5 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
6 Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include <Common/UefiBaseTypes.h>
12 #include <CommonLib.h>
13 #include <IndustryStandard/PeImage.h>
14 #include "PeCoffLib.h"
18 EFI_IMAGE_OPTIONAL_HEADER32
*Optional32
;
19 EFI_IMAGE_OPTIONAL_HEADER64
*Optional64
;
20 } EFI_IMAGE_OPTIONAL_HEADER_POINTER
;
24 PeCoffLoaderGetPeHeader (
25 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
26 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION
**PeHdr
,
27 OUT EFI_TE_IMAGE_HEADER
**TeHdr
32 PeCoffLoaderCheckImageType (
33 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
34 IN EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
,
35 IN EFI_TE_IMAGE_HEADER
*TeHdr
40 PeCoffLoaderImageAddress (
41 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
46 PeCoffLoaderRelocateIa32Image (
49 IN OUT CHAR8
**FixupData
,
55 PeCoffLoaderRelocateArmImage (
58 IN OUT CHAR8
**FixupData
,
64 PeCoffLoaderGetPeHeader (
65 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
66 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION
**PeHdr
,
67 OUT EFI_TE_IMAGE_HEADER
**TeHdr
73 Retrieves the PE or TE Header from a PE/COFF or TE image
77 ImageContext - The context of the image being loaded
79 PeHdr - The buffer in which to return the PE header
81 TeHdr - The buffer in which to return the TE header
85 RETURN_SUCCESS if the PE or TE Header is read,
86 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
91 EFI_IMAGE_DOS_HEADER DosHdr
;
94 ImageContext
->IsTeImage
= FALSE
;
96 // Read the DOS image headers
98 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
99 Status
= ImageContext
->ImageRead (
100 ImageContext
->Handle
,
105 if (RETURN_ERROR (Status
)) {
106 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
110 ImageContext
->PeCoffHeaderOffset
= 0;
111 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
113 // DOS image header is present, so read the PE header after the DOS image header
115 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
118 // Get the PE/COFF Header pointer
120 *PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINTN
)ImageContext
->Handle
+ ImageContext
->PeCoffHeaderOffset
);
121 if ((*PeHdr
)->Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
123 // Check the PE/COFF Header Signature. If not, then try to get a TE header
125 *TeHdr
= (EFI_TE_IMAGE_HEADER
*)*PeHdr
;
126 if ((*TeHdr
)->Signature
!= EFI_TE_IMAGE_HEADER_SIGNATURE
) {
127 return RETURN_UNSUPPORTED
;
129 ImageContext
->IsTeImage
= TRUE
;
132 return RETURN_SUCCESS
;
137 PeCoffLoaderCheckImageType (
138 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
139 IN EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
,
140 IN EFI_TE_IMAGE_HEADER
*TeHdr
146 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
150 ImageContext - The context of the image being loaded
152 PeHdr - The buffer in which to return the PE header
154 TeHdr - The buffer in which to return the TE header
158 RETURN_SUCCESS if the PE/COFF or TE image is supported
159 RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported.
164 // See if the machine type is supported.
165 // We support a native machine type (IA-32/Itanium-based)
167 if (ImageContext
->IsTeImage
== FALSE
) {
168 ImageContext
->Machine
= PeHdr
->Pe32
.FileHeader
.Machine
;
170 ImageContext
->Machine
= TeHdr
->Machine
;
173 if (ImageContext
->Machine
!= EFI_IMAGE_MACHINE_IA32
&& \
174 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_X64
&& \
175 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_ARMT
&& \
176 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_EBC
&& \
177 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_AARCH64
) {
178 if (ImageContext
->Machine
== IMAGE_FILE_MACHINE_ARM
) {
180 // There are two types of ARM images. Pure ARM and ARM/Thumb.
181 // If we see the ARM say it is the ARM/Thumb so there is only
182 // a single machine type we need to check for ARM.
184 ImageContext
->Machine
= EFI_IMAGE_MACHINE_ARMT
;
185 if (ImageContext
->IsTeImage
== FALSE
) {
186 PeHdr
->Pe32
.FileHeader
.Machine
= ImageContext
->Machine
;
188 TeHdr
->Machine
= ImageContext
->Machine
;
193 // unsupported PeImage machine type
195 return RETURN_UNSUPPORTED
;
200 // See if the image type is supported. We support EFI Applications,
201 // EFI Boot Service Drivers, EFI Runtime Drivers and EFI SAL Drivers.
203 if (ImageContext
->IsTeImage
== FALSE
) {
204 ImageContext
->ImageType
= PeHdr
->Pe32
.OptionalHeader
.Subsystem
;
206 ImageContext
->ImageType
= (UINT16
) (TeHdr
->Subsystem
);
209 if (ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
&& \
210 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
&& \
211 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
&& \
212 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
) {
214 // unsupported PeImage subsystem type
216 return RETURN_UNSUPPORTED
;
219 return RETURN_SUCCESS
;
224 PeCoffLoaderGetImageInfo (
225 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
231 Retrieves information on a PE/COFF image
235 This - Calling context
236 ImageContext - The context of the image being loaded
240 RETURN_SUCCESS - The information on the PE/COFF image was collected.
241 RETURN_INVALID_PARAMETER - ImageContext is NULL.
242 RETURN_UNSUPPORTED - The PE/COFF image is not supported.
243 Otherwise - The error status from reading the PE/COFF image using the
244 ImageContext->ImageRead() function
248 RETURN_STATUS Status
;
249 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
250 EFI_TE_IMAGE_HEADER
*TeHdr
;
251 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
254 UINTN DebugDirectoryEntryRva
;
255 UINTN DebugDirectoryEntryFileOffset
;
256 UINTN SectionHeaderOffset
;
257 EFI_IMAGE_SECTION_HEADER SectionHeader
;
258 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
259 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
263 DebugDirectoryEntry
= NULL
;
264 DebugDirectoryEntryRva
= 0;
266 if (NULL
== ImageContext
) {
267 return RETURN_INVALID_PARAMETER
;
272 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
274 Status
= PeCoffLoaderGetPeHeader (ImageContext
, &PeHdr
, &TeHdr
);
275 if (RETURN_ERROR (Status
)) {
280 // Verify machine type
282 Status
= PeCoffLoaderCheckImageType (ImageContext
, PeHdr
, TeHdr
);
283 if (RETURN_ERROR (Status
)) {
286 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
289 // Retrieve the base address of the image
291 if (!(ImageContext
->IsTeImage
)) {
292 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
293 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) OptionHeader
.Optional32
->ImageBase
;
295 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) OptionHeader
.Optional64
->ImageBase
;
298 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) (TeHdr
->ImageBase
+ TeHdr
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
301 // Initialize the alternate destination address to 0 indicating that it
302 // should not be used.
304 ImageContext
->DestinationAddress
= 0;
307 // Initialize the codeview pointer.
309 ImageContext
->CodeView
= NULL
;
310 ImageContext
->PdbPointer
= NULL
;
313 // Three cases with regards to relocations:
314 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
315 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
316 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
317 // has no base relocs to apply
318 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
320 // Look at the file header to determine if relocations have been stripped, and
321 // save this info in the image context for later use.
323 if ((!(ImageContext
->IsTeImage
)) && ((PeHdr
->Pe32
.FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
324 ImageContext
->RelocationsStripped
= TRUE
;
325 } else if ((ImageContext
->IsTeImage
) && (TeHdr
->DataDirectory
[0].Size
== 0) && (TeHdr
->DataDirectory
[0].VirtualAddress
== 0)) {
326 ImageContext
->RelocationsStripped
= TRUE
;
328 ImageContext
->RelocationsStripped
= FALSE
;
331 if (!(ImageContext
->IsTeImage
)) {
333 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
334 ImageContext
->ImageSize
= (UINT64
) OptionHeader
.Optional32
->SizeOfImage
;
335 ImageContext
->SectionAlignment
= OptionHeader
.Optional32
->SectionAlignment
;
336 ImageContext
->SizeOfHeaders
= OptionHeader
.Optional32
->SizeOfHeaders
;
339 // Modify ImageSize to contain .PDB file name if required and initialize
342 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
343 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
344 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
347 ImageContext
->ImageSize
= (UINT64
) OptionHeader
.Optional64
->SizeOfImage
;
348 ImageContext
->SectionAlignment
= OptionHeader
.Optional64
->SectionAlignment
;
349 ImageContext
->SizeOfHeaders
= OptionHeader
.Optional64
->SizeOfHeaders
;
352 // Modify ImageSize to contain .PDB file name if required and initialize
355 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
356 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
357 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
361 if (DebugDirectoryEntryRva
!= 0) {
363 // Determine the file offset of the debug directory... This means we walk
364 // the sections to find which section contains the RVA of the debug
367 DebugDirectoryEntryFileOffset
= 0;
369 SectionHeaderOffset
= (UINTN
)(
370 ImageContext
->PeCoffHeaderOffset
+
372 sizeof (EFI_IMAGE_FILE_HEADER
) +
373 PeHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
376 for (Index
= 0; Index
< PeHdr
->Pe32
.FileHeader
.NumberOfSections
; Index
++) {
378 // Read section header from file
380 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
381 Status
= ImageContext
->ImageRead (
382 ImageContext
->Handle
,
387 if (RETURN_ERROR (Status
)) {
388 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
392 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
393 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
394 DebugDirectoryEntryFileOffset
=
395 DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
399 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
402 if (DebugDirectoryEntryFileOffset
!= 0) {
403 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
405 // Read next debug directory entry
407 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
408 Status
= ImageContext
->ImageRead (
409 ImageContext
->Handle
,
410 DebugDirectoryEntryFileOffset
+ Index
,
414 if (RETURN_ERROR (Status
)) {
415 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
419 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
420 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
421 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
422 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
425 return RETURN_SUCCESS
;
431 ImageContext
->ImageSize
= 0;
432 ImageContext
->SectionAlignment
= 4096;
433 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
) TeHdr
->BaseOfCode
- (UINTN
) TeHdr
->StrippedSize
;
435 DebugDirectoryEntry
= &TeHdr
->DataDirectory
[1];
436 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
437 SectionHeaderOffset
= (UINTN
) (sizeof (EFI_TE_IMAGE_HEADER
));
439 DebugDirectoryEntryFileOffset
= 0;
441 for (Index
= 0; Index
< TeHdr
->NumberOfSections
;) {
443 // Read section header from file
445 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
446 Status
= ImageContext
->ImageRead (
447 ImageContext
->Handle
,
452 if (RETURN_ERROR (Status
)) {
453 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
457 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
458 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
459 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
460 SectionHeader
.VirtualAddress
+
461 SectionHeader
.PointerToRawData
+
462 sizeof (EFI_TE_IMAGE_HEADER
) -
466 // File offset of the debug directory was found, if this is not the last
467 // section, then skip to the last section for calculating the image size.
469 if (Index
< (UINTN
) TeHdr
->NumberOfSections
- 1) {
470 SectionHeaderOffset
+= (TeHdr
->NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
471 Index
= TeHdr
->NumberOfSections
- 1;
477 // In Te image header there is not a field to describe the ImageSize.
478 // Actually, the ImageSize equals the RVA plus the VirtualSize of
479 // the last section mapped into memory (Must be rounded up to
480 // a multiple of Section Alignment). Per the PE/COFF specification, the
481 // section headers in the Section Table must appear in order of the RVA
482 // values for the corresponding sections. So the ImageSize can be determined
483 // by the RVA and the VirtualSize of the last section header in the
486 if ((++Index
) == (UINTN
) TeHdr
->NumberOfSections
) {
487 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
+
488 ImageContext
->SectionAlignment
- 1) & ~(ImageContext
->SectionAlignment
- 1);
491 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
494 if (DebugDirectoryEntryFileOffset
!= 0) {
495 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
497 // Read next debug directory entry
499 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
500 Status
= ImageContext
->ImageRead (
501 ImageContext
->Handle
,
502 DebugDirectoryEntryFileOffset
,
506 if (RETURN_ERROR (Status
)) {
507 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
511 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
512 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
513 return RETURN_SUCCESS
;
519 return RETURN_SUCCESS
;
524 PeCoffLoaderImageAddress (
525 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
532 Converts an image address to the loaded address
536 ImageContext - The context of the image being loaded
538 Address - The address to be converted to the loaded address
542 NULL if the address can not be converted, otherwise, the converted address
546 if (Address
>= ImageContext
->ImageSize
) {
547 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
551 return (UINT8
*) ((UINTN
) ImageContext
->ImageAddress
+ Address
);
556 PeCoffLoaderRelocateImage (
557 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
563 Relocates a PE/COFF image in memory
567 This - Calling context
569 ImageContext - Contains information on the loaded image to relocate
573 RETURN_SUCCESS if the PE/COFF image was relocated
574 RETURN_LOAD_ERROR if the image is not a valid PE/COFF image
575 RETURN_UNSUPPORTED not support
579 RETURN_STATUS Status
;
580 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
581 EFI_TE_IMAGE_HEADER
*TeHdr
;
582 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
584 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
585 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
594 PHYSICAL_ADDRESS BaseAddress
;
596 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
603 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
606 // If there are no relocation entries, then we are done
608 if (ImageContext
->RelocationsStripped
) {
609 return RETURN_SUCCESS
;
613 // Use DestinationAddress field of ImageContext as the relocation address even if it is 0.
615 BaseAddress
= ImageContext
->DestinationAddress
;
617 if (!(ImageContext
->IsTeImage
)) {
618 PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)((UINTN
)ImageContext
->ImageAddress
+
619 ImageContext
->PeCoffHeaderOffset
);
620 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
621 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
622 Adjust
= (UINT64
) BaseAddress
- OptionHeader
.Optional32
->ImageBase
;
623 OptionHeader
.Optional32
->ImageBase
= (UINT32
) BaseAddress
;
624 MachineType
= ImageContext
->Machine
;
626 // Find the relocation block
628 // Per the PE/COFF spec, you can't assume that a given data directory
629 // is present in the image. You have to check the NumberOfRvaAndSizes in
630 // the optional header to verify a desired directory entry is there.
632 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
633 RelocDir
= &OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
634 if ((RelocDir
!= NULL
) && (RelocDir
->Size
> 0)) {
635 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
636 RelocBaseEnd
= PeCoffLoaderImageAddress (
638 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
640 if (RelocBase
== NULL
|| RelocBaseEnd
== NULL
|| RelocBaseEnd
< RelocBase
) {
641 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
642 return RETURN_LOAD_ERROR
;
646 // Set base and end to bypass processing below.
648 RelocBase
= RelocBaseEnd
= 0;
652 // Set base and end to bypass processing below.
654 RelocBase
= RelocBaseEnd
= 0;
657 Adjust
= (UINT64
) BaseAddress
- OptionHeader
.Optional64
->ImageBase
;
658 OptionHeader
.Optional64
->ImageBase
= BaseAddress
;
659 MachineType
= ImageContext
->Machine
;
661 // Find the relocation block
663 // Per the PE/COFF spec, you can't assume that a given data directory
664 // is present in the image. You have to check the NumberOfRvaAndSizes in
665 // the optional header to verify a desired directory entry is there.
667 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
668 RelocDir
= &OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
669 if ((RelocDir
!= NULL
) && (RelocDir
->Size
> 0)) {
670 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
671 RelocBaseEnd
= PeCoffLoaderImageAddress (
673 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
675 if (RelocBase
== NULL
|| RelocBaseEnd
== NULL
|| RelocBaseEnd
< RelocBase
) {
676 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
677 return RETURN_LOAD_ERROR
;
681 // Set base and end to bypass processing below.
683 RelocBase
= RelocBaseEnd
= 0;
687 // Set base and end to bypass processing below.
689 RelocBase
= RelocBaseEnd
= 0;
693 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
694 Adjust
= (UINT64
) (BaseAddress
- TeHdr
->ImageBase
);
695 TeHdr
->ImageBase
= (UINT64
) (BaseAddress
);
696 MachineType
= TeHdr
->Machine
;
699 // Find the relocation block
701 RelocDir
= &TeHdr
->DataDirectory
[0];
702 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(
703 ImageContext
->ImageAddress
+
704 RelocDir
->VirtualAddress
+
705 sizeof(EFI_TE_IMAGE_HEADER
) -
708 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) ((UINTN
) RelocBase
+ (UINTN
) RelocDir
->Size
- 1);
712 // Run the relocation information and apply the fixups
714 FixupData
= ImageContext
->FixupData
;
715 while (RelocBase
< RelocBaseEnd
) {
717 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
718 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
719 if (!(ImageContext
->IsTeImage
)) {
720 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
);
721 if (FixupBase
== NULL
) {
722 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
723 return RETURN_LOAD_ERROR
;
726 FixupBase
= (CHAR8
*)(UINTN
)(ImageContext
->ImageAddress
+
727 RelocBase
->VirtualAddress
+
728 sizeof(EFI_TE_IMAGE_HEADER
) -
733 if ((CHAR8
*) RelocEnd
< (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
) ||
734 (CHAR8
*) RelocEnd
> (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+
735 (UINTN
)ImageContext
->ImageSize
)) {
736 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
737 return RETURN_LOAD_ERROR
;
741 // Run this relocation record
743 while (Reloc
< RelocEnd
) {
745 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
746 switch ((*Reloc
) >> 12) {
747 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
750 case EFI_IMAGE_REL_BASED_HIGH
:
751 F16
= (UINT16
*) Fixup
;
752 *F16
= (UINT16
) (*F16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
753 if (FixupData
!= NULL
) {
754 *(UINT16
*) FixupData
= *F16
;
755 FixupData
= FixupData
+ sizeof (UINT16
);
759 case EFI_IMAGE_REL_BASED_LOW
:
760 F16
= (UINT16
*) Fixup
;
761 *F16
= (UINT16
) (*F16
+ (UINT16
) Adjust
);
762 if (FixupData
!= NULL
) {
763 *(UINT16
*) FixupData
= *F16
;
764 FixupData
= FixupData
+ sizeof (UINT16
);
768 case EFI_IMAGE_REL_BASED_HIGHLOW
:
769 F32
= (UINT32
*) Fixup
;
770 *F32
= *F32
+ (UINT32
) Adjust
;
771 if (FixupData
!= NULL
) {
772 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
773 *(UINT32
*) FixupData
= *F32
;
774 FixupData
= FixupData
+ sizeof (UINT32
);
778 case EFI_IMAGE_REL_BASED_DIR64
:
779 F64
= (UINT64
*) Fixup
;
780 *F64
= *F64
+ (UINT64
) Adjust
;
781 if (FixupData
!= NULL
) {
782 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT64
));
783 *(UINT64
*) FixupData
= *F64
;
784 FixupData
= FixupData
+ sizeof (UINT64
);
788 case EFI_IMAGE_REL_BASED_HIGHADJ
:
790 // Return the same EFI_UNSUPPORTED return code as
791 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
792 // the relocation type.
794 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
795 return RETURN_UNSUPPORTED
;
798 switch (MachineType
) {
799 case EFI_IMAGE_MACHINE_IA32
:
800 Status
= PeCoffLoaderRelocateIa32Image (Reloc
, Fixup
, &FixupData
, Adjust
);
802 case EFI_IMAGE_MACHINE_ARMT
:
803 Status
= PeCoffLoaderRelocateArmImage (&Reloc
, Fixup
, &FixupData
, Adjust
);
806 Status
= RETURN_UNSUPPORTED
;
809 if (RETURN_ERROR (Status
)) {
810 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
816 // Next relocation record
824 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
827 return RETURN_SUCCESS
;
832 PeCoffLoaderLoadImage (
833 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
839 Loads a PE/COFF image into memory
843 This - Calling context
845 ImageContext - Contains information on image to load into memory
849 RETURN_SUCCESS if the PE/COFF image was loaded
850 RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
851 RETURN_LOAD_ERROR if the image is a runtime driver with no relocations
852 RETURN_INVALID_PARAMETER if the image address is invalid
856 RETURN_STATUS Status
;
857 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
858 EFI_TE_IMAGE_HEADER
*TeHdr
;
859 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
860 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
861 EFI_IMAGE_SECTION_HEADER
*Section
;
862 UINTN NumberOfSections
;
867 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
868 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
870 UINT32 TempDebugEntryRva
;
871 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
875 OptionHeader
.Header
= NULL
;
879 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
882 // Copy the provided context info into our local version, get what we
883 // can from the original image, and then use that to make sure everything
886 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
888 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
889 if (RETURN_ERROR (Status
)) {
894 // Make sure there is enough allocated space for the image being loaded
896 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
897 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
898 return RETURN_BUFFER_TOO_SMALL
;
902 // If there's no relocations, then make sure it's not a runtime driver,
903 // and that it's being loaded at the linked address.
905 if (CheckContext
.RelocationsStripped
) {
907 // If the image does not contain relocations and it is a runtime driver
908 // then return an error.
910 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
911 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
912 return RETURN_LOAD_ERROR
;
915 // If the image does not contain relocations, and the requested load address
916 // is not the linked address, then return an error.
918 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
919 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
920 return RETURN_INVALID_PARAMETER
;
924 // Make sure the allocated space has the proper section alignment
926 if (!(ImageContext
->IsTeImage
)) {
927 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
928 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
929 return RETURN_INVALID_PARAMETER
;
933 // Read the entire PE/COFF or TE header into memory
935 if (!(ImageContext
->IsTeImage
)) {
936 Status
= ImageContext
->ImageRead (
937 ImageContext
->Handle
,
939 &ImageContext
->SizeOfHeaders
,
940 (VOID
*) (UINTN
) ImageContext
->ImageAddress
943 PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)
944 ((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
946 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
948 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
949 (UINTN
)ImageContext
->ImageAddress
+
950 ImageContext
->PeCoffHeaderOffset
+
952 sizeof(EFI_IMAGE_FILE_HEADER
) +
953 PeHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
955 NumberOfSections
= (UINTN
) (PeHdr
->Pe32
.FileHeader
.NumberOfSections
);
957 Status
= ImageContext
->ImageRead (
958 ImageContext
->Handle
,
960 &ImageContext
->SizeOfHeaders
,
961 (VOID
*) (UINTN
) ImageContext
->ImageAddress
964 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
966 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
967 (UINTN
)ImageContext
->ImageAddress
+
968 sizeof(EFI_TE_IMAGE_HEADER
)
970 NumberOfSections
= (UINTN
) (TeHdr
->NumberOfSections
);
974 if (RETURN_ERROR (Status
)) {
975 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
976 return RETURN_LOAD_ERROR
;
980 // Load each section of the image
982 Section
= FirstSection
;
983 for (Index
= 0, MaxEnd
= NULL
; Index
< NumberOfSections
; Index
++) {
986 // Compute sections address
988 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
);
989 End
= PeCoffLoaderImageAddress (
991 Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1
995 // If the base start or end address resolved to 0, then fail.
997 if ((Base
== NULL
) || (End
== NULL
)) {
998 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
999 return RETURN_LOAD_ERROR
;
1003 if (ImageContext
->IsTeImage
) {
1004 Base
= (CHAR8
*) ((UINTN
) Base
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
1005 End
= (CHAR8
*) ((UINTN
) End
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
1015 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
1016 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
1017 Size
= (UINTN
) Section
->SizeOfRawData
;
1020 if (Section
->SizeOfRawData
) {
1021 if (!(ImageContext
->IsTeImage
)) {
1022 Status
= ImageContext
->ImageRead (
1023 ImageContext
->Handle
,
1024 Section
->PointerToRawData
,
1029 Status
= ImageContext
->ImageRead (
1030 ImageContext
->Handle
,
1031 Section
->PointerToRawData
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
,
1037 if (RETURN_ERROR (Status
)) {
1038 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1044 // If raw size is less then virt size, zero fill the remaining
1047 if (Size
< Section
->Misc
.VirtualSize
) {
1048 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
1058 // Get image's entry point
1060 if (!(ImageContext
->IsTeImage
)) {
1061 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (
1063 PeHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
1066 ImageContext
->EntryPoint
= (UINTN
)ImageContext
->ImageAddress
+
1067 (UINTN
)TeHdr
->AddressOfEntryPoint
+
1068 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1069 (UINTN
) TeHdr
->StrippedSize
;
1073 // Determine the size of the fixup data
1075 // Per the PE/COFF spec, you can't assume that a given data directory
1076 // is present in the image. You have to check the NumberOfRvaAndSizes in
1077 // the optional header to verify a desired directory entry is there.
1079 if (!(ImageContext
->IsTeImage
)) {
1080 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1081 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1082 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
1083 &OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1084 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1086 ImageContext
->FixupDataSize
= 0;
1089 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1090 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
1091 &OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1092 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1094 ImageContext
->FixupDataSize
= 0;
1098 DirectoryEntry
= &TeHdr
->DataDirectory
[0];
1099 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1102 // Consumer must allocate a buffer for the relocation fixup log.
1103 // Only used for runtime drivers.
1105 ImageContext
->FixupData
= NULL
;
1108 // Load the Codeview info if present
1110 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
1111 if (!(ImageContext
->IsTeImage
)) {
1112 DebugEntry
= PeCoffLoaderImageAddress (
1114 ImageContext
->DebugDirectoryEntryRva
1117 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(UINTN
)(
1118 ImageContext
->ImageAddress
+
1119 ImageContext
->DebugDirectoryEntryRva
+
1120 sizeof(EFI_TE_IMAGE_HEADER
) -
1125 if (DebugEntry
!= NULL
) {
1126 TempDebugEntryRva
= DebugEntry
->RVA
;
1127 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
1129 if ((UINTN
) Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
1130 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
1132 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
1136 if (TempDebugEntryRva
!= 0) {
1137 if (!(ImageContext
->IsTeImage
)) {
1138 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
);
1140 ImageContext
->CodeView
= (VOID
*)(
1141 (UINTN
)ImageContext
->ImageAddress
+
1142 (UINTN
)TempDebugEntryRva
+
1143 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1144 (UINTN
) TeHdr
->StrippedSize
1148 if (ImageContext
->CodeView
== NULL
) {
1149 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1150 return RETURN_LOAD_ERROR
;
1153 if (DebugEntry
->RVA
== 0) {
1154 Size
= DebugEntry
->SizeOfData
;
1155 if (!(ImageContext
->IsTeImage
)) {
1156 Status
= ImageContext
->ImageRead (
1157 ImageContext
->Handle
,
1158 DebugEntry
->FileOffset
,
1160 ImageContext
->CodeView
1163 Status
= ImageContext
->ImageRead (
1164 ImageContext
->Handle
,
1165 DebugEntry
->FileOffset
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHdr
->StrippedSize
,
1167 ImageContext
->CodeView
1170 // Should we apply fix up to this field according to the size difference between PE and TE?
1171 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1172 // in original PE image.
1176 if (RETURN_ERROR (Status
)) {
1177 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1178 return RETURN_LOAD_ERROR
;
1181 DebugEntry
->RVA
= TempDebugEntryRva
;
1184 switch (*(UINT32
*) ImageContext
->CodeView
) {
1185 case CODEVIEW_SIGNATURE_NB10
:
1186 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1189 case CODEVIEW_SIGNATURE_RSDS
:
1190 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
1193 case CODEVIEW_SIGNATURE_MTOC
:
1194 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
);
1207 Returns a pointer to the PDB file name for a raw PE/COFF image that is not
1208 loaded into system memory with the PE/COFF Loader Library functions.
1210 Returns the PDB file name for the PE/COFF image specified by Pe32Data. If
1211 the PE/COFF image specified by Pe32Data is not a valid, then NULL is
1212 returned. If the PE/COFF image specified by Pe32Data does not contain a
1213 debug directory entry, then NULL is returned. If the debug directory entry
1214 in the PE/COFF image specified by Pe32Data does not contain a PDB file name,
1215 then NULL is returned.
1216 If Pe32Data is NULL, then return NULL.
1218 @param Pe32Data Pointer to the PE/COFF image that is loaded in system
1221 @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL
1222 if it cannot be retrieved.
1227 PeCoffLoaderGetPdbPointer (
1231 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1232 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1233 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
1234 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
1236 VOID
*CodeViewEntryPointer
;
1238 UINT32 NumberOfRvaAndSizes
;
1240 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
1241 UINT32 Index
, Index1
;
1243 if (Pe32Data
== NULL
) {
1248 DirectoryEntry
= NULL
;
1250 NumberOfRvaAndSizes
= 0;
1253 SectionHeader
= NULL
;
1255 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)Pe32Data
;
1256 if (EFI_IMAGE_DOS_SIGNATURE
== DosHdr
->e_magic
) {
1258 // DOS image header is present, so read the PE header after the DOS image header.
1260 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
) Pe32Data
+ (UINTN
) ((DosHdr
->e_lfanew
) & 0x0ffff));
1263 // DOS image header is not present, so PE header is at the image base.
1265 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)Pe32Data
;
1268 if (EFI_TE_IMAGE_HEADER_SIGNATURE
== Hdr
.Te
->Signature
) {
1269 if (Hdr
.Te
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
!= 0) {
1270 DirectoryEntry
= &Hdr
.Te
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
];
1271 TEImageAdjust
= sizeof (EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->StrippedSize
;
1274 // Get the DebugEntry offset in the raw data image.
1276 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (Hdr
.Te
+ 1);
1277 Index
= Hdr
.Te
->NumberOfSections
;
1278 for (Index1
= 0; Index1
< Index
; Index1
++) {
1279 if ((DirectoryEntry
->VirtualAddress
>= SectionHeader
[Index1
].VirtualAddress
) &&
1280 (DirectoryEntry
->VirtualAddress
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1281 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)((UINTN
) Hdr
.Te
+
1282 DirectoryEntry
->VirtualAddress
-
1283 SectionHeader
[Index1
].VirtualAddress
+
1284 SectionHeader
[Index1
].PointerToRawData
+
1290 } else if (EFI_IMAGE_NT_SIGNATURE
== Hdr
.Pe32
->Signature
) {
1292 // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.
1293 // It is due to backward-compatibility, for some system might
1294 // generate PE32+ image with PE32 Magic.
1296 switch (Hdr
.Pe32
->FileHeader
.Machine
) {
1297 case EFI_IMAGE_MACHINE_IA32
:
1298 case EFI_IMAGE_MACHINE_ARMT
:
1300 // Assume PE32 image with IA32 Machine field.
1302 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
1304 case EFI_IMAGE_MACHINE_X64
:
1306 // Assume PE32+ image with X64 Machine field
1308 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
1312 // For unknown Machine field, use Magic in optional Header
1314 Magic
= Hdr
.Pe32
->OptionalHeader
.Magic
;
1317 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
1318 (UINT8
*) Hdr
.Pe32
+
1320 sizeof (EFI_IMAGE_FILE_HEADER
) +
1321 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
1323 Index
= Hdr
.Pe32
->FileHeader
.NumberOfSections
;
1325 if (EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
== Magic
) {
1327 // Use PE32 offset get Debug Directory Entry
1329 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1330 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
1331 } else if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
1333 // Use PE32+ offset get Debug Directory Entry
1335 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1336 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
1339 if (NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
|| DirectoryEntry
->VirtualAddress
== 0) {
1340 DirectoryEntry
= NULL
;
1344 // Get the DebugEntry offset in the raw data image.
1346 for (Index1
= 0; Index1
< Index
; Index1
++) {
1347 if ((DirectoryEntry
->VirtualAddress
>= SectionHeader
[Index1
].VirtualAddress
) &&
1348 (DirectoryEntry
->VirtualAddress
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1349 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*) (
1351 DirectoryEntry
->VirtualAddress
-
1352 SectionHeader
[Index1
].VirtualAddress
+
1353 SectionHeader
[Index1
].PointerToRawData
);
1362 if (NULL
== DebugEntry
|| NULL
== DirectoryEntry
) {
1367 // Scan the directory to find the debug entry.
1369 for (DirCount
= 0; DirCount
< DirectoryEntry
->Size
; DirCount
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
), DebugEntry
++) {
1370 if (EFI_IMAGE_DEBUG_TYPE_CODEVIEW
== DebugEntry
->Type
) {
1371 if (DebugEntry
->SizeOfData
> 0) {
1373 // Get the DebugEntry offset in the raw data image.
1375 CodeViewEntryPointer
= NULL
;
1376 for (Index1
= 0; Index1
< Index
; Index1
++) {
1377 if ((DebugEntry
->RVA
>= SectionHeader
[Index1
].VirtualAddress
) &&
1378 (DebugEntry
->RVA
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1379 CodeViewEntryPointer
= (VOID
*) (
1381 (UINTN
) DebugEntry
->RVA
-
1382 SectionHeader
[Index1
].VirtualAddress
+
1383 SectionHeader
[Index1
].PointerToRawData
+
1384 (UINTN
)TEImageAdjust
);
1388 if (Index1
>= Index
) {
1390 // Can't find CodeViewEntryPointer in raw PE/COFF image.
1394 switch (* (UINT32
*) CodeViewEntryPointer
) {
1395 case CODEVIEW_SIGNATURE_NB10
:
1396 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
));
1397 case CODEVIEW_SIGNATURE_RSDS
:
1398 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
));
1399 case CODEVIEW_SIGNATURE_MTOC
:
1400 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
));
1414 PeCoffLoaderGetEntryPoint (
1416 OUT VOID
**EntryPoint
,
1417 OUT VOID
**BaseOfImage
1420 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1421 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1423 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)Pe32Data
;
1424 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
1426 // DOS image header is present, so read the PE header after the DOS image header.
1428 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
) Pe32Data
+ (UINTN
) ((DosHdr
->e_lfanew
) & 0x0ffff));
1431 // DOS image header is not present, so PE header is at the image base.
1433 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)Pe32Data
;
1437 // Calculate the entry point relative to the start of the image.
1438 // AddressOfEntryPoint is common for PE32 & PE32+
1440 if (Hdr
.Te
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
1441 *BaseOfImage
= (VOID
*)(UINTN
)(Hdr
.Te
->ImageBase
+ Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
1442 *EntryPoint
= (VOID
*)((UINTN
)*BaseOfImage
+ (Hdr
.Te
->AddressOfEntryPoint
& 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->StrippedSize
);
1443 return RETURN_SUCCESS
;
1444 } else if (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
) {
1445 *EntryPoint
= (VOID
*)(UINTN
)Hdr
.Pe32
->OptionalHeader
.AddressOfEntryPoint
;
1446 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1447 *BaseOfImage
= (VOID
*)(UINTN
)Hdr
.Pe32
->OptionalHeader
.ImageBase
;
1449 *BaseOfImage
= (VOID
*)(UINTN
)Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
1451 *EntryPoint
= (VOID
*)(UINTN
)((UINTN
)*EntryPoint
+ (UINTN
)*BaseOfImage
);
1452 return RETURN_SUCCESS
;
1455 return RETURN_UNSUPPORTED
;