3 Functions to get info and load PE/COFF image.
5 Copyright (c) 2004 - 2016, 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 PeCoffLoaderRelocateIpfImage (
63 IN OUT CHAR8
**FixupData
,
68 PeCoffLoaderRelocateArmImage (
71 IN OUT CHAR8
**FixupData
,
77 PeCoffLoaderGetPeHeader (
78 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
79 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION
**PeHdr
,
80 OUT EFI_TE_IMAGE_HEADER
**TeHdr
86 Retrieves the PE or TE Header from a PE/COFF or TE image
90 ImageContext - The context of the image being loaded
92 PeHdr - The buffer in which to return the PE header
94 TeHdr - The buffer in which to return the TE header
98 RETURN_SUCCESS if the PE or TE Header is read,
99 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
103 RETURN_STATUS Status
;
104 EFI_IMAGE_DOS_HEADER DosHdr
;
107 ImageContext
->IsTeImage
= FALSE
;
109 // Read the DOS image headers
111 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
112 Status
= ImageContext
->ImageRead (
113 ImageContext
->Handle
,
118 if (RETURN_ERROR (Status
)) {
119 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
123 ImageContext
->PeCoffHeaderOffset
= 0;
124 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
126 // DOS image header is present, so read the PE header after the DOS image header
128 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
131 // Get the PE/COFF Header pointer
133 *PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINTN
)ImageContext
->Handle
+ ImageContext
->PeCoffHeaderOffset
);
134 if ((*PeHdr
)->Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
136 // Check the PE/COFF Header Signature. If not, then try to get a TE header
138 *TeHdr
= (EFI_TE_IMAGE_HEADER
*)*PeHdr
;
139 if ((*TeHdr
)->Signature
!= EFI_TE_IMAGE_HEADER_SIGNATURE
) {
140 return RETURN_UNSUPPORTED
;
142 ImageContext
->IsTeImage
= TRUE
;
145 return RETURN_SUCCESS
;
150 PeCoffLoaderCheckImageType (
151 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
152 IN EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
,
153 IN EFI_TE_IMAGE_HEADER
*TeHdr
159 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
163 ImageContext - The context of the image being loaded
165 PeHdr - The buffer in which to return the PE header
167 TeHdr - The buffer in which to return the TE header
171 RETURN_SUCCESS if the PE/COFF or TE image is supported
172 RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported.
177 // See if the machine type is supported.
178 // We support a native machine type (IA-32/Itanium-based)
180 if (ImageContext
->IsTeImage
== FALSE
) {
181 ImageContext
->Machine
= PeHdr
->Pe32
.FileHeader
.Machine
;
183 ImageContext
->Machine
= TeHdr
->Machine
;
186 if (ImageContext
->Machine
!= EFI_IMAGE_MACHINE_IA32
&& \
187 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_IA64
&& \
188 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_X64
&& \
189 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_ARMT
&& \
190 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_EBC
&& \
191 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_AARCH64
) {
192 if (ImageContext
->Machine
== IMAGE_FILE_MACHINE_ARM
) {
194 // There are two types of ARM images. Pure ARM and ARM/Thumb.
195 // If we see the ARM say it is the ARM/Thumb so there is only
196 // a single machine type we need to check for ARM.
198 ImageContext
->Machine
= EFI_IMAGE_MACHINE_ARMT
;
199 if (ImageContext
->IsTeImage
== FALSE
) {
200 PeHdr
->Pe32
.FileHeader
.Machine
= ImageContext
->Machine
;
202 TeHdr
->Machine
= ImageContext
->Machine
;
207 // unsupported PeImage machine type
209 return RETURN_UNSUPPORTED
;
214 // See if the image type is supported. We support EFI Applications,
215 // EFI Boot Service Drivers, EFI Runtime Drivers and EFI SAL Drivers.
217 if (ImageContext
->IsTeImage
== FALSE
) {
218 ImageContext
->ImageType
= PeHdr
->Pe32
.OptionalHeader
.Subsystem
;
220 ImageContext
->ImageType
= (UINT16
) (TeHdr
->Subsystem
);
223 if (ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
&& \
224 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
&& \
225 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
&& \
226 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
) {
228 // upsupported PeImage subsystem type
230 return RETURN_UNSUPPORTED
;
233 return RETURN_SUCCESS
;
238 PeCoffLoaderGetImageInfo (
239 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
245 Retrieves information on a PE/COFF image
249 This - Calling context
250 ImageContext - The context of the image being loaded
254 RETURN_SUCCESS - The information on the PE/COFF image was collected.
255 RETURN_INVALID_PARAMETER - ImageContext is NULL.
256 RETURN_UNSUPPORTED - The PE/COFF image is not supported.
257 Otherwise - The error status from reading the PE/COFF image using the
258 ImageContext->ImageRead() function
262 RETURN_STATUS Status
;
263 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
264 EFI_TE_IMAGE_HEADER
*TeHdr
;
265 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
268 UINTN DebugDirectoryEntryRva
;
269 UINTN DebugDirectoryEntryFileOffset
;
270 UINTN SectionHeaderOffset
;
271 EFI_IMAGE_SECTION_HEADER SectionHeader
;
272 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
273 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
277 DebugDirectoryEntry
= NULL
;
278 DebugDirectoryEntryRva
= 0;
280 if (NULL
== ImageContext
) {
281 return RETURN_INVALID_PARAMETER
;
286 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
288 Status
= PeCoffLoaderGetPeHeader (ImageContext
, &PeHdr
, &TeHdr
);
289 if (RETURN_ERROR (Status
)) {
294 // Verify machine type
296 Status
= PeCoffLoaderCheckImageType (ImageContext
, PeHdr
, TeHdr
);
297 if (RETURN_ERROR (Status
)) {
300 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
303 // Retrieve the base address of the image
305 if (!(ImageContext
->IsTeImage
)) {
306 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
307 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) OptionHeader
.Optional32
->ImageBase
;
309 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) OptionHeader
.Optional64
->ImageBase
;
312 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) (TeHdr
->ImageBase
+ TeHdr
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
315 // Initialize the alternate destination address to 0 indicating that it
316 // should not be used.
318 ImageContext
->DestinationAddress
= 0;
321 // Initialize the codeview pointer.
323 ImageContext
->CodeView
= NULL
;
324 ImageContext
->PdbPointer
= NULL
;
327 // Three cases with regards to relocations:
328 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
329 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
330 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
331 // has no base relocs to apply
332 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
334 // Look at the file header to determine if relocations have been stripped, and
335 // save this info in the image context for later use.
337 if ((!(ImageContext
->IsTeImage
)) && ((PeHdr
->Pe32
.FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
338 ImageContext
->RelocationsStripped
= TRUE
;
339 } else if ((ImageContext
->IsTeImage
) && (TeHdr
->DataDirectory
[0].Size
== 0) && (TeHdr
->DataDirectory
[0].VirtualAddress
== 0)) {
340 ImageContext
->RelocationsStripped
= TRUE
;
342 ImageContext
->RelocationsStripped
= FALSE
;
345 if (!(ImageContext
->IsTeImage
)) {
347 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
348 ImageContext
->ImageSize
= (UINT64
) OptionHeader
.Optional32
->SizeOfImage
;
349 ImageContext
->SectionAlignment
= OptionHeader
.Optional32
->SectionAlignment
;
350 ImageContext
->SizeOfHeaders
= OptionHeader
.Optional32
->SizeOfHeaders
;
353 // Modify ImageSize to contain .PDB file name if required and initialize
356 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
357 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
358 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
361 ImageContext
->ImageSize
= (UINT64
) OptionHeader
.Optional64
->SizeOfImage
;
362 ImageContext
->SectionAlignment
= OptionHeader
.Optional64
->SectionAlignment
;
363 ImageContext
->SizeOfHeaders
= OptionHeader
.Optional64
->SizeOfHeaders
;
366 // Modify ImageSize to contain .PDB file name if required and initialize
369 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
370 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
371 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
375 if (DebugDirectoryEntryRva
!= 0) {
377 // Determine the file offset of the debug directory... This means we walk
378 // the sections to find which section contains the RVA of the debug
381 DebugDirectoryEntryFileOffset
= 0;
383 SectionHeaderOffset
= (UINTN
)(
384 ImageContext
->PeCoffHeaderOffset
+
386 sizeof (EFI_IMAGE_FILE_HEADER
) +
387 PeHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
390 for (Index
= 0; Index
< PeHdr
->Pe32
.FileHeader
.NumberOfSections
; Index
++) {
392 // Read section header from file
394 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
395 Status
= ImageContext
->ImageRead (
396 ImageContext
->Handle
,
401 if (RETURN_ERROR (Status
)) {
402 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
406 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
407 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
408 DebugDirectoryEntryFileOffset
=
409 DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
413 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
416 if (DebugDirectoryEntryFileOffset
!= 0) {
417 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
419 // Read next debug directory entry
421 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
422 Status
= ImageContext
->ImageRead (
423 ImageContext
->Handle
,
424 DebugDirectoryEntryFileOffset
+ Index
,
428 if (RETURN_ERROR (Status
)) {
429 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
433 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
434 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
435 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
436 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
439 return RETURN_SUCCESS
;
445 ImageContext
->ImageSize
= 0;
446 ImageContext
->SectionAlignment
= 4096;
447 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
) TeHdr
->BaseOfCode
- (UINTN
) TeHdr
->StrippedSize
;
449 DebugDirectoryEntry
= &TeHdr
->DataDirectory
[1];
450 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
451 SectionHeaderOffset
= (UINTN
) (sizeof (EFI_TE_IMAGE_HEADER
));
453 DebugDirectoryEntryFileOffset
= 0;
455 for (Index
= 0; Index
< TeHdr
->NumberOfSections
;) {
457 // Read section header from file
459 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
460 Status
= ImageContext
->ImageRead (
461 ImageContext
->Handle
,
466 if (RETURN_ERROR (Status
)) {
467 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
471 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
472 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
473 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
474 SectionHeader
.VirtualAddress
+
475 SectionHeader
.PointerToRawData
+
476 sizeof (EFI_TE_IMAGE_HEADER
) -
480 // File offset of the debug directory was found, if this is not the last
481 // section, then skip to the last section for calculating the image size.
483 if (Index
< (UINTN
) TeHdr
->NumberOfSections
- 1) {
484 SectionHeaderOffset
+= (TeHdr
->NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
485 Index
= TeHdr
->NumberOfSections
- 1;
491 // In Te image header there is not a field to describe the ImageSize.
492 // Actually, the ImageSize equals the RVA plus the VirtualSize of
493 // the last section mapped into memory (Must be rounded up to
494 // a mulitple of Section Alignment). Per the PE/COFF specification, the
495 // section headers in the Section Table must appear in order of the RVA
496 // values for the corresponding sections. So the ImageSize can be determined
497 // by the RVA and the VirtualSize of the last section header in the
500 if ((++Index
) == (UINTN
) TeHdr
->NumberOfSections
) {
501 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
+
502 ImageContext
->SectionAlignment
- 1) & ~(ImageContext
->SectionAlignment
- 1);
505 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
508 if (DebugDirectoryEntryFileOffset
!= 0) {
509 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
511 // Read next debug directory entry
513 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
514 Status
= ImageContext
->ImageRead (
515 ImageContext
->Handle
,
516 DebugDirectoryEntryFileOffset
,
520 if (RETURN_ERROR (Status
)) {
521 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
525 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
526 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
527 return RETURN_SUCCESS
;
533 return RETURN_SUCCESS
;
538 PeCoffLoaderImageAddress (
539 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
546 Converts an image address to the loaded address
550 ImageContext - The context of the image being loaded
552 Address - The address to be converted to the loaded address
556 NULL if the address can not be converted, otherwise, the converted address
560 if (Address
>= ImageContext
->ImageSize
) {
561 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
565 return (UINT8
*) ((UINTN
) ImageContext
->ImageAddress
+ Address
);
570 PeCoffLoaderRelocateImage (
571 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
577 Relocates a PE/COFF image in memory
581 This - Calling context
583 ImageContext - Contains information on the loaded image to relocate
587 RETURN_SUCCESS if the PE/COFF image was relocated
588 RETURN_LOAD_ERROR if the image is not a valid PE/COFF image
589 RETURN_UNSUPPORTED not support
593 RETURN_STATUS Status
;
594 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
595 EFI_TE_IMAGE_HEADER
*TeHdr
;
596 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
598 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
599 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
608 PHYSICAL_ADDRESS BaseAddress
;
610 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
617 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
620 // If there are no relocation entries, then we are done
622 if (ImageContext
->RelocationsStripped
) {
623 return RETURN_SUCCESS
;
627 // Use DestinationAddress field of ImageContext as the relocation address even if it is 0.
629 BaseAddress
= ImageContext
->DestinationAddress
;
631 if (!(ImageContext
->IsTeImage
)) {
632 PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)((UINTN
)ImageContext
->ImageAddress
+
633 ImageContext
->PeCoffHeaderOffset
);
634 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
635 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
636 Adjust
= (UINT64
) BaseAddress
- OptionHeader
.Optional32
->ImageBase
;
637 OptionHeader
.Optional32
->ImageBase
= (UINT32
) BaseAddress
;
638 MachineType
= ImageContext
->Machine
;
640 // Find the relocation block
642 // Per the PE/COFF spec, you can't assume that a given data directory
643 // is present in the image. You have to check the NumberOfRvaAndSizes in
644 // the optional header to verify a desired directory entry is there.
646 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
647 RelocDir
= &OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
648 if ((RelocDir
!= NULL
) && (RelocDir
->Size
> 0)) {
649 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
650 RelocBaseEnd
= PeCoffLoaderImageAddress (
652 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
654 if (RelocBase
== NULL
|| RelocBaseEnd
== NULL
|| RelocBaseEnd
< RelocBase
) {
655 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
656 return RETURN_LOAD_ERROR
;
660 // Set base and end to bypass processing below.
662 RelocBase
= RelocBaseEnd
= 0;
666 // Set base and end to bypass processing below.
668 RelocBase
= RelocBaseEnd
= 0;
671 Adjust
= (UINT64
) BaseAddress
- OptionHeader
.Optional64
->ImageBase
;
672 OptionHeader
.Optional64
->ImageBase
= BaseAddress
;
673 MachineType
= ImageContext
->Machine
;
675 // Find the relocation block
677 // Per the PE/COFF spec, you can't assume that a given data directory
678 // is present in the image. You have to check the NumberOfRvaAndSizes in
679 // the optional header to verify a desired directory entry is there.
681 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
682 RelocDir
= &OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
683 if ((RelocDir
!= NULL
) && (RelocDir
->Size
> 0)) {
684 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
685 RelocBaseEnd
= PeCoffLoaderImageAddress (
687 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
689 if (RelocBase
== NULL
|| RelocBaseEnd
== NULL
|| RelocBaseEnd
< RelocBase
) {
690 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
691 return RETURN_LOAD_ERROR
;
695 // Set base and end to bypass processing below.
697 RelocBase
= RelocBaseEnd
= 0;
701 // Set base and end to bypass processing below.
703 RelocBase
= RelocBaseEnd
= 0;
707 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
708 Adjust
= (UINT64
) (BaseAddress
- TeHdr
->ImageBase
);
709 TeHdr
->ImageBase
= (UINT64
) (BaseAddress
);
710 MachineType
= TeHdr
->Machine
;
713 // Find the relocation block
715 RelocDir
= &TeHdr
->DataDirectory
[0];
716 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(
717 ImageContext
->ImageAddress
+
718 RelocDir
->VirtualAddress
+
719 sizeof(EFI_TE_IMAGE_HEADER
) -
722 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) ((UINTN
) RelocBase
+ (UINTN
) RelocDir
->Size
- 1);
726 // Run the relocation information and apply the fixups
728 FixupData
= ImageContext
->FixupData
;
729 while (RelocBase
< RelocBaseEnd
) {
731 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
732 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
733 if (!(ImageContext
->IsTeImage
)) {
734 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
);
735 if (FixupBase
== NULL
) {
736 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
737 return RETURN_LOAD_ERROR
;
740 FixupBase
= (CHAR8
*)(UINTN
)(ImageContext
->ImageAddress
+
741 RelocBase
->VirtualAddress
+
742 sizeof(EFI_TE_IMAGE_HEADER
) -
747 if ((CHAR8
*) RelocEnd
< (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
) ||
748 (CHAR8
*) RelocEnd
> (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+
749 (UINTN
)ImageContext
->ImageSize
)) {
750 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
751 return RETURN_LOAD_ERROR
;
755 // Run this relocation record
757 while (Reloc
< RelocEnd
) {
759 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
760 switch ((*Reloc
) >> 12) {
761 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
764 case EFI_IMAGE_REL_BASED_HIGH
:
765 F16
= (UINT16
*) Fixup
;
766 *F16
= (UINT16
) (*F16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
767 if (FixupData
!= NULL
) {
768 *(UINT16
*) FixupData
= *F16
;
769 FixupData
= FixupData
+ sizeof (UINT16
);
773 case EFI_IMAGE_REL_BASED_LOW
:
774 F16
= (UINT16
*) Fixup
;
775 *F16
= (UINT16
) (*F16
+ (UINT16
) Adjust
);
776 if (FixupData
!= NULL
) {
777 *(UINT16
*) FixupData
= *F16
;
778 FixupData
= FixupData
+ sizeof (UINT16
);
782 case EFI_IMAGE_REL_BASED_HIGHLOW
:
783 F32
= (UINT32
*) Fixup
;
784 *F32
= *F32
+ (UINT32
) Adjust
;
785 if (FixupData
!= NULL
) {
786 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
787 *(UINT32
*) FixupData
= *F32
;
788 FixupData
= FixupData
+ sizeof (UINT32
);
792 case EFI_IMAGE_REL_BASED_DIR64
:
793 F64
= (UINT64
*) Fixup
;
794 *F64
= *F64
+ (UINT64
) Adjust
;
795 if (FixupData
!= NULL
) {
796 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT64
));
797 *(UINT64
*) FixupData
= *F64
;
798 FixupData
= FixupData
+ sizeof (UINT64
);
802 case EFI_IMAGE_REL_BASED_HIGHADJ
:
804 // Return the same EFI_UNSUPPORTED return code as
805 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
806 // the relocation type.
808 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
809 return RETURN_UNSUPPORTED
;
812 switch (MachineType
) {
813 case EFI_IMAGE_MACHINE_IA32
:
814 Status
= PeCoffLoaderRelocateIa32Image (Reloc
, Fixup
, &FixupData
, Adjust
);
816 case EFI_IMAGE_MACHINE_ARMT
:
817 Status
= PeCoffLoaderRelocateArmImage (&Reloc
, Fixup
, &FixupData
, Adjust
);
819 case EFI_IMAGE_MACHINE_IA64
:
820 Status
= PeCoffLoaderRelocateIpfImage (Reloc
, Fixup
, &FixupData
, Adjust
);
823 Status
= RETURN_UNSUPPORTED
;
826 if (RETURN_ERROR (Status
)) {
827 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
833 // Next relocation record
841 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
844 return RETURN_SUCCESS
;
849 PeCoffLoaderLoadImage (
850 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
856 Loads a PE/COFF image into memory
860 This - Calling context
862 ImageContext - Contains information on image to load into memory
866 RETURN_SUCCESS if the PE/COFF image was loaded
867 RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
868 RETURN_LOAD_ERROR if the image is a runtime driver with no relocations
869 RETURN_INVALID_PARAMETER if the image address is invalid
873 RETURN_STATUS Status
;
874 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
875 EFI_TE_IMAGE_HEADER
*TeHdr
;
876 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
877 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
878 EFI_IMAGE_SECTION_HEADER
*Section
;
879 UINTN NumberOfSections
;
884 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
885 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
887 UINT32 TempDebugEntryRva
;
888 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
892 OptionHeader
.Header
= NULL
;
896 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
899 // Copy the provided context info into our local version, get what we
900 // can from the original image, and then use that to make sure everything
903 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
905 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
906 if (RETURN_ERROR (Status
)) {
911 // Make sure there is enough allocated space for the image being loaded
913 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
914 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
915 return RETURN_BUFFER_TOO_SMALL
;
919 // If there's no relocations, then make sure it's not a runtime driver,
920 // and that it's being loaded at the linked address.
922 if (CheckContext
.RelocationsStripped
) {
924 // If the image does not contain relocations and it is a runtime driver
925 // then return an error.
927 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
928 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
929 return RETURN_LOAD_ERROR
;
932 // If the image does not contain relocations, and the requested load address
933 // is not the linked address, then return an error.
935 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
936 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
937 return RETURN_INVALID_PARAMETER
;
941 // Make sure the allocated space has the proper section alignment
943 if (!(ImageContext
->IsTeImage
)) {
944 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
945 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
946 return RETURN_INVALID_PARAMETER
;
950 // Read the entire PE/COFF or TE header into memory
952 if (!(ImageContext
->IsTeImage
)) {
953 Status
= ImageContext
->ImageRead (
954 ImageContext
->Handle
,
956 &ImageContext
->SizeOfHeaders
,
957 (VOID
*) (UINTN
) ImageContext
->ImageAddress
960 PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)
961 ((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
963 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
965 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
966 (UINTN
)ImageContext
->ImageAddress
+
967 ImageContext
->PeCoffHeaderOffset
+
969 sizeof(EFI_IMAGE_FILE_HEADER
) +
970 PeHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
972 NumberOfSections
= (UINTN
) (PeHdr
->Pe32
.FileHeader
.NumberOfSections
);
974 Status
= ImageContext
->ImageRead (
975 ImageContext
->Handle
,
977 &ImageContext
->SizeOfHeaders
,
978 (VOID
*) (UINTN
) ImageContext
->ImageAddress
981 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
983 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
984 (UINTN
)ImageContext
->ImageAddress
+
985 sizeof(EFI_TE_IMAGE_HEADER
)
987 NumberOfSections
= (UINTN
) (TeHdr
->NumberOfSections
);
991 if (RETURN_ERROR (Status
)) {
992 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
993 return RETURN_LOAD_ERROR
;
997 // Load each section of the image
999 Section
= FirstSection
;
1000 for (Index
= 0, MaxEnd
= NULL
; Index
< NumberOfSections
; Index
++) {
1003 // Compute sections address
1005 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
);
1006 End
= PeCoffLoaderImageAddress (
1008 Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1
1012 // If the base start or end address resolved to 0, then fail.
1014 if ((Base
== NULL
) || (End
== NULL
)) {
1015 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
1016 return RETURN_LOAD_ERROR
;
1020 if (ImageContext
->IsTeImage
) {
1021 Base
= (CHAR8
*) ((UINTN
) Base
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
1022 End
= (CHAR8
*) ((UINTN
) End
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
1032 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
1033 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
1034 Size
= (UINTN
) Section
->SizeOfRawData
;
1037 if (Section
->SizeOfRawData
) {
1038 if (!(ImageContext
->IsTeImage
)) {
1039 Status
= ImageContext
->ImageRead (
1040 ImageContext
->Handle
,
1041 Section
->PointerToRawData
,
1046 Status
= ImageContext
->ImageRead (
1047 ImageContext
->Handle
,
1048 Section
->PointerToRawData
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
,
1054 if (RETURN_ERROR (Status
)) {
1055 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1061 // If raw size is less then virt size, zero fill the remaining
1064 if (Size
< Section
->Misc
.VirtualSize
) {
1065 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
1075 // Get image's entry point
1077 if (!(ImageContext
->IsTeImage
)) {
1078 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (
1080 PeHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
1083 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (
1084 (UINTN
)ImageContext
->ImageAddress
+
1085 (UINTN
)TeHdr
->AddressOfEntryPoint
+
1086 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1087 (UINTN
) TeHdr
->StrippedSize
1092 // Determine the size of the fixup data
1094 // Per the PE/COFF spec, you can't assume that a given data directory
1095 // is present in the image. You have to check the NumberOfRvaAndSizes in
1096 // the optional header to verify a desired directory entry is there.
1098 if (!(ImageContext
->IsTeImage
)) {
1099 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1100 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1101 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
1102 &OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1103 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1105 ImageContext
->FixupDataSize
= 0;
1108 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1109 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
1110 &OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1111 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1113 ImageContext
->FixupDataSize
= 0;
1117 DirectoryEntry
= &TeHdr
->DataDirectory
[0];
1118 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1121 // Consumer must allocate a buffer for the relocation fixup log.
1122 // Only used for runtime drivers.
1124 ImageContext
->FixupData
= NULL
;
1127 // Load the Codeview info if present
1129 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
1130 if (!(ImageContext
->IsTeImage
)) {
1131 DebugEntry
= PeCoffLoaderImageAddress (
1133 ImageContext
->DebugDirectoryEntryRva
1136 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(UINTN
)(
1137 ImageContext
->ImageAddress
+
1138 ImageContext
->DebugDirectoryEntryRva
+
1139 sizeof(EFI_TE_IMAGE_HEADER
) -
1144 if (DebugEntry
!= NULL
) {
1145 TempDebugEntryRva
= DebugEntry
->RVA
;
1146 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
1148 if ((UINTN
) Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
1149 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
1151 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
1155 if (TempDebugEntryRva
!= 0) {
1156 if (!(ImageContext
->IsTeImage
)) {
1157 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
);
1159 ImageContext
->CodeView
= (VOID
*)(
1160 (UINTN
)ImageContext
->ImageAddress
+
1161 (UINTN
)TempDebugEntryRva
+
1162 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1163 (UINTN
) TeHdr
->StrippedSize
1167 if (ImageContext
->CodeView
== NULL
) {
1168 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1169 return RETURN_LOAD_ERROR
;
1172 if (DebugEntry
->RVA
== 0) {
1173 Size
= DebugEntry
->SizeOfData
;
1174 if (!(ImageContext
->IsTeImage
)) {
1175 Status
= ImageContext
->ImageRead (
1176 ImageContext
->Handle
,
1177 DebugEntry
->FileOffset
,
1179 ImageContext
->CodeView
1182 Status
= ImageContext
->ImageRead (
1183 ImageContext
->Handle
,
1184 DebugEntry
->FileOffset
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHdr
->StrippedSize
,
1186 ImageContext
->CodeView
1189 // Should we apply fix up to this field according to the size difference between PE and TE?
1190 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1191 // in original PE image.
1195 if (RETURN_ERROR (Status
)) {
1196 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1197 return RETURN_LOAD_ERROR
;
1200 DebugEntry
->RVA
= TempDebugEntryRva
;
1203 switch (*(UINT32
*) ImageContext
->CodeView
) {
1204 case CODEVIEW_SIGNATURE_NB10
:
1205 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1208 case CODEVIEW_SIGNATURE_RSDS
:
1209 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
1212 case CODEVIEW_SIGNATURE_MTOC
:
1213 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
);
1226 Returns a pointer to the PDB file name for a raw PE/COFF image that is not
1227 loaded into system memory with the PE/COFF Loader Library functions.
1229 Returns the PDB file name for the PE/COFF image specified by Pe32Data. If
1230 the PE/COFF image specified by Pe32Data is not a valid, then NULL is
1231 returned. If the PE/COFF image specified by Pe32Data does not contain a
1232 debug directory entry, then NULL is returned. If the debug directory entry
1233 in the PE/COFF image specified by Pe32Data does not contain a PDB file name,
1234 then NULL is returned.
1235 If Pe32Data is NULL, then return NULL.
1237 @param Pe32Data Pointer to the PE/COFF image that is loaded in system
1240 @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL
1241 if it cannot be retrieved.
1246 PeCoffLoaderGetPdbPointer (
1250 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1251 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1252 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
1253 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
1255 VOID
*CodeViewEntryPointer
;
1257 UINT32 NumberOfRvaAndSizes
;
1259 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
1260 UINT32 Index
, Index1
;
1262 if (Pe32Data
== NULL
) {
1267 DirectoryEntry
= NULL
;
1269 NumberOfRvaAndSizes
= 0;
1272 SectionHeader
= NULL
;
1274 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)Pe32Data
;
1275 if (EFI_IMAGE_DOS_SIGNATURE
== DosHdr
->e_magic
) {
1277 // DOS image header is present, so read the PE header after the DOS image header.
1279 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
) Pe32Data
+ (UINTN
) ((DosHdr
->e_lfanew
) & 0x0ffff));
1282 // DOS image header is not present, so PE header is at the image base.
1284 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)Pe32Data
;
1287 if (EFI_TE_IMAGE_HEADER_SIGNATURE
== Hdr
.Te
->Signature
) {
1288 if (Hdr
.Te
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
!= 0) {
1289 DirectoryEntry
= &Hdr
.Te
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
];
1290 TEImageAdjust
= sizeof (EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->StrippedSize
;
1293 // Get the DebugEntry offset in the raw data image.
1295 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (Hdr
.Te
+ 1);
1296 Index
= Hdr
.Te
->NumberOfSections
;
1297 for (Index1
= 0; Index1
< Index
; Index1
++) {
1298 if ((DirectoryEntry
->VirtualAddress
>= SectionHeader
[Index1
].VirtualAddress
) &&
1299 (DirectoryEntry
->VirtualAddress
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1300 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)((UINTN
) Hdr
.Te
+
1301 DirectoryEntry
->VirtualAddress
-
1302 SectionHeader
[Index1
].VirtualAddress
+
1303 SectionHeader
[Index1
].PointerToRawData
+
1309 } else if (EFI_IMAGE_NT_SIGNATURE
== Hdr
.Pe32
->Signature
) {
1311 // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.
1312 // It is due to backward-compatibility, for some system might
1313 // generate PE32+ image with PE32 Magic.
1315 switch (Hdr
.Pe32
->FileHeader
.Machine
) {
1316 case EFI_IMAGE_MACHINE_IA32
:
1317 case EFI_IMAGE_MACHINE_ARMT
:
1319 // Assume PE32 image with IA32 Machine field.
1321 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
1323 case EFI_IMAGE_MACHINE_X64
:
1324 case EFI_IMAGE_MACHINE_IPF
:
1326 // Assume PE32+ image with X64 or IPF Machine field
1328 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
1332 // For unknow Machine field, use Magic in optional Header
1334 Magic
= Hdr
.Pe32
->OptionalHeader
.Magic
;
1337 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
1338 (UINT8
*) Hdr
.Pe32
+
1340 sizeof (EFI_IMAGE_FILE_HEADER
) +
1341 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
1343 Index
= Hdr
.Pe32
->FileHeader
.NumberOfSections
;
1345 if (EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
== Magic
) {
1347 // Use PE32 offset get Debug Directory Entry
1349 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1350 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
1351 } else if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
1353 // Use PE32+ offset get Debug Directory Entry
1355 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1356 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
1359 if (NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
|| DirectoryEntry
->VirtualAddress
== 0) {
1360 DirectoryEntry
= NULL
;
1364 // Get the DebugEntry offset in the raw data image.
1366 for (Index1
= 0; Index1
< Index
; Index1
++) {
1367 if ((DirectoryEntry
->VirtualAddress
>= SectionHeader
[Index1
].VirtualAddress
) &&
1368 (DirectoryEntry
->VirtualAddress
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1369 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*) (
1371 DirectoryEntry
->VirtualAddress
-
1372 SectionHeader
[Index1
].VirtualAddress
+
1373 SectionHeader
[Index1
].PointerToRawData
);
1382 if (NULL
== DebugEntry
|| NULL
== DirectoryEntry
) {
1387 // Scan the directory to find the debug entry.
1389 for (DirCount
= 0; DirCount
< DirectoryEntry
->Size
; DirCount
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
), DebugEntry
++) {
1390 if (EFI_IMAGE_DEBUG_TYPE_CODEVIEW
== DebugEntry
->Type
) {
1391 if (DebugEntry
->SizeOfData
> 0) {
1393 // Get the DebugEntry offset in the raw data image.
1395 CodeViewEntryPointer
= NULL
;
1396 for (Index1
= 0; Index1
< Index
; Index1
++) {
1397 if ((DebugEntry
->RVA
>= SectionHeader
[Index1
].VirtualAddress
) &&
1398 (DebugEntry
->RVA
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1399 CodeViewEntryPointer
= (VOID
*) (
1401 (UINTN
) DebugEntry
->RVA
-
1402 SectionHeader
[Index1
].VirtualAddress
+
1403 SectionHeader
[Index1
].PointerToRawData
+
1404 (UINTN
)TEImageAdjust
);
1408 if (Index1
>= Index
) {
1410 // Can't find CodeViewEntryPointer in raw PE/COFF image.
1414 switch (* (UINT32
*) CodeViewEntryPointer
) {
1415 case CODEVIEW_SIGNATURE_NB10
:
1416 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
));
1417 case CODEVIEW_SIGNATURE_RSDS
:
1418 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
));
1419 case CODEVIEW_SIGNATURE_MTOC
:
1420 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
));
1434 PeCoffLoaderGetEntryPoint (
1436 OUT VOID
**EntryPoint
,
1437 OUT VOID
**BaseOfImage
1440 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1441 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1443 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)Pe32Data
;
1444 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
1446 // DOS image header is present, so read the PE header after the DOS image header.
1448 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
) Pe32Data
+ (UINTN
) ((DosHdr
->e_lfanew
) & 0x0ffff));
1451 // DOS image header is not present, so PE header is at the image base.
1453 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)Pe32Data
;
1457 // Calculate the entry point relative to the start of the image.
1458 // AddressOfEntryPoint is common for PE32 & PE32+
1460 if (Hdr
.Te
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
1461 *BaseOfImage
= (VOID
*)(UINTN
)(Hdr
.Te
->ImageBase
+ Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
1462 *EntryPoint
= (VOID
*)((UINTN
)*BaseOfImage
+ (Hdr
.Te
->AddressOfEntryPoint
& 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->StrippedSize
);
1463 return RETURN_SUCCESS
;
1464 } else if (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
) {
1465 *EntryPoint
= (VOID
*)(UINTN
)Hdr
.Pe32
->OptionalHeader
.AddressOfEntryPoint
;
1466 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1467 *BaseOfImage
= (VOID
*)(UINTN
)Hdr
.Pe32
->OptionalHeader
.ImageBase
;
1469 *BaseOfImage
= (VOID
*)(UINTN
)Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
1471 *EntryPoint
= (VOID
*)(UINTN
)((UINTN
)*EntryPoint
+ (UINTN
)*BaseOfImage
);
1472 return RETURN_SUCCESS
;
1475 return RETURN_UNSUPPORTED
;