3 Functions to get info and load PE/COFF image.
5 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
6 Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include <Common/UefiBaseTypes.h>
18 #include <CommonLib.h>
19 #include <IndustryStandard/PeImage.h>
20 #include "PeCoffLib.h"
24 EFI_IMAGE_OPTIONAL_HEADER32
*Optional32
;
25 EFI_IMAGE_OPTIONAL_HEADER64
*Optional64
;
26 } EFI_IMAGE_OPTIONAL_HEADER_POINTER
;
30 PeCoffLoaderGetPeHeader (
31 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
32 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION
**PeHdr
,
33 OUT EFI_TE_IMAGE_HEADER
**TeHdr
38 PeCoffLoaderCheckImageType (
39 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
40 IN EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
,
41 IN EFI_TE_IMAGE_HEADER
*TeHdr
46 PeCoffLoaderImageAddress (
47 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
52 PeCoffLoaderRelocateIa32Image (
55 IN OUT CHAR8
**FixupData
,
60 PeCoffLoaderRelocateX64Image (
63 IN OUT CHAR8
**FixupData
,
68 PeCoffLoaderRelocateIpfImage (
71 IN OUT CHAR8
**FixupData
,
76 PeCoffLoaderRelocateArmImage (
79 IN OUT CHAR8
**FixupData
,
84 PeCoffLoaderRelocateAArch64Image (
87 IN OUT CHAR8
**FixupData
,
93 PeCoffLoaderGetPeHeader (
94 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
95 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION
**PeHdr
,
96 OUT EFI_TE_IMAGE_HEADER
**TeHdr
102 Retrieves the PE or TE Header from a PE/COFF or TE image
106 ImageContext - The context of the image being loaded
108 PeHdr - The buffer in which to return the PE header
110 TeHdr - The buffer in which to return the TE header
114 RETURN_SUCCESS if the PE or TE Header is read,
115 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
119 RETURN_STATUS Status
;
120 EFI_IMAGE_DOS_HEADER DosHdr
;
123 ImageContext
->IsTeImage
= FALSE
;
125 // Read the DOS image headers
127 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
128 Status
= ImageContext
->ImageRead (
129 ImageContext
->Handle
,
134 if (RETURN_ERROR (Status
)) {
135 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
139 ImageContext
->PeCoffHeaderOffset
= 0;
140 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
142 // DOS image header is present, so read the PE header after the DOS image header
144 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
147 // Get the PE/COFF Header pointer
149 *PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINTN
)ImageContext
->Handle
+ ImageContext
->PeCoffHeaderOffset
);
150 if ((*PeHdr
)->Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
152 // Check the PE/COFF Header Signature. If not, then try to get a TE header
154 *TeHdr
= (EFI_TE_IMAGE_HEADER
*)*PeHdr
;
155 if ((*TeHdr
)->Signature
!= EFI_TE_IMAGE_HEADER_SIGNATURE
) {
156 return RETURN_UNSUPPORTED
;
158 ImageContext
->IsTeImage
= TRUE
;
161 return RETURN_SUCCESS
;
166 PeCoffLoaderCheckImageType (
167 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
168 IN EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
,
169 IN EFI_TE_IMAGE_HEADER
*TeHdr
175 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
179 ImageContext - The context of the image being loaded
181 PeHdr - The buffer in which to return the PE header
183 TeHdr - The buffer in which to return the TE header
187 RETURN_SUCCESS if the PE/COFF or TE image is supported
188 RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported.
193 // See if the machine type is supported.
194 // We support a native machine type (IA-32/Itanium-based)
196 if (ImageContext
->IsTeImage
== FALSE
) {
197 ImageContext
->Machine
= PeHdr
->Pe32
.FileHeader
.Machine
;
199 ImageContext
->Machine
= TeHdr
->Machine
;
202 if (ImageContext
->Machine
!= EFI_IMAGE_MACHINE_IA32
&& \
203 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_IA64
&& \
204 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_X64
&& \
205 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_ARMT
&& \
206 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_EBC
&& \
207 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_AARCH64
) {
208 if (ImageContext
->Machine
== IMAGE_FILE_MACHINE_ARM
) {
210 // There are two types of ARM images. Pure ARM and ARM/Thumb.
211 // If we see the ARM say it is the ARM/Thumb so there is only
212 // a single machine type we need to check for ARM.
214 ImageContext
->Machine
= EFI_IMAGE_MACHINE_ARMT
;
215 if (ImageContext
->IsTeImage
== FALSE
) {
216 PeHdr
->Pe32
.FileHeader
.Machine
= ImageContext
->Machine
;
218 TeHdr
->Machine
= ImageContext
->Machine
;
223 // unsupported PeImage machine type
225 return RETURN_UNSUPPORTED
;
230 // See if the image type is supported. We support EFI Applications,
231 // EFI Boot Service Drivers, EFI Runtime Drivers and EFI SAL Drivers.
233 if (ImageContext
->IsTeImage
== FALSE
) {
234 ImageContext
->ImageType
= PeHdr
->Pe32
.OptionalHeader
.Subsystem
;
236 ImageContext
->ImageType
= (UINT16
) (TeHdr
->Subsystem
);
239 if (ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
&& \
240 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
&& \
241 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
&& \
242 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
) {
244 // upsupported PeImage subsystem type
246 return RETURN_UNSUPPORTED
;
249 return RETURN_SUCCESS
;
254 PeCoffLoaderGetImageInfo (
255 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
261 Retrieves information on a PE/COFF image
265 This - Calling context
266 ImageContext - The context of the image being loaded
270 RETURN_SUCCESS - The information on the PE/COFF image was collected.
271 RETURN_INVALID_PARAMETER - ImageContext is NULL.
272 RETURN_UNSUPPORTED - The PE/COFF image is not supported.
273 Otherwise - The error status from reading the PE/COFF image using the
274 ImageContext->ImageRead() function
278 RETURN_STATUS Status
;
279 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
280 EFI_TE_IMAGE_HEADER
*TeHdr
;
281 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
284 UINTN DebugDirectoryEntryRva
;
285 UINTN DebugDirectoryEntryFileOffset
;
286 UINTN SectionHeaderOffset
;
287 EFI_IMAGE_SECTION_HEADER SectionHeader
;
288 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
289 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
293 DebugDirectoryEntry
= NULL
;
294 DebugDirectoryEntryRva
= 0;
296 if (NULL
== ImageContext
) {
297 return RETURN_INVALID_PARAMETER
;
302 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
304 Status
= PeCoffLoaderGetPeHeader (ImageContext
, &PeHdr
, &TeHdr
);
305 if (RETURN_ERROR (Status
)) {
310 // Verify machine type
312 Status
= PeCoffLoaderCheckImageType (ImageContext
, PeHdr
, TeHdr
);
313 if (RETURN_ERROR (Status
)) {
316 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
319 // Retrieve the base address of the image
321 if (!(ImageContext
->IsTeImage
)) {
322 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
323 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) OptionHeader
.Optional32
->ImageBase
;
325 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) OptionHeader
.Optional64
->ImageBase
;
328 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) (TeHdr
->ImageBase
+ TeHdr
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
331 // Initialize the alternate destination address to 0 indicating that it
332 // should not be used.
334 ImageContext
->DestinationAddress
= 0;
337 // Initialize the codeview pointer.
339 ImageContext
->CodeView
= NULL
;
340 ImageContext
->PdbPointer
= NULL
;
343 // Three cases with regards to relocations:
344 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
345 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
346 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
347 // has no base relocs to apply
348 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
350 // Look at the file header to determine if relocations have been stripped, and
351 // save this info in the image context for later use.
353 if ((!(ImageContext
->IsTeImage
)) && ((PeHdr
->Pe32
.FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
354 ImageContext
->RelocationsStripped
= TRUE
;
355 } else if ((ImageContext
->IsTeImage
) && (TeHdr
->DataDirectory
[0].Size
== 0)) {
356 ImageContext
->RelocationsStripped
= TRUE
;
358 ImageContext
->RelocationsStripped
= FALSE
;
361 if (!(ImageContext
->IsTeImage
)) {
363 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
364 ImageContext
->ImageSize
= (UINT64
) OptionHeader
.Optional32
->SizeOfImage
;
365 ImageContext
->SectionAlignment
= OptionHeader
.Optional32
->SectionAlignment
;
366 ImageContext
->SizeOfHeaders
= OptionHeader
.Optional32
->SizeOfHeaders
;
369 // Modify ImageSize to contain .PDB file name if required and initialize
372 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
373 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
374 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
377 ImageContext
->ImageSize
= (UINT64
) OptionHeader
.Optional64
->SizeOfImage
;
378 ImageContext
->SectionAlignment
= OptionHeader
.Optional64
->SectionAlignment
;
379 ImageContext
->SizeOfHeaders
= OptionHeader
.Optional64
->SizeOfHeaders
;
382 // Modify ImageSize to contain .PDB file name if required and initialize
385 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
386 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
387 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
391 if (DebugDirectoryEntryRva
!= 0) {
393 // Determine the file offset of the debug directory... This means we walk
394 // the sections to find which section contains the RVA of the debug
397 DebugDirectoryEntryFileOffset
= 0;
399 SectionHeaderOffset
= (UINTN
)(
400 ImageContext
->PeCoffHeaderOffset
+
402 sizeof (EFI_IMAGE_FILE_HEADER
) +
403 PeHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
406 for (Index
= 0; Index
< PeHdr
->Pe32
.FileHeader
.NumberOfSections
; Index
++) {
408 // Read section header from file
410 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
411 Status
= ImageContext
->ImageRead (
412 ImageContext
->Handle
,
417 if (RETURN_ERROR (Status
)) {
418 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
422 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
423 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
424 DebugDirectoryEntryFileOffset
=
425 DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
429 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
432 if (DebugDirectoryEntryFileOffset
!= 0) {
433 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
435 // Read next debug directory entry
437 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
438 Status
= ImageContext
->ImageRead (
439 ImageContext
->Handle
,
440 DebugDirectoryEntryFileOffset
+ Index
,
444 if (RETURN_ERROR (Status
)) {
445 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
449 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
450 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
451 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
452 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
455 return RETURN_SUCCESS
;
461 ImageContext
->ImageSize
= 0;
462 ImageContext
->SectionAlignment
= 4096;
463 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
) TeHdr
->BaseOfCode
- (UINTN
) TeHdr
->StrippedSize
;
465 DebugDirectoryEntry
= &TeHdr
->DataDirectory
[1];
466 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
467 SectionHeaderOffset
= (UINTN
) (sizeof (EFI_TE_IMAGE_HEADER
));
469 DebugDirectoryEntryFileOffset
= 0;
471 for (Index
= 0; Index
< TeHdr
->NumberOfSections
;) {
473 // Read section header from file
475 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
476 Status
= ImageContext
->ImageRead (
477 ImageContext
->Handle
,
482 if (RETURN_ERROR (Status
)) {
483 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
487 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
488 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
489 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
490 SectionHeader
.VirtualAddress
+
491 SectionHeader
.PointerToRawData
+
492 sizeof (EFI_TE_IMAGE_HEADER
) -
496 // File offset of the debug directory was found, if this is not the last
497 // section, then skip to the last section for calculating the image size.
499 if (Index
< (UINTN
) TeHdr
->NumberOfSections
- 1) {
500 SectionHeaderOffset
+= (TeHdr
->NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
501 Index
= TeHdr
->NumberOfSections
- 1;
507 // In Te image header there is not a field to describe the ImageSize.
508 // Actually, the ImageSize equals the RVA plus the VirtualSize of
509 // the last section mapped into memory (Must be rounded up to
510 // a mulitple of Section Alignment). Per the PE/COFF specification, the
511 // section headers in the Section Table must appear in order of the RVA
512 // values for the corresponding sections. So the ImageSize can be determined
513 // by the RVA and the VirtualSize of the last section header in the
516 if ((++Index
) == (UINTN
) TeHdr
->NumberOfSections
) {
517 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
+
518 ImageContext
->SectionAlignment
- 1) & ~(ImageContext
->SectionAlignment
- 1);
521 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
524 if (DebugDirectoryEntryFileOffset
!= 0) {
525 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
527 // Read next debug directory entry
529 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
530 Status
= ImageContext
->ImageRead (
531 ImageContext
->Handle
,
532 DebugDirectoryEntryFileOffset
,
536 if (RETURN_ERROR (Status
)) {
537 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
541 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
542 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
543 return RETURN_SUCCESS
;
549 return RETURN_SUCCESS
;
554 PeCoffLoaderImageAddress (
555 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
562 Converts an image address to the loaded address
566 ImageContext - The context of the image being loaded
568 Address - The address to be converted to the loaded address
572 NULL if the address can not be converted, otherwise, the converted address
576 if (Address
>= ImageContext
->ImageSize
) {
577 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
581 return (UINT8
*) ((UINTN
) ImageContext
->ImageAddress
+ Address
);
586 PeCoffLoaderRelocateImage (
587 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
593 Relocates a PE/COFF image in memory
597 This - Calling context
599 ImageContext - Contains information on the loaded image to relocate
603 RETURN_SUCCESS if the PE/COFF image was relocated
604 RETURN_LOAD_ERROR if the image is not a valid PE/COFF image
605 RETURN_UNSUPPORTED not support
609 RETURN_STATUS Status
;
610 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
611 EFI_TE_IMAGE_HEADER
*TeHdr
;
612 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
614 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
615 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
623 PHYSICAL_ADDRESS BaseAddress
;
625 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
632 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
635 // If there are no relocation entries, then we are done
637 if (ImageContext
->RelocationsStripped
) {
638 return RETURN_SUCCESS
;
642 // Use DestinationAddress field of ImageContext as the relocation address even if it is 0.
644 BaseAddress
= ImageContext
->DestinationAddress
;
646 if (!(ImageContext
->IsTeImage
)) {
647 PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)((UINTN
)ImageContext
->ImageAddress
+
648 ImageContext
->PeCoffHeaderOffset
);
649 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
650 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
651 Adjust
= (UINT64
) BaseAddress
- OptionHeader
.Optional32
->ImageBase
;
652 OptionHeader
.Optional32
->ImageBase
= (UINT32
) BaseAddress
;
653 MachineType
= ImageContext
->Machine
;
655 // Find the relocation block
657 // Per the PE/COFF spec, you can't assume that a given data directory
658 // is present in the image. You have to check the NumberOfRvaAndSizes in
659 // the optional header to verify a desired directory entry is there.
661 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
662 RelocDir
= &OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
663 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
664 RelocBaseEnd
= PeCoffLoaderImageAddress (
666 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
670 // Set base and end to bypass processing below.
672 RelocBase
= RelocBaseEnd
= 0;
675 Adjust
= (UINT64
) BaseAddress
- OptionHeader
.Optional64
->ImageBase
;
676 OptionHeader
.Optional64
->ImageBase
= BaseAddress
;
677 MachineType
= ImageContext
->Machine
;
679 // Find the relocation block
681 // Per the PE/COFF spec, you can't assume that a given data directory
682 // is present in the image. You have to check the NumberOfRvaAndSizes in
683 // the optional header to verify a desired directory entry is there.
685 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
686 RelocDir
= &OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
687 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
688 RelocBaseEnd
= PeCoffLoaderImageAddress (
690 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
694 // Set base and end to bypass processing below.
696 RelocBase
= RelocBaseEnd
= 0;
700 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
701 Adjust
= (UINT64
) (BaseAddress
- TeHdr
->ImageBase
);
702 TeHdr
->ImageBase
= (UINT64
) (BaseAddress
);
703 MachineType
= TeHdr
->Machine
;
706 // Find the relocation block
708 RelocDir
= &TeHdr
->DataDirectory
[0];
709 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(
710 ImageContext
->ImageAddress
+
711 RelocDir
->VirtualAddress
+
712 sizeof(EFI_TE_IMAGE_HEADER
) -
715 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) ((UINTN
) RelocBase
+ (UINTN
) RelocDir
->Size
- 1);
719 // Run the relocation information and apply the fixups
721 FixupData
= ImageContext
->FixupData
;
722 while (RelocBase
< RelocBaseEnd
) {
724 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
725 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
726 if (!(ImageContext
->IsTeImage
)) {
727 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
);
729 FixupBase
= (CHAR8
*)(UINTN
)(ImageContext
->ImageAddress
+
730 RelocBase
->VirtualAddress
+
731 sizeof(EFI_TE_IMAGE_HEADER
) -
736 if ((CHAR8
*) RelocEnd
< (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
) ||
737 (CHAR8
*) RelocEnd
> (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+
738 (UINTN
)ImageContext
->ImageSize
)) {
739 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
740 return RETURN_LOAD_ERROR
;
744 // Run this relocation record
746 while (Reloc
< RelocEnd
) {
748 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
749 switch ((*Reloc
) >> 12) {
750 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
753 case EFI_IMAGE_REL_BASED_HIGH
:
754 F16
= (UINT16
*) Fixup
;
755 *F16
= (UINT16
) (*F16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
756 if (FixupData
!= NULL
) {
757 *(UINT16
*) FixupData
= *F16
;
758 FixupData
= FixupData
+ sizeof (UINT16
);
762 case EFI_IMAGE_REL_BASED_LOW
:
763 F16
= (UINT16
*) Fixup
;
764 *F16
= (UINT16
) (*F16
+ (UINT16
) Adjust
);
765 if (FixupData
!= NULL
) {
766 *(UINT16
*) FixupData
= *F16
;
767 FixupData
= FixupData
+ sizeof (UINT16
);
771 case EFI_IMAGE_REL_BASED_HIGHLOW
:
772 F32
= (UINT32
*) Fixup
;
773 *F32
= *F32
+ (UINT32
) Adjust
;
774 if (FixupData
!= NULL
) {
775 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
776 *(UINT32
*) FixupData
= *F32
;
777 FixupData
= FixupData
+ sizeof (UINT32
);
781 case EFI_IMAGE_REL_BASED_HIGHADJ
:
783 // Return the same EFI_UNSUPPORTED return code as
784 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
785 // the relocation type.
787 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
788 return RETURN_UNSUPPORTED
;
791 switch (MachineType
) {
792 case EFI_IMAGE_MACHINE_IA32
:
793 Status
= PeCoffLoaderRelocateIa32Image (Reloc
, Fixup
, &FixupData
, Adjust
);
795 case EFI_IMAGE_MACHINE_ARMT
:
796 Status
= PeCoffLoaderRelocateArmImage (&Reloc
, Fixup
, &FixupData
, Adjust
);
798 case EFI_IMAGE_MACHINE_X64
:
799 Status
= PeCoffLoaderRelocateX64Image (Reloc
, Fixup
, &FixupData
, Adjust
);
801 case EFI_IMAGE_MACHINE_IA64
:
802 Status
= PeCoffLoaderRelocateIpfImage (Reloc
, Fixup
, &FixupData
, Adjust
);
804 case EFI_IMAGE_MACHINE_AARCH64
:
805 Status
= PeCoffLoaderRelocateAArch64Image (Reloc
, Fixup
, &FixupData
, Adjust
);
808 Status
= RETURN_UNSUPPORTED
;
811 if (RETURN_ERROR (Status
)) {
812 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
818 // Next relocation record
826 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
829 return RETURN_SUCCESS
;
834 PeCoffLoaderLoadImage (
835 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
841 Loads a PE/COFF image into memory
845 This - Calling context
847 ImageContext - Contains information on image to load into memory
851 RETURN_SUCCESS if the PE/COFF image was loaded
852 RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
853 RETURN_LOAD_ERROR if the image is a runtime driver with no relocations
854 RETURN_INVALID_PARAMETER if the image address is invalid
858 RETURN_STATUS Status
;
859 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
860 EFI_TE_IMAGE_HEADER
*TeHdr
;
861 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
862 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
863 EFI_IMAGE_SECTION_HEADER
*Section
;
864 UINTN NumberOfSections
;
869 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
870 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
872 UINT32 TempDebugEntryRva
;
873 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
877 OptionHeader
.Header
= NULL
;
881 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
884 // Copy the provided context info into our local version, get what we
885 // can from the original image, and then use that to make sure everything
888 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
890 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
891 if (RETURN_ERROR (Status
)) {
896 // Make sure there is enough allocated space for the image being loaded
898 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
899 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
900 return RETURN_BUFFER_TOO_SMALL
;
904 // If there's no relocations, then make sure it's not a runtime driver,
905 // and that it's being loaded at the linked address.
907 if (CheckContext
.RelocationsStripped
) {
909 // If the image does not contain relocations and it is a runtime driver
910 // then return an error.
912 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
913 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
914 return RETURN_LOAD_ERROR
;
917 // If the image does not contain relocations, and the requested load address
918 // is not the linked address, then return an error.
920 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
921 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
922 return RETURN_INVALID_PARAMETER
;
926 // Make sure the allocated space has the proper section alignment
928 if (!(ImageContext
->IsTeImage
)) {
929 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
930 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
931 return RETURN_INVALID_PARAMETER
;
935 // Read the entire PE/COFF or TE header into memory
937 if (!(ImageContext
->IsTeImage
)) {
938 Status
= ImageContext
->ImageRead (
939 ImageContext
->Handle
,
941 &ImageContext
->SizeOfHeaders
,
942 (VOID
*) (UINTN
) ImageContext
->ImageAddress
945 PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)
946 ((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
948 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
950 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
951 (UINTN
)ImageContext
->ImageAddress
+
952 ImageContext
->PeCoffHeaderOffset
+
954 sizeof(EFI_IMAGE_FILE_HEADER
) +
955 PeHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
957 NumberOfSections
= (UINTN
) (PeHdr
->Pe32
.FileHeader
.NumberOfSections
);
959 Status
= ImageContext
->ImageRead (
960 ImageContext
->Handle
,
962 &ImageContext
->SizeOfHeaders
,
963 (VOID
*) (UINTN
) ImageContext
->ImageAddress
966 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
968 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
969 (UINTN
)ImageContext
->ImageAddress
+
970 sizeof(EFI_TE_IMAGE_HEADER
)
972 NumberOfSections
= (UINTN
) (TeHdr
->NumberOfSections
);
976 if (RETURN_ERROR (Status
)) {
977 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
978 return RETURN_LOAD_ERROR
;
982 // Load each section of the image
984 Section
= FirstSection
;
985 for (Index
= 0, MaxEnd
= NULL
; Index
< NumberOfSections
; Index
++) {
988 // Compute sections address
990 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
);
991 End
= PeCoffLoaderImageAddress (
993 Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1
997 // If the base start or end address resolved to 0, then fail.
999 if ((Base
== NULL
) || (End
== NULL
)) {
1000 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
1001 return RETURN_LOAD_ERROR
;
1005 if (ImageContext
->IsTeImage
) {
1006 Base
= (CHAR8
*) ((UINTN
) Base
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
1007 End
= (CHAR8
*) ((UINTN
) End
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
1017 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
1018 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
1019 Size
= (UINTN
) Section
->SizeOfRawData
;
1022 if (Section
->SizeOfRawData
) {
1023 if (!(ImageContext
->IsTeImage
)) {
1024 Status
= ImageContext
->ImageRead (
1025 ImageContext
->Handle
,
1026 Section
->PointerToRawData
,
1031 Status
= ImageContext
->ImageRead (
1032 ImageContext
->Handle
,
1033 Section
->PointerToRawData
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
,
1039 if (RETURN_ERROR (Status
)) {
1040 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1046 // If raw size is less then virt size, zero fill the remaining
1049 if (Size
< Section
->Misc
.VirtualSize
) {
1050 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
1060 // Get image's entry point
1062 if (!(ImageContext
->IsTeImage
)) {
1063 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (
1065 PeHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
1068 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (
1069 (UINTN
)ImageContext
->ImageAddress
+
1070 (UINTN
)TeHdr
->AddressOfEntryPoint
+
1071 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1072 (UINTN
) TeHdr
->StrippedSize
1077 // Determine the size of the fixup data
1079 // Per the PE/COFF spec, you can't assume that a given data directory
1080 // is present in the image. You have to check the NumberOfRvaAndSizes in
1081 // the optional header to verify a desired directory entry is there.
1083 if (!(ImageContext
->IsTeImage
)) {
1084 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1085 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1086 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
1087 &OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1088 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1090 ImageContext
->FixupDataSize
= 0;
1093 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1094 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
1095 &OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1096 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1098 ImageContext
->FixupDataSize
= 0;
1102 DirectoryEntry
= &TeHdr
->DataDirectory
[0];
1103 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1106 // Consumer must allocate a buffer for the relocation fixup log.
1107 // Only used for runtime drivers.
1109 ImageContext
->FixupData
= NULL
;
1112 // Load the Codeview info if present
1114 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
1115 if (!(ImageContext
->IsTeImage
)) {
1116 DebugEntry
= PeCoffLoaderImageAddress (
1118 ImageContext
->DebugDirectoryEntryRva
1121 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(UINTN
)(
1122 ImageContext
->ImageAddress
+
1123 ImageContext
->DebugDirectoryEntryRva
+
1124 sizeof(EFI_TE_IMAGE_HEADER
) -
1129 if (DebugEntry
!= NULL
) {
1130 TempDebugEntryRva
= DebugEntry
->RVA
;
1131 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
1133 if ((UINTN
) Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
1134 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
1136 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
1140 if (TempDebugEntryRva
!= 0) {
1141 if (!(ImageContext
->IsTeImage
)) {
1142 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
);
1144 ImageContext
->CodeView
= (VOID
*)(
1145 (UINTN
)ImageContext
->ImageAddress
+
1146 (UINTN
)TempDebugEntryRva
+
1147 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1148 (UINTN
) TeHdr
->StrippedSize
1152 if (ImageContext
->CodeView
== NULL
) {
1153 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1154 return RETURN_LOAD_ERROR
;
1157 if (DebugEntry
->RVA
== 0) {
1158 Size
= DebugEntry
->SizeOfData
;
1159 if (!(ImageContext
->IsTeImage
)) {
1160 Status
= ImageContext
->ImageRead (
1161 ImageContext
->Handle
,
1162 DebugEntry
->FileOffset
,
1164 ImageContext
->CodeView
1167 Status
= ImageContext
->ImageRead (
1168 ImageContext
->Handle
,
1169 DebugEntry
->FileOffset
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHdr
->StrippedSize
,
1171 ImageContext
->CodeView
1174 // Should we apply fix up to this field according to the size difference between PE and TE?
1175 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1176 // in original PE image.
1180 if (RETURN_ERROR (Status
)) {
1181 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1182 return RETURN_LOAD_ERROR
;
1185 DebugEntry
->RVA
= TempDebugEntryRva
;
1188 switch (*(UINT32
*) ImageContext
->CodeView
) {
1189 case CODEVIEW_SIGNATURE_NB10
:
1190 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1193 case CODEVIEW_SIGNATURE_RSDS
:
1194 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
1197 case CODEVIEW_SIGNATURE_MTOC
:
1198 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
);
1211 Returns a pointer to the PDB file name for a raw PE/COFF image that is not
1212 loaded into system memory with the PE/COFF Loader Library functions.
1214 Returns the PDB file name for the PE/COFF image specified by Pe32Data. If
1215 the PE/COFF image specified by Pe32Data is not a valid, then NULL is
1216 returned. If the PE/COFF image specified by Pe32Data does not contain a
1217 debug directory entry, then NULL is returned. If the debug directory entry
1218 in the PE/COFF image specified by Pe32Data does not contain a PDB file name,
1219 then NULL is returned.
1220 If Pe32Data is NULL, then return NULL.
1222 @param Pe32Data Pointer to the PE/COFF image that is loaded in system
1225 @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL
1226 if it cannot be retrieved.
1231 PeCoffLoaderGetPdbPointer (
1235 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1236 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1237 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
1238 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
1240 VOID
*CodeViewEntryPointer
;
1242 UINT32 NumberOfRvaAndSizes
;
1244 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
1245 UINT32 Index
, Index1
;
1247 if (Pe32Data
== NULL
) {
1252 DirectoryEntry
= NULL
;
1254 NumberOfRvaAndSizes
= 0;
1257 SectionHeader
= NULL
;
1259 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)Pe32Data
;
1260 if (EFI_IMAGE_DOS_SIGNATURE
== DosHdr
->e_magic
) {
1262 // DOS image header is present, so read the PE header after the DOS image header.
1264 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
) Pe32Data
+ (UINTN
) ((DosHdr
->e_lfanew
) & 0x0ffff));
1267 // DOS image header is not present, so PE header is at the image base.
1269 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)Pe32Data
;
1272 if (EFI_TE_IMAGE_HEADER_SIGNATURE
== Hdr
.Te
->Signature
) {
1273 if (Hdr
.Te
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
!= 0) {
1274 DirectoryEntry
= &Hdr
.Te
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
];
1275 TEImageAdjust
= sizeof (EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->StrippedSize
;
1278 // Get the DebugEntry offset in the raw data image.
1280 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (Hdr
.Te
+ 1);
1281 Index
= Hdr
.Te
->NumberOfSections
;
1282 for (Index1
= 0; Index1
< Index
; Index1
++) {
1283 if ((DirectoryEntry
->VirtualAddress
>= SectionHeader
[Index1
].VirtualAddress
) &&
1284 (DirectoryEntry
->VirtualAddress
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1285 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)((UINTN
) Hdr
.Te
+
1286 DirectoryEntry
->VirtualAddress
-
1287 SectionHeader
[Index1
].VirtualAddress
+
1288 SectionHeader
[Index1
].PointerToRawData
+
1294 } else if (EFI_IMAGE_NT_SIGNATURE
== Hdr
.Pe32
->Signature
) {
1296 // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.
1297 // It is due to backward-compatibility, for some system might
1298 // generate PE32+ image with PE32 Magic.
1300 switch (Hdr
.Pe32
->FileHeader
.Machine
) {
1301 case EFI_IMAGE_MACHINE_IA32
:
1302 case EFI_IMAGE_MACHINE_ARMT
:
1304 // Assume PE32 image with IA32 Machine field.
1306 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
1308 case EFI_IMAGE_MACHINE_X64
:
1309 case EFI_IMAGE_MACHINE_IPF
:
1311 // Assume PE32+ image with X64 or IPF Machine field
1313 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
1317 // For unknow Machine field, use Magic in optional Header
1319 Magic
= Hdr
.Pe32
->OptionalHeader
.Magic
;
1322 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
1323 (UINT8
*) Hdr
.Pe32
+
1325 sizeof (EFI_IMAGE_FILE_HEADER
) +
1326 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
1328 Index
= Hdr
.Pe32
->FileHeader
.NumberOfSections
;
1330 if (EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
== Magic
) {
1332 // Use PE32 offset get Debug Directory Entry
1334 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1335 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
1336 } else if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
1338 // Use PE32+ offset get Debug Directory Entry
1340 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1341 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
1344 if (NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
|| DirectoryEntry
->VirtualAddress
== 0) {
1345 DirectoryEntry
= NULL
;
1349 // Get the DebugEntry offset in the raw data image.
1351 for (Index1
= 0; Index1
< Index
; Index1
++) {
1352 if ((DirectoryEntry
->VirtualAddress
>= SectionHeader
[Index1
].VirtualAddress
) &&
1353 (DirectoryEntry
->VirtualAddress
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1354 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*) (
1356 DirectoryEntry
->VirtualAddress
-
1357 SectionHeader
[Index1
].VirtualAddress
+
1358 SectionHeader
[Index1
].PointerToRawData
);
1367 if (NULL
== DebugEntry
|| NULL
== DirectoryEntry
) {
1372 // Scan the directory to find the debug entry.
1374 for (DirCount
= 0; DirCount
< DirectoryEntry
->Size
; DirCount
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
), DebugEntry
++) {
1375 if (EFI_IMAGE_DEBUG_TYPE_CODEVIEW
== DebugEntry
->Type
) {
1376 if (DebugEntry
->SizeOfData
> 0) {
1378 // Get the DebugEntry offset in the raw data image.
1380 CodeViewEntryPointer
= NULL
;
1381 for (Index1
= 0; Index1
< Index
; Index1
++) {
1382 if ((DebugEntry
->RVA
>= SectionHeader
[Index1
].VirtualAddress
) &&
1383 (DebugEntry
->RVA
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1384 CodeViewEntryPointer
= (VOID
*) (
1386 (UINTN
) DebugEntry
->RVA
-
1387 SectionHeader
[Index1
].VirtualAddress
+
1388 SectionHeader
[Index1
].PointerToRawData
+
1389 (UINTN
)TEImageAdjust
);
1393 if (Index1
>= Index
) {
1395 // Can't find CodeViewEntryPointer in raw PE/COFF image.
1399 switch (* (UINT32
*) CodeViewEntryPointer
) {
1400 case CODEVIEW_SIGNATURE_NB10
:
1401 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
));
1402 case CODEVIEW_SIGNATURE_RSDS
:
1403 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
));
1404 case CODEVIEW_SIGNATURE_MTOC
:
1405 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
));
1419 PeCoffLoaderGetEntryPoint (
1421 OUT VOID
**EntryPoint
,
1422 OUT VOID
**BaseOfImage
1425 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1426 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1428 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)Pe32Data
;
1429 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
1431 // DOS image header is present, so read the PE header after the DOS image header.
1433 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
) Pe32Data
+ (UINTN
) ((DosHdr
->e_lfanew
) & 0x0ffff));
1436 // DOS image header is not present, so PE header is at the image base.
1438 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)Pe32Data
;
1442 // Calculate the entry point relative to the start of the image.
1443 // AddressOfEntryPoint is common for PE32 & PE32+
1445 if (Hdr
.Te
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
1446 *BaseOfImage
= (VOID
*)(UINTN
)(Hdr
.Te
->ImageBase
+ Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
1447 *EntryPoint
= (VOID
*)((UINTN
)*BaseOfImage
+ (Hdr
.Te
->AddressOfEntryPoint
& 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->StrippedSize
);
1448 return RETURN_SUCCESS
;
1449 } else if (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
) {
1450 *EntryPoint
= (VOID
*)(UINTN
)Hdr
.Pe32
->OptionalHeader
.AddressOfEntryPoint
;
1451 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1452 *BaseOfImage
= (VOID
*)(UINTN
)Hdr
.Pe32
->OptionalHeader
.ImageBase
;
1454 *BaseOfImage
= (VOID
*)(UINTN
)Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
1456 *EntryPoint
= (VOID
*)(UINTN
)((UINTN
)*EntryPoint
+ (UINTN
)*BaseOfImage
);
1457 return RETURN_SUCCESS
;
1460 return RETURN_UNSUPPORTED
;