3 Functions to get info and load PE/COFF image.
5 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include <Common/UefiBaseTypes.h>
17 #include <CommonLib.h>
18 #include <IndustryStandard/PeImage.h>
19 #include "PeCoffLib.h"
23 EFI_IMAGE_OPTIONAL_HEADER32
*Optional32
;
24 EFI_IMAGE_OPTIONAL_HEADER64
*Optional64
;
25 } EFI_IMAGE_OPTIONAL_HEADER_POINTER
;
29 PeCoffLoaderGetPeHeader (
30 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
31 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION
**PeHdr
,
32 OUT EFI_TE_IMAGE_HEADER
**TeHdr
37 PeCoffLoaderCheckImageType (
38 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
39 IN EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
,
40 IN EFI_TE_IMAGE_HEADER
*TeHdr
45 PeCoffLoaderImageAddress (
46 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
51 PeCoffLoaderRelocateIa32Image (
54 IN OUT CHAR8
**FixupData
,
59 PeCoffLoaderRelocateX64Image (
62 IN OUT CHAR8
**FixupData
,
67 PeCoffLoaderRelocateIpfImage (
70 IN OUT CHAR8
**FixupData
,
75 PeCoffLoaderRelocateArmImage (
78 IN OUT CHAR8
**FixupData
,
84 PeCoffLoaderGetPeHeader (
85 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
86 OUT EFI_IMAGE_OPTIONAL_HEADER_UNION
**PeHdr
,
87 OUT EFI_TE_IMAGE_HEADER
**TeHdr
93 Retrieves the PE or TE Header from a PE/COFF or TE image
97 ImageContext - The context of the image being loaded
99 PeHdr - The buffer in which to return the PE header
101 TeHdr - The buffer in which to return the TE header
105 RETURN_SUCCESS if the PE or TE Header is read,
106 Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
110 RETURN_STATUS Status
;
111 EFI_IMAGE_DOS_HEADER DosHdr
;
114 ImageContext
->IsTeImage
= FALSE
;
116 // Read the DOS image headers
118 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
119 Status
= ImageContext
->ImageRead (
120 ImageContext
->Handle
,
125 if (RETURN_ERROR (Status
)) {
126 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
130 ImageContext
->PeCoffHeaderOffset
= 0;
131 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
133 // DOS image header is present, so read the PE header after the DOS image header
135 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
138 // Get the PE/COFF Header pointer
140 *PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*) ((UINTN
)ImageContext
->Handle
+ ImageContext
->PeCoffHeaderOffset
);
141 if ((*PeHdr
)->Pe32
.Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
143 // Check the PE/COFF Header Signature. If not, then try to get a TE header
145 *TeHdr
= (EFI_TE_IMAGE_HEADER
*)*PeHdr
;
146 if ((*TeHdr
)->Signature
!= EFI_TE_IMAGE_HEADER_SIGNATURE
) {
147 return RETURN_UNSUPPORTED
;
149 ImageContext
->IsTeImage
= TRUE
;
152 return RETURN_SUCCESS
;
157 PeCoffLoaderCheckImageType (
158 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
159 IN EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
,
160 IN EFI_TE_IMAGE_HEADER
*TeHdr
166 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
170 ImageContext - The context of the image being loaded
172 PeHdr - The buffer in which to return the PE header
174 TeHdr - The buffer in which to return the TE header
178 RETURN_SUCCESS if the PE/COFF or TE image is supported
179 RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported.
184 // See if the machine type is supported.
185 // We support a native machine type (IA-32/Itanium-based)
187 if (ImageContext
->IsTeImage
== FALSE
) {
188 ImageContext
->Machine
= PeHdr
->Pe32
.FileHeader
.Machine
;
190 ImageContext
->Machine
= TeHdr
->Machine
;
193 if (ImageContext
->Machine
!= EFI_IMAGE_MACHINE_IA32
&& \
194 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_IA64
&& \
195 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_X64
&& \
196 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_ARMT
&& \
197 ImageContext
->Machine
!= EFI_IMAGE_MACHINE_EBC
) {
198 if (ImageContext
->Machine
== IMAGE_FILE_MACHINE_ARM
) {
200 // There are two types of ARM images. Pure ARM and ARM/Thumb.
201 // If we see the ARM say it is the ARM/Thumb so there is only
202 // a single machine type we need to check for ARM.
204 ImageContext
->Machine
= EFI_IMAGE_MACHINE_ARMT
;
205 if (ImageContext
->IsTeImage
== FALSE
) {
206 PeHdr
->Pe32
.FileHeader
.Machine
= ImageContext
->Machine
;
208 TeHdr
->Machine
= ImageContext
->Machine
;
213 // unsupported PeImage machine type
215 return RETURN_UNSUPPORTED
;
220 // See if the image type is supported. We support EFI Applications,
221 // EFI Boot Service Drivers, EFI Runtime Drivers and EFI SAL Drivers.
223 if (ImageContext
->IsTeImage
== FALSE
) {
224 ImageContext
->ImageType
= PeHdr
->Pe32
.OptionalHeader
.Subsystem
;
226 ImageContext
->ImageType
= (UINT16
) (TeHdr
->Subsystem
);
229 if (ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
&& \
230 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
&& \
231 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
&& \
232 ImageContext
->ImageType
!= EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
) {
234 // upsupported PeImage subsystem type
236 return RETURN_UNSUPPORTED
;
239 return RETURN_SUCCESS
;
244 PeCoffLoaderGetImageInfo (
245 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
251 Retrieves information on a PE/COFF image
255 This - Calling context
256 ImageContext - The context of the image being loaded
260 RETURN_SUCCESS - The information on the PE/COFF image was collected.
261 RETURN_INVALID_PARAMETER - ImageContext is NULL.
262 RETURN_UNSUPPORTED - The PE/COFF image is not supported.
263 Otherwise - The error status from reading the PE/COFF image using the
264 ImageContext->ImageRead() function
268 RETURN_STATUS Status
;
269 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
270 EFI_TE_IMAGE_HEADER
*TeHdr
;
271 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
274 UINTN DebugDirectoryEntryRva
;
275 UINTN DebugDirectoryEntryFileOffset
;
276 UINTN SectionHeaderOffset
;
277 EFI_IMAGE_SECTION_HEADER SectionHeader
;
278 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
279 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
283 DebugDirectoryEntry
= NULL
;
284 DebugDirectoryEntryRva
= 0;
286 if (NULL
== ImageContext
) {
287 return RETURN_INVALID_PARAMETER
;
292 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
294 Status
= PeCoffLoaderGetPeHeader (ImageContext
, &PeHdr
, &TeHdr
);
295 if (RETURN_ERROR (Status
)) {
300 // Verify machine type
302 Status
= PeCoffLoaderCheckImageType (ImageContext
, PeHdr
, TeHdr
);
303 if (RETURN_ERROR (Status
)) {
306 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
309 // Retrieve the base address of the image
311 if (!(ImageContext
->IsTeImage
)) {
312 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
313 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) OptionHeader
.Optional32
->ImageBase
;
315 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) OptionHeader
.Optional64
->ImageBase
;
318 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) (TeHdr
->ImageBase
+ TeHdr
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
321 // Initialize the alternate destination address to 0 indicating that it
322 // should not be used.
324 ImageContext
->DestinationAddress
= 0;
327 // Initialize the codeview pointer.
329 ImageContext
->CodeView
= NULL
;
330 ImageContext
->PdbPointer
= NULL
;
333 // Three cases with regards to relocations:
334 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
335 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
336 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
337 // has no base relocs to apply
338 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
340 // Look at the file header to determine if relocations have been stripped, and
341 // save this info in the image context for later use.
343 if ((!(ImageContext
->IsTeImage
)) && ((PeHdr
->Pe32
.FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
344 ImageContext
->RelocationsStripped
= TRUE
;
345 } else if ((ImageContext
->IsTeImage
) && (TeHdr
->DataDirectory
[0].Size
== 0)) {
346 ImageContext
->RelocationsStripped
= TRUE
;
348 ImageContext
->RelocationsStripped
= FALSE
;
351 if (!(ImageContext
->IsTeImage
)) {
353 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
354 ImageContext
->ImageSize
= (UINT64
) OptionHeader
.Optional32
->SizeOfImage
;
355 ImageContext
->SectionAlignment
= OptionHeader
.Optional32
->SectionAlignment
;
356 ImageContext
->SizeOfHeaders
= OptionHeader
.Optional32
->SizeOfHeaders
;
359 // Modify ImageSize to contain .PDB file name if required and initialize
362 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
363 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
364 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
367 ImageContext
->ImageSize
= (UINT64
) OptionHeader
.Optional64
->SizeOfImage
;
368 ImageContext
->SectionAlignment
= OptionHeader
.Optional64
->SectionAlignment
;
369 ImageContext
->SizeOfHeaders
= OptionHeader
.Optional64
->SizeOfHeaders
;
372 // Modify ImageSize to contain .PDB file name if required and initialize
375 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
376 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
377 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
381 if (DebugDirectoryEntryRva
!= 0) {
383 // Determine the file offset of the debug directory... This means we walk
384 // the sections to find which section contains the RVA of the debug
387 DebugDirectoryEntryFileOffset
= 0;
389 SectionHeaderOffset
= (UINTN
)(
390 ImageContext
->PeCoffHeaderOffset
+
392 sizeof (EFI_IMAGE_FILE_HEADER
) +
393 PeHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
396 for (Index
= 0; Index
< PeHdr
->Pe32
.FileHeader
.NumberOfSections
; Index
++) {
398 // Read section header from file
400 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
401 Status
= ImageContext
->ImageRead (
402 ImageContext
->Handle
,
407 if (RETURN_ERROR (Status
)) {
408 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
412 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
413 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
414 DebugDirectoryEntryFileOffset
=
415 DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
419 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
422 if (DebugDirectoryEntryFileOffset
!= 0) {
423 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
425 // Read next debug directory entry
427 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
428 Status
= ImageContext
->ImageRead (
429 ImageContext
->Handle
,
430 DebugDirectoryEntryFileOffset
+ Index
,
434 if (RETURN_ERROR (Status
)) {
435 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
439 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
440 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
441 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
442 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
445 return RETURN_SUCCESS
;
451 ImageContext
->ImageSize
= 0;
452 ImageContext
->SectionAlignment
= 4096;
453 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
) TeHdr
->BaseOfCode
- (UINTN
) TeHdr
->StrippedSize
;
455 DebugDirectoryEntry
= &TeHdr
->DataDirectory
[1];
456 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
457 SectionHeaderOffset
= (UINTN
) (sizeof (EFI_TE_IMAGE_HEADER
));
459 DebugDirectoryEntryFileOffset
= 0;
461 for (Index
= 0; Index
< TeHdr
->NumberOfSections
;) {
463 // Read section header from file
465 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
466 Status
= ImageContext
->ImageRead (
467 ImageContext
->Handle
,
472 if (RETURN_ERROR (Status
)) {
473 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
477 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
478 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
479 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
480 SectionHeader
.VirtualAddress
+
481 SectionHeader
.PointerToRawData
+
482 sizeof (EFI_TE_IMAGE_HEADER
) -
486 // File offset of the debug directory was found, if this is not the last
487 // section, then skip to the last section for calculating the image size.
489 if (Index
< (UINTN
) TeHdr
->NumberOfSections
- 1) {
490 SectionHeaderOffset
+= (TeHdr
->NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
491 Index
= TeHdr
->NumberOfSections
- 1;
497 // In Te image header there is not a field to describe the ImageSize.
498 // Actually, the ImageSize equals the RVA plus the VirtualSize of
499 // the last section mapped into memory (Must be rounded up to
500 // a mulitple of Section Alignment). Per the PE/COFF specification, the
501 // section headers in the Section Table must appear in order of the RVA
502 // values for the corresponding sections. So the ImageSize can be determined
503 // by the RVA and the VirtualSize of the last section header in the
506 if ((++Index
) == (UINTN
) TeHdr
->NumberOfSections
) {
507 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
+
508 ImageContext
->SectionAlignment
- 1) & ~(ImageContext
->SectionAlignment
- 1);
511 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
514 if (DebugDirectoryEntryFileOffset
!= 0) {
515 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
517 // Read next debug directory entry
519 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
520 Status
= ImageContext
->ImageRead (
521 ImageContext
->Handle
,
522 DebugDirectoryEntryFileOffset
,
526 if (RETURN_ERROR (Status
)) {
527 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
531 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
532 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
533 return RETURN_SUCCESS
;
539 return RETURN_SUCCESS
;
544 PeCoffLoaderImageAddress (
545 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
552 Converts an image address to the loaded address
556 ImageContext - The context of the image being loaded
558 Address - The address to be converted to the loaded address
562 NULL if the address can not be converted, otherwise, the converted address
566 if (Address
>= ImageContext
->ImageSize
) {
567 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
571 return (UINT8
*) ((UINTN
) ImageContext
->ImageAddress
+ Address
);
576 PeCoffLoaderRelocateImage (
577 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
583 Relocates a PE/COFF image in memory
587 This - Calling context
589 ImageContext - Contains information on the loaded image to relocate
593 RETURN_SUCCESS if the PE/COFF image was relocated
594 RETURN_LOAD_ERROR if the image is not a valid PE/COFF image
595 RETURN_UNSUPPORTED not support
599 RETURN_STATUS Status
;
600 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
601 EFI_TE_IMAGE_HEADER
*TeHdr
;
602 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
604 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
605 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
613 PHYSICAL_ADDRESS BaseAddress
;
615 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
622 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
625 // If there are no relocation entries, then we are done
627 if (ImageContext
->RelocationsStripped
) {
628 return RETURN_SUCCESS
;
632 // Use DestinationAddress field of ImageContext as the relocation address even if it is 0.
634 BaseAddress
= ImageContext
->DestinationAddress
;
636 if (!(ImageContext
->IsTeImage
)) {
637 PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)((UINTN
)ImageContext
->ImageAddress
+
638 ImageContext
->PeCoffHeaderOffset
);
639 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
640 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
641 Adjust
= (UINT64
) BaseAddress
- OptionHeader
.Optional32
->ImageBase
;
642 OptionHeader
.Optional32
->ImageBase
= (UINT32
) BaseAddress
;
643 MachineType
= ImageContext
->Machine
;
645 // Find the relocation block
647 // Per the PE/COFF spec, you can't assume that a given data directory
648 // is present in the image. You have to check the NumberOfRvaAndSizes in
649 // the optional header to verify a desired directory entry is there.
651 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
652 RelocDir
= &OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
653 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
654 RelocBaseEnd
= PeCoffLoaderImageAddress (
656 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
660 // Set base and end to bypass processing below.
662 RelocBase
= RelocBaseEnd
= 0;
665 Adjust
= (UINT64
) BaseAddress
- OptionHeader
.Optional64
->ImageBase
;
666 OptionHeader
.Optional64
->ImageBase
= BaseAddress
;
667 MachineType
= ImageContext
->Machine
;
669 // Find the relocation block
671 // Per the PE/COFF spec, you can't assume that a given data directory
672 // is present in the image. You have to check the NumberOfRvaAndSizes in
673 // the optional header to verify a desired directory entry is there.
675 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
676 RelocDir
= &OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
677 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
678 RelocBaseEnd
= PeCoffLoaderImageAddress (
680 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
684 // Set base and end to bypass processing below.
686 RelocBase
= RelocBaseEnd
= 0;
690 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
691 Adjust
= (UINT64
) (BaseAddress
- TeHdr
->ImageBase
);
692 TeHdr
->ImageBase
= (UINT64
) (BaseAddress
);
693 MachineType
= TeHdr
->Machine
;
696 // Find the relocation block
698 RelocDir
= &TeHdr
->DataDirectory
[0];
699 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(
700 ImageContext
->ImageAddress
+
701 RelocDir
->VirtualAddress
+
702 sizeof(EFI_TE_IMAGE_HEADER
) -
705 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) ((UINTN
) RelocBase
+ (UINTN
) RelocDir
->Size
- 1);
709 // Run the relocation information and apply the fixups
711 FixupData
= ImageContext
->FixupData
;
712 while (RelocBase
< RelocBaseEnd
) {
714 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
715 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
716 if (!(ImageContext
->IsTeImage
)) {
717 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
);
719 FixupBase
= (CHAR8
*)(UINTN
)(ImageContext
->ImageAddress
+
720 RelocBase
->VirtualAddress
+
721 sizeof(EFI_TE_IMAGE_HEADER
) -
726 if ((CHAR8
*) RelocEnd
< (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
) ||
727 (CHAR8
*) RelocEnd
> (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+
728 (UINTN
)ImageContext
->ImageSize
)) {
729 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
730 return RETURN_LOAD_ERROR
;
734 // Run this relocation record
736 while (Reloc
< RelocEnd
) {
738 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
739 switch ((*Reloc
) >> 12) {
740 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
743 case EFI_IMAGE_REL_BASED_HIGH
:
744 F16
= (UINT16
*) Fixup
;
745 *F16
= (UINT16
) (*F16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
746 if (FixupData
!= NULL
) {
747 *(UINT16
*) FixupData
= *F16
;
748 FixupData
= FixupData
+ sizeof (UINT16
);
752 case EFI_IMAGE_REL_BASED_LOW
:
753 F16
= (UINT16
*) Fixup
;
754 *F16
= (UINT16
) (*F16
+ (UINT16
) Adjust
);
755 if (FixupData
!= NULL
) {
756 *(UINT16
*) FixupData
= *F16
;
757 FixupData
= FixupData
+ sizeof (UINT16
);
761 case EFI_IMAGE_REL_BASED_HIGHLOW
:
762 F32
= (UINT32
*) Fixup
;
763 *F32
= *F32
+ (UINT32
) Adjust
;
764 if (FixupData
!= NULL
) {
765 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
766 *(UINT32
*) FixupData
= *F32
;
767 FixupData
= FixupData
+ sizeof (UINT32
);
771 case EFI_IMAGE_REL_BASED_HIGHADJ
:
773 // Return the same EFI_UNSUPPORTED return code as
774 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
775 // the relocation type.
777 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
778 return RETURN_UNSUPPORTED
;
781 switch (MachineType
) {
782 case EFI_IMAGE_MACHINE_IA32
:
783 Status
= PeCoffLoaderRelocateIa32Image (Reloc
, Fixup
, &FixupData
, Adjust
);
785 case EFI_IMAGE_MACHINE_ARMT
:
786 Status
= PeCoffLoaderRelocateArmImage (&Reloc
, Fixup
, &FixupData
, Adjust
);
788 case EFI_IMAGE_MACHINE_X64
:
789 Status
= PeCoffLoaderRelocateX64Image (Reloc
, Fixup
, &FixupData
, Adjust
);
791 case EFI_IMAGE_MACHINE_IA64
:
792 Status
= PeCoffLoaderRelocateIpfImage (Reloc
, Fixup
, &FixupData
, Adjust
);
795 Status
= RETURN_UNSUPPORTED
;
798 if (RETURN_ERROR (Status
)) {
799 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
805 // Next relocation record
813 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
816 return RETURN_SUCCESS
;
821 PeCoffLoaderLoadImage (
822 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
828 Loads a PE/COFF image into memory
832 This - Calling context
834 ImageContext - Contains information on image to load into memory
838 RETURN_SUCCESS if the PE/COFF image was loaded
839 RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
840 RETURN_LOAD_ERROR if the image is a runtime driver with no relocations
841 RETURN_INVALID_PARAMETER if the image address is invalid
845 RETURN_STATUS Status
;
846 EFI_IMAGE_OPTIONAL_HEADER_UNION
*PeHdr
;
847 EFI_TE_IMAGE_HEADER
*TeHdr
;
848 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
849 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
850 EFI_IMAGE_SECTION_HEADER
*Section
;
851 UINTN NumberOfSections
;
856 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
857 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
859 UINT32 TempDebugEntryRva
;
860 EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader
;
864 OptionHeader
.Header
= NULL
;
868 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
871 // Copy the provided context info into our local version, get what we
872 // can from the original image, and then use that to make sure everything
875 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
877 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
878 if (RETURN_ERROR (Status
)) {
883 // Make sure there is enough allocated space for the image being loaded
885 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
886 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
887 return RETURN_BUFFER_TOO_SMALL
;
891 // If there's no relocations, then make sure it's not a runtime driver,
892 // and that it's being loaded at the linked address.
894 if (CheckContext
.RelocationsStripped
) {
896 // If the image does not contain relocations and it is a runtime driver
897 // then return an error.
899 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
900 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
901 return RETURN_LOAD_ERROR
;
904 // If the image does not contain relocations, and the requested load address
905 // is not the linked address, then return an error.
907 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
908 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
909 return RETURN_INVALID_PARAMETER
;
913 // Make sure the allocated space has the proper section alignment
915 if (!(ImageContext
->IsTeImage
)) {
916 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
917 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
918 return RETURN_INVALID_PARAMETER
;
922 // Read the entire PE/COFF or TE header into memory
924 if (!(ImageContext
->IsTeImage
)) {
925 Status
= ImageContext
->ImageRead (
926 ImageContext
->Handle
,
928 &ImageContext
->SizeOfHeaders
,
929 (VOID
*) (UINTN
) ImageContext
->ImageAddress
932 PeHdr
= (EFI_IMAGE_OPTIONAL_HEADER_UNION
*)
933 ((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
935 OptionHeader
.Header
= (VOID
*) &(PeHdr
->Pe32
.OptionalHeader
);
937 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
938 (UINTN
)ImageContext
->ImageAddress
+
939 ImageContext
->PeCoffHeaderOffset
+
941 sizeof(EFI_IMAGE_FILE_HEADER
) +
942 PeHdr
->Pe32
.FileHeader
.SizeOfOptionalHeader
944 NumberOfSections
= (UINTN
) (PeHdr
->Pe32
.FileHeader
.NumberOfSections
);
946 Status
= ImageContext
->ImageRead (
947 ImageContext
->Handle
,
949 &ImageContext
->SizeOfHeaders
,
950 (VOID
*) (UINTN
) ImageContext
->ImageAddress
953 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
955 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
956 (UINTN
)ImageContext
->ImageAddress
+
957 sizeof(EFI_TE_IMAGE_HEADER
)
959 NumberOfSections
= (UINTN
) (TeHdr
->NumberOfSections
);
963 if (RETURN_ERROR (Status
)) {
964 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
965 return RETURN_LOAD_ERROR
;
969 // Load each section of the image
971 Section
= FirstSection
;
972 for (Index
= 0, MaxEnd
= NULL
; Index
< NumberOfSections
; Index
++) {
975 // Compute sections address
977 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
);
978 End
= PeCoffLoaderImageAddress (
980 Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1
982 if (ImageContext
->IsTeImage
) {
983 Base
= (CHAR8
*) ((UINTN
) Base
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
984 End
= (CHAR8
*) ((UINTN
) End
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
991 // If the base start or end address resolved to 0, then fail.
993 if ((Base
== NULL
) || (End
== NULL
)) {
994 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
995 return RETURN_LOAD_ERROR
;
1001 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
1002 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
1003 Size
= (UINTN
) Section
->SizeOfRawData
;
1006 if (Section
->SizeOfRawData
) {
1007 if (!(ImageContext
->IsTeImage
)) {
1008 Status
= ImageContext
->ImageRead (
1009 ImageContext
->Handle
,
1010 Section
->PointerToRawData
,
1015 Status
= ImageContext
->ImageRead (
1016 ImageContext
->Handle
,
1017 Section
->PointerToRawData
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
,
1023 if (RETURN_ERROR (Status
)) {
1024 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1030 // If raw size is less then virt size, zero fill the remaining
1033 if (Size
< Section
->Misc
.VirtualSize
) {
1034 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
1044 // Get image's entry point
1046 if (!(ImageContext
->IsTeImage
)) {
1047 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (
1049 PeHdr
->Pe32
.OptionalHeader
.AddressOfEntryPoint
1052 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (
1053 (UINTN
)ImageContext
->ImageAddress
+
1054 (UINTN
)TeHdr
->AddressOfEntryPoint
+
1055 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1056 (UINTN
) TeHdr
->StrippedSize
1061 // Determine the size of the fixup data
1063 // Per the PE/COFF spec, you can't assume that a given data directory
1064 // is present in the image. You have to check the NumberOfRvaAndSizes in
1065 // the optional header to verify a desired directory entry is there.
1067 if (!(ImageContext
->IsTeImage
)) {
1068 if (PeHdr
->Pe32
.OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1069 if (OptionHeader
.Optional32
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1070 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
1071 &OptionHeader
.Optional32
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1072 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1074 ImageContext
->FixupDataSize
= 0;
1077 if (OptionHeader
.Optional64
->NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1078 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
1079 &OptionHeader
.Optional64
->DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1080 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1082 ImageContext
->FixupDataSize
= 0;
1086 DirectoryEntry
= &TeHdr
->DataDirectory
[0];
1087 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1090 // Consumer must allocate a buffer for the relocation fixup log.
1091 // Only used for runtime drivers.
1093 ImageContext
->FixupData
= NULL
;
1096 // Load the Codeview info if present
1098 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
1099 if (!(ImageContext
->IsTeImage
)) {
1100 DebugEntry
= PeCoffLoaderImageAddress (
1102 ImageContext
->DebugDirectoryEntryRva
1105 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(UINTN
)(
1106 ImageContext
->ImageAddress
+
1107 ImageContext
->DebugDirectoryEntryRva
+
1108 sizeof(EFI_TE_IMAGE_HEADER
) -
1113 if (DebugEntry
!= NULL
) {
1114 TempDebugEntryRva
= DebugEntry
->RVA
;
1115 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
1117 if ((UINTN
) Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
1118 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
1120 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
1124 if (TempDebugEntryRva
!= 0) {
1125 if (!(ImageContext
->IsTeImage
)) {
1126 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
);
1128 ImageContext
->CodeView
= (VOID
*)(
1129 (UINTN
)ImageContext
->ImageAddress
+
1130 (UINTN
)TempDebugEntryRva
+
1131 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1132 (UINTN
) TeHdr
->StrippedSize
1136 if (ImageContext
->CodeView
== NULL
) {
1137 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1138 return RETURN_LOAD_ERROR
;
1141 if (DebugEntry
->RVA
== 0) {
1142 Size
= DebugEntry
->SizeOfData
;
1143 if (!(ImageContext
->IsTeImage
)) {
1144 Status
= ImageContext
->ImageRead (
1145 ImageContext
->Handle
,
1146 DebugEntry
->FileOffset
,
1148 ImageContext
->CodeView
1151 Status
= ImageContext
->ImageRead (
1152 ImageContext
->Handle
,
1153 DebugEntry
->FileOffset
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHdr
->StrippedSize
,
1155 ImageContext
->CodeView
1158 // Should we apply fix up to this field according to the size difference between PE and TE?
1159 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1160 // in original PE image.
1164 if (RETURN_ERROR (Status
)) {
1165 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1166 return RETURN_LOAD_ERROR
;
1169 DebugEntry
->RVA
= TempDebugEntryRva
;
1172 switch (*(UINT32
*) ImageContext
->CodeView
) {
1173 case CODEVIEW_SIGNATURE_NB10
:
1174 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1177 case CODEVIEW_SIGNATURE_RSDS
:
1178 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
1181 case CODEVIEW_SIGNATURE_MTOC
:
1182 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
);
1195 Returns a pointer to the PDB file name for a raw PE/COFF image that is not
1196 loaded into system memory with the PE/COFF Loader Library functions.
1198 Returns the PDB file name for the PE/COFF image specified by Pe32Data. If
1199 the PE/COFF image specified by Pe32Data is not a valid, then NULL is
1200 returned. If the PE/COFF image specified by Pe32Data does not contain a
1201 debug directory entry, then NULL is returned. If the debug directory entry
1202 in the PE/COFF image specified by Pe32Data does not contain a PDB file name,
1203 then NULL is returned.
1204 If Pe32Data is NULL, then return NULL.
1206 @param Pe32Data Pointer to the PE/COFF image that is loaded in system
1209 @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL
1210 if it cannot be retrieved.
1215 PeCoffLoaderGetPdbPointer (
1219 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1220 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1221 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
1222 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
1224 VOID
*CodeViewEntryPointer
;
1226 UINT32 NumberOfRvaAndSizes
;
1228 EFI_IMAGE_SECTION_HEADER
*SectionHeader
;
1229 UINT32 Index
, Index1
;
1231 if (Pe32Data
== NULL
) {
1236 DirectoryEntry
= NULL
;
1238 NumberOfRvaAndSizes
= 0;
1241 SectionHeader
= NULL
;
1243 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)Pe32Data
;
1244 if (EFI_IMAGE_DOS_SIGNATURE
== DosHdr
->e_magic
) {
1246 // DOS image header is present, so read the PE header after the DOS image header.
1248 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
) Pe32Data
+ (UINTN
) ((DosHdr
->e_lfanew
) & 0x0ffff));
1251 // DOS image header is not present, so PE header is at the image base.
1253 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)Pe32Data
;
1256 if (EFI_TE_IMAGE_HEADER_SIGNATURE
== Hdr
.Te
->Signature
) {
1257 if (Hdr
.Te
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
].VirtualAddress
!= 0) {
1258 DirectoryEntry
= &Hdr
.Te
->DataDirectory
[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG
];
1259 TEImageAdjust
= sizeof (EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->StrippedSize
;
1262 // Get the DebugEntry offset in the raw data image.
1264 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (Hdr
.Te
+ 1);
1265 Index
= Hdr
.Te
->NumberOfSections
;
1266 for (Index1
= 0; Index1
< Index
; Index1
++) {
1267 if ((DirectoryEntry
->VirtualAddress
>= SectionHeader
[Index1
].VirtualAddress
) &&
1268 (DirectoryEntry
->VirtualAddress
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1269 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)((UINTN
) Hdr
.Te
+
1270 DirectoryEntry
->VirtualAddress
-
1271 SectionHeader
[Index1
].VirtualAddress
+
1272 SectionHeader
[Index1
].PointerToRawData
+
1278 } else if (EFI_IMAGE_NT_SIGNATURE
== Hdr
.Pe32
->Signature
) {
1280 // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.
1281 // It is due to backward-compatibility, for some system might
1282 // generate PE32+ image with PE32 Magic.
1284 switch (Hdr
.Pe32
->FileHeader
.Machine
) {
1285 case EFI_IMAGE_MACHINE_IA32
:
1286 case EFI_IMAGE_MACHINE_ARMT
:
1288 // Assume PE32 image with IA32 Machine field.
1290 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
;
1292 case EFI_IMAGE_MACHINE_X64
:
1293 case EFI_IMAGE_MACHINE_IPF
:
1295 // Assume PE32+ image with X64 or IPF Machine field
1297 Magic
= EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
1301 // For unknow Machine field, use Magic in optional Header
1303 Magic
= Hdr
.Pe32
->OptionalHeader
.Magic
;
1306 SectionHeader
= (EFI_IMAGE_SECTION_HEADER
*) (
1307 (UINT8
*) Hdr
.Pe32
+
1309 sizeof (EFI_IMAGE_FILE_HEADER
) +
1310 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
1312 Index
= Hdr
.Pe32
->FileHeader
.NumberOfSections
;
1314 if (EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
== Magic
) {
1316 // Use PE32 offset get Debug Directory Entry
1318 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1319 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
1320 } else if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
1322 // Use PE32+ offset get Debug Directory Entry
1324 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1325 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
1328 if (NumberOfRvaAndSizes
<= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
|| DirectoryEntry
->VirtualAddress
== 0) {
1329 DirectoryEntry
= NULL
;
1333 // Get the DebugEntry offset in the raw data image.
1335 for (Index1
= 0; Index1
< Index
; Index1
++) {
1336 if ((DirectoryEntry
->VirtualAddress
>= SectionHeader
[Index1
].VirtualAddress
) &&
1337 (DirectoryEntry
->VirtualAddress
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1338 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*) (
1340 DirectoryEntry
->VirtualAddress
-
1341 SectionHeader
[Index1
].VirtualAddress
+
1342 SectionHeader
[Index1
].PointerToRawData
);
1351 if (NULL
== DebugEntry
|| NULL
== DirectoryEntry
) {
1356 // Scan the directory to find the debug entry.
1358 for (DirCount
= 0; DirCount
< DirectoryEntry
->Size
; DirCount
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
), DebugEntry
++) {
1359 if (EFI_IMAGE_DEBUG_TYPE_CODEVIEW
== DebugEntry
->Type
) {
1360 if (DebugEntry
->SizeOfData
> 0) {
1362 // Get the DebugEntry offset in the raw data image.
1364 CodeViewEntryPointer
= NULL
;
1365 for (Index1
= 0; Index1
< Index
; Index1
++) {
1366 if ((DebugEntry
->RVA
>= SectionHeader
[Index1
].VirtualAddress
) &&
1367 (DebugEntry
->RVA
< (SectionHeader
[Index1
].VirtualAddress
+ SectionHeader
[Index1
].Misc
.VirtualSize
))) {
1368 CodeViewEntryPointer
= (VOID
*) (
1370 (UINTN
) DebugEntry
->RVA
-
1371 SectionHeader
[Index1
].VirtualAddress
+
1372 SectionHeader
[Index1
].PointerToRawData
+
1373 (UINTN
)TEImageAdjust
);
1377 if (Index1
>= Index
) {
1379 // Can't find CodeViewEntryPointer in raw PE/COFF image.
1383 switch (* (UINT32
*) CodeViewEntryPointer
) {
1384 case CODEVIEW_SIGNATURE_NB10
:
1385 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
));
1386 case CODEVIEW_SIGNATURE_RSDS
:
1387 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
));
1388 case CODEVIEW_SIGNATURE_MTOC
:
1389 return (VOID
*) ((CHAR8
*)CodeViewEntryPointer
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
));
1403 PeCoffLoaderGetEntryPoint (
1405 OUT VOID
**EntryPoint
,
1406 OUT VOID
**BaseOfImage
1409 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1410 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1412 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)Pe32Data
;
1413 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
1415 // DOS image header is present, so read the PE header after the DOS image header.
1417 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
) Pe32Data
+ (UINTN
) ((DosHdr
->e_lfanew
) & 0x0ffff));
1420 // DOS image header is not present, so PE header is at the image base.
1422 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)Pe32Data
;
1426 // Calculate the entry point relative to the start of the image.
1427 // AddressOfEntryPoint is common for PE32 & PE32+
1429 if (Hdr
.Te
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
1430 *BaseOfImage
= (VOID
*)(UINTN
)(Hdr
.Te
->ImageBase
+ Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
1431 *EntryPoint
= (VOID
*)((UINTN
)*BaseOfImage
+ (Hdr
.Te
->AddressOfEntryPoint
& 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->StrippedSize
);
1432 return RETURN_SUCCESS
;
1433 } else if (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
) {
1434 *EntryPoint
= (VOID
*)(UINTN
)Hdr
.Pe32
->OptionalHeader
.AddressOfEntryPoint
;
1435 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1436 *BaseOfImage
= (VOID
*)(UINTN
)Hdr
.Pe32
->OptionalHeader
.ImageBase
;
1438 *BaseOfImage
= (VOID
*)(UINTN
)Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
1440 *EntryPoint
= (VOID
*)(UINTN
)((UINTN
)*EntryPoint
+ (UINTN
)*BaseOfImage
);
1441 return RETURN_SUCCESS
;
1444 return RETURN_UNSUPPORTED
;