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 Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
12 #include <Common/UefiBaseTypes.h>
13 #include <CommonLib.h>
14 #include <IndustryStandard/PeImage.h>
15 #include "PeCoffLib.h"
19 EFI_IMAGE_OPTIONAL_HEADER32
*Optional32
;
20 EFI_IMAGE_OPTIONAL_HEADER64
*Optional64
;
21 } EFI_IMAGE_OPTIONAL_HEADER_POINTER
;
25 PeCoffLoaderGetPeHeader (
26 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
27 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION
**PeHdr
,
28 OUT EFI_TE_IMAGE_HEADER
**TeHdr
33 PeCoffLoaderCheckImageType (
34 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
35 IN EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
,
36 IN EFI_TE_IMAGE_HEADER
*TeHdr
41 PeCoffLoaderImageAddress (
42 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
47 PeCoffLoaderRelocateIa32Image (
50 IN OUT CHAR8
**FixupData
,
56 PeCoffLoaderRelocateArmImage (
59 IN OUT CHAR8
**FixupData
,
64 PeCoffLoaderRelocateRiscVImage (
67 IN OUT CHAR8
**FixupData
,
73 PeCoffLoaderGetPeHeader (
74 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
75 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION
**PeHdr
,
76 OUT EFI_TE_IMAGE_HEADER
**TeHdr
82 Retrieves the PE or TE Header from a PE/COFF or TE image
86 ImageContext - The context of the image being loaded
88 PeHdr - The buffer in which to return the PE header
90 TeHdr - The buffer in which to return the TE header
94 RETURN_SUCCESS if the PE or TE Header is read,
95 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
100 EFI_IMAGE_DOS_HEADER DosHdr
;
103 ImageContext
->IsTeImage
= FALSE
;
105 // Read the DOS image headers
107 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
108 Status
= ImageContext
->ImageRead (
109 ImageContext
->Handle
,
114 if (RETURN_ERROR (Status
)) {
115 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
119 ImageContext
->PeCoffHeaderOffset
= 0;
120 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
122 // DOS image header is present, so read the PE header after the DOS image header
124 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
127 // Get the PE/COFF Header pointer
129 *PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINTN
)ImageContext
->Handle
+ ImageContext
->PeCoffHeaderOffset
);
130 if ((*PeHdr
)->Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
132 // Check the PE/COFF Header Signature. If not, then try to get a TE header
134 *TeHdr
= (EFI_TE_IMAGE_HEADER
*)*PeHdr
;
135 if ((*TeHdr
)->Signature
!= EFI_TE_IMAGE_HEADER_SIGNATURE
) {
136 return RETURN_UNSUPPORTED
;
138 ImageContext
->IsTeImage
= TRUE
;
141 return RETURN_SUCCESS
;
146 PeCoffLoaderCheckImageType (
147 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
148 IN EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
,
149 IN EFI_TE_IMAGE_HEADER
*TeHdr
155 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
159 ImageContext - The context of the image being loaded
161 PeHdr - The buffer in which to return the PE header
163 TeHdr - The buffer in which to return the TE header
167 RETURN_SUCCESS if the PE/COFF or TE image is supported
168 RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported.
173 // See if the machine type is supported.
174 // We support a native machine type (IA-32/Itanium-based)
176 if (ImageContext
->IsTeImage
== FALSE
) {
177 ImageContext
->Machine
= PeHdr
->Pe32
.FileHeader
.Machine
;
179 ImageContext
->Machine
= TeHdr
->Machine
;
182 if (ImageContext
->Machine
!= EFI_IMAGE_MACHINE_IA32
&& \
183 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_X64
&& \
184 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_ARMT
&& \
185 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_EBC
&& \
186 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_AARCH64
&& \
187 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_RISCV64
) {
188 if (ImageContext
->Machine
== IMAGE_FILE_MACHINE_ARM
) {
190 // There are two types of ARM images. Pure ARM and ARM/Thumb.
191 // If we see the ARM say it is the ARM/Thumb so there is only
192 // a single machine type we need to check for ARM.
194 ImageContext
->Machine
= EFI_IMAGE_MACHINE_ARMT
;
195 if (ImageContext
->IsTeImage
== FALSE
) {
196 PeHdr
->Pe32
.FileHeader
.Machine
= ImageContext
->Machine
;
198 TeHdr
->Machine
= ImageContext
->Machine
;
203 // unsupported PeImage machine type
205 return RETURN_UNSUPPORTED
;
210 // See if the image type is supported. We support EFI Applications,
211 // EFI Boot Service Drivers, EFI Runtime Drivers and EFI SAL Drivers.
213 if (ImageContext
->IsTeImage
== FALSE
) {
214 ImageContext
->ImageType
= PeHdr
->Pe32
.OptionalHeader
.Subsystem
;
216 ImageContext
->ImageType
= (UINT16
) (TeHdr
->Subsystem
);
219 if (ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
&& \
220 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
&& \
221 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
&& \
222 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
) {
224 // unsupported PeImage subsystem type
226 return RETURN_UNSUPPORTED
;
229 return RETURN_SUCCESS
;
234 PeCoffLoaderGetImageInfo (
235 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
241 Retrieves information on a PE/COFF image
245 This - Calling context
246 ImageContext - The context of the image being loaded
250 RETURN_SUCCESS - The information on the PE/COFF image was collected.
251 RETURN_INVALID_PARAMETER - ImageContext is NULL.
252 RETURN_UNSUPPORTED - The PE/COFF image is not supported.
253 Otherwise - The error status from reading the PE/COFF image using the
254 ImageContext->ImageRead() function
258 RETURN_STATUS Status
;
259 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
260 EFI_TE_IMAGE_HEADER
*TeHdr
;
261 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
264 UINTN DebugDirectoryEntryRva
;
265 UINTN DebugDirectoryEntryFileOffset
;
266 UINTN SectionHeaderOffset
;
267 EFI_IMAGE_SECTION_HEADER SectionHeader
;
268 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
269 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
273 DebugDirectoryEntry
= NULL
;
274 DebugDirectoryEntryRva
= 0;
276 if (NULL
== ImageContext
) {
277 return RETURN_INVALID_PARAMETER
;
282 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
284 Status
= PeCoffLoaderGetPeHeader (ImageContext
, &PeHdr
, &TeHdr
);
285 if (RETURN_ERROR (Status
)) {
290 // Verify machine type
292 Status
= PeCoffLoaderCheckImageType (ImageContext
, PeHdr
, TeHdr
);
293 if (RETURN_ERROR (Status
)) {
296 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
299 // Retrieve the base address of the image
301 if (!(ImageContext
->IsTeImage
)) {
302 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
303 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) OptionHeader
.Optional32
->ImageBase
;
305 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) OptionHeader
.Optional64
->ImageBase
;
308 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) (TeHdr
->ImageBase
+ TeHdr
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
311 // Initialize the alternate destination address to 0 indicating that it
312 // should not be used.
314 ImageContext
->DestinationAddress
= 0;
317 // Initialize the codeview pointer.
319 ImageContext
->CodeView
= NULL
;
320 ImageContext
->PdbPointer
= NULL
;
323 // Three cases with regards to relocations:
324 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
325 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
326 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
327 // has no base relocs to apply
328 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
330 // Look at the file header to determine if relocations have been stripped, and
331 // save this info in the image context for later use.
333 if ((!(ImageContext
->IsTeImage
)) && ((PeHdr
->Pe32
.FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
334 ImageContext
->RelocationsStripped
= TRUE
;
335 } else if ((ImageContext
->IsTeImage
) && (TeHdr
->DataDirectory
[0].Size
== 0) && (TeHdr
->DataDirectory
[0].VirtualAddress
== 0)) {
336 ImageContext
->RelocationsStripped
= TRUE
;
338 ImageContext
->RelocationsStripped
= FALSE
;
341 if (!(ImageContext
->IsTeImage
)) {
343 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
344 ImageContext
->ImageSize
= (UINT64
) OptionHeader
.Optional32
->SizeOfImage
;
345 ImageContext
->SectionAlignment
= OptionHeader
.Optional32
->SectionAlignment
;
346 ImageContext
->SizeOfHeaders
= OptionHeader
.Optional32
->SizeOfHeaders
;
349 // Modify ImageSize to contain .PDB file name if required and initialize
352 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
353 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
354 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
357 ImageContext
->ImageSize
= (UINT64
) OptionHeader
.Optional64
->SizeOfImage
;
358 ImageContext
->SectionAlignment
= OptionHeader
.Optional64
->SectionAlignment
;
359 ImageContext
->SizeOfHeaders
= OptionHeader
.Optional64
->SizeOfHeaders
;
362 // Modify ImageSize to contain .PDB file name if required and initialize
365 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
366 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
367 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
371 if (DebugDirectoryEntryRva
!= 0) {
373 // Determine the file offset of the debug directory... This means we walk
374 // the sections to find which section contains the RVA of the debug
377 DebugDirectoryEntryFileOffset
= 0;
379 SectionHeaderOffset
= (UINTN
)(
380 ImageContext
->PeCoffHeaderOffset
+
382 sizeof (EFI_IMAGE_FILE_HEADER
) +
383 PeHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
386 for (Index
= 0; Index
< PeHdr
->Pe32
.FileHeader
.NumberOfSections
; Index
++) {
388 // Read section header from file
390 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
391 Status
= ImageContext
->ImageRead (
392 ImageContext
->Handle
,
397 if (RETURN_ERROR (Status
)) {
398 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
402 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
403 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
404 DebugDirectoryEntryFileOffset
=
405 DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
409 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
412 if (DebugDirectoryEntryFileOffset
!= 0) {
413 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
415 // Read next debug directory entry
417 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
418 Status
= ImageContext
->ImageRead (
419 ImageContext
->Handle
,
420 DebugDirectoryEntryFileOffset
+ Index
,
424 if (RETURN_ERROR (Status
)) {
425 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
429 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
430 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
431 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
432 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
435 return RETURN_SUCCESS
;
441 ImageContext
->ImageSize
= 0;
442 ImageContext
->SectionAlignment
= 4096;
443 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
) TeHdr
->BaseOfCode
- (UINTN
) TeHdr
->StrippedSize
;
445 DebugDirectoryEntry
= &TeHdr
->DataDirectory
[1];
446 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
447 SectionHeaderOffset
= (UINTN
) (sizeof (EFI_TE_IMAGE_HEADER
));
449 DebugDirectoryEntryFileOffset
= 0;
451 for (Index
= 0; Index
< TeHdr
->NumberOfSections
;) {
453 // Read section header from file
455 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
456 Status
= ImageContext
->ImageRead (
457 ImageContext
->Handle
,
462 if (RETURN_ERROR (Status
)) {
463 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
467 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
468 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
469 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
470 SectionHeader
.VirtualAddress
+
471 SectionHeader
.PointerToRawData
+
472 sizeof (EFI_TE_IMAGE_HEADER
) -
476 // File offset of the debug directory was found, if this is not the last
477 // section, then skip to the last section for calculating the image size.
479 if (Index
< (UINTN
) TeHdr
->NumberOfSections
- 1) {
480 SectionHeaderOffset
+= (TeHdr
->NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
481 Index
= TeHdr
->NumberOfSections
- 1;
487 // In Te image header there is not a field to describe the ImageSize.
488 // Actually, the ImageSize equals the RVA plus the VirtualSize of
489 // the last section mapped into memory (Must be rounded up to
490 // a multiple of Section Alignment). Per the PE/COFF specification, the
491 // section headers in the Section Table must appear in order of the RVA
492 // values for the corresponding sections. So the ImageSize can be determined
493 // by the RVA and the VirtualSize of the last section header in the
496 if ((++Index
) == (UINTN
) TeHdr
->NumberOfSections
) {
497 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
+
498 ImageContext
->SectionAlignment
- 1) & ~(ImageContext
->SectionAlignment
- 1);
501 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
504 if (DebugDirectoryEntryFileOffset
!= 0) {
505 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
507 // Read next debug directory entry
509 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
510 Status
= ImageContext
->ImageRead (
511 ImageContext
->Handle
,
512 DebugDirectoryEntryFileOffset
,
516 if (RETURN_ERROR (Status
)) {
517 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
521 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
522 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
523 return RETURN_SUCCESS
;
529 return RETURN_SUCCESS
;
534 PeCoffLoaderImageAddress (
535 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
542 Converts an image address to the loaded address
546 ImageContext - The context of the image being loaded
548 Address - The address to be converted to the loaded address
552 NULL if the address can not be converted, otherwise, the converted address
556 if (Address
>= ImageContext
->ImageSize
) {
557 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
561 return (UINT8
*) ((UINTN
) ImageContext
->ImageAddress
+ Address
);
566 PeCoffLoaderRelocateImage (
567 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
573 Relocates a PE/COFF image in memory
577 This - Calling context
579 ImageContext - Contains information on the loaded image to relocate
583 RETURN_SUCCESS if the PE/COFF image was relocated
584 RETURN_LOAD_ERROR if the image is not a valid PE/COFF image
585 RETURN_UNSUPPORTED not support
589 RETURN_STATUS Status
;
590 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
591 EFI_TE_IMAGE_HEADER
*TeHdr
;
592 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
594 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
595 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
604 PHYSICAL_ADDRESS BaseAddress
;
606 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
613 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
616 // If there are no relocation entries, then we are done
618 if (ImageContext
->RelocationsStripped
) {
619 return RETURN_SUCCESS
;
623 // Use DestinationAddress field of ImageContext as the relocation address even if it is 0.
625 BaseAddress
= ImageContext
->DestinationAddress
;
627 if (!(ImageContext
->IsTeImage
)) {
628 PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)((UINTN
)ImageContext
->ImageAddress
+
629 ImageContext
->PeCoffHeaderOffset
);
630 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
631 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
632 Adjust
= (UINT64
) BaseAddress
- OptionHeader
.Optional32
->ImageBase
;
633 OptionHeader
.Optional32
->ImageBase
= (UINT32
) BaseAddress
;
634 MachineType
= ImageContext
->Machine
;
636 // Find the relocation block
638 // Per the PE/COFF spec, you can't assume that a given data directory
639 // is present in the image. You have to check the NumberOfRvaAndSizes in
640 // the optional header to verify a desired directory entry is there.
642 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
643 RelocDir
= &OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
644 if ((RelocDir
!= NULL
) && (RelocDir
->Size
> 0)) {
645 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
646 RelocBaseEnd
= PeCoffLoaderImageAddress (
648 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
650 if (RelocBase
== NULL
|| RelocBaseEnd
== NULL
|| RelocBaseEnd
< RelocBase
) {
651 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
652 return RETURN_LOAD_ERROR
;
656 // Set base and end to bypass processing below.
658 RelocBase
= RelocBaseEnd
= 0;
662 // Set base and end to bypass processing below.
664 RelocBase
= RelocBaseEnd
= 0;
667 Adjust
= (UINT64
) BaseAddress
- OptionHeader
.Optional64
->ImageBase
;
668 OptionHeader
.Optional64
->ImageBase
= BaseAddress
;
669 MachineType
= ImageContext
->Machine
;
671 // Find the relocation block
673 // Per the PE/COFF spec, you can't assume that a given data directory
674 // is present in the image. You have to check the NumberOfRvaAndSizes in
675 // the optional header to verify a desired directory entry is there.
677 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
678 RelocDir
= &OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
679 if ((RelocDir
!= NULL
) && (RelocDir
->Size
> 0)) {
680 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
681 RelocBaseEnd
= PeCoffLoaderImageAddress (
683 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
685 if (RelocBase
== NULL
|| RelocBaseEnd
== NULL
|| RelocBaseEnd
< RelocBase
) {
686 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
687 return RETURN_LOAD_ERROR
;
691 // Set base and end to bypass processing below.
693 RelocBase
= RelocBaseEnd
= 0;
697 // Set base and end to bypass processing below.
699 RelocBase
= RelocBaseEnd
= 0;
703 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
704 Adjust
= (UINT64
) (BaseAddress
- TeHdr
->ImageBase
);
705 TeHdr
->ImageBase
= (UINT64
) (BaseAddress
);
706 MachineType
= TeHdr
->Machine
;
709 // Find the relocation block
711 RelocDir
= &TeHdr
->DataDirectory
[0];
712 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(
713 ImageContext
->ImageAddress
+
714 RelocDir
->VirtualAddress
+
715 sizeof(EFI_TE_IMAGE_HEADER
) -
718 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) ((UINTN
) RelocBase
+ (UINTN
) RelocDir
->Size
- 1);
722 // Run the relocation information and apply the fixups
724 FixupData
= ImageContext
->FixupData
;
725 while (RelocBase
< RelocBaseEnd
) {
727 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
728 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
729 if (!(ImageContext
->IsTeImage
)) {
730 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
);
731 if (FixupBase
== NULL
) {
732 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
733 return RETURN_LOAD_ERROR
;
736 FixupBase
= (CHAR8
*)(UINTN
)(ImageContext
->ImageAddress
+
737 RelocBase
->VirtualAddress
+
738 sizeof(EFI_TE_IMAGE_HEADER
) -
743 if ((CHAR8
*) RelocEnd
< (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
) ||
744 (CHAR8
*) RelocEnd
> (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+
745 (UINTN
)ImageContext
->ImageSize
)) {
746 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
747 return RETURN_LOAD_ERROR
;
751 // Run this relocation record
753 while (Reloc
< RelocEnd
) {
755 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
756 switch ((*Reloc
) >> 12) {
757 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
760 case EFI_IMAGE_REL_BASED_HIGH
:
761 F16
= (UINT16
*) Fixup
;
762 *F16
= (UINT16
) (*F16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
763 if (FixupData
!= NULL
) {
764 *(UINT16
*) FixupData
= *F16
;
765 FixupData
= FixupData
+ sizeof (UINT16
);
769 case EFI_IMAGE_REL_BASED_LOW
:
770 F16
= (UINT16
*) Fixup
;
771 *F16
= (UINT16
) (*F16
+ (UINT16
) Adjust
);
772 if (FixupData
!= NULL
) {
773 *(UINT16
*) FixupData
= *F16
;
774 FixupData
= FixupData
+ sizeof (UINT16
);
778 case EFI_IMAGE_REL_BASED_HIGHLOW
:
779 F32
= (UINT32
*) Fixup
;
780 *F32
= *F32
+ (UINT32
) Adjust
;
781 if (FixupData
!= NULL
) {
782 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
783 *(UINT32
*) FixupData
= *F32
;
784 FixupData
= FixupData
+ sizeof (UINT32
);
788 case EFI_IMAGE_REL_BASED_DIR64
:
789 F64
= (UINT64
*) Fixup
;
790 *F64
= *F64
+ (UINT64
) Adjust
;
791 if (FixupData
!= NULL
) {
792 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT64
));
793 *(UINT64
*) FixupData
= *F64
;
794 FixupData
= FixupData
+ sizeof (UINT64
);
798 case EFI_IMAGE_REL_BASED_HIGHADJ
:
800 // Return the same EFI_UNSUPPORTED return code as
801 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
802 // the relocation type.
804 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
805 return RETURN_UNSUPPORTED
;
808 switch (MachineType
) {
809 case EFI_IMAGE_MACHINE_IA32
:
810 Status
= PeCoffLoaderRelocateIa32Image (Reloc
, Fixup
, &FixupData
, Adjust
);
812 case EFI_IMAGE_MACHINE_ARMT
:
813 Status
= PeCoffLoaderRelocateArmImage (&Reloc
, Fixup
, &FixupData
, Adjust
);
815 case EFI_IMAGE_MACHINE_RISCV64
:
816 Status
= PeCoffLoaderRelocateRiscVImage (Reloc
, Fixup
, &FixupData
, Adjust
);
819 Status
= RETURN_UNSUPPORTED
;
822 if (RETURN_ERROR (Status
)) {
823 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
829 // Next relocation record
837 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
840 return RETURN_SUCCESS
;
845 PeCoffLoaderLoadImage (
846 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
852 Loads a PE/COFF image into memory
856 This - Calling context
858 ImageContext - Contains information on image to load into memory
862 RETURN_SUCCESS if the PE/COFF image was loaded
863 RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
864 RETURN_LOAD_ERROR if the image is a runtime driver with no relocations
865 RETURN_INVALID_PARAMETER if the image address is invalid
869 RETURN_STATUS Status
;
870 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
871 EFI_TE_IMAGE_HEADER
*TeHdr
;
872 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
873 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
874 EFI_IMAGE_SECTION_HEADER
*Section
;
875 UINTN NumberOfSections
;
880 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
881 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
883 UINT32 TempDebugEntryRva
;
884 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
888 OptionHeader
.Header
= NULL
;
892 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
895 // Copy the provided context info into our local version, get what we
896 // can from the original image, and then use that to make sure everything
899 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
901 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
902 if (RETURN_ERROR (Status
)) {
907 // Make sure there is enough allocated space for the image being loaded
909 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
910 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
911 return RETURN_BUFFER_TOO_SMALL
;
915 // If there's no relocations, then make sure it's not a runtime driver,
916 // and that it's being loaded at the linked address.
918 if (CheckContext
.RelocationsStripped
) {
920 // If the image does not contain relocations and it is a runtime driver
921 // then return an error.
923 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
924 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
925 return RETURN_LOAD_ERROR
;
928 // If the image does not contain relocations, and the requested load address
929 // is not the linked address, then return an error.
931 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
932 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
933 return RETURN_INVALID_PARAMETER
;
937 // Make sure the allocated space has the proper section alignment
939 if (!(ImageContext
->IsTeImage
)) {
940 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
941 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
942 return RETURN_INVALID_PARAMETER
;
946 // Read the entire PE/COFF or TE header into memory
948 if (!(ImageContext
->IsTeImage
)) {
949 Status
= ImageContext
->ImageRead (
950 ImageContext
->Handle
,
952 &ImageContext
->SizeOfHeaders
,
953 (VOID
*) (UINTN
) ImageContext
->ImageAddress
956 PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)
957 ((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
959 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
961 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
962 (UINTN
)ImageContext
->ImageAddress
+
963 ImageContext
->PeCoffHeaderOffset
+
965 sizeof(EFI_IMAGE_FILE_HEADER
) +
966 PeHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
968 NumberOfSections
= (UINTN
) (PeHdr
->Pe32
.FileHeader
.NumberOfSections
);
970 Status
= ImageContext
->ImageRead (
971 ImageContext
->Handle
,
973 &ImageContext
->SizeOfHeaders
,
974 (VOID
*) (UINTN
) ImageContext
->ImageAddress
977 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
979 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
980 (UINTN
)ImageContext
->ImageAddress
+
981 sizeof(EFI_TE_IMAGE_HEADER
)
983 NumberOfSections
= (UINTN
) (TeHdr
->NumberOfSections
);
987 if (RETURN_ERROR (Status
)) {
988 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
989 return RETURN_LOAD_ERROR
;
993 // Load each section of the image
995 Section
= FirstSection
;
996 for (Index
= 0, MaxEnd
= NULL
; Index
< NumberOfSections
; Index
++) {
999 // Compute sections address
1001 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
);
1002 End
= PeCoffLoaderImageAddress (
1004 Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1
1008 // If the base start or end address resolved to 0, then fail.
1010 if ((Base
== NULL
) || (End
== NULL
)) {
1011 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
1012 return RETURN_LOAD_ERROR
;
1016 if (ImageContext
->IsTeImage
) {
1017 Base
= (CHAR8
*) ((UINTN
) Base
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
1018 End
= (CHAR8
*) ((UINTN
) End
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
1028 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
1029 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
1030 Size
= (UINTN
) Section
->SizeOfRawData
;
1033 if (Section
->SizeOfRawData
) {
1034 if (!(ImageContext
->IsTeImage
)) {
1035 Status
= ImageContext
->ImageRead (
1036 ImageContext
->Handle
,
1037 Section
->PointerToRawData
,
1042 Status
= ImageContext
->ImageRead (
1043 ImageContext
->Handle
,
1044 Section
->PointerToRawData
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
,
1050 if (RETURN_ERROR (Status
)) {
1051 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1057 // If raw size is less then virt size, zero fill the remaining
1060 if (Size
< Section
->Misc
.VirtualSize
) {
1061 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
1071 // Get image's entry point
1073 if (!(ImageContext
->IsTeImage
)) {
1074 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (
1076 PeHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
1079 ImageContext
->EntryPoint
= (UINTN
)ImageContext
->ImageAddress
+
1080 (UINTN
)TeHdr
->AddressOfEntryPoint
+
1081 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1082 (UINTN
) TeHdr
->StrippedSize
;
1086 // Determine the size of the fixup data
1088 // Per the PE/COFF spec, you can't assume that a given data directory
1089 // is present in the image. You have to check the NumberOfRvaAndSizes in
1090 // the optional header to verify a desired directory entry is there.
1092 if (!(ImageContext
->IsTeImage
)) {
1093 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1094 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1095 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
1096 &OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1097 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1099 ImageContext
->FixupDataSize
= 0;
1102 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1103 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
1104 &OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1105 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1107 ImageContext
->FixupDataSize
= 0;
1111 DirectoryEntry
= &TeHdr
->DataDirectory
[0];
1112 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1115 // Consumer must allocate a buffer for the relocation fixup log.
1116 // Only used for runtime drivers.
1118 ImageContext
->FixupData
= NULL
;
1121 // Load the Codeview info if present
1123 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
1124 if (!(ImageContext
->IsTeImage
)) {
1125 DebugEntry
= PeCoffLoaderImageAddress (
1127 ImageContext
->DebugDirectoryEntryRva
1130 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(UINTN
)(
1131 ImageContext
->ImageAddress
+
1132 ImageContext
->DebugDirectoryEntryRva
+
1133 sizeof(EFI_TE_IMAGE_HEADER
) -
1138 if (DebugEntry
!= NULL
) {
1139 TempDebugEntryRva
= DebugEntry
->RVA
;
1140 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
1142 if ((UINTN
) Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
1143 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
1145 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
1149 if (TempDebugEntryRva
!= 0) {
1150 if (!(ImageContext
->IsTeImage
)) {
1151 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
);
1153 ImageContext
->CodeView
= (VOID
*)(
1154 (UINTN
)ImageContext
->ImageAddress
+
1155 (UINTN
)TempDebugEntryRva
+
1156 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1157 (UINTN
) TeHdr
->StrippedSize
1161 if (ImageContext
->CodeView
== NULL
) {
1162 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1163 return RETURN_LOAD_ERROR
;
1166 if (DebugEntry
->RVA
== 0) {
1167 Size
= DebugEntry
->SizeOfData
;
1168 if (!(ImageContext
->IsTeImage
)) {
1169 Status
= ImageContext
->ImageRead (
1170 ImageContext
->Handle
,
1171 DebugEntry
->FileOffset
,
1173 ImageContext
->CodeView
1176 Status
= ImageContext
->ImageRead (
1177 ImageContext
->Handle
,
1178 DebugEntry
->FileOffset
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHdr
->StrippedSize
,
1180 ImageContext
->CodeView
1183 // Should we apply fix up to this field according to the size difference between PE and TE?
1184 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1185 // in original PE image.
1189 if (RETURN_ERROR (Status
)) {
1190 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1191 return RETURN_LOAD_ERROR
;
1194 DebugEntry
->RVA
= TempDebugEntryRva
;
1197 switch (*(UINT32
*) ImageContext
->CodeView
) {
1198 case CODEVIEW_SIGNATURE_NB10
:
1199 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1202 case CODEVIEW_SIGNATURE_RSDS
:
1203 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
1206 case CODEVIEW_SIGNATURE_MTOC
:
1207 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
);
1220 Returns a pointer to the PDB file name for a raw PE/COFF image that is not
1221 loaded into system memory with the PE/COFF Loader Library functions.
1223 Returns the PDB file name for the PE/COFF image specified by Pe32Data. If
1224 the PE/COFF image specified by Pe32Data is not a valid, then NULL is
1225 returned. If the PE/COFF image specified by Pe32Data does not contain a
1226 debug directory entry, then NULL is returned. If the debug directory entry
1227 in the PE/COFF image specified by Pe32Data does not contain a PDB file name,
1228 then NULL is returned.
1229 If Pe32Data is NULL, then return NULL.
1231 @param Pe32Data Pointer to the PE/COFF image that is loaded in system
1234 @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL
1235 if it cannot be retrieved.
1240 PeCoffLoaderGetPdbPointer (
1244 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1245 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1246 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
1247 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
1249 VOID
*CodeViewEntryPointer
;
1251 UINT32 NumberOfRvaAndSizes
;
1253 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
1254 UINT32 Index
, Index1
;
1256 if (Pe32Data
== NULL
) {
1261 DirectoryEntry
= NULL
;
1263 NumberOfRvaAndSizes
= 0;
1266 SectionHeader
= NULL
;
1268 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)Pe32Data
;
1269 if (EFI_IMAGE_DOS_SIGNATURE
== DosHdr
->e_magic
) {
1271 // DOS image header is present, so read the PE header after the DOS image header.
1273 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
) Pe32Data
+ (UINTN
) ((DosHdr
->e_lfanew
) & 0x0ffff));
1276 // DOS image header is not present, so PE header is at the image base.
1278 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)Pe32Data
;
1281 if (EFI_TE_IMAGE_HEADER_SIGNATURE
== Hdr
.Te
->Signature
) {
1282 if (Hdr
.Te
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
!= 0) {
1283 DirectoryEntry
= &Hdr
.Te
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
];
1284 TEImageAdjust
= sizeof (EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->StrippedSize
;
1287 // Get the DebugEntry offset in the raw data image.
1289 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (Hdr
.Te
+ 1);
1290 Index
= Hdr
.Te
->NumberOfSections
;
1291 for (Index1
= 0; Index1
< Index
; Index1
++) {
1292 if ((DirectoryEntry
->VirtualAddress
>= SectionHeader
[Index1
].VirtualAddress
) &&
1293 (DirectoryEntry
->VirtualAddress
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1294 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)((UINTN
) Hdr
.Te
+
1295 DirectoryEntry
->VirtualAddress
-
1296 SectionHeader
[Index1
].VirtualAddress
+
1297 SectionHeader
[Index1
].PointerToRawData
+
1303 } else if (EFI_IMAGE_NT_SIGNATURE
== Hdr
.Pe32
->Signature
) {
1305 // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.
1306 // It is due to backward-compatibility, for some system might
1307 // generate PE32+ image with PE32 Magic.
1309 switch (Hdr
.Pe32
->FileHeader
.Machine
) {
1310 case EFI_IMAGE_MACHINE_IA32
:
1311 case EFI_IMAGE_MACHINE_ARMT
:
1313 // Assume PE32 image with IA32 Machine field.
1315 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
1317 case EFI_IMAGE_MACHINE_X64
:
1319 // Assume PE32+ image with X64 Machine field
1321 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
1325 // For unknown Machine field, use Magic in optional Header
1327 Magic
= Hdr
.Pe32
->OptionalHeader
.Magic
;
1330 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
1331 (UINT8
*) Hdr
.Pe32
+
1333 sizeof (EFI_IMAGE_FILE_HEADER
) +
1334 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
1336 Index
= Hdr
.Pe32
->FileHeader
.NumberOfSections
;
1338 if (EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
== Magic
) {
1340 // Use PE32 offset get Debug Directory Entry
1342 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1343 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
1344 } else if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
1346 // Use PE32+ offset get Debug Directory Entry
1348 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1349 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
1352 if (NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
|| DirectoryEntry
->VirtualAddress
== 0) {
1353 DirectoryEntry
= NULL
;
1357 // Get the DebugEntry offset in the raw data image.
1359 for (Index1
= 0; Index1
< Index
; Index1
++) {
1360 if ((DirectoryEntry
->VirtualAddress
>= SectionHeader
[Index1
].VirtualAddress
) &&
1361 (DirectoryEntry
->VirtualAddress
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1362 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*) (
1364 DirectoryEntry
->VirtualAddress
-
1365 SectionHeader
[Index1
].VirtualAddress
+
1366 SectionHeader
[Index1
].PointerToRawData
);
1375 if (NULL
== DebugEntry
|| NULL
== DirectoryEntry
) {
1380 // Scan the directory to find the debug entry.
1382 for (DirCount
= 0; DirCount
< DirectoryEntry
->Size
; DirCount
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
), DebugEntry
++) {
1383 if (EFI_IMAGE_DEBUG_TYPE_CODEVIEW
== DebugEntry
->Type
) {
1384 if (DebugEntry
->SizeOfData
> 0) {
1386 // Get the DebugEntry offset in the raw data image.
1388 CodeViewEntryPointer
= NULL
;
1389 for (Index1
= 0; Index1
< Index
; Index1
++) {
1390 if ((DebugEntry
->RVA
>= SectionHeader
[Index1
].VirtualAddress
) &&
1391 (DebugEntry
->RVA
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1392 CodeViewEntryPointer
= (VOID
*) (
1394 (UINTN
) DebugEntry
->RVA
-
1395 SectionHeader
[Index1
].VirtualAddress
+
1396 SectionHeader
[Index1
].PointerToRawData
+
1397 (UINTN
)TEImageAdjust
);
1401 if (Index1
>= Index
) {
1403 // Can't find CodeViewEntryPointer in raw PE/COFF image.
1407 switch (* (UINT32
*) CodeViewEntryPointer
) {
1408 case CODEVIEW_SIGNATURE_NB10
:
1409 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
));
1410 case CODEVIEW_SIGNATURE_RSDS
:
1411 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
));
1412 case CODEVIEW_SIGNATURE_MTOC
:
1413 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
));
1427 PeCoffLoaderGetEntryPoint (
1429 OUT VOID
**EntryPoint
,
1430 OUT VOID
**BaseOfImage
1433 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1434 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1436 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)Pe32Data
;
1437 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
1439 // DOS image header is present, so read the PE header after the DOS image header.
1441 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
) Pe32Data
+ (UINTN
) ((DosHdr
->e_lfanew
) & 0x0ffff));
1444 // DOS image header is not present, so PE header is at the image base.
1446 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)Pe32Data
;
1450 // Calculate the entry point relative to the start of the image.
1451 // AddressOfEntryPoint is common for PE32 & PE32+
1453 if (Hdr
.Te
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
1454 *BaseOfImage
= (VOID
*)(UINTN
)(Hdr
.Te
->ImageBase
+ Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
1455 *EntryPoint
= (VOID
*)((UINTN
)*BaseOfImage
+ (Hdr
.Te
->AddressOfEntryPoint
& 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->StrippedSize
);
1456 return RETURN_SUCCESS
;
1457 } else if (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
) {
1458 *EntryPoint
= (VOID
*)(UINTN
)Hdr
.Pe32
->OptionalHeader
.AddressOfEntryPoint
;
1459 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1460 *BaseOfImage
= (VOID
*)(UINTN
)Hdr
.Pe32
->OptionalHeader
.ImageBase
;
1462 *BaseOfImage
= (VOID
*)(UINTN
)Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
1464 *EntryPoint
= (VOID
*)(UINTN
)((UINTN
)*EntryPoint
+ (UINTN
)*BaseOfImage
);
1465 return RETURN_SUCCESS
;
1468 return RETURN_UNSUPPORTED
;