2 Base PE/COFF loader supports loading any PE32/PE32+ or TE image, but
3 only supports relocating IA32, x64, IPF, and EBC images.
5 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
6 Portions copyright (c) 2008 - 2009, Apple Inc. 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 "BasePeCoffLibInternals.h"
20 Retrieves the magic value from the PE/COFF header.
22 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
24 @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32
25 @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+
29 PeCoffLoaderGetPeHeaderMagicValue (
30 IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
34 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
35 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
36 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
37 // then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
39 if (Hdr
.Pe32
->FileHeader
.Machine
== IMAGE_FILE_MACHINE_IA64
&& Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
40 return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
43 // Return the magic value from the PC/COFF Optional Header
45 return Hdr
.Pe32
->OptionalHeader
.Magic
;
50 Retrieves the PE or TE Header from a PE/COFF or TE image.
51 Also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
52 SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
54 @param ImageContext The context of the image being loaded.
55 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
57 @retval RETURN_SUCCESS The PE or TE Header is read.
58 @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.
62 PeCoffLoaderGetPeHeader (
63 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
64 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
68 EFI_IMAGE_DOS_HEADER DosHdr
;
71 UINT32 SectionHeaderOffset
;
74 EFI_IMAGE_SECTION_HEADER SectionHeader
;
77 // Read the DOS image header to check for its existence
79 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
80 Status
= ImageContext
->ImageRead (
86 if (RETURN_ERROR (Status
)) {
87 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
91 ImageContext
->PeCoffHeaderOffset
= 0;
92 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
94 // DOS image header is present, so read the PE header after the DOS image
97 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
101 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
102 // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
103 // determines if this is a PE32 or PE32+ image. The magic is in the same
104 // location in both images.
106 Size
= sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
);
107 Status
= ImageContext
->ImageRead (
108 ImageContext
->Handle
,
109 ImageContext
->PeCoffHeaderOffset
,
113 if (RETURN_ERROR (Status
)) {
114 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
119 // Use Signature to figure out if we understand the image format
121 if (Hdr
.Te
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
122 ImageContext
->IsTeImage
= TRUE
;
123 ImageContext
->Machine
= Hdr
.Te
->Machine
;
124 ImageContext
->ImageType
= (UINT16
)(Hdr
.Te
->Subsystem
);
126 // For TeImage, SectionAlignment is undefined to be set to Zero
127 // ImageSize can be calculated.
129 ImageContext
->ImageSize
= 0;
130 ImageContext
->SectionAlignment
= 0;
131 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
)Hdr
.Te
->BaseOfCode
- (UINTN
)Hdr
.Te
->StrippedSize
;
133 } else if (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
) {
134 ImageContext
->IsTeImage
= FALSE
;
135 ImageContext
->Machine
= Hdr
.Pe32
->FileHeader
.Machine
;
137 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
139 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
141 // 1. Check FileHeader.SizeOfOptionalHeader filed.
143 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
< Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) {
144 return RETURN_UNSUPPORTED
;
147 if (Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
!= sizeof (EFI_IMAGE_OPTIONAL_HEADER32
) - (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
- Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) * sizeof (EFI_IMAGE_DATA_DIRECTORY
)) {
148 return RETURN_UNSUPPORTED
;
152 // 2. Check the OptionalHeader.SizeOfHeaders field.
153 // This field will be use like the following mode, so just compare the result.
154 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
156 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1 < Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) {
157 if (Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
< (UINT32
)((UINT8
*)(&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1]) - (UINT8
*) &Hdr
)) {
158 return RETURN_UNSUPPORTED
;
163 // Read Hdr.Pe32.OptionalHeader.SizeOfHeaders data from file
166 Status
= ImageContext
->ImageRead (
167 ImageContext
->Handle
,
168 Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- 1,
172 if (RETURN_ERROR (Status
)) {
177 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
178 // Read the last byte to make sure the data is in the image region.
179 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
181 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
< Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) {
182 if (Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
!= 0) {
184 // Check the member data to avoid overflow.
186 if ((UINT32
) (~0) - Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
<
187 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
) {
188 return RETURN_INVALID_PARAMETER
;
192 // Read section header from file
195 Status
= ImageContext
->ImageRead (
196 ImageContext
->Handle
,
197 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
+
198 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
- 1,
202 if (RETURN_ERROR (Status
)) {
211 ImageContext
->ImageType
= Hdr
.Pe32
->OptionalHeader
.Subsystem
;
212 ImageContext
->ImageSize
= (UINT64
)Hdr
.Pe32
->OptionalHeader
.SizeOfImage
;
213 ImageContext
->SectionAlignment
= Hdr
.Pe32
->OptionalHeader
.SectionAlignment
;
214 ImageContext
->SizeOfHeaders
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
;
216 } else if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
218 // 1. Check FileHeader.SizeOfOptionalHeader filed.
220 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
< Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
221 return RETURN_UNSUPPORTED
;
224 if (Hdr
.Pe32Plus
->FileHeader
.SizeOfOptionalHeader
!= sizeof (EFI_IMAGE_OPTIONAL_HEADER32
) - (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
- Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) * sizeof (EFI_IMAGE_DATA_DIRECTORY
)) {
225 return RETURN_UNSUPPORTED
;
229 // 2. Check the OptionalHeader.SizeOfHeaders field.
230 // This field will be use like the following mode, so just compare the result.
231 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
233 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1 < Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
234 if (Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
< (UINT32
)((UINT8
*)(&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1]) - (UINT8
*) &Hdr
)) {
235 return RETURN_UNSUPPORTED
;
240 // Read Hdr.Pe32.OptionalHeader.SizeOfHeaders data from file
243 Status
= ImageContext
->ImageRead (
244 ImageContext
->Handle
,
245 Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- 1,
249 if (RETURN_ERROR (Status
)) {
254 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
255 // Read the last byte to make sure the data is in the image region.
256 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
258 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
< Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
259 if (Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
!= 0) {
261 // Check the member data to avoid overflow.
263 if ((UINT32
) (~0) - Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
<
264 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
) {
265 return RETURN_INVALID_PARAMETER
;
269 // Read section header from file
272 Status
= ImageContext
->ImageRead (
273 ImageContext
->Handle
,
274 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
+
275 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
- 1,
279 if (RETURN_ERROR (Status
)) {
288 ImageContext
->ImageType
= Hdr
.Pe32Plus
->OptionalHeader
.Subsystem
;
289 ImageContext
->ImageSize
= (UINT64
) Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
;
290 ImageContext
->SectionAlignment
= Hdr
.Pe32Plus
->OptionalHeader
.SectionAlignment
;
291 ImageContext
->SizeOfHeaders
= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
;
293 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
294 return RETURN_UNSUPPORTED
;
297 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
298 return RETURN_UNSUPPORTED
;
301 if (!PeCoffLoaderImageFormatSupported (ImageContext
->Machine
)) {
303 // If the PE/COFF loader does not support the image type return
304 // unsupported. This library can support lots of types of images
305 // this does not mean the user of this library can call the entry
306 // point of the image.
308 return RETURN_UNSUPPORTED
;
312 // Check each section field.
314 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
315 for (Index
= 0; Index
< Hdr
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
317 // Read section header from file
319 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
320 Status
= ImageContext
->ImageRead (
321 ImageContext
->Handle
,
326 if (RETURN_ERROR (Status
)) {
330 if (SectionHeader
.SizeOfRawData
> 0) {
332 // Check the member data to avoid overflow.
334 if ((UINT32
) (~0) - SectionHeader
.PointerToRawData
< SectionHeader
.SizeOfRawData
) {
335 return RETURN_INVALID_PARAMETER
;
339 // Base on the ImageRead function to check the section data field.
340 // Read the last byte to make sure the data is in the image region.
343 Status
= ImageContext
->ImageRead (
344 ImageContext
->Handle
,
345 SectionHeader
.PointerToRawData
+ SectionHeader
.SizeOfRawData
- 1,
349 if (RETURN_ERROR (Status
)) {
355 // Check next section.
357 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
360 return RETURN_SUCCESS
;
365 Retrieves information about a PE/COFF image.
367 Computes the PeCoffHeaderOffset, IsTeImage, ImageType, ImageAddress, ImageSize,
368 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and
369 DebugDirectoryEntryRva fields of the ImageContext structure.
370 If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.
371 If the PE/COFF image accessed through the ImageRead service in the ImageContext
372 structure is not a supported PE/COFF image type, then return RETURN_UNSUPPORTED.
373 If any errors occur while computing the fields of ImageContext,
374 then the error status is returned in the ImageError field of ImageContext.
375 If the image is a TE image, then SectionAlignment is set to 0.
376 The ImageRead and Handle fields of ImageContext structure must be valid prior
377 to invoking this service.
379 Also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
380 SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
382 @param ImageContext The pointer to the image context structure that describes the PE/COFF
383 image that needs to be examined by this function.
385 @retval RETURN_SUCCESS The information on the PE/COFF image was collected.
386 @retval RETURN_INVALID_PARAMETER ImageContext is NULL.
387 @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.
392 PeCoffLoaderGetImageInfo (
393 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
396 RETURN_STATUS Status
;
397 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
398 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
399 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
402 UINTN DebugDirectoryEntryRva
;
403 UINTN DebugDirectoryEntryFileOffset
;
404 UINTN SectionHeaderOffset
;
405 EFI_IMAGE_SECTION_HEADER SectionHeader
;
406 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
407 UINT32 NumberOfRvaAndSizes
;
410 if (ImageContext
== NULL
) {
411 return RETURN_INVALID_PARAMETER
;
416 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
418 Hdr
.Union
= &HdrData
;
419 Status
= PeCoffLoaderGetPeHeader (ImageContext
, Hdr
);
420 if (RETURN_ERROR (Status
)) {
424 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
427 // Retrieve the base address of the image
429 if (!(ImageContext
->IsTeImage
)) {
430 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
434 ImageContext
->ImageAddress
= Hdr
.Pe32
->OptionalHeader
.ImageBase
;
439 ImageContext
->ImageAddress
= Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
442 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
)(Hdr
.Te
->ImageBase
+ Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
446 // Initialize the alternate destination address to 0 indicating that it
447 // should not be used.
449 ImageContext
->DestinationAddress
= 0;
452 // Initialize the debug codeview pointer.
454 ImageContext
->DebugDirectoryEntryRva
= 0;
455 ImageContext
->CodeView
= NULL
;
456 ImageContext
->PdbPointer
= NULL
;
459 // Three cases with regards to relocations:
460 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
461 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
462 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
463 // has no base relocs to apply
464 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
466 // Look at the file header to determine if relocations have been stripped, and
467 // save this information in the image context for later use.
469 if ((!(ImageContext
->IsTeImage
)) && ((Hdr
.Pe32
->FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
470 ImageContext
->RelocationsStripped
= TRUE
;
471 } else if ((ImageContext
->IsTeImage
) && (Hdr
.Te
->DataDirectory
[0].Size
== 0) && (Hdr
.Te
->DataDirectory
[0].VirtualAddress
== 0)) {
472 ImageContext
->RelocationsStripped
= TRUE
;
474 ImageContext
->RelocationsStripped
= FALSE
;
478 // TE Image Relocation Data Directory Entry size is non-zero, but the Relocation Data Directory Virtual Address is zero.
479 // This case is not a valid TE image.
481 if ((ImageContext
->IsTeImage
) && (Hdr
.Te
->DataDirectory
[0].Size
!= 0) && (Hdr
.Te
->DataDirectory
[0].VirtualAddress
== 0)) {
482 return RETURN_INVALID_PARAMETER
;
485 if (!(ImageContext
->IsTeImage
)) {
486 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
490 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
491 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
496 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
497 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
500 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
502 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
505 // Determine the file offset of the debug directory... This means we walk
506 // the sections to find which section contains the RVA of the debug
509 DebugDirectoryEntryFileOffset
= 0;
511 SectionHeaderOffset
= (UINTN
)(
512 ImageContext
->PeCoffHeaderOffset
+
514 sizeof (EFI_IMAGE_FILE_HEADER
) +
515 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
518 for (Index
= 0; Index
< Hdr
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
520 // Read section header from file
522 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
523 Status
= ImageContext
->ImageRead (
524 ImageContext
->Handle
,
529 if (RETURN_ERROR (Status
)) {
530 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
534 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
535 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
537 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
541 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
544 if (DebugDirectoryEntryFileOffset
!= 0) {
545 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
547 // Read next debug directory entry
549 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
550 Status
= ImageContext
->ImageRead (
551 ImageContext
->Handle
,
552 DebugDirectoryEntryFileOffset
+ Index
,
556 if (RETURN_ERROR (Status
)) {
557 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
560 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
561 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
562 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
563 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
566 return RETURN_SUCCESS
;
573 DebugDirectoryEntry
= &Hdr
.Te
->DataDirectory
[1];
574 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
575 SectionHeaderOffset
= (UINTN
)(sizeof (EFI_TE_IMAGE_HEADER
));
577 DebugDirectoryEntryFileOffset
= 0;
579 for (Index
= 0; Index
< Hdr
.Te
->NumberOfSections
;) {
581 // Read section header from file
583 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
584 Status
= ImageContext
->ImageRead (
585 ImageContext
->Handle
,
590 if (RETURN_ERROR (Status
)) {
591 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
595 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
596 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
597 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
598 SectionHeader
.VirtualAddress
+
599 SectionHeader
.PointerToRawData
+
600 sizeof (EFI_TE_IMAGE_HEADER
) -
601 Hdr
.Te
->StrippedSize
;
604 // File offset of the debug directory was found, if this is not the last
605 // section, then skip to the last section for calculating the image size.
607 if (Index
< (UINTN
) Hdr
.Te
->NumberOfSections
- 1) {
608 SectionHeaderOffset
+= (Hdr
.Te
->NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
609 Index
= Hdr
.Te
->NumberOfSections
- 1;
615 // In Te image header there is not a field to describe the ImageSize.
616 // Actually, the ImageSize equals the RVA plus the VirtualSize of
617 // the last section mapped into memory (Must be rounded up to
618 // a multiple of Section Alignment). Per the PE/COFF specification, the
619 // section headers in the Section Table must appear in order of the RVA
620 // values for the corresponding sections. So the ImageSize can be determined
621 // by the RVA and the VirtualSize of the last section header in the
624 if ((++Index
) == (UINTN
)Hdr
.Te
->NumberOfSections
) {
625 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
);
628 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
631 if (DebugDirectoryEntryFileOffset
!= 0) {
632 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
634 // Read next debug directory entry
636 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
637 Status
= ImageContext
->ImageRead (
638 ImageContext
->Handle
,
639 DebugDirectoryEntryFileOffset
+ Index
,
643 if (RETURN_ERROR (Status
)) {
644 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
648 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
649 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
650 return RETURN_SUCCESS
;
656 return RETURN_SUCCESS
;
661 Converts an image address to the loaded address.
663 @param ImageContext The context of the image being loaded.
664 @param Address The relative virtual address to be converted to the loaded address.
666 @return The converted address or NULL if the address can not be converted.
670 PeCoffLoaderImageAddress (
671 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
676 // Make sure that Address and ImageSize is correct for the loaded image.
678 if (Address
>= ImageContext
->ImageSize
) {
679 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
683 return (CHAR8
*)((UINTN
) ImageContext
->ImageAddress
+ Address
);
687 Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().
689 If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of
690 ImageContext as the relocation base address. Otherwise, use the DestinationAddress field
691 of ImageContext as the relocation base address. The caller must allocate the relocation
692 fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.
694 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress,
695 ImageSize, DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders,
696 DebugDirectoryEntryRva, EntryPoint, FixupDataSize, CodeView, PdbPointer, and FixupData of
697 the ImageContext structure must be valid prior to invoking this service.
699 If ImageContext is NULL, then ASSERT().
701 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
702 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
703 prior to transferring control to a PE/COFF image that is loaded using this library.
705 @param ImageContext The pointer to the image context structure that describes the PE/COFF
706 image that is being relocated.
708 @retval RETURN_SUCCESS The PE/COFF image was relocated.
709 Extended status information is in the ImageError field of ImageContext.
710 @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.
711 Extended status information is in the ImageError field of ImageContext.
712 @retval RETURN_UNSUPPORTED A relocation record type is not supported.
713 Extended status information is in the ImageError field of ImageContext.
718 PeCoffLoaderRelocateImage (
719 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
722 RETURN_STATUS Status
;
723 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
724 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
726 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
727 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
736 PHYSICAL_ADDRESS BaseAddress
;
737 UINT32 NumberOfRvaAndSizes
;
740 ASSERT (ImageContext
!= NULL
);
745 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
748 // If there are no relocation entries, then we are done
750 if (ImageContext
->RelocationsStripped
) {
751 // Applies additional environment specific actions to relocate fixups
752 // to a PE/COFF image if needed
753 PeCoffLoaderRelocateImageExtraAction (ImageContext
);
754 return RETURN_SUCCESS
;
758 // If the destination address is not 0, use that rather than the
759 // image address as the relocation target.
761 if (ImageContext
->DestinationAddress
!= 0) {
762 BaseAddress
= ImageContext
->DestinationAddress
;
764 BaseAddress
= ImageContext
->ImageAddress
;
767 if (!(ImageContext
->IsTeImage
)) {
768 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
770 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
772 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
776 Adjust
= (UINT64
)BaseAddress
- Hdr
.Pe32
->OptionalHeader
.ImageBase
;
778 Hdr
.Pe32
->OptionalHeader
.ImageBase
= (UINT32
)BaseAddress
;
781 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
782 RelocDir
= &Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
787 Adjust
= (UINT64
) BaseAddress
- Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
789 Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
= (UINT64
)BaseAddress
;
792 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
793 RelocDir
= &Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
797 // Find the relocation block
798 // Per the PE/COFF spec, you can't assume that a given data directory
799 // is present in the image. You have to check the NumberOfRvaAndSizes in
800 // the optional header to verify a desired directory entry is there.
803 if ((NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) && (RelocDir
->Size
> 0)) {
804 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
805 RelocBaseEnd
= PeCoffLoaderImageAddress (
807 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
809 if (RelocBase
== NULL
|| RelocBaseEnd
== NULL
) {
810 return RETURN_LOAD_ERROR
;
814 // Set base and end to bypass processing below.
816 RelocBase
= RelocBaseEnd
= NULL
;
819 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
820 Adjust
= (UINT64
) (BaseAddress
- Hdr
.Te
->StrippedSize
+ sizeof (EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->ImageBase
);
822 Hdr
.Te
->ImageBase
= (UINT64
) (BaseAddress
- Hdr
.Te
->StrippedSize
+ sizeof (EFI_TE_IMAGE_HEADER
));
826 // Find the relocation block
828 RelocDir
= &Hdr
.Te
->DataDirectory
[0];
829 if (RelocDir
->Size
> 0) {
830 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(
831 ImageContext
->ImageAddress
+
832 RelocDir
->VirtualAddress
+
833 sizeof(EFI_TE_IMAGE_HEADER
) -
836 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) ((UINTN
) RelocBase
+ (UINTN
) RelocDir
->Size
- 1);
839 // Set base and end to bypass processing below.
841 RelocBase
= RelocBaseEnd
= NULL
;
846 // If Adjust is not zero, then apply fix ups to the image
850 // Run the relocation information and apply the fixups
852 FixupData
= ImageContext
->FixupData
;
853 while (RelocBase
< RelocBaseEnd
) {
855 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
856 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
859 // Make sure RelocEnd is in the Image range.
861 if ((CHAR8
*) RelocEnd
< (CHAR8
*)((UINTN
) ImageContext
->ImageAddress
) ||
862 (CHAR8
*) RelocEnd
> (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+ (UINTN
)ImageContext
->ImageSize
)) {
863 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
864 return RETURN_LOAD_ERROR
;
867 if (!(ImageContext
->IsTeImage
)) {
868 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
);
869 if (FixupBase
== NULL
) {
870 return RETURN_LOAD_ERROR
;
873 FixupBase
= (CHAR8
*)(UINTN
)(ImageContext
->ImageAddress
+
874 RelocBase
->VirtualAddress
+
875 sizeof(EFI_TE_IMAGE_HEADER
) -
881 // Run this relocation record
883 while (Reloc
< RelocEnd
) {
885 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
886 switch ((*Reloc
) >> 12) {
887 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
890 case EFI_IMAGE_REL_BASED_HIGH
:
891 Fixup16
= (UINT16
*) Fixup
;
892 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
893 if (FixupData
!= NULL
) {
894 *(UINT16
*) FixupData
= *Fixup16
;
895 FixupData
= FixupData
+ sizeof (UINT16
);
899 case EFI_IMAGE_REL_BASED_LOW
:
900 Fixup16
= (UINT16
*) Fixup
;
901 *Fixup16
= (UINT16
) (*Fixup16
+ (UINT16
) Adjust
);
902 if (FixupData
!= NULL
) {
903 *(UINT16
*) FixupData
= *Fixup16
;
904 FixupData
= FixupData
+ sizeof (UINT16
);
908 case EFI_IMAGE_REL_BASED_HIGHLOW
:
909 Fixup32
= (UINT32
*) Fixup
;
910 *Fixup32
= *Fixup32
+ (UINT32
) Adjust
;
911 if (FixupData
!= NULL
) {
912 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
913 *(UINT32
*)FixupData
= *Fixup32
;
914 FixupData
= FixupData
+ sizeof (UINT32
);
918 case EFI_IMAGE_REL_BASED_DIR64
:
919 Fixup64
= (UINT64
*) Fixup
;
920 *Fixup64
= *Fixup64
+ (UINT64
) Adjust
;
921 if (FixupData
!= NULL
) {
922 FixupData
= ALIGN_POINTER (FixupData
, sizeof(UINT64
));
923 *(UINT64
*)(FixupData
) = *Fixup64
;
924 FixupData
= FixupData
+ sizeof(UINT64
);
930 // The common code does not handle some of the stranger IPF relocations
931 // PeCoffLoaderRelocateImageEx () adds support for these complex fixups
932 // on IPF and is a No-Op on other architectures.
934 Status
= PeCoffLoaderRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
935 if (RETURN_ERROR (Status
)) {
936 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
942 // Next relocation record
950 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
954 // Adjust the EntryPoint to match the linked-to address
956 if (ImageContext
->DestinationAddress
!= 0) {
957 ImageContext
->EntryPoint
-= (UINT64
) ImageContext
->ImageAddress
;
958 ImageContext
->EntryPoint
+= (UINT64
) ImageContext
->DestinationAddress
;
962 // Applies additional environment specific actions to relocate fixups
963 // to a PE/COFF image if needed
964 PeCoffLoaderRelocateImageExtraAction (ImageContext
);
966 return RETURN_SUCCESS
;
970 Loads a PE/COFF image into memory.
972 Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
973 specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate
974 the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
975 The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.
976 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress, ImageSize,
977 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
978 fields of the ImageContext structure must be valid prior to invoking this service.
980 If ImageContext is NULL, then ASSERT().
982 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
983 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
984 prior to transferring control to a PE/COFF image that is loaded using this library.
986 @param ImageContext The pointer to the image context structure that describes the PE/COFF
987 image that is being loaded.
989 @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by
990 the ImageAddress and ImageSize fields of ImageContext.
991 Extended status information is in the ImageError field of ImageContext.
992 @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.
993 Extended status information is in the ImageError field of ImageContext.
994 @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.
995 Extended status information is in the ImageError field of ImageContext.
996 @retval RETURN_INVALID_PARAMETER The image address is invalid.
997 Extended status information is in the ImageError field of ImageContext.
1002 PeCoffLoaderLoadImage (
1003 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1006 RETURN_STATUS Status
;
1007 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1008 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
1009 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
1010 EFI_IMAGE_SECTION_HEADER
*Section
;
1011 UINTN NumberOfSections
;
1016 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
1017 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
1019 UINT32 TempDebugEntryRva
;
1020 UINT32 NumberOfRvaAndSizes
;
1022 EFI_IMAGE_RESOURCE_DIRECTORY
*ResourceDirectory
;
1023 EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*ResourceDirectoryEntry
;
1024 EFI_IMAGE_RESOURCE_DIRECTORY_STRING
*ResourceDirectoryString
;
1025 EFI_IMAGE_RESOURCE_DATA_ENTRY
*ResourceDataEntry
;
1029 ASSERT (ImageContext
!= NULL
);
1034 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
1037 // Copy the provided context information into our local version, get what we
1038 // can from the original image, and then use that to make sure everything
1041 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
1043 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
1044 if (RETURN_ERROR (Status
)) {
1049 // Make sure there is enough allocated space for the image being loaded
1051 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
1052 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
1053 return RETURN_BUFFER_TOO_SMALL
;
1055 if (ImageContext
->ImageAddress
== 0) {
1057 // Image cannot be loaded into 0 address.
1059 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1060 return RETURN_INVALID_PARAMETER
;
1063 // If there's no relocations, then make sure it's not a runtime driver,
1064 // and that it's being loaded at the linked address.
1066 if (CheckContext
.RelocationsStripped
) {
1068 // If the image does not contain relocations and it is a runtime driver
1069 // then return an error.
1071 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
1072 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
1073 return RETURN_LOAD_ERROR
;
1076 // If the image does not contain relocations, and the requested load address
1077 // is not the linked address, then return an error.
1079 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
1080 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1081 return RETURN_INVALID_PARAMETER
;
1085 // Make sure the allocated space has the proper section alignment
1087 if (!(ImageContext
->IsTeImage
)) {
1088 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
1089 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
1090 return RETURN_INVALID_PARAMETER
;
1094 // Read the entire PE/COFF or TE header into memory
1096 if (!(ImageContext
->IsTeImage
)) {
1097 Status
= ImageContext
->ImageRead (
1098 ImageContext
->Handle
,
1100 &ImageContext
->SizeOfHeaders
,
1101 (VOID
*) (UINTN
) ImageContext
->ImageAddress
1104 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
1106 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
1107 (UINTN
)ImageContext
->ImageAddress
+
1108 ImageContext
->PeCoffHeaderOffset
+
1110 sizeof(EFI_IMAGE_FILE_HEADER
) +
1111 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
1113 NumberOfSections
= (UINTN
) (Hdr
.Pe32
->FileHeader
.NumberOfSections
);
1115 Status
= ImageContext
->ImageRead (
1116 ImageContext
->Handle
,
1118 &ImageContext
->SizeOfHeaders
,
1119 (void *)(UINTN
)ImageContext
->ImageAddress
1122 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
1124 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
1125 (UINTN
)ImageContext
->ImageAddress
+
1126 sizeof(EFI_TE_IMAGE_HEADER
)
1128 NumberOfSections
= (UINTN
) (Hdr
.Te
->NumberOfSections
);
1132 if (RETURN_ERROR (Status
)) {
1133 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1134 return RETURN_LOAD_ERROR
;
1138 // Load each section of the image
1140 Section
= FirstSection
;
1141 for (Index
= 0, MaxEnd
= NULL
; Index
< NumberOfSections
; Index
++) {
1145 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
1146 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
1147 Size
= (UINTN
) Section
->SizeOfRawData
;
1151 // Compute sections address
1153 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
);
1154 End
= PeCoffLoaderImageAddress (
1156 Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1
1160 // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.
1162 if ((Size
> 0) && ((Base
== NULL
) || (End
== NULL
))) {
1163 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
1164 return RETURN_LOAD_ERROR
;
1167 if (ImageContext
->IsTeImage
) {
1168 Base
= (CHAR8
*)((UINTN
) Base
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
)Hdr
.Te
->StrippedSize
);
1169 End
= (CHAR8
*)((UINTN
) End
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
)Hdr
.Te
->StrippedSize
);
1176 if (Section
->SizeOfRawData
> 0) {
1177 if (!(ImageContext
->IsTeImage
)) {
1178 Status
= ImageContext
->ImageRead (
1179 ImageContext
->Handle
,
1180 Section
->PointerToRawData
,
1185 Status
= ImageContext
->ImageRead (
1186 ImageContext
->Handle
,
1187 Section
->PointerToRawData
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
)Hdr
.Te
->StrippedSize
,
1193 if (RETURN_ERROR (Status
)) {
1194 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1200 // If raw size is less then virtual size, zero fill the remaining
1203 if (Size
< Section
->Misc
.VirtualSize
) {
1204 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
1214 // Get image's entry point
1216 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
1217 if (!(ImageContext
->IsTeImage
)) {
1219 // Sizes of AddressOfEntryPoint are different so we need to do this safely
1221 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1225 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1227 (UINTN
)Hdr
.Pe32
->OptionalHeader
.AddressOfEntryPoint
1233 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1235 (UINTN
)Hdr
.Pe32Plus
->OptionalHeader
.AddressOfEntryPoint
1239 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (
1240 (UINTN
)ImageContext
->ImageAddress
+
1241 (UINTN
)Hdr
.Te
->AddressOfEntryPoint
+
1242 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1243 (UINTN
)Hdr
.Te
->StrippedSize
1248 // Determine the size of the fixup data
1250 // Per the PE/COFF spec, you can't assume that a given data directory
1251 // is present in the image. You have to check the NumberOfRvaAndSizes in
1252 // the optional header to verify a desired directory entry is there.
1254 if (!(ImageContext
->IsTeImage
)) {
1255 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1259 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1260 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1265 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1266 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1269 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1270 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1272 ImageContext
->FixupDataSize
= 0;
1275 DirectoryEntry
= &Hdr
.Te
->DataDirectory
[0];
1276 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1279 // Consumer must allocate a buffer for the relocation fixup log.
1280 // Only used for runtime drivers.
1282 ImageContext
->FixupData
= NULL
;
1285 // Load the Codeview information if present
1287 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
1288 if (!(ImageContext
->IsTeImage
)) {
1289 DebugEntry
= PeCoffLoaderImageAddress (
1291 ImageContext
->DebugDirectoryEntryRva
1294 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(UINTN
)(
1295 ImageContext
->ImageAddress
+
1296 ImageContext
->DebugDirectoryEntryRva
+
1297 sizeof(EFI_TE_IMAGE_HEADER
) -
1298 Hdr
.Te
->StrippedSize
1302 if (DebugEntry
!= NULL
) {
1303 TempDebugEntryRva
= DebugEntry
->RVA
;
1304 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
1306 if ((UINTN
)Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
1307 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
1309 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
1313 if (TempDebugEntryRva
!= 0) {
1314 if (!(ImageContext
->IsTeImage
)) {
1315 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
);
1317 ImageContext
->CodeView
= (VOID
*)(
1318 (UINTN
)ImageContext
->ImageAddress
+
1319 (UINTN
)TempDebugEntryRva
+
1320 (UINTN
)sizeof (EFI_TE_IMAGE_HEADER
) -
1321 (UINTN
) Hdr
.Te
->StrippedSize
1325 if (ImageContext
->CodeView
== NULL
) {
1326 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1327 return RETURN_LOAD_ERROR
;
1330 if (DebugEntry
->RVA
== 0) {
1331 Size
= DebugEntry
->SizeOfData
;
1332 if (!(ImageContext
->IsTeImage
)) {
1333 Status
= ImageContext
->ImageRead (
1334 ImageContext
->Handle
,
1335 DebugEntry
->FileOffset
,
1337 ImageContext
->CodeView
1340 Status
= ImageContext
->ImageRead (
1341 ImageContext
->Handle
,
1342 DebugEntry
->FileOffset
+ sizeof (EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->StrippedSize
,
1344 ImageContext
->CodeView
1347 // Should we apply fix up to this field according to the size difference between PE and TE?
1348 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1349 // in original PE image.
1353 if (RETURN_ERROR (Status
)) {
1354 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1355 return RETURN_LOAD_ERROR
;
1358 DebugEntry
->RVA
= TempDebugEntryRva
;
1361 switch (*(UINT32
*) ImageContext
->CodeView
) {
1362 case CODEVIEW_SIGNATURE_NB10
:
1363 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1366 case CODEVIEW_SIGNATURE_RSDS
:
1367 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
1370 case CODEVIEW_SIGNATURE_MTOC
:
1371 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
);
1382 // Get Image's HII resource section
1384 ImageContext
->HiiResourceData
= 0;
1385 if (!(ImageContext
->IsTeImage
)) {
1386 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1390 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
];
1395 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
];
1398 if (DirectoryEntry
->Size
!= 0) {
1399 Base
= PeCoffLoaderImageAddress (ImageContext
, DirectoryEntry
->VirtualAddress
);
1401 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) Base
;
1402 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1404 for (Index
= 0; Index
< ResourceDirectory
->NumberOfNamedEntries
; Index
++) {
1405 if (ResourceDirectoryEntry
->u1
.s
.NameIsString
) {
1406 ResourceDirectoryString
= (EFI_IMAGE_RESOURCE_DIRECTORY_STRING
*) (Base
+ ResourceDirectoryEntry
->u1
.s
.NameOffset
);
1407 String
= &ResourceDirectoryString
->String
[0];
1409 if (ResourceDirectoryString
->Length
== 3 &&
1410 String
[0] == L
'H' &&
1411 String
[1] == L
'I' &&
1412 String
[2] == L
'I') {
1414 // Resource Type "HII" found
1416 if (ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1418 // Move to next level - resource Name
1420 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) (Base
+ ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
);
1421 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1423 if (ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1425 // Move to next level - resource Language
1427 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) (Base
+ ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
);
1428 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1433 // Now it ought to be resource Data
1435 if (!ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1436 ResourceDataEntry
= (EFI_IMAGE_RESOURCE_DATA_ENTRY
*) (Base
+ ResourceDirectoryEntry
->u2
.OffsetToData
);
1437 ImageContext
->HiiResourceData
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (ImageContext
, ResourceDataEntry
->OffsetToData
);
1442 ResourceDirectoryEntry
++;
1453 Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI
1456 This function reapplies relocation fixups to the PE/COFF image specified by ImageBase
1457 and ImageSize so the image will execute correctly when the PE/COFF image is mapped
1458 to the address specified by VirtualImageBase. RelocationData must be identical
1459 to the FiuxupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure
1460 after this PE/COFF image was relocated with PeCoffLoaderRelocateImage().
1462 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1463 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1464 prior to transferring control to a PE/COFF image that is loaded using this library.
1466 @param ImageBase The base address of a PE/COFF image that has been loaded
1467 and relocated into system memory.
1468 @param VirtImageBase The request virtual address that the PE/COFF image is to
1470 @param ImageSize The size, in bytes, of the PE/COFF image.
1471 @param RelocationData A pointer to the relocation data that was collected when the PE/COFF
1472 image was relocated using PeCoffLoaderRelocateImage().
1477 PeCoffLoaderRelocateImageForRuntime (
1478 IN PHYSICAL_ADDRESS ImageBase
,
1479 IN PHYSICAL_ADDRESS VirtImageBase
,
1481 IN VOID
*RelocationData
1486 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1487 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1488 UINT32 NumberOfRvaAndSizes
;
1489 EFI_IMAGE_DATA_DIRECTORY
*DataDirectory
;
1490 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
1491 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
1492 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
1502 RETURN_STATUS Status
;
1505 OldBase
= (CHAR8
*)((UINTN
)ImageBase
);
1506 NewBase
= (CHAR8
*)((UINTN
)VirtImageBase
);
1507 Adjust
= (UINTN
) NewBase
- (UINTN
) OldBase
;
1510 // Find the image's relocate dir info
1512 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)OldBase
;
1513 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
1515 // Valid DOS header so get address of PE header
1517 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)(((CHAR8
*)DosHdr
) + DosHdr
->e_lfanew
);
1520 // No Dos header so assume image starts with PE header.
1522 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)OldBase
;
1525 if (Hdr
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
1527 // Not a valid PE image so Exit
1532 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
1534 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1538 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1539 DataDirectory
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[0]);
1544 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1545 DataDirectory
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[0]);
1549 // Find the relocation block
1551 // Per the PE/COFF spec, you can't assume that a given data directory
1552 // is present in the image. You have to check the NumberOfRvaAndSizes in
1553 // the optional header to verify a desired directory entry is there.
1555 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1556 RelocDir
= DataDirectory
+ EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
;
1557 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(ImageBase
+ RelocDir
->VirtualAddress
);
1558 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(ImageBase
+ RelocDir
->VirtualAddress
+ RelocDir
->Size
);
1561 // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.
1568 // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.
1570 ASSERT (RelocBase
!= NULL
&& RelocBaseEnd
!= NULL
);
1573 // Run the whole relocation block. And re-fixup data that has not been
1574 // modified. The FixupData is used to see if the image has been modified
1575 // since it was relocated. This is so data sections that have been updated
1576 // by code will not be fixed up, since that would set them back to
1579 FixupData
= RelocationData
;
1580 while (RelocBase
< RelocBaseEnd
) {
1582 Reloc
= (UINT16
*) ((UINT8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
1583 RelocEnd
= (UINT16
*) ((UINT8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
1584 FixupBase
= (CHAR8
*) ((UINTN
)ImageBase
) + RelocBase
->VirtualAddress
;
1587 // Run this relocation record
1589 while (Reloc
< RelocEnd
) {
1591 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
1592 switch ((*Reloc
) >> 12) {
1594 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
1597 case EFI_IMAGE_REL_BASED_HIGH
:
1598 Fixup16
= (UINT16
*) Fixup
;
1599 if (*(UINT16
*) FixupData
== *Fixup16
) {
1600 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
1603 FixupData
= FixupData
+ sizeof (UINT16
);
1606 case EFI_IMAGE_REL_BASED_LOW
:
1607 Fixup16
= (UINT16
*) Fixup
;
1608 if (*(UINT16
*) FixupData
== *Fixup16
) {
1609 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) Adjust
& 0xffff));
1612 FixupData
= FixupData
+ sizeof (UINT16
);
1615 case EFI_IMAGE_REL_BASED_HIGHLOW
:
1616 Fixup32
= (UINT32
*) Fixup
;
1617 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
1618 if (*(UINT32
*) FixupData
== *Fixup32
) {
1619 *Fixup32
= *Fixup32
+ (UINT32
) Adjust
;
1622 FixupData
= FixupData
+ sizeof (UINT32
);
1625 case EFI_IMAGE_REL_BASED_DIR64
:
1626 Fixup64
= (UINT64
*)Fixup
;
1627 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT64
));
1628 if (*(UINT64
*) FixupData
== *Fixup64
) {
1629 *Fixup64
= *Fixup64
+ (UINT64
)Adjust
;
1632 FixupData
= FixupData
+ sizeof (UINT64
);
1635 case EFI_IMAGE_REL_BASED_HIGHADJ
:
1637 // Not valid Relocation type for UEFI image, ASSERT
1644 // Only Itanium requires ConvertPeImage_Ex
1646 Status
= PeHotRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
1647 if (RETURN_ERROR (Status
)) {
1652 // Next relocation record
1659 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
1665 Reads contents of a PE/COFF image from a buffer in system memory.
1667 This is the default implementation of a PE_COFF_LOADER_READ_FILE function
1668 that assumes FileHandle pointer to the beginning of a PE/COFF image.
1669 This function reads contents of the PE/COFF image that starts at the system memory
1670 address specified by FileHandle. The read operation copies ReadSize bytes from the
1671 PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer.
1672 The size of the buffer actually read is returned in ReadSize.
1674 If FileHandle is NULL, then ASSERT().
1675 If ReadSize is NULL, then ASSERT().
1676 If Buffer is NULL, then ASSERT().
1678 @param FileHandle The pointer to base of the input stream
1679 @param FileOffset Offset into the PE/COFF image to begin the read operation.
1680 @param ReadSize On input, the size in bytes of the requested read operation.
1681 On output, the number of bytes actually read.
1682 @param Buffer Output buffer that contains the data read from the PE/COFF image.
1684 @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into
1689 PeCoffLoaderImageReadFromMemory (
1690 IN VOID
*FileHandle
,
1691 IN UINTN FileOffset
,
1692 IN OUT UINTN
*ReadSize
,
1696 ASSERT (ReadSize
!= NULL
);
1697 ASSERT (FileHandle
!= NULL
);
1698 ASSERT (Buffer
!= NULL
);
1700 CopyMem (Buffer
, ((UINT8
*)FileHandle
) + FileOffset
, *ReadSize
);
1701 return RETURN_SUCCESS
;
1705 Unloads a loaded PE/COFF image from memory and releases its taken resource.
1706 Releases any environment specific resources that were allocated when the image
1707 specified by ImageContext was loaded using PeCoffLoaderLoadImage().
1709 For NT32 emulator, the PE/COFF image loaded by system needs to release.
1710 For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded,
1711 this function can simply return RETURN_SUCCESS.
1713 If ImageContext is NULL, then ASSERT().
1715 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1716 image to be unloaded.
1718 @retval RETURN_SUCCESS The PE/COFF image was unloaded successfully.
1722 PeCoffLoaderUnloadImage (
1723 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1727 // Applies additional environment specific actions to unload a
1728 // PE/COFF image if needed
1730 PeCoffLoaderUnloadImageExtraAction (ImageContext
);
1731 return RETURN_SUCCESS
;