2 Base PE/COFF loader supports loading any PE32/PE32+ or TE image, but
3 only supports relocating IA32, x64, IPF, ARM, RISC-V, LoongArch and EBC images.
5 Caution: This file requires additional review when modified.
6 This library will have external input - PE/COFF image.
7 This external input must be validated carefully to avoid security issue like
8 buffer overflow, integer overflow.
10 The basic guideline is that caller need provide ImageContext->ImageRead () with the
11 necessary data range check, to make sure when this library reads PE/COFF image, the
12 PE image buffer is always in valid range.
13 This library will also do some additional check for PE header fields.
15 PeCoffLoaderGetPeHeader() routine will do basic check for PE/COFF header.
16 PeCoffLoaderGetImageInfo() routine will do basic check for whole PE/COFF image.
18 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
19 Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
20 Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
21 Portions Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.<BR>
22 SPDX-License-Identifier: BSD-2-Clause-Patent
26 #include "BasePeCoffLibInternals.h"
29 Adjust some fields in section header for TE image.
31 @param SectionHeader Pointer to the section header.
32 @param TeStrippedOffset Size adjust for the TE image.
36 PeCoffLoaderAdjustOffsetForTeImage (
37 EFI_IMAGE_SECTION_HEADER
*SectionHeader
,
38 UINT32 TeStrippedOffset
41 SectionHeader
->VirtualAddress
-= TeStrippedOffset
;
42 SectionHeader
->PointerToRawData
-= TeStrippedOffset
;
46 Retrieves the PE or TE Header from a PE/COFF or TE image.
48 Caution: This function may receive untrusted input.
49 PE/COFF image is external input, so this routine will
50 also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
51 SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
53 @param ImageContext The context of the image being loaded.
54 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
56 @retval RETURN_SUCCESS The PE or TE Header is read.
57 @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.
61 PeCoffLoaderGetPeHeader (
62 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
63 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
67 EFI_IMAGE_DOS_HEADER DosHdr
;
70 UINT32 SectionHeaderOffset
;
72 UINT32 HeaderWithoutDataDir
;
74 UINTN NumberOfSections
;
75 EFI_IMAGE_SECTION_HEADER SectionHeader
;
78 // Read the DOS image header to check for its existence
80 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
82 Status
= ImageContext
->ImageRead (
88 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
89 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
90 if (Size
!= ReadSize
) {
91 Status
= RETURN_UNSUPPORTED
;
97 ImageContext
->PeCoffHeaderOffset
= 0;
98 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
100 // DOS image header is present, so read the PE header after the DOS image
103 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
107 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
108 // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
109 // determines if this is a PE32 or PE32+ image. The magic is in the same
110 // location in both images.
112 Size
= sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
);
114 Status
= ImageContext
->ImageRead (
115 ImageContext
->Handle
,
116 ImageContext
->PeCoffHeaderOffset
,
120 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
121 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
122 if (Size
!= ReadSize
) {
123 Status
= RETURN_UNSUPPORTED
;
130 // Use Signature to figure out if we understand the image format
132 if (Hdr
.Te
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
133 ImageContext
->IsTeImage
= TRUE
;
134 ImageContext
->Machine
= Hdr
.Te
->Machine
;
135 ImageContext
->ImageType
= (UINT16
)(Hdr
.Te
->Subsystem
);
137 // For TeImage, SectionAlignment is undefined to be set to Zero
138 // ImageSize can be calculated.
140 ImageContext
->ImageSize
= 0;
141 ImageContext
->SectionAlignment
= 0;
142 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
)Hdr
.Te
->BaseOfCode
- (UINTN
)Hdr
.Te
->StrippedSize
;
145 // Check the StrippedSize.
147 if (sizeof (EFI_TE_IMAGE_HEADER
) >= (UINT32
)Hdr
.Te
->StrippedSize
) {
148 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
149 return RETURN_UNSUPPORTED
;
153 // Check the SizeOfHeaders field.
155 if (Hdr
.Te
->BaseOfCode
<= Hdr
.Te
->StrippedSize
) {
156 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
157 return RETURN_UNSUPPORTED
;
161 // Read last byte of Hdr.Te->SizeOfHeaders from the file.
165 Status
= ImageContext
->ImageRead (
166 ImageContext
->Handle
,
167 ImageContext
->SizeOfHeaders
- 1,
171 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
172 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
173 if (Size
!= ReadSize
) {
174 Status
= RETURN_UNSUPPORTED
;
181 // TE Image Data Directory Entry size is non-zero, but the Data Directory Virtual Address is zero.
182 // This case is not a valid TE image.
184 if (((Hdr
.Te
->DataDirectory
[0].Size
!= 0) && (Hdr
.Te
->DataDirectory
[0].VirtualAddress
== 0)) ||
185 ((Hdr
.Te
->DataDirectory
[1].Size
!= 0) && (Hdr
.Te
->DataDirectory
[1].VirtualAddress
== 0)))
187 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
188 return RETURN_UNSUPPORTED
;
190 } else if (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
) {
191 ImageContext
->IsTeImage
= FALSE
;
192 ImageContext
->Machine
= Hdr
.Pe32
->FileHeader
.Machine
;
194 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
196 // 1. Check OptionalHeader.NumberOfRvaAndSizes filed.
198 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
< Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) {
199 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
200 return RETURN_UNSUPPORTED
;
204 // 2. Check the FileHeader.SizeOfOptionalHeader field.
205 // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
206 // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
208 HeaderWithoutDataDir
= sizeof (EFI_IMAGE_OPTIONAL_HEADER32
) - sizeof (EFI_IMAGE_DATA_DIRECTORY
) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
;
209 if (((UINT32
)Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
- HeaderWithoutDataDir
) !=
210 Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
* sizeof (EFI_IMAGE_DATA_DIRECTORY
))
212 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
213 return RETURN_UNSUPPORTED
;
216 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
218 // 3. Check the FileHeader.NumberOfSections field.
220 if (Hdr
.Pe32
->OptionalHeader
.SizeOfImage
<= SectionHeaderOffset
) {
221 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
222 return RETURN_UNSUPPORTED
;
225 if ((Hdr
.Pe32
->OptionalHeader
.SizeOfImage
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
<= Hdr
.Pe32
->FileHeader
.NumberOfSections
) {
226 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
227 return RETURN_UNSUPPORTED
;
231 // 4. Check the OptionalHeader.SizeOfHeaders field.
233 if (Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
<= SectionHeaderOffset
) {
234 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
235 return RETURN_UNSUPPORTED
;
238 if (Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
>= Hdr
.Pe32
->OptionalHeader
.SizeOfImage
) {
239 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
240 return RETURN_UNSUPPORTED
;
243 if ((Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
< (UINT32
)Hdr
.Pe32
->FileHeader
.NumberOfSections
) {
244 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
245 return RETURN_UNSUPPORTED
;
249 // 4.2 Read last byte of Hdr.Pe32.OptionalHeader.SizeOfHeaders from the file.
253 Status
= ImageContext
->ImageRead (
254 ImageContext
->Handle
,
255 Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- 1,
259 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
260 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
261 if (Size
!= ReadSize
) {
262 Status
= RETURN_UNSUPPORTED
;
269 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
270 // Read the last byte to make sure the data is in the image region.
271 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
273 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
< Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) {
274 if (Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
!= 0) {
276 // Check the member data to avoid overflow.
278 if ((UINT32
)(~0) - Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
<
279 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
)
281 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
282 return RETURN_UNSUPPORTED
;
286 // Read last byte of section header from file
290 Status
= ImageContext
->ImageRead (
291 ImageContext
->Handle
,
292 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
+
293 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
- 1,
297 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
298 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
299 if (Size
!= ReadSize
) {
300 Status
= RETURN_UNSUPPORTED
;
311 ImageContext
->ImageType
= Hdr
.Pe32
->OptionalHeader
.Subsystem
;
312 ImageContext
->ImageSize
= (UINT64
)Hdr
.Pe32
->OptionalHeader
.SizeOfImage
;
313 ImageContext
->SectionAlignment
= Hdr
.Pe32
->OptionalHeader
.SectionAlignment
;
314 ImageContext
->SizeOfHeaders
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
;
315 } else if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
317 // 1. Check FileHeader.NumberOfRvaAndSizes filed.
319 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
< Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
320 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
321 return RETURN_UNSUPPORTED
;
325 // 2. Check the FileHeader.SizeOfOptionalHeader field.
326 // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
327 // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
329 HeaderWithoutDataDir
= sizeof (EFI_IMAGE_OPTIONAL_HEADER64
) - sizeof (EFI_IMAGE_DATA_DIRECTORY
) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
;
330 if (((UINT32
)Hdr
.Pe32Plus
->FileHeader
.SizeOfOptionalHeader
- HeaderWithoutDataDir
) !=
331 Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
* sizeof (EFI_IMAGE_DATA_DIRECTORY
))
333 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
334 return RETURN_UNSUPPORTED
;
337 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32Plus
->FileHeader
.SizeOfOptionalHeader
;
339 // 3. Check the FileHeader.NumberOfSections field.
341 if (Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
<= SectionHeaderOffset
) {
342 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
343 return RETURN_UNSUPPORTED
;
346 if ((Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
<= Hdr
.Pe32Plus
->FileHeader
.NumberOfSections
) {
347 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
348 return RETURN_UNSUPPORTED
;
352 // 4. Check the OptionalHeader.SizeOfHeaders field.
354 if (Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
<= SectionHeaderOffset
) {
355 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
356 return RETURN_UNSUPPORTED
;
359 if (Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
>= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
) {
360 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
361 return RETURN_UNSUPPORTED
;
364 if ((Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
< (UINT32
)Hdr
.Pe32Plus
->FileHeader
.NumberOfSections
) {
365 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
366 return RETURN_UNSUPPORTED
;
370 // 4.2 Read last byte of Hdr.Pe32Plus.OptionalHeader.SizeOfHeaders from the file.
374 Status
= ImageContext
->ImageRead (
375 ImageContext
->Handle
,
376 Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- 1,
380 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
381 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
382 if (Size
!= ReadSize
) {
383 Status
= RETURN_UNSUPPORTED
;
390 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
391 // Read the last byte to make sure the data is in the image region.
392 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
394 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
< Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
395 if (Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
!= 0) {
397 // Check the member data to avoid overflow.
399 if ((UINT32
)(~0) - Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
<
400 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
)
402 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
403 return RETURN_UNSUPPORTED
;
407 // Read last byte of section header from file
411 Status
= ImageContext
->ImageRead (
412 ImageContext
->Handle
,
413 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
+
414 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
- 1,
418 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
419 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
420 if (Size
!= ReadSize
) {
421 Status
= RETURN_UNSUPPORTED
;
432 ImageContext
->ImageType
= Hdr
.Pe32Plus
->OptionalHeader
.Subsystem
;
433 ImageContext
->ImageSize
= (UINT64
)Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
;
434 ImageContext
->SectionAlignment
= Hdr
.Pe32Plus
->OptionalHeader
.SectionAlignment
;
435 ImageContext
->SizeOfHeaders
= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
;
437 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
438 return RETURN_UNSUPPORTED
;
441 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
442 return RETURN_UNSUPPORTED
;
445 if (!PeCoffLoaderImageFormatSupported (ImageContext
->Machine
)) {
447 // If the PE/COFF loader does not support the image type return
448 // unsupported. This library can support lots of types of images
449 // this does not mean the user of this library can call the entry
450 // point of the image.
452 return RETURN_UNSUPPORTED
;
456 // Check each section field.
458 if (ImageContext
->IsTeImage
) {
459 SectionHeaderOffset
= sizeof (EFI_TE_IMAGE_HEADER
);
460 NumberOfSections
= (UINTN
)(Hdr
.Te
->NumberOfSections
);
462 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
463 NumberOfSections
= (UINTN
)(Hdr
.Pe32
->FileHeader
.NumberOfSections
);
466 for (Index
= 0; Index
< NumberOfSections
; Index
++) {
468 // Read section header from file
470 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
472 Status
= ImageContext
->ImageRead (
473 ImageContext
->Handle
,
478 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
479 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
480 if (Size
!= ReadSize
) {
481 Status
= RETURN_UNSUPPORTED
;
488 // Adjust some field in Section Header for TE image.
490 if (ImageContext
->IsTeImage
) {
491 PeCoffLoaderAdjustOffsetForTeImage (&SectionHeader
, (UINT32
)Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
494 if (SectionHeader
.SizeOfRawData
> 0) {
496 // Section data should bigger than the Pe header.
498 if ((SectionHeader
.VirtualAddress
< ImageContext
->SizeOfHeaders
) ||
499 (SectionHeader
.PointerToRawData
< ImageContext
->SizeOfHeaders
))
501 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
502 return RETURN_UNSUPPORTED
;
506 // Check the member data to avoid overflow.
508 if ((UINT32
)(~0) - SectionHeader
.PointerToRawData
< SectionHeader
.SizeOfRawData
) {
509 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
510 return RETURN_UNSUPPORTED
;
514 // Base on the ImageRead function to check the section data field.
515 // Read the last byte to make sure the data is in the image region.
519 Status
= ImageContext
->ImageRead (
520 ImageContext
->Handle
,
521 SectionHeader
.PointerToRawData
+ SectionHeader
.SizeOfRawData
- 1,
525 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
526 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
527 if (Size
!= ReadSize
) {
528 Status
= RETURN_UNSUPPORTED
;
536 // Check next section.
538 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
541 return RETURN_SUCCESS
;
545 Retrieves information about a PE/COFF image.
547 Computes the PeCoffHeaderOffset, IsTeImage, ImageType, ImageAddress, ImageSize,
548 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and
549 DebugDirectoryEntryRva fields of the ImageContext structure.
550 If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.
551 If the PE/COFF image accessed through the ImageRead service in the ImageContext
552 structure is not a supported PE/COFF image type, then return RETURN_UNSUPPORTED.
553 If any errors occur while computing the fields of ImageContext,
554 then the error status is returned in the ImageError field of ImageContext.
555 If the image is a TE image, then SectionAlignment is set to 0.
556 The ImageRead and Handle fields of ImageContext structure must be valid prior
557 to invoking this service.
559 Caution: This function may receive untrusted input.
560 PE/COFF image is external input, so this routine will
561 also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
562 SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
564 @param ImageContext The pointer to the image context structure that describes the PE/COFF
565 image that needs to be examined by this function.
567 @retval RETURN_SUCCESS The information on the PE/COFF image was collected.
568 @retval RETURN_INVALID_PARAMETER ImageContext is NULL.
569 @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.
574 PeCoffLoaderGetImageInfo (
575 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
578 RETURN_STATUS Status
;
579 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
580 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
581 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
585 UINTN DebugDirectoryEntryRva
;
586 UINTN DebugDirectoryEntryFileOffset
;
587 UINTN SectionHeaderOffset
;
588 EFI_IMAGE_SECTION_HEADER SectionHeader
;
589 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
590 UINT32 NumberOfRvaAndSizes
;
591 UINT32 TeStrippedOffset
;
593 if (ImageContext
== NULL
) {
594 return RETURN_INVALID_PARAMETER
;
600 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
602 Hdr
.Union
= &HdrData
;
603 Status
= PeCoffLoaderGetPeHeader (ImageContext
, Hdr
);
604 if (RETURN_ERROR (Status
)) {
609 // Retrieve the base address of the image
611 if (!(ImageContext
->IsTeImage
)) {
612 TeStrippedOffset
= 0;
613 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
617 ImageContext
->ImageAddress
= Hdr
.Pe32
->OptionalHeader
.ImageBase
;
622 ImageContext
->ImageAddress
= Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
625 TeStrippedOffset
= (UINT32
)Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
626 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
)(Hdr
.Te
->ImageBase
+ TeStrippedOffset
);
630 // Initialize the alternate destination address to 0 indicating that it
631 // should not be used.
633 ImageContext
->DestinationAddress
= 0;
636 // Initialize the debug codeview pointer.
638 ImageContext
->DebugDirectoryEntryRva
= 0;
639 ImageContext
->CodeView
= NULL
;
640 ImageContext
->PdbPointer
= NULL
;
643 // Three cases with regards to relocations:
644 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
645 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
646 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
647 // has no base relocs to apply
648 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
650 // Look at the file header to determine if relocations have been stripped, and
651 // save this information in the image context for later use.
653 if ((!(ImageContext
->IsTeImage
)) && ((Hdr
.Pe32
->FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
654 ImageContext
->RelocationsStripped
= TRUE
;
655 } else if ((ImageContext
->IsTeImage
) && (Hdr
.Te
->DataDirectory
[0].Size
== 0) && (Hdr
.Te
->DataDirectory
[0].VirtualAddress
== 0)) {
656 ImageContext
->RelocationsStripped
= TRUE
;
658 ImageContext
->RelocationsStripped
= FALSE
;
661 if (!(ImageContext
->IsTeImage
)) {
662 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
666 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
667 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
672 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
673 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
676 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
677 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
680 // Determine the file offset of the debug directory... This means we walk
681 // the sections to find which section contains the RVA of the debug
684 DebugDirectoryEntryFileOffset
= 0;
686 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+
688 sizeof (EFI_IMAGE_FILE_HEADER
) +
689 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
691 for (Index
= 0; Index
< Hdr
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
693 // Read section header from file
695 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
697 Status
= ImageContext
->ImageRead (
698 ImageContext
->Handle
,
703 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
704 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
705 if (Size
!= ReadSize
) {
706 Status
= RETURN_UNSUPPORTED
;
712 if ((DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
) &&
713 (DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
))
715 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
719 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
722 if (DebugDirectoryEntryFileOffset
!= 0) {
723 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
725 // Read next debug directory entry
727 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
729 Status
= ImageContext
->ImageRead (
730 ImageContext
->Handle
,
731 DebugDirectoryEntryFileOffset
+ Index
,
735 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
736 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
737 if (Size
!= ReadSize
) {
738 Status
= RETURN_UNSUPPORTED
;
745 // From PeCoff spec, when DebugEntry.RVA == 0 means this debug info will not load into memory.
746 // Here we will always load EFI_IMAGE_DEBUG_TYPE_CODEVIEW type debug info. so need adjust the
747 // ImageContext->ImageSize when DebugEntry.RVA == 0.
749 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
750 ImageContext
->DebugDirectoryEntryRva
= (UINT32
)(DebugDirectoryEntryRva
+ Index
);
751 if ((DebugEntry
.RVA
== 0) && (DebugEntry
.FileOffset
!= 0)) {
752 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
755 return RETURN_SUCCESS
;
761 DebugDirectoryEntry
= &Hdr
.Te
->DataDirectory
[1];
762 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
763 SectionHeaderOffset
= (UINTN
)(sizeof (EFI_TE_IMAGE_HEADER
));
765 DebugDirectoryEntryFileOffset
= 0;
767 for (Index
= 0; Index
< Hdr
.Te
->NumberOfSections
;) {
769 // Read section header from file
771 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
773 Status
= ImageContext
->ImageRead (
774 ImageContext
->Handle
,
779 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
780 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
781 if (Size
!= ReadSize
) {
782 Status
= RETURN_UNSUPPORTED
;
788 if ((DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
) &&
789 (DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
))
791 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
792 SectionHeader
.VirtualAddress
+
793 SectionHeader
.PointerToRawData
-
797 // File offset of the debug directory was found, if this is not the last
798 // section, then skip to the last section for calculating the image size.
800 if (Index
< (UINTN
)Hdr
.Te
->NumberOfSections
- 1) {
801 SectionHeaderOffset
+= (Hdr
.Te
->NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
802 Index
= Hdr
.Te
->NumberOfSections
- 1;
808 // In Te image header there is not a field to describe the ImageSize.
809 // Actually, the ImageSize equals the RVA plus the VirtualSize of
810 // the last section mapped into memory (Must be rounded up to
811 // a multiple of Section Alignment). Per the PE/COFF specification, the
812 // section headers in the Section Table must appear in order of the RVA
813 // values for the corresponding sections. So the ImageSize can be determined
814 // by the RVA and the VirtualSize of the last section header in the
817 if ((++Index
) == (UINTN
)Hdr
.Te
->NumberOfSections
) {
818 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) - TeStrippedOffset
;
821 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
824 if (DebugDirectoryEntryFileOffset
!= 0) {
825 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
827 // Read next debug directory entry
829 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
831 Status
= ImageContext
->ImageRead (
832 ImageContext
->Handle
,
833 DebugDirectoryEntryFileOffset
+ Index
,
837 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
838 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
839 if (Size
!= ReadSize
) {
840 Status
= RETURN_UNSUPPORTED
;
846 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
847 ImageContext
->DebugDirectoryEntryRva
= (UINT32
)(DebugDirectoryEntryRva
+ Index
);
848 return RETURN_SUCCESS
;
854 return RETURN_SUCCESS
;
858 Converts an image address to the loaded address.
860 @param ImageContext The context of the image being loaded.
861 @param Address The address to be converted to the loaded address.
862 @param TeStrippedOffset Stripped offset for TE image.
864 @return The converted address or NULL if the address can not be converted.
868 PeCoffLoaderImageAddress (
869 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
871 IN UINTN TeStrippedOffset
875 // Make sure that Address and ImageSize is correct for the loaded image.
877 if (Address
>= ImageContext
->ImageSize
+ TeStrippedOffset
) {
878 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
882 return (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+ Address
- TeStrippedOffset
);
886 Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().
888 If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of
889 ImageContext as the relocation base address. Otherwise, use the DestinationAddress field
890 of ImageContext as the relocation base address. The caller must allocate the relocation
891 fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.
893 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress,
894 ImageSize, DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders,
895 DebugDirectoryEntryRva, EntryPoint, FixupDataSize, CodeView, PdbPointer, and FixupData of
896 the ImageContext structure must be valid prior to invoking this service.
898 If ImageContext is NULL, then ASSERT().
900 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
901 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
902 prior to transferring control to a PE/COFF image that is loaded using this library.
904 @param ImageContext The pointer to the image context structure that describes the PE/COFF
905 image that is being relocated.
907 @retval RETURN_SUCCESS The PE/COFF image was relocated.
908 Extended status information is in the ImageError field of ImageContext.
909 @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.
910 Extended status information is in the ImageError field of ImageContext.
911 @retval RETURN_UNSUPPORTED A relocation record type is not supported.
912 Extended status information is in the ImageError field of ImageContext.
917 PeCoffLoaderRelocateImage (
918 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
921 RETURN_STATUS Status
;
922 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
923 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
925 EFI_IMAGE_BASE_RELOCATION
*RelocBaseOrg
;
926 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
927 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
936 PHYSICAL_ADDRESS BaseAddress
;
937 UINT32 NumberOfRvaAndSizes
;
938 UINT32 TeStrippedOffset
;
940 ASSERT (ImageContext
!= NULL
);
945 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
948 // If there are no relocation entries, then we are done
950 if (ImageContext
->RelocationsStripped
) {
951 // Applies additional environment specific actions to relocate fixups
952 // to a PE/COFF image if needed
953 PeCoffLoaderRelocateImageExtraAction (ImageContext
);
954 return RETURN_SUCCESS
;
958 // If the destination address is not 0, use that rather than the
959 // image address as the relocation target.
961 if (ImageContext
->DestinationAddress
!= 0) {
962 BaseAddress
= ImageContext
->DestinationAddress
;
964 BaseAddress
= ImageContext
->ImageAddress
;
967 if (!(ImageContext
->IsTeImage
)) {
968 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
969 TeStrippedOffset
= 0;
971 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
975 Adjust
= (UINT64
)BaseAddress
- Hdr
.Pe32
->OptionalHeader
.ImageBase
;
977 Hdr
.Pe32
->OptionalHeader
.ImageBase
= (UINT32
)BaseAddress
;
980 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
981 RelocDir
= &Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
986 Adjust
= (UINT64
)BaseAddress
- Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
988 Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
= (UINT64
)BaseAddress
;
991 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
992 RelocDir
= &Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
996 // Find the relocation block
997 // Per the PE/COFF spec, you can't assume that a given data directory
998 // is present in the image. You have to check the NumberOfRvaAndSizes in
999 // the optional header to verify a desired directory entry is there.
1001 if ((NumberOfRvaAndSizes
< EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
)) {
1005 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
1006 TeStrippedOffset
= (UINT32
)Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
1007 Adjust
= (UINT64
)(BaseAddress
- (Hdr
.Te
->ImageBase
+ TeStrippedOffset
));
1009 Hdr
.Te
->ImageBase
= (UINT64
)(BaseAddress
- TeStrippedOffset
);
1013 // Find the relocation block
1015 RelocDir
= &Hdr
.Te
->DataDirectory
[0];
1018 if ((RelocDir
!= NULL
) && (RelocDir
->Size
> 0)) {
1019 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
, TeStrippedOffset
);
1020 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*)PeCoffLoaderImageAddress (
1022 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1,
1025 if ((RelocBase
== NULL
) || (RelocBaseEnd
== NULL
) || ((UINTN
)RelocBaseEnd
< (UINTN
)RelocBase
)) {
1026 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1027 return RETURN_LOAD_ERROR
;
1031 // Set base and end to bypass processing below.
1033 RelocBase
= RelocBaseEnd
= NULL
;
1036 RelocBaseOrg
= RelocBase
;
1039 // If Adjust is not zero, then apply fix ups to the image
1043 // Run the relocation information and apply the fixups
1045 FixupData
= ImageContext
->FixupData
;
1046 while ((UINTN
)RelocBase
< (UINTN
)RelocBaseEnd
) {
1047 Reloc
= (UINT16
*)((CHAR8
*)RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
1049 // Add check for RelocBase->SizeOfBlock field.
1051 if (RelocBase
->SizeOfBlock
== 0) {
1052 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1053 return RETURN_LOAD_ERROR
;
1056 if ((UINTN
)RelocBase
> MAX_ADDRESS
- RelocBase
->SizeOfBlock
) {
1057 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1058 return RETURN_LOAD_ERROR
;
1061 RelocEnd
= (UINT16
*)((CHAR8
*)RelocBase
+ RelocBase
->SizeOfBlock
);
1062 if ((UINTN
)RelocEnd
> (UINTN
)RelocBaseOrg
+ RelocDir
->Size
) {
1063 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1064 return RETURN_LOAD_ERROR
;
1067 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
, TeStrippedOffset
);
1068 if (FixupBase
== NULL
) {
1069 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1070 return RETURN_LOAD_ERROR
;
1074 // Run this relocation record
1076 while ((UINTN
)Reloc
< (UINTN
)RelocEnd
) {
1077 Fixup
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
+ (*Reloc
& 0xFFF), TeStrippedOffset
);
1078 if (Fixup
== NULL
) {
1079 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1080 return RETURN_LOAD_ERROR
;
1083 switch ((*Reloc
) >> 12) {
1084 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
1087 case EFI_IMAGE_REL_BASED_HIGH
:
1088 Fixup16
= (UINT16
*)Fixup
;
1089 *Fixup16
= (UINT16
)(*Fixup16
+ ((UINT16
)((UINT32
)Adjust
>> 16)));
1090 if (FixupData
!= NULL
) {
1091 *(UINT16
*)FixupData
= *Fixup16
;
1092 FixupData
= FixupData
+ sizeof (UINT16
);
1097 case EFI_IMAGE_REL_BASED_LOW
:
1098 Fixup16
= (UINT16
*)Fixup
;
1099 *Fixup16
= (UINT16
)(*Fixup16
+ (UINT16
)Adjust
);
1100 if (FixupData
!= NULL
) {
1101 *(UINT16
*)FixupData
= *Fixup16
;
1102 FixupData
= FixupData
+ sizeof (UINT16
);
1107 case EFI_IMAGE_REL_BASED_HIGHLOW
:
1108 Fixup32
= (UINT32
*)Fixup
;
1109 *Fixup32
= *Fixup32
+ (UINT32
)Adjust
;
1110 if (FixupData
!= NULL
) {
1111 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
1112 *(UINT32
*)FixupData
= *Fixup32
;
1113 FixupData
= FixupData
+ sizeof (UINT32
);
1118 case EFI_IMAGE_REL_BASED_DIR64
:
1119 Fixup64
= (UINT64
*)Fixup
;
1120 *Fixup64
= *Fixup64
+ (UINT64
)Adjust
;
1121 if (FixupData
!= NULL
) {
1122 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT64
));
1123 *(UINT64
*)(FixupData
) = *Fixup64
;
1124 FixupData
= FixupData
+ sizeof (UINT64
);
1131 // The common code does not handle some of the stranger IPF relocations
1132 // PeCoffLoaderRelocateImageEx () adds support for these complex fixups
1133 // on IPF and is a No-Op on other architectures.
1135 Status
= PeCoffLoaderRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
1136 if (RETURN_ERROR (Status
)) {
1137 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1143 // Next relocation record
1151 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)RelocEnd
;
1154 ASSERT ((UINTN
)FixupData
<= (UINTN
)ImageContext
->FixupData
+ ImageContext
->FixupDataSize
);
1157 // Adjust the EntryPoint to match the linked-to address
1159 if (ImageContext
->DestinationAddress
!= 0) {
1160 ImageContext
->EntryPoint
-= (UINT64
)ImageContext
->ImageAddress
;
1161 ImageContext
->EntryPoint
+= (UINT64
)ImageContext
->DestinationAddress
;
1165 // Applies additional environment specific actions to relocate fixups
1166 // to a PE/COFF image if needed
1167 PeCoffLoaderRelocateImageExtraAction (ImageContext
);
1169 return RETURN_SUCCESS
;
1173 Loads a PE/COFF image into memory.
1175 Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
1176 specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate
1177 the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
1178 The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.
1179 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress, ImageSize,
1180 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
1181 fields of the ImageContext structure must be valid prior to invoking this service.
1183 If ImageContext is NULL, then ASSERT().
1185 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1186 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1187 prior to transferring control to a PE/COFF image that is loaded using this library.
1189 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1190 image that is being loaded.
1192 @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by
1193 the ImageAddress and ImageSize fields of ImageContext.
1194 Extended status information is in the ImageError field of ImageContext.
1195 @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.
1196 Extended status information is in the ImageError field of ImageContext.
1197 @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.
1198 Extended status information is in the ImageError field of ImageContext.
1199 @retval RETURN_INVALID_PARAMETER The image address is invalid.
1200 Extended status information is in the ImageError field of ImageContext.
1205 PeCoffLoaderLoadImage (
1206 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1209 RETURN_STATUS Status
;
1210 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1211 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
1212 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
1213 EFI_IMAGE_SECTION_HEADER
*Section
;
1214 UINTN NumberOfSections
;
1218 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
1219 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
1221 UINT32 TempDebugEntryRva
;
1222 UINT32 NumberOfRvaAndSizes
;
1223 EFI_IMAGE_RESOURCE_DIRECTORY
*ResourceDirectory
;
1224 EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*ResourceDirectoryEntry
;
1225 EFI_IMAGE_RESOURCE_DIRECTORY_STRING
*ResourceDirectoryString
;
1226 EFI_IMAGE_RESOURCE_DATA_ENTRY
*ResourceDataEntry
;
1229 UINT32 TeStrippedOffset
;
1231 ASSERT (ImageContext
!= NULL
);
1236 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
1239 // Copy the provided context information into our local version, get what we
1240 // can from the original image, and then use that to make sure everything
1243 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
1245 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
1246 if (RETURN_ERROR (Status
)) {
1251 // Make sure there is enough allocated space for the image being loaded
1253 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
1254 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
1255 return RETURN_BUFFER_TOO_SMALL
;
1258 if (ImageContext
->ImageAddress
== 0) {
1260 // Image cannot be loaded into 0 address.
1262 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1263 return RETURN_INVALID_PARAMETER
;
1267 // If there's no relocations, then make sure it's not a runtime driver,
1268 // and that it's being loaded at the linked address.
1270 if (CheckContext
.RelocationsStripped
) {
1272 // If the image does not contain relocations and it is a runtime driver
1273 // then return an error.
1275 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
1276 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
1277 return RETURN_LOAD_ERROR
;
1281 // If the image does not contain relocations, and the requested load address
1282 // is not the linked address, then return an error.
1284 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
1285 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1286 return RETURN_INVALID_PARAMETER
;
1291 // Make sure the allocated space has the proper section alignment
1293 if (!(ImageContext
->IsTeImage
)) {
1294 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
1295 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
1296 return RETURN_INVALID_PARAMETER
;
1301 // Read the entire PE/COFF or TE header into memory
1303 if (!(ImageContext
->IsTeImage
)) {
1304 Status
= ImageContext
->ImageRead (
1305 ImageContext
->Handle
,
1307 &ImageContext
->SizeOfHeaders
,
1308 (VOID
*)(UINTN
)ImageContext
->ImageAddress
1311 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
1313 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*)(
1314 (UINTN
)ImageContext
->ImageAddress
+
1315 ImageContext
->PeCoffHeaderOffset
+
1317 sizeof (EFI_IMAGE_FILE_HEADER
) +
1318 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
1320 NumberOfSections
= (UINTN
)(Hdr
.Pe32
->FileHeader
.NumberOfSections
);
1321 TeStrippedOffset
= 0;
1323 Status
= ImageContext
->ImageRead (
1324 ImageContext
->Handle
,
1326 &ImageContext
->SizeOfHeaders
,
1327 (void *)(UINTN
)ImageContext
->ImageAddress
1330 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
1331 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*)(
1332 (UINTN
)ImageContext
->ImageAddress
+
1333 sizeof (EFI_TE_IMAGE_HEADER
)
1335 NumberOfSections
= (UINTN
)(Hdr
.Te
->NumberOfSections
);
1336 TeStrippedOffset
= (UINT32
)Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
1339 if (RETURN_ERROR (Status
)) {
1340 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1341 return RETURN_LOAD_ERROR
;
1345 // Load each section of the image
1347 Section
= FirstSection
;
1348 for (Index
= 0; Index
< NumberOfSections
; Index
++) {
1352 Size
= (UINTN
)Section
->Misc
.VirtualSize
;
1353 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
1354 Size
= (UINTN
)Section
->SizeOfRawData
;
1358 // Compute sections address
1360 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
, TeStrippedOffset
);
1361 End
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1, TeStrippedOffset
);
1364 // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.
1366 if ((Size
> 0) && ((Base
== NULL
) || (End
== NULL
))) {
1367 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
1368 return RETURN_LOAD_ERROR
;
1371 if (Section
->SizeOfRawData
> 0) {
1372 Status
= ImageContext
->ImageRead (
1373 ImageContext
->Handle
,
1374 Section
->PointerToRawData
- TeStrippedOffset
,
1378 if (RETURN_ERROR (Status
)) {
1379 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1385 // If raw size is less then virtual size, zero fill the remaining
1388 if (Size
< Section
->Misc
.VirtualSize
) {
1389 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
1399 // Get image's entry point
1401 if (!(ImageContext
->IsTeImage
)) {
1403 // Sizes of AddressOfEntryPoint are different so we need to do this safely
1405 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1409 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1411 (UINTN
)Hdr
.Pe32
->OptionalHeader
.AddressOfEntryPoint
,
1418 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1420 (UINTN
)Hdr
.Pe32Plus
->OptionalHeader
.AddressOfEntryPoint
,
1425 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1427 (UINTN
)Hdr
.Te
->AddressOfEntryPoint
,
1433 // Determine the size of the fixup data
1435 // Per the PE/COFF spec, you can't assume that a given data directory
1436 // is present in the image. You have to check the NumberOfRvaAndSizes in
1437 // the optional header to verify a desired directory entry is there.
1439 if (!(ImageContext
->IsTeImage
)) {
1440 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1444 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1445 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1450 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1451 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1455 // Must use UINT64 here, because there might a case that 32bit loader to load 64bit image.
1457 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1458 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINT64
);
1460 ImageContext
->FixupDataSize
= 0;
1463 DirectoryEntry
= &Hdr
.Te
->DataDirectory
[0];
1464 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINT64
);
1468 // Consumer must allocate a buffer for the relocation fixup log.
1469 // Only used for runtime drivers.
1471 ImageContext
->FixupData
= NULL
;
1474 // Load the Codeview information if present
1476 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
1477 DebugEntry
= PeCoffLoaderImageAddress (
1479 ImageContext
->DebugDirectoryEntryRva
,
1482 if (DebugEntry
== NULL
) {
1483 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1484 return RETURN_LOAD_ERROR
;
1487 TempDebugEntryRva
= DebugEntry
->RVA
;
1488 if ((DebugEntry
->RVA
== 0) && (DebugEntry
->FileOffset
!= 0)) {
1490 if ((UINTN
)Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
1491 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
1493 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
1497 if (TempDebugEntryRva
!= 0) {
1498 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
, TeStrippedOffset
);
1499 if (ImageContext
->CodeView
== NULL
) {
1500 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1501 return RETURN_LOAD_ERROR
;
1504 if (DebugEntry
->RVA
== 0) {
1505 Size
= DebugEntry
->SizeOfData
;
1506 Status
= ImageContext
->ImageRead (
1507 ImageContext
->Handle
,
1508 DebugEntry
->FileOffset
- TeStrippedOffset
,
1510 ImageContext
->CodeView
1513 // Should we apply fix up to this field according to the size difference between PE and TE?
1514 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1515 // in original PE image.
1518 if (RETURN_ERROR (Status
)) {
1519 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1520 return RETURN_LOAD_ERROR
;
1523 DebugEntry
->RVA
= TempDebugEntryRva
;
1526 switch (*(UINT32
*)ImageContext
->CodeView
) {
1527 case CODEVIEW_SIGNATURE_NB10
:
1528 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
)) {
1529 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1530 return RETURN_UNSUPPORTED
;
1533 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1536 case CODEVIEW_SIGNATURE_RSDS
:
1537 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
)) {
1538 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1539 return RETURN_UNSUPPORTED
;
1542 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
1545 case CODEVIEW_SIGNATURE_MTOC
:
1546 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
)) {
1547 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1548 return RETURN_UNSUPPORTED
;
1551 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
);
1561 // Get Image's HII resource section
1563 ImageContext
->HiiResourceData
= 0;
1564 if (!(ImageContext
->IsTeImage
)) {
1565 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1569 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1570 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
];
1575 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1576 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
];
1579 if ((NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
) && (DirectoryEntry
->Size
!= 0)) {
1580 Base
= PeCoffLoaderImageAddress (ImageContext
, DirectoryEntry
->VirtualAddress
, 0);
1582 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*)Base
;
1583 Offset
= sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) *
1584 (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1585 if (Offset
> DirectoryEntry
->Size
) {
1586 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1587 return RETURN_UNSUPPORTED
;
1590 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(ResourceDirectory
+ 1);
1592 for (Index
= 0; Index
< ResourceDirectory
->NumberOfNamedEntries
; Index
++) {
1593 if (ResourceDirectoryEntry
->u1
.s
.NameIsString
) {
1595 // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.
1597 if (ResourceDirectoryEntry
->u1
.s
.NameOffset
>= DirectoryEntry
->Size
) {
1598 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1599 return RETURN_UNSUPPORTED
;
1602 ResourceDirectoryString
= (EFI_IMAGE_RESOURCE_DIRECTORY_STRING
*)(Base
+ ResourceDirectoryEntry
->u1
.s
.NameOffset
);
1603 String
= &ResourceDirectoryString
->String
[0];
1605 if ((ResourceDirectoryString
->Length
== 3) &&
1606 (String
[0] == L
'H') &&
1607 (String
[1] == L
'I') &&
1608 (String
[2] == L
'I'))
1611 // Resource Type "HII" found
1613 if (ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1615 // Move to next level - resource Name
1617 if (ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
>= DirectoryEntry
->Size
) {
1618 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1619 return RETURN_UNSUPPORTED
;
1622 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*)(Base
+ ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
);
1623 Offset
= ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
+ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) +
1624 sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) * (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1625 if (Offset
> DirectoryEntry
->Size
) {
1626 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1627 return RETURN_UNSUPPORTED
;
1630 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(ResourceDirectory
+ 1);
1632 if (ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1634 // Move to next level - resource Language
1636 if (ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
>= DirectoryEntry
->Size
) {
1637 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1638 return RETURN_UNSUPPORTED
;
1641 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*)(Base
+ ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
);
1642 Offset
= ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
+ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) +
1643 sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) * (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1644 if (Offset
> DirectoryEntry
->Size
) {
1645 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1646 return RETURN_UNSUPPORTED
;
1649 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(ResourceDirectory
+ 1);
1654 // Now it ought to be resource Data
1656 if (!ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1657 if (ResourceDirectoryEntry
->u2
.OffsetToData
>= DirectoryEntry
->Size
) {
1658 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1659 return RETURN_UNSUPPORTED
;
1662 ResourceDataEntry
= (EFI_IMAGE_RESOURCE_DATA_ENTRY
*)(Base
+ ResourceDirectoryEntry
->u2
.OffsetToData
);
1663 ImageContext
->HiiResourceData
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (ImageContext
, ResourceDataEntry
->OffsetToData
, 0);
1669 ResourceDirectoryEntry
++;
1679 Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI
1682 This function reapplies relocation fixups to the PE/COFF image specified by ImageBase
1683 and ImageSize so the image will execute correctly when the PE/COFF image is mapped
1684 to the address specified by VirtualImageBase. RelocationData must be identical
1685 to the FiuxupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure
1686 after this PE/COFF image was relocated with PeCoffLoaderRelocateImage().
1688 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1689 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1690 prior to transferring control to a PE/COFF image that is loaded using this library.
1692 @param ImageBase The base address of a PE/COFF image that has been loaded
1693 and relocated into system memory.
1694 @param VirtImageBase The request virtual address that the PE/COFF image is to
1696 @param ImageSize The size, in bytes, of the PE/COFF image.
1697 @param RelocationData A pointer to the relocation data that was collected when the PE/COFF
1698 image was relocated using PeCoffLoaderRelocateImage().
1703 PeCoffLoaderRelocateImageForRuntime (
1704 IN PHYSICAL_ADDRESS ImageBase
,
1705 IN PHYSICAL_ADDRESS VirtImageBase
,
1707 IN VOID
*RelocationData
1712 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1713 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1714 UINT32 NumberOfRvaAndSizes
;
1715 EFI_IMAGE_DATA_DIRECTORY
*DataDirectory
;
1716 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
1717 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
1718 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
1719 EFI_IMAGE_BASE_RELOCATION
*RelocBaseOrig
;
1729 RETURN_STATUS Status
;
1730 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
1732 if ((RelocationData
== NULL
) || (ImageBase
== 0x0) || (VirtImageBase
== 0x0)) {
1736 OldBase
= (CHAR8
*)((UINTN
)ImageBase
);
1737 NewBase
= (CHAR8
*)((UINTN
)VirtImageBase
);
1738 Adjust
= (UINTN
)NewBase
- (UINTN
)OldBase
;
1740 ImageContext
.ImageAddress
= ImageBase
;
1741 ImageContext
.ImageSize
= ImageSize
;
1744 // Find the image's relocate dir info
1746 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)OldBase
;
1747 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
1749 // Valid DOS header so get address of PE header
1751 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)(((CHAR8
*)DosHdr
) + DosHdr
->e_lfanew
);
1754 // No Dos header so assume image starts with PE header.
1756 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)OldBase
;
1759 if (Hdr
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
1761 // Not a valid PE image so Exit
1766 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1770 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1771 DataDirectory
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[0]);
1776 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1777 DataDirectory
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[0]);
1781 // Find the relocation block
1783 // Per the PE/COFF spec, you can't assume that a given data directory
1784 // is present in the image. You have to check the NumberOfRvaAndSizes in
1785 // the optional header to verify a desired directory entry is there.
1788 RelocBaseEnd
= NULL
;
1789 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1790 RelocDir
= DataDirectory
+ EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
;
1791 if ((RelocDir
!= NULL
) && (RelocDir
->Size
> 0)) {
1792 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)PeCoffLoaderImageAddress (&ImageContext
, RelocDir
->VirtualAddress
, 0);
1793 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*)PeCoffLoaderImageAddress (
1795 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1,
1800 if ((RelocBase
== NULL
) || (RelocBaseEnd
== NULL
) || ((UINTN
)RelocBaseEnd
< (UINTN
)RelocBase
)) {
1802 // relocation block is not valid, just return
1808 // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.
1815 // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.
1817 ASSERT (RelocBase
!= NULL
&& RelocBaseEnd
!= NULL
);
1821 // Run the whole relocation block. And re-fixup data that has not been
1822 // modified. The FixupData is used to see if the image has been modified
1823 // since it was relocated. This is so data sections that have been updated
1824 // by code will not be fixed up, since that would set them back to
1827 FixupData
= RelocationData
;
1828 RelocBaseOrig
= RelocBase
;
1829 while ((UINTN
)RelocBase
< (UINTN
)RelocBaseEnd
) {
1831 // Add check for RelocBase->SizeOfBlock field.
1833 if ((RelocBase
->SizeOfBlock
== 0) || (RelocBase
->SizeOfBlock
> RelocDir
->Size
)) {
1835 // Data invalid, cannot continue to relocate the image, just return.
1840 Reloc
= (UINT16
*)((UINT8
*)RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
1841 RelocEnd
= (UINT16
*)((UINT8
*)RelocBase
+ RelocBase
->SizeOfBlock
);
1842 if ((UINTN
)RelocEnd
> (UINTN
)RelocBaseOrig
+ RelocDir
->Size
) {
1846 FixupBase
= PeCoffLoaderImageAddress (&ImageContext
, RelocBase
->VirtualAddress
, 0);
1847 if (FixupBase
== NULL
) {
1852 // Run this relocation record
1854 while ((UINTN
)Reloc
< (UINTN
)RelocEnd
) {
1855 Fixup
= PeCoffLoaderImageAddress (&ImageContext
, RelocBase
->VirtualAddress
+ (*Reloc
& 0xFFF), 0);
1856 if (Fixup
== NULL
) {
1860 switch ((*Reloc
) >> 12) {
1861 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
1864 case EFI_IMAGE_REL_BASED_HIGH
:
1865 Fixup16
= (UINT16
*)Fixup
;
1866 if (*(UINT16
*)FixupData
== *Fixup16
) {
1867 *Fixup16
= (UINT16
)(*Fixup16
+ ((UINT16
)((UINT32
)Adjust
>> 16)));
1870 FixupData
= FixupData
+ sizeof (UINT16
);
1873 case EFI_IMAGE_REL_BASED_LOW
:
1874 Fixup16
= (UINT16
*)Fixup
;
1875 if (*(UINT16
*)FixupData
== *Fixup16
) {
1876 *Fixup16
= (UINT16
)(*Fixup16
+ ((UINT16
)Adjust
& 0xffff));
1879 FixupData
= FixupData
+ sizeof (UINT16
);
1882 case EFI_IMAGE_REL_BASED_HIGHLOW
:
1883 Fixup32
= (UINT32
*)Fixup
;
1884 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
1885 if (*(UINT32
*)FixupData
== *Fixup32
) {
1886 *Fixup32
= *Fixup32
+ (UINT32
)Adjust
;
1889 FixupData
= FixupData
+ sizeof (UINT32
);
1892 case EFI_IMAGE_REL_BASED_DIR64
:
1893 Fixup64
= (UINT64
*)Fixup
;
1894 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT64
));
1895 if (*(UINT64
*)FixupData
== *Fixup64
) {
1896 *Fixup64
= *Fixup64
+ (UINT64
)Adjust
;
1899 FixupData
= FixupData
+ sizeof (UINT64
);
1904 // Only Itanium requires ConvertPeImage_Ex
1906 Status
= PeHotRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
1907 if (RETURN_ERROR (Status
)) {
1913 // Next relocation record
1921 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)RelocEnd
;
1927 Reads contents of a PE/COFF image from a buffer in system memory.
1929 This is the default implementation of a PE_COFF_LOADER_READ_FILE function
1930 that assumes FileHandle pointer to the beginning of a PE/COFF image.
1931 This function reads contents of the PE/COFF image that starts at the system memory
1932 address specified by FileHandle. The read operation copies ReadSize bytes from the
1933 PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer.
1934 The size of the buffer actually read is returned in ReadSize.
1936 The caller must make sure the FileOffset and ReadSize within the file scope.
1938 If FileHandle is NULL, then ASSERT().
1939 If ReadSize is NULL, then ASSERT().
1940 If Buffer is NULL, then ASSERT().
1942 @param FileHandle The pointer to base of the input stream
1943 @param FileOffset Offset into the PE/COFF image to begin the read operation.
1944 @param ReadSize On input, the size in bytes of the requested read operation.
1945 On output, the number of bytes actually read.
1946 @param Buffer Output buffer that contains the data read from the PE/COFF image.
1948 @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into
1953 PeCoffLoaderImageReadFromMemory (
1954 IN VOID
*FileHandle
,
1955 IN UINTN FileOffset
,
1956 IN OUT UINTN
*ReadSize
,
1960 ASSERT (ReadSize
!= NULL
);
1961 ASSERT (FileHandle
!= NULL
);
1962 ASSERT (Buffer
!= NULL
);
1964 CopyMem (Buffer
, ((UINT8
*)FileHandle
) + FileOffset
, *ReadSize
);
1965 return RETURN_SUCCESS
;
1969 Unloads a loaded PE/COFF image from memory and releases its taken resource.
1970 Releases any environment specific resources that were allocated when the image
1971 specified by ImageContext was loaded using PeCoffLoaderLoadImage().
1973 For NT32 emulator, the PE/COFF image loaded by system needs to release.
1974 For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded,
1975 this function can simply return RETURN_SUCCESS.
1977 If ImageContext is NULL, then ASSERT().
1979 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1980 image to be unloaded.
1982 @retval RETURN_SUCCESS The PE/COFF image was unloaded successfully.
1986 PeCoffLoaderUnloadImage (
1987 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1991 // Applies additional environment specific actions to unload a
1992 // PE/COFF image if needed
1994 PeCoffLoaderUnloadImageExtraAction (ImageContext
);
1995 return RETURN_SUCCESS
;