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 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
,
61 PeCoffLoaderRelocateArmImage (
64 IN OUT CHAR8
**FixupData
,
70 PeCoffLoaderGetPeHeader (
71 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
72 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION
**PeHdr
,
73 OUT EFI_TE_IMAGE_HEADER
**TeHdr
79 Retrieves the PE or TE Header from a PE/COFF or TE image
83 ImageContext - The context of the image being loaded
85 PeHdr - The buffer in which to return the PE header
87 TeHdr - The buffer in which to return the TE header
91 RETURN_SUCCESS if the PE or TE Header is read,
92 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
97 EFI_IMAGE_DOS_HEADER DosHdr
;
100 ImageContext
->IsTeImage
= FALSE
;
102 // Read the DOS image headers
104 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
105 Status
= ImageContext
->ImageRead (
106 ImageContext
->Handle
,
111 if (RETURN_ERROR (Status
)) {
112 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
116 ImageContext
->PeCoffHeaderOffset
= 0;
117 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
119 // DOS image header is present, so read the PE header after the DOS image header
121 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
124 // Get the PE/COFF Header pointer
126 *PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINTN
)ImageContext
->Handle
+ ImageContext
->PeCoffHeaderOffset
);
127 if ((*PeHdr
)->Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
129 // Check the PE/COFF Header Signature. If not, then try to get a TE header
131 *TeHdr
= (EFI_TE_IMAGE_HEADER
*)*PeHdr
;
132 if ((*TeHdr
)->Signature
!= EFI_TE_IMAGE_HEADER_SIGNATURE
) {
133 return RETURN_UNSUPPORTED
;
135 ImageContext
->IsTeImage
= TRUE
;
138 return RETURN_SUCCESS
;
143 PeCoffLoaderCheckImageType (
144 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
145 IN EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
,
146 IN EFI_TE_IMAGE_HEADER
*TeHdr
152 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
156 ImageContext - The context of the image being loaded
158 PeHdr - The buffer in which to return the PE header
160 TeHdr - The buffer in which to return the TE header
164 RETURN_SUCCESS if the PE/COFF or TE image is supported
165 RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported.
170 // See if the machine type is supported.
171 // We support a native machine type (IA-32/Itanium-based)
173 if (ImageContext
->IsTeImage
== FALSE
) {
174 ImageContext
->Machine
= PeHdr
->Pe32
.FileHeader
.Machine
;
176 ImageContext
->Machine
= TeHdr
->Machine
;
179 if (ImageContext
->Machine
!= EFI_IMAGE_MACHINE_IA32
&& \
180 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_X64
&& \
181 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_ARMT
&& \
182 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_EBC
&& \
183 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_AARCH64
) {
184 if (ImageContext
->Machine
== IMAGE_FILE_MACHINE_ARM
) {
186 // There are two types of ARM images. Pure ARM and ARM/Thumb.
187 // If we see the ARM say it is the ARM/Thumb so there is only
188 // a single machine type we need to check for ARM.
190 ImageContext
->Machine
= EFI_IMAGE_MACHINE_ARMT
;
191 if (ImageContext
->IsTeImage
== FALSE
) {
192 PeHdr
->Pe32
.FileHeader
.Machine
= ImageContext
->Machine
;
194 TeHdr
->Machine
= ImageContext
->Machine
;
199 // unsupported PeImage machine type
201 return RETURN_UNSUPPORTED
;
206 // See if the image type is supported. We support EFI Applications,
207 // EFI Boot Service Drivers, EFI Runtime Drivers and EFI SAL Drivers.
209 if (ImageContext
->IsTeImage
== FALSE
) {
210 ImageContext
->ImageType
= PeHdr
->Pe32
.OptionalHeader
.Subsystem
;
212 ImageContext
->ImageType
= (UINT16
) (TeHdr
->Subsystem
);
215 if (ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
&& \
216 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
&& \
217 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
&& \
218 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
) {
220 // upsupported PeImage subsystem type
222 return RETURN_UNSUPPORTED
;
225 return RETURN_SUCCESS
;
230 PeCoffLoaderGetImageInfo (
231 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
237 Retrieves information on a PE/COFF image
241 This - Calling context
242 ImageContext - The context of the image being loaded
246 RETURN_SUCCESS - The information on the PE/COFF image was collected.
247 RETURN_INVALID_PARAMETER - ImageContext is NULL.
248 RETURN_UNSUPPORTED - The PE/COFF image is not supported.
249 Otherwise - The error status from reading the PE/COFF image using the
250 ImageContext->ImageRead() function
254 RETURN_STATUS Status
;
255 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
256 EFI_TE_IMAGE_HEADER
*TeHdr
;
257 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
260 UINTN DebugDirectoryEntryRva
;
261 UINTN DebugDirectoryEntryFileOffset
;
262 UINTN SectionHeaderOffset
;
263 EFI_IMAGE_SECTION_HEADER SectionHeader
;
264 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
265 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
269 DebugDirectoryEntry
= NULL
;
270 DebugDirectoryEntryRva
= 0;
272 if (NULL
== ImageContext
) {
273 return RETURN_INVALID_PARAMETER
;
278 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
280 Status
= PeCoffLoaderGetPeHeader (ImageContext
, &PeHdr
, &TeHdr
);
281 if (RETURN_ERROR (Status
)) {
286 // Verify machine type
288 Status
= PeCoffLoaderCheckImageType (ImageContext
, PeHdr
, TeHdr
);
289 if (RETURN_ERROR (Status
)) {
292 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
295 // Retrieve the base address of the image
297 if (!(ImageContext
->IsTeImage
)) {
298 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
299 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) OptionHeader
.Optional32
->ImageBase
;
301 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) OptionHeader
.Optional64
->ImageBase
;
304 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) (TeHdr
->ImageBase
+ TeHdr
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
307 // Initialize the alternate destination address to 0 indicating that it
308 // should not be used.
310 ImageContext
->DestinationAddress
= 0;
313 // Initialize the codeview pointer.
315 ImageContext
->CodeView
= NULL
;
316 ImageContext
->PdbPointer
= NULL
;
319 // Three cases with regards to relocations:
320 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
321 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
322 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
323 // has no base relocs to apply
324 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
326 // Look at the file header to determine if relocations have been stripped, and
327 // save this info in the image context for later use.
329 if ((!(ImageContext
->IsTeImage
)) && ((PeHdr
->Pe32
.FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
330 ImageContext
->RelocationsStripped
= TRUE
;
331 } else if ((ImageContext
->IsTeImage
) && (TeHdr
->DataDirectory
[0].Size
== 0) && (TeHdr
->DataDirectory
[0].VirtualAddress
== 0)) {
332 ImageContext
->RelocationsStripped
= TRUE
;
334 ImageContext
->RelocationsStripped
= FALSE
;
337 if (!(ImageContext
->IsTeImage
)) {
339 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
340 ImageContext
->ImageSize
= (UINT64
) OptionHeader
.Optional32
->SizeOfImage
;
341 ImageContext
->SectionAlignment
= OptionHeader
.Optional32
->SectionAlignment
;
342 ImageContext
->SizeOfHeaders
= OptionHeader
.Optional32
->SizeOfHeaders
;
345 // Modify ImageSize to contain .PDB file name if required and initialize
348 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
349 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
350 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
353 ImageContext
->ImageSize
= (UINT64
) OptionHeader
.Optional64
->SizeOfImage
;
354 ImageContext
->SectionAlignment
= OptionHeader
.Optional64
->SectionAlignment
;
355 ImageContext
->SizeOfHeaders
= OptionHeader
.Optional64
->SizeOfHeaders
;
358 // Modify ImageSize to contain .PDB file name if required and initialize
361 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
362 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
363 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
367 if (DebugDirectoryEntryRva
!= 0) {
369 // Determine the file offset of the debug directory... This means we walk
370 // the sections to find which section contains the RVA of the debug
373 DebugDirectoryEntryFileOffset
= 0;
375 SectionHeaderOffset
= (UINTN
)(
376 ImageContext
->PeCoffHeaderOffset
+
378 sizeof (EFI_IMAGE_FILE_HEADER
) +
379 PeHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
382 for (Index
= 0; Index
< PeHdr
->Pe32
.FileHeader
.NumberOfSections
; Index
++) {
384 // Read section header from file
386 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
387 Status
= ImageContext
->ImageRead (
388 ImageContext
->Handle
,
393 if (RETURN_ERROR (Status
)) {
394 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
398 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
399 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
400 DebugDirectoryEntryFileOffset
=
401 DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
405 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
408 if (DebugDirectoryEntryFileOffset
!= 0) {
409 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
411 // Read next debug directory entry
413 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
414 Status
= ImageContext
->ImageRead (
415 ImageContext
->Handle
,
416 DebugDirectoryEntryFileOffset
+ Index
,
420 if (RETURN_ERROR (Status
)) {
421 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
425 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
426 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
427 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
428 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
431 return RETURN_SUCCESS
;
437 ImageContext
->ImageSize
= 0;
438 ImageContext
->SectionAlignment
= 4096;
439 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
) TeHdr
->BaseOfCode
- (UINTN
) TeHdr
->StrippedSize
;
441 DebugDirectoryEntry
= &TeHdr
->DataDirectory
[1];
442 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
443 SectionHeaderOffset
= (UINTN
) (sizeof (EFI_TE_IMAGE_HEADER
));
445 DebugDirectoryEntryFileOffset
= 0;
447 for (Index
= 0; Index
< TeHdr
->NumberOfSections
;) {
449 // Read section header from file
451 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
452 Status
= ImageContext
->ImageRead (
453 ImageContext
->Handle
,
458 if (RETURN_ERROR (Status
)) {
459 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
463 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
464 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
465 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
466 SectionHeader
.VirtualAddress
+
467 SectionHeader
.PointerToRawData
+
468 sizeof (EFI_TE_IMAGE_HEADER
) -
472 // File offset of the debug directory was found, if this is not the last
473 // section, then skip to the last section for calculating the image size.
475 if (Index
< (UINTN
) TeHdr
->NumberOfSections
- 1) {
476 SectionHeaderOffset
+= (TeHdr
->NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
477 Index
= TeHdr
->NumberOfSections
- 1;
483 // In Te image header there is not a field to describe the ImageSize.
484 // Actually, the ImageSize equals the RVA plus the VirtualSize of
485 // the last section mapped into memory (Must be rounded up to
486 // a mulitple of Section Alignment). Per the PE/COFF specification, the
487 // section headers in the Section Table must appear in order of the RVA
488 // values for the corresponding sections. So the ImageSize can be determined
489 // by the RVA and the VirtualSize of the last section header in the
492 if ((++Index
) == (UINTN
) TeHdr
->NumberOfSections
) {
493 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
+
494 ImageContext
->SectionAlignment
- 1) & ~(ImageContext
->SectionAlignment
- 1);
497 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
500 if (DebugDirectoryEntryFileOffset
!= 0) {
501 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
503 // Read next debug directory entry
505 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
506 Status
= ImageContext
->ImageRead (
507 ImageContext
->Handle
,
508 DebugDirectoryEntryFileOffset
,
512 if (RETURN_ERROR (Status
)) {
513 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
517 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
518 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
519 return RETURN_SUCCESS
;
525 return RETURN_SUCCESS
;
530 PeCoffLoaderImageAddress (
531 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
538 Converts an image address to the loaded address
542 ImageContext - The context of the image being loaded
544 Address - The address to be converted to the loaded address
548 NULL if the address can not be converted, otherwise, the converted address
552 if (Address
>= ImageContext
->ImageSize
) {
553 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
557 return (UINT8
*) ((UINTN
) ImageContext
->ImageAddress
+ Address
);
562 PeCoffLoaderRelocateImage (
563 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
569 Relocates a PE/COFF image in memory
573 This - Calling context
575 ImageContext - Contains information on the loaded image to relocate
579 RETURN_SUCCESS if the PE/COFF image was relocated
580 RETURN_LOAD_ERROR if the image is not a valid PE/COFF image
581 RETURN_UNSUPPORTED not support
585 RETURN_STATUS Status
;
586 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
587 EFI_TE_IMAGE_HEADER
*TeHdr
;
588 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
590 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
591 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
600 PHYSICAL_ADDRESS BaseAddress
;
602 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
609 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
612 // If there are no relocation entries, then we are done
614 if (ImageContext
->RelocationsStripped
) {
615 return RETURN_SUCCESS
;
619 // Use DestinationAddress field of ImageContext as the relocation address even if it is 0.
621 BaseAddress
= ImageContext
->DestinationAddress
;
623 if (!(ImageContext
->IsTeImage
)) {
624 PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)((UINTN
)ImageContext
->ImageAddress
+
625 ImageContext
->PeCoffHeaderOffset
);
626 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
627 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
628 Adjust
= (UINT64
) BaseAddress
- OptionHeader
.Optional32
->ImageBase
;
629 OptionHeader
.Optional32
->ImageBase
= (UINT32
) BaseAddress
;
630 MachineType
= ImageContext
->Machine
;
632 // Find the relocation block
634 // Per the PE/COFF spec, you can't assume that a given data directory
635 // is present in the image. You have to check the NumberOfRvaAndSizes in
636 // the optional header to verify a desired directory entry is there.
638 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
639 RelocDir
= &OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
640 if ((RelocDir
!= NULL
) && (RelocDir
->Size
> 0)) {
641 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
642 RelocBaseEnd
= PeCoffLoaderImageAddress (
644 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
646 if (RelocBase
== NULL
|| RelocBaseEnd
== NULL
|| RelocBaseEnd
< RelocBase
) {
647 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
648 return RETURN_LOAD_ERROR
;
652 // Set base and end to bypass processing below.
654 RelocBase
= RelocBaseEnd
= 0;
658 // Set base and end to bypass processing below.
660 RelocBase
= RelocBaseEnd
= 0;
663 Adjust
= (UINT64
) BaseAddress
- OptionHeader
.Optional64
->ImageBase
;
664 OptionHeader
.Optional64
->ImageBase
= BaseAddress
;
665 MachineType
= ImageContext
->Machine
;
667 // Find the relocation block
669 // Per the PE/COFF spec, you can't assume that a given data directory
670 // is present in the image. You have to check the NumberOfRvaAndSizes in
671 // the optional header to verify a desired directory entry is there.
673 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
674 RelocDir
= &OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
675 if ((RelocDir
!= NULL
) && (RelocDir
->Size
> 0)) {
676 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
677 RelocBaseEnd
= PeCoffLoaderImageAddress (
679 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
681 if (RelocBase
== NULL
|| RelocBaseEnd
== NULL
|| RelocBaseEnd
< RelocBase
) {
682 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
683 return RETURN_LOAD_ERROR
;
687 // Set base and end to bypass processing below.
689 RelocBase
= RelocBaseEnd
= 0;
693 // Set base and end to bypass processing below.
695 RelocBase
= RelocBaseEnd
= 0;
699 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
700 Adjust
= (UINT64
) (BaseAddress
- TeHdr
->ImageBase
);
701 TeHdr
->ImageBase
= (UINT64
) (BaseAddress
);
702 MachineType
= TeHdr
->Machine
;
705 // Find the relocation block
707 RelocDir
= &TeHdr
->DataDirectory
[0];
708 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(
709 ImageContext
->ImageAddress
+
710 RelocDir
->VirtualAddress
+
711 sizeof(EFI_TE_IMAGE_HEADER
) -
714 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) ((UINTN
) RelocBase
+ (UINTN
) RelocDir
->Size
- 1);
718 // Run the relocation information and apply the fixups
720 FixupData
= ImageContext
->FixupData
;
721 while (RelocBase
< RelocBaseEnd
) {
723 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
724 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
725 if (!(ImageContext
->IsTeImage
)) {
726 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
);
727 if (FixupBase
== NULL
) {
728 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
729 return RETURN_LOAD_ERROR
;
732 FixupBase
= (CHAR8
*)(UINTN
)(ImageContext
->ImageAddress
+
733 RelocBase
->VirtualAddress
+
734 sizeof(EFI_TE_IMAGE_HEADER
) -
739 if ((CHAR8
*) RelocEnd
< (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
) ||
740 (CHAR8
*) RelocEnd
> (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+
741 (UINTN
)ImageContext
->ImageSize
)) {
742 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
743 return RETURN_LOAD_ERROR
;
747 // Run this relocation record
749 while (Reloc
< RelocEnd
) {
751 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
752 switch ((*Reloc
) >> 12) {
753 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
756 case EFI_IMAGE_REL_BASED_HIGH
:
757 F16
= (UINT16
*) Fixup
;
758 *F16
= (UINT16
) (*F16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
759 if (FixupData
!= NULL
) {
760 *(UINT16
*) FixupData
= *F16
;
761 FixupData
= FixupData
+ sizeof (UINT16
);
765 case EFI_IMAGE_REL_BASED_LOW
:
766 F16
= (UINT16
*) Fixup
;
767 *F16
= (UINT16
) (*F16
+ (UINT16
) Adjust
);
768 if (FixupData
!= NULL
) {
769 *(UINT16
*) FixupData
= *F16
;
770 FixupData
= FixupData
+ sizeof (UINT16
);
774 case EFI_IMAGE_REL_BASED_HIGHLOW
:
775 F32
= (UINT32
*) Fixup
;
776 *F32
= *F32
+ (UINT32
) Adjust
;
777 if (FixupData
!= NULL
) {
778 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
779 *(UINT32
*) FixupData
= *F32
;
780 FixupData
= FixupData
+ sizeof (UINT32
);
784 case EFI_IMAGE_REL_BASED_DIR64
:
785 F64
= (UINT64
*) Fixup
;
786 *F64
= *F64
+ (UINT64
) Adjust
;
787 if (FixupData
!= NULL
) {
788 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT64
));
789 *(UINT64
*) FixupData
= *F64
;
790 FixupData
= FixupData
+ sizeof (UINT64
);
794 case EFI_IMAGE_REL_BASED_HIGHADJ
:
796 // Return the same EFI_UNSUPPORTED return code as
797 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
798 // the relocation type.
800 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
801 return RETURN_UNSUPPORTED
;
804 switch (MachineType
) {
805 case EFI_IMAGE_MACHINE_IA32
:
806 Status
= PeCoffLoaderRelocateIa32Image (Reloc
, Fixup
, &FixupData
, Adjust
);
808 case EFI_IMAGE_MACHINE_ARMT
:
809 Status
= PeCoffLoaderRelocateArmImage (&Reloc
, Fixup
, &FixupData
, Adjust
);
812 Status
= RETURN_UNSUPPORTED
;
815 if (RETURN_ERROR (Status
)) {
816 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
822 // Next relocation record
830 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
833 return RETURN_SUCCESS
;
838 PeCoffLoaderLoadImage (
839 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
845 Loads a PE/COFF image into memory
849 This - Calling context
851 ImageContext - Contains information on image to load into memory
855 RETURN_SUCCESS if the PE/COFF image was loaded
856 RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
857 RETURN_LOAD_ERROR if the image is a runtime driver with no relocations
858 RETURN_INVALID_PARAMETER if the image address is invalid
862 RETURN_STATUS Status
;
863 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
864 EFI_TE_IMAGE_HEADER
*TeHdr
;
865 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
866 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
867 EFI_IMAGE_SECTION_HEADER
*Section
;
868 UINTN NumberOfSections
;
873 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
874 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
876 UINT32 TempDebugEntryRva
;
877 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
881 OptionHeader
.Header
= NULL
;
885 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
888 // Copy the provided context info into our local version, get what we
889 // can from the original image, and then use that to make sure everything
892 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
894 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
895 if (RETURN_ERROR (Status
)) {
900 // Make sure there is enough allocated space for the image being loaded
902 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
903 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
904 return RETURN_BUFFER_TOO_SMALL
;
908 // If there's no relocations, then make sure it's not a runtime driver,
909 // and that it's being loaded at the linked address.
911 if (CheckContext
.RelocationsStripped
) {
913 // If the image does not contain relocations and it is a runtime driver
914 // then return an error.
916 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
917 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
918 return RETURN_LOAD_ERROR
;
921 // If the image does not contain relocations, and the requested load address
922 // is not the linked address, then return an error.
924 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
925 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
926 return RETURN_INVALID_PARAMETER
;
930 // Make sure the allocated space has the proper section alignment
932 if (!(ImageContext
->IsTeImage
)) {
933 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
934 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
935 return RETURN_INVALID_PARAMETER
;
939 // Read the entire PE/COFF or TE header into memory
941 if (!(ImageContext
->IsTeImage
)) {
942 Status
= ImageContext
->ImageRead (
943 ImageContext
->Handle
,
945 &ImageContext
->SizeOfHeaders
,
946 (VOID
*) (UINTN
) ImageContext
->ImageAddress
949 PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)
950 ((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
952 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
954 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
955 (UINTN
)ImageContext
->ImageAddress
+
956 ImageContext
->PeCoffHeaderOffset
+
958 sizeof(EFI_IMAGE_FILE_HEADER
) +
959 PeHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
961 NumberOfSections
= (UINTN
) (PeHdr
->Pe32
.FileHeader
.NumberOfSections
);
963 Status
= ImageContext
->ImageRead (
964 ImageContext
->Handle
,
966 &ImageContext
->SizeOfHeaders
,
967 (VOID
*) (UINTN
) ImageContext
->ImageAddress
970 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
972 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
973 (UINTN
)ImageContext
->ImageAddress
+
974 sizeof(EFI_TE_IMAGE_HEADER
)
976 NumberOfSections
= (UINTN
) (TeHdr
->NumberOfSections
);
980 if (RETURN_ERROR (Status
)) {
981 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
982 return RETURN_LOAD_ERROR
;
986 // Load each section of the image
988 Section
= FirstSection
;
989 for (Index
= 0, MaxEnd
= NULL
; Index
< NumberOfSections
; Index
++) {
992 // Compute sections address
994 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
);
995 End
= PeCoffLoaderImageAddress (
997 Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1
1001 // If the base start or end address resolved to 0, then fail.
1003 if ((Base
== NULL
) || (End
== NULL
)) {
1004 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
1005 return RETURN_LOAD_ERROR
;
1009 if (ImageContext
->IsTeImage
) {
1010 Base
= (CHAR8
*) ((UINTN
) Base
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
1011 End
= (CHAR8
*) ((UINTN
) End
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
1021 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
1022 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
1023 Size
= (UINTN
) Section
->SizeOfRawData
;
1026 if (Section
->SizeOfRawData
) {
1027 if (!(ImageContext
->IsTeImage
)) {
1028 Status
= ImageContext
->ImageRead (
1029 ImageContext
->Handle
,
1030 Section
->PointerToRawData
,
1035 Status
= ImageContext
->ImageRead (
1036 ImageContext
->Handle
,
1037 Section
->PointerToRawData
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
,
1043 if (RETURN_ERROR (Status
)) {
1044 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1050 // If raw size is less then virt size, zero fill the remaining
1053 if (Size
< Section
->Misc
.VirtualSize
) {
1054 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
1064 // Get image's entry point
1066 if (!(ImageContext
->IsTeImage
)) {
1067 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (
1069 PeHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
1072 ImageContext
->EntryPoint
= (UINTN
)ImageContext
->ImageAddress
+
1073 (UINTN
)TeHdr
->AddressOfEntryPoint
+
1074 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1075 (UINTN
) TeHdr
->StrippedSize
;
1079 // Determine the size of the fixup data
1081 // Per the PE/COFF spec, you can't assume that a given data directory
1082 // is present in the image. You have to check the NumberOfRvaAndSizes in
1083 // the optional header to verify a desired directory entry is there.
1085 if (!(ImageContext
->IsTeImage
)) {
1086 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1087 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1088 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
1089 &OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1090 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1092 ImageContext
->FixupDataSize
= 0;
1095 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1096 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
1097 &OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1098 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1100 ImageContext
->FixupDataSize
= 0;
1104 DirectoryEntry
= &TeHdr
->DataDirectory
[0];
1105 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1108 // Consumer must allocate a buffer for the relocation fixup log.
1109 // Only used for runtime drivers.
1111 ImageContext
->FixupData
= NULL
;
1114 // Load the Codeview info if present
1116 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
1117 if (!(ImageContext
->IsTeImage
)) {
1118 DebugEntry
= PeCoffLoaderImageAddress (
1120 ImageContext
->DebugDirectoryEntryRva
1123 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(UINTN
)(
1124 ImageContext
->ImageAddress
+
1125 ImageContext
->DebugDirectoryEntryRva
+
1126 sizeof(EFI_TE_IMAGE_HEADER
) -
1131 if (DebugEntry
!= NULL
) {
1132 TempDebugEntryRva
= DebugEntry
->RVA
;
1133 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
1135 if ((UINTN
) Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
1136 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
1138 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
1142 if (TempDebugEntryRva
!= 0) {
1143 if (!(ImageContext
->IsTeImage
)) {
1144 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
);
1146 ImageContext
->CodeView
= (VOID
*)(
1147 (UINTN
)ImageContext
->ImageAddress
+
1148 (UINTN
)TempDebugEntryRva
+
1149 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1150 (UINTN
) TeHdr
->StrippedSize
1154 if (ImageContext
->CodeView
== NULL
) {
1155 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1156 return RETURN_LOAD_ERROR
;
1159 if (DebugEntry
->RVA
== 0) {
1160 Size
= DebugEntry
->SizeOfData
;
1161 if (!(ImageContext
->IsTeImage
)) {
1162 Status
= ImageContext
->ImageRead (
1163 ImageContext
->Handle
,
1164 DebugEntry
->FileOffset
,
1166 ImageContext
->CodeView
1169 Status
= ImageContext
->ImageRead (
1170 ImageContext
->Handle
,
1171 DebugEntry
->FileOffset
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHdr
->StrippedSize
,
1173 ImageContext
->CodeView
1176 // Should we apply fix up to this field according to the size difference between PE and TE?
1177 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1178 // in original PE image.
1182 if (RETURN_ERROR (Status
)) {
1183 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1184 return RETURN_LOAD_ERROR
;
1187 DebugEntry
->RVA
= TempDebugEntryRva
;
1190 switch (*(UINT32
*) ImageContext
->CodeView
) {
1191 case CODEVIEW_SIGNATURE_NB10
:
1192 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1195 case CODEVIEW_SIGNATURE_RSDS
:
1196 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
1199 case CODEVIEW_SIGNATURE_MTOC
:
1200 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
);
1213 Returns a pointer to the PDB file name for a raw PE/COFF image that is not
1214 loaded into system memory with the PE/COFF Loader Library functions.
1216 Returns the PDB file name for the PE/COFF image specified by Pe32Data. If
1217 the PE/COFF image specified by Pe32Data is not a valid, then NULL is
1218 returned. If the PE/COFF image specified by Pe32Data does not contain a
1219 debug directory entry, then NULL is returned. If the debug directory entry
1220 in the PE/COFF image specified by Pe32Data does not contain a PDB file name,
1221 then NULL is returned.
1222 If Pe32Data is NULL, then return NULL.
1224 @param Pe32Data Pointer to the PE/COFF image that is loaded in system
1227 @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL
1228 if it cannot be retrieved.
1233 PeCoffLoaderGetPdbPointer (
1237 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1238 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1239 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
1240 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
1242 VOID
*CodeViewEntryPointer
;
1244 UINT32 NumberOfRvaAndSizes
;
1246 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
1247 UINT32 Index
, Index1
;
1249 if (Pe32Data
== NULL
) {
1254 DirectoryEntry
= NULL
;
1256 NumberOfRvaAndSizes
= 0;
1259 SectionHeader
= NULL
;
1261 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)Pe32Data
;
1262 if (EFI_IMAGE_DOS_SIGNATURE
== DosHdr
->e_magic
) {
1264 // DOS image header is present, so read the PE header after the DOS image header.
1266 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
) Pe32Data
+ (UINTN
) ((DosHdr
->e_lfanew
) & 0x0ffff));
1269 // DOS image header is not present, so PE header is at the image base.
1271 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)Pe32Data
;
1274 if (EFI_TE_IMAGE_HEADER_SIGNATURE
== Hdr
.Te
->Signature
) {
1275 if (Hdr
.Te
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
!= 0) {
1276 DirectoryEntry
= &Hdr
.Te
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
];
1277 TEImageAdjust
= sizeof (EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->StrippedSize
;
1280 // Get the DebugEntry offset in the raw data image.
1282 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (Hdr
.Te
+ 1);
1283 Index
= Hdr
.Te
->NumberOfSections
;
1284 for (Index1
= 0; Index1
< Index
; Index1
++) {
1285 if ((DirectoryEntry
->VirtualAddress
>= SectionHeader
[Index1
].VirtualAddress
) &&
1286 (DirectoryEntry
->VirtualAddress
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1287 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)((UINTN
) Hdr
.Te
+
1288 DirectoryEntry
->VirtualAddress
-
1289 SectionHeader
[Index1
].VirtualAddress
+
1290 SectionHeader
[Index1
].PointerToRawData
+
1296 } else if (EFI_IMAGE_NT_SIGNATURE
== Hdr
.Pe32
->Signature
) {
1298 // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.
1299 // It is due to backward-compatibility, for some system might
1300 // generate PE32+ image with PE32 Magic.
1302 switch (Hdr
.Pe32
->FileHeader
.Machine
) {
1303 case EFI_IMAGE_MACHINE_IA32
:
1304 case EFI_IMAGE_MACHINE_ARMT
:
1306 // Assume PE32 image with IA32 Machine field.
1308 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
1310 case EFI_IMAGE_MACHINE_X64
:
1312 // Assume PE32+ image with X64 Machine field
1314 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
1318 // For unknow Machine field, use Magic in optional Header
1320 Magic
= Hdr
.Pe32
->OptionalHeader
.Magic
;
1323 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
1324 (UINT8
*) Hdr
.Pe32
+
1326 sizeof (EFI_IMAGE_FILE_HEADER
) +
1327 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
1329 Index
= Hdr
.Pe32
->FileHeader
.NumberOfSections
;
1331 if (EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
== Magic
) {
1333 // Use PE32 offset get Debug Directory Entry
1335 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1336 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
1337 } else if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
1339 // Use PE32+ offset get Debug Directory Entry
1341 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1342 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
1345 if (NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
|| DirectoryEntry
->VirtualAddress
== 0) {
1346 DirectoryEntry
= NULL
;
1350 // Get the DebugEntry offset in the raw data image.
1352 for (Index1
= 0; Index1
< Index
; Index1
++) {
1353 if ((DirectoryEntry
->VirtualAddress
>= SectionHeader
[Index1
].VirtualAddress
) &&
1354 (DirectoryEntry
->VirtualAddress
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1355 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*) (
1357 DirectoryEntry
->VirtualAddress
-
1358 SectionHeader
[Index1
].VirtualAddress
+
1359 SectionHeader
[Index1
].PointerToRawData
);
1368 if (NULL
== DebugEntry
|| NULL
== DirectoryEntry
) {
1373 // Scan the directory to find the debug entry.
1375 for (DirCount
= 0; DirCount
< DirectoryEntry
->Size
; DirCount
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
), DebugEntry
++) {
1376 if (EFI_IMAGE_DEBUG_TYPE_CODEVIEW
== DebugEntry
->Type
) {
1377 if (DebugEntry
->SizeOfData
> 0) {
1379 // Get the DebugEntry offset in the raw data image.
1381 CodeViewEntryPointer
= NULL
;
1382 for (Index1
= 0; Index1
< Index
; Index1
++) {
1383 if ((DebugEntry
->RVA
>= SectionHeader
[Index1
].VirtualAddress
) &&
1384 (DebugEntry
->RVA
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1385 CodeViewEntryPointer
= (VOID
*) (
1387 (UINTN
) DebugEntry
->RVA
-
1388 SectionHeader
[Index1
].VirtualAddress
+
1389 SectionHeader
[Index1
].PointerToRawData
+
1390 (UINTN
)TEImageAdjust
);
1394 if (Index1
>= Index
) {
1396 // Can't find CodeViewEntryPointer in raw PE/COFF image.
1400 switch (* (UINT32
*) CodeViewEntryPointer
) {
1401 case CODEVIEW_SIGNATURE_NB10
:
1402 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
));
1403 case CODEVIEW_SIGNATURE_RSDS
:
1404 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
));
1405 case CODEVIEW_SIGNATURE_MTOC
:
1406 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
));
1420 PeCoffLoaderGetEntryPoint (
1422 OUT VOID
**EntryPoint
,
1423 OUT VOID
**BaseOfImage
1426 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1427 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1429 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)Pe32Data
;
1430 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
1432 // DOS image header is present, so read the PE header after the DOS image header.
1434 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
) Pe32Data
+ (UINTN
) ((DosHdr
->e_lfanew
) & 0x0ffff));
1437 // DOS image header is not present, so PE header is at the image base.
1439 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)Pe32Data
;
1443 // Calculate the entry point relative to the start of the image.
1444 // AddressOfEntryPoint is common for PE32 & PE32+
1446 if (Hdr
.Te
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
1447 *BaseOfImage
= (VOID
*)(UINTN
)(Hdr
.Te
->ImageBase
+ Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
1448 *EntryPoint
= (VOID
*)((UINTN
)*BaseOfImage
+ (Hdr
.Te
->AddressOfEntryPoint
& 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->StrippedSize
);
1449 return RETURN_SUCCESS
;
1450 } else if (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
) {
1451 *EntryPoint
= (VOID
*)(UINTN
)Hdr
.Pe32
->OptionalHeader
.AddressOfEntryPoint
;
1452 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1453 *BaseOfImage
= (VOID
*)(UINTN
)Hdr
.Pe32
->OptionalHeader
.ImageBase
;
1455 *BaseOfImage
= (VOID
*)(UINTN
)Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
1457 *EntryPoint
= (VOID
*)(UINTN
)((UINTN
)*EntryPoint
+ (UINTN
)*BaseOfImage
);
1458 return RETURN_SUCCESS
;
1461 return RETURN_UNSUPPORTED
;