2 Base PE/COFF loader supports loading any PE32/PE32+ or TE image, but
3 only supports relocating IA32, x64, IPF, ARM, RISC-V 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 SPDX-License-Identifier: BSD-2-Clause-Patent
25 #include "BasePeCoffLibInternals.h"
28 Adjust some fields in section header for TE image.
30 @param SectionHeader Pointer to the section header.
31 @param TeStrippedOffset Size adjust for the TE image.
35 PeCoffLoaderAdjustOffsetForTeImage (
36 EFI_IMAGE_SECTION_HEADER
*SectionHeader
,
37 UINT32 TeStrippedOffset
40 SectionHeader
->VirtualAddress
-= TeStrippedOffset
;
41 SectionHeader
->PointerToRawData
-= TeStrippedOffset
;
45 Retrieves the PE or TE Header from a PE/COFF or TE image.
47 Caution: This function may receive untrusted input.
48 PE/COFF image is external input, so this routine will
49 also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
50 SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
52 @param ImageContext The context of the image being loaded.
53 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
55 @retval RETURN_SUCCESS The PE or TE Header is read.
56 @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.
60 PeCoffLoaderGetPeHeader (
61 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
62 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
66 EFI_IMAGE_DOS_HEADER DosHdr
;
69 UINT32 SectionHeaderOffset
;
71 UINT32 HeaderWithoutDataDir
;
73 UINTN NumberOfSections
;
74 EFI_IMAGE_SECTION_HEADER SectionHeader
;
77 // Read the DOS image header to check for its existence
79 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
81 Status
= ImageContext
->ImageRead (
87 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
88 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
89 if (Size
!= ReadSize
) {
90 Status
= RETURN_UNSUPPORTED
;
95 ImageContext
->PeCoffHeaderOffset
= 0;
96 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
98 // DOS image header is present, so read the PE header after the DOS image
101 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
105 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
106 // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
107 // determines if this is a PE32 or PE32+ image. The magic is in the same
108 // location in both images.
110 Size
= sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
);
112 Status
= ImageContext
->ImageRead (
113 ImageContext
->Handle
,
114 ImageContext
->PeCoffHeaderOffset
,
118 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
119 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
120 if (Size
!= ReadSize
) {
121 Status
= RETURN_UNSUPPORTED
;
127 // Use Signature to figure out if we understand the image format
129 if (Hdr
.Te
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
130 ImageContext
->IsTeImage
= TRUE
;
131 ImageContext
->Machine
= Hdr
.Te
->Machine
;
132 ImageContext
->ImageType
= (UINT16
)(Hdr
.Te
->Subsystem
);
134 // For TeImage, SectionAlignment is undefined to be set to Zero
135 // ImageSize can be calculated.
137 ImageContext
->ImageSize
= 0;
138 ImageContext
->SectionAlignment
= 0;
139 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
)Hdr
.Te
->BaseOfCode
- (UINTN
)Hdr
.Te
->StrippedSize
;
142 // Check the StrippedSize.
144 if (sizeof (EFI_TE_IMAGE_HEADER
) >= (UINT32
)Hdr
.Te
->StrippedSize
) {
145 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
146 return RETURN_UNSUPPORTED
;
150 // Check the SizeOfHeaders field.
152 if (Hdr
.Te
->BaseOfCode
<= Hdr
.Te
->StrippedSize
) {
153 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
154 return RETURN_UNSUPPORTED
;
158 // Read last byte of Hdr.Te->SizeOfHeaders from the file.
162 Status
= ImageContext
->ImageRead (
163 ImageContext
->Handle
,
164 ImageContext
->SizeOfHeaders
- 1,
168 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
169 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
170 if (Size
!= ReadSize
) {
171 Status
= RETURN_UNSUPPORTED
;
177 // TE Image Data Directory Entry size is non-zero, but the Data Directory Virtual Address is zero.
178 // This case is not a valid TE image.
180 if ((Hdr
.Te
->DataDirectory
[0].Size
!= 0 && Hdr
.Te
->DataDirectory
[0].VirtualAddress
== 0) ||
181 (Hdr
.Te
->DataDirectory
[1].Size
!= 0 && Hdr
.Te
->DataDirectory
[1].VirtualAddress
== 0)) {
182 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
183 return RETURN_UNSUPPORTED
;
185 } else if (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
) {
186 ImageContext
->IsTeImage
= FALSE
;
187 ImageContext
->Machine
= Hdr
.Pe32
->FileHeader
.Machine
;
189 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
191 // 1. Check OptionalHeader.NumberOfRvaAndSizes filed.
193 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
< Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) {
194 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
195 return RETURN_UNSUPPORTED
;
199 // 2. Check the FileHeader.SizeOfOptionalHeader field.
200 // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
201 // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
203 HeaderWithoutDataDir
= sizeof (EFI_IMAGE_OPTIONAL_HEADER32
) - sizeof (EFI_IMAGE_DATA_DIRECTORY
) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
;
204 if (((UINT32
)Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
- HeaderWithoutDataDir
) !=
205 Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
* sizeof (EFI_IMAGE_DATA_DIRECTORY
)) {
206 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
207 return RETURN_UNSUPPORTED
;
210 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
212 // 3. Check the FileHeader.NumberOfSections field.
214 if (Hdr
.Pe32
->OptionalHeader
.SizeOfImage
<= SectionHeaderOffset
) {
215 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
216 return RETURN_UNSUPPORTED
;
218 if ((Hdr
.Pe32
->OptionalHeader
.SizeOfImage
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
<= Hdr
.Pe32
->FileHeader
.NumberOfSections
) {
219 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
220 return RETURN_UNSUPPORTED
;
224 // 4. Check the OptionalHeader.SizeOfHeaders field.
226 if (Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
<= SectionHeaderOffset
) {
227 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
228 return RETURN_UNSUPPORTED
;
230 if (Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
>= Hdr
.Pe32
->OptionalHeader
.SizeOfImage
) {
231 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
232 return RETURN_UNSUPPORTED
;
234 if ((Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
< (UINT32
)Hdr
.Pe32
->FileHeader
.NumberOfSections
) {
235 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
236 return RETURN_UNSUPPORTED
;
240 // 4.2 Read last byte of Hdr.Pe32.OptionalHeader.SizeOfHeaders from the file.
244 Status
= ImageContext
->ImageRead (
245 ImageContext
->Handle
,
246 Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- 1,
250 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
251 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
252 if (Size
!= ReadSize
) {
253 Status
= RETURN_UNSUPPORTED
;
259 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
260 // Read the last byte to make sure the data is in the image region.
261 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
263 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
< Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) {
264 if (Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
!= 0) {
266 // Check the member data to avoid overflow.
268 if ((UINT32
) (~0) - Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
<
269 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
) {
270 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
271 return RETURN_UNSUPPORTED
;
275 // Read last byte of section header from file
279 Status
= ImageContext
->ImageRead (
280 ImageContext
->Handle
,
281 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
+
282 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
- 1,
286 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
287 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
288 if (Size
!= ReadSize
) {
289 Status
= RETURN_UNSUPPORTED
;
299 ImageContext
->ImageType
= Hdr
.Pe32
->OptionalHeader
.Subsystem
;
300 ImageContext
->ImageSize
= (UINT64
)Hdr
.Pe32
->OptionalHeader
.SizeOfImage
;
301 ImageContext
->SectionAlignment
= Hdr
.Pe32
->OptionalHeader
.SectionAlignment
;
302 ImageContext
->SizeOfHeaders
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
;
304 } else if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
306 // 1. Check FileHeader.NumberOfRvaAndSizes filed.
308 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
< Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
309 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
310 return RETURN_UNSUPPORTED
;
313 // 2. Check the FileHeader.SizeOfOptionalHeader field.
314 // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
315 // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
317 HeaderWithoutDataDir
= sizeof (EFI_IMAGE_OPTIONAL_HEADER64
) - sizeof (EFI_IMAGE_DATA_DIRECTORY
) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
;
318 if (((UINT32
)Hdr
.Pe32Plus
->FileHeader
.SizeOfOptionalHeader
- HeaderWithoutDataDir
) !=
319 Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
* sizeof (EFI_IMAGE_DATA_DIRECTORY
)) {
320 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
321 return RETURN_UNSUPPORTED
;
324 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32Plus
->FileHeader
.SizeOfOptionalHeader
;
326 // 3. Check the FileHeader.NumberOfSections field.
328 if (Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
<= SectionHeaderOffset
) {
329 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
330 return RETURN_UNSUPPORTED
;
332 if ((Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
<= Hdr
.Pe32Plus
->FileHeader
.NumberOfSections
) {
333 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
334 return RETURN_UNSUPPORTED
;
338 // 4. Check the OptionalHeader.SizeOfHeaders field.
340 if (Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
<= SectionHeaderOffset
) {
341 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
342 return RETURN_UNSUPPORTED
;
344 if (Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
>= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
) {
345 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
346 return RETURN_UNSUPPORTED
;
348 if ((Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
< (UINT32
)Hdr
.Pe32Plus
->FileHeader
.NumberOfSections
) {
349 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
350 return RETURN_UNSUPPORTED
;
354 // 4.2 Read last byte of Hdr.Pe32Plus.OptionalHeader.SizeOfHeaders from the file.
358 Status
= ImageContext
->ImageRead (
359 ImageContext
->Handle
,
360 Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- 1,
364 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
365 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
366 if (Size
!= ReadSize
) {
367 Status
= RETURN_UNSUPPORTED
;
373 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
374 // Read the last byte to make sure the data is in the image region.
375 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
377 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
< Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
378 if (Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
!= 0) {
380 // Check the member data to avoid overflow.
382 if ((UINT32
) (~0) - Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
<
383 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
) {
384 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
385 return RETURN_UNSUPPORTED
;
389 // Read last byte of section header from file
393 Status
= ImageContext
->ImageRead (
394 ImageContext
->Handle
,
395 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
+
396 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
- 1,
400 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
401 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
402 if (Size
!= ReadSize
) {
403 Status
= RETURN_UNSUPPORTED
;
413 ImageContext
->ImageType
= Hdr
.Pe32Plus
->OptionalHeader
.Subsystem
;
414 ImageContext
->ImageSize
= (UINT64
) Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
;
415 ImageContext
->SectionAlignment
= Hdr
.Pe32Plus
->OptionalHeader
.SectionAlignment
;
416 ImageContext
->SizeOfHeaders
= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
;
418 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
419 return RETURN_UNSUPPORTED
;
422 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
423 return RETURN_UNSUPPORTED
;
426 if (!PeCoffLoaderImageFormatSupported (ImageContext
->Machine
)) {
428 // If the PE/COFF loader does not support the image type return
429 // unsupported. This library can support lots of types of images
430 // this does not mean the user of this library can call the entry
431 // point of the image.
433 return RETURN_UNSUPPORTED
;
437 // Check each section field.
439 if (ImageContext
->IsTeImage
) {
440 SectionHeaderOffset
= sizeof(EFI_TE_IMAGE_HEADER
);
441 NumberOfSections
= (UINTN
) (Hdr
.Te
->NumberOfSections
);
443 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
444 NumberOfSections
= (UINTN
) (Hdr
.Pe32
->FileHeader
.NumberOfSections
);
447 for (Index
= 0; Index
< NumberOfSections
; Index
++) {
449 // Read section header from file
451 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
453 Status
= ImageContext
->ImageRead (
454 ImageContext
->Handle
,
459 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
460 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
461 if (Size
!= ReadSize
) {
462 Status
= RETURN_UNSUPPORTED
;
468 // Adjust some field in Section Header for TE image.
470 if (ImageContext
->IsTeImage
) {
471 PeCoffLoaderAdjustOffsetForTeImage (&SectionHeader
, (UINT32
)Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
474 if (SectionHeader
.SizeOfRawData
> 0) {
476 // Section data should bigger than the Pe header.
478 if (SectionHeader
.VirtualAddress
< ImageContext
->SizeOfHeaders
||
479 SectionHeader
.PointerToRawData
< ImageContext
->SizeOfHeaders
) {
480 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
481 return RETURN_UNSUPPORTED
;
485 // Check the member data to avoid overflow.
487 if ((UINT32
) (~0) - SectionHeader
.PointerToRawData
< SectionHeader
.SizeOfRawData
) {
488 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
489 return RETURN_UNSUPPORTED
;
493 // Base on the ImageRead function to check the section data field.
494 // Read the last byte to make sure the data is in the image region.
498 Status
= ImageContext
->ImageRead (
499 ImageContext
->Handle
,
500 SectionHeader
.PointerToRawData
+ SectionHeader
.SizeOfRawData
- 1,
504 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
505 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
506 if (Size
!= ReadSize
) {
507 Status
= RETURN_UNSUPPORTED
;
514 // Check next section.
516 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
519 return RETURN_SUCCESS
;
524 Retrieves information about a PE/COFF image.
526 Computes the PeCoffHeaderOffset, IsTeImage, ImageType, ImageAddress, ImageSize,
527 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and
528 DebugDirectoryEntryRva fields of the ImageContext structure.
529 If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.
530 If the PE/COFF image accessed through the ImageRead service in the ImageContext
531 structure is not a supported PE/COFF image type, then return RETURN_UNSUPPORTED.
532 If any errors occur while computing the fields of ImageContext,
533 then the error status is returned in the ImageError field of ImageContext.
534 If the image is a TE image, then SectionAlignment is set to 0.
535 The ImageRead and Handle fields of ImageContext structure must be valid prior
536 to invoking this service.
538 Caution: This function may receive untrusted input.
539 PE/COFF image is external input, so this routine will
540 also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
541 SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
543 @param ImageContext The pointer to the image context structure that describes the PE/COFF
544 image that needs to be examined by this function.
546 @retval RETURN_SUCCESS The information on the PE/COFF image was collected.
547 @retval RETURN_INVALID_PARAMETER ImageContext is NULL.
548 @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.
553 PeCoffLoaderGetImageInfo (
554 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
557 RETURN_STATUS Status
;
558 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
559 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
560 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
564 UINTN DebugDirectoryEntryRva
;
565 UINTN DebugDirectoryEntryFileOffset
;
566 UINTN SectionHeaderOffset
;
567 EFI_IMAGE_SECTION_HEADER SectionHeader
;
568 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
569 UINT32 NumberOfRvaAndSizes
;
570 UINT32 TeStrippedOffset
;
572 if (ImageContext
== NULL
) {
573 return RETURN_INVALID_PARAMETER
;
578 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
580 Hdr
.Union
= &HdrData
;
581 Status
= PeCoffLoaderGetPeHeader (ImageContext
, Hdr
);
582 if (RETURN_ERROR (Status
)) {
587 // Retrieve the base address of the image
589 if (!(ImageContext
->IsTeImage
)) {
590 TeStrippedOffset
= 0;
591 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
595 ImageContext
->ImageAddress
= Hdr
.Pe32
->OptionalHeader
.ImageBase
;
600 ImageContext
->ImageAddress
= Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
603 TeStrippedOffset
= (UINT32
)Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
604 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
)(Hdr
.Te
->ImageBase
+ TeStrippedOffset
);
608 // Initialize the alternate destination address to 0 indicating that it
609 // should not be used.
611 ImageContext
->DestinationAddress
= 0;
614 // Initialize the debug codeview pointer.
616 ImageContext
->DebugDirectoryEntryRva
= 0;
617 ImageContext
->CodeView
= NULL
;
618 ImageContext
->PdbPointer
= NULL
;
621 // Three cases with regards to relocations:
622 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
623 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
624 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
625 // has no base relocs to apply
626 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
628 // Look at the file header to determine if relocations have been stripped, and
629 // save this information in the image context for later use.
631 if ((!(ImageContext
->IsTeImage
)) && ((Hdr
.Pe32
->FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
632 ImageContext
->RelocationsStripped
= TRUE
;
633 } else if ((ImageContext
->IsTeImage
) && (Hdr
.Te
->DataDirectory
[0].Size
== 0) && (Hdr
.Te
->DataDirectory
[0].VirtualAddress
== 0)) {
634 ImageContext
->RelocationsStripped
= TRUE
;
636 ImageContext
->RelocationsStripped
= FALSE
;
639 if (!(ImageContext
->IsTeImage
)) {
640 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
644 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
645 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
650 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
651 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
654 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
656 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
659 // Determine the file offset of the debug directory... This means we walk
660 // the sections to find which section contains the RVA of the debug
663 DebugDirectoryEntryFileOffset
= 0;
665 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+
667 sizeof (EFI_IMAGE_FILE_HEADER
) +
668 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
670 for (Index
= 0; Index
< Hdr
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
672 // Read section header from file
674 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
676 Status
= ImageContext
->ImageRead (
677 ImageContext
->Handle
,
682 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
683 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
684 if (Size
!= ReadSize
) {
685 Status
= RETURN_UNSUPPORTED
;
690 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
691 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
693 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
697 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
700 if (DebugDirectoryEntryFileOffset
!= 0) {
701 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
703 // Read next debug directory entry
705 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
707 Status
= ImageContext
->ImageRead (
708 ImageContext
->Handle
,
709 DebugDirectoryEntryFileOffset
+ Index
,
713 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
714 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
715 if (Size
!= ReadSize
) {
716 Status
= RETURN_UNSUPPORTED
;
722 // From PeCoff spec, when DebugEntry.RVA == 0 means this debug info will not load into memory.
723 // Here we will always load EFI_IMAGE_DEBUG_TYPE_CODEVIEW type debug info. so need adjust the
724 // ImageContext->ImageSize when DebugEntry.RVA == 0.
726 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
727 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
728 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
729 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
732 return RETURN_SUCCESS
;
739 DebugDirectoryEntry
= &Hdr
.Te
->DataDirectory
[1];
740 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
741 SectionHeaderOffset
= (UINTN
)(sizeof (EFI_TE_IMAGE_HEADER
));
743 DebugDirectoryEntryFileOffset
= 0;
745 for (Index
= 0; Index
< Hdr
.Te
->NumberOfSections
;) {
747 // Read section header from file
749 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
751 Status
= ImageContext
->ImageRead (
752 ImageContext
->Handle
,
757 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
758 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
759 if (Size
!= ReadSize
) {
760 Status
= RETURN_UNSUPPORTED
;
765 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
766 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
767 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
768 SectionHeader
.VirtualAddress
+
769 SectionHeader
.PointerToRawData
-
773 // File offset of the debug directory was found, if this is not the last
774 // section, then skip to the last section for calculating the image size.
776 if (Index
< (UINTN
) Hdr
.Te
->NumberOfSections
- 1) {
777 SectionHeaderOffset
+= (Hdr
.Te
->NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
778 Index
= Hdr
.Te
->NumberOfSections
- 1;
784 // In Te image header there is not a field to describe the ImageSize.
785 // Actually, the ImageSize equals the RVA plus the VirtualSize of
786 // the last section mapped into memory (Must be rounded up to
787 // a multiple of Section Alignment). Per the PE/COFF specification, the
788 // section headers in the Section Table must appear in order of the RVA
789 // values for the corresponding sections. So the ImageSize can be determined
790 // by the RVA and the VirtualSize of the last section header in the
793 if ((++Index
) == (UINTN
)Hdr
.Te
->NumberOfSections
) {
794 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) - TeStrippedOffset
;
797 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
800 if (DebugDirectoryEntryFileOffset
!= 0) {
801 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
803 // Read next debug directory entry
805 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
807 Status
= ImageContext
->ImageRead (
808 ImageContext
->Handle
,
809 DebugDirectoryEntryFileOffset
+ Index
,
813 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
814 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
815 if (Size
!= ReadSize
) {
816 Status
= RETURN_UNSUPPORTED
;
821 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
822 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
823 return RETURN_SUCCESS
;
829 return RETURN_SUCCESS
;
834 Converts an image address to the loaded address.
836 @param ImageContext The context of the image being loaded.
837 @param Address The address to be converted to the loaded address.
838 @param TeStrippedOffset Stripped offset for TE image.
840 @return The converted address or NULL if the address can not be converted.
844 PeCoffLoaderImageAddress (
845 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
847 IN UINTN TeStrippedOffset
851 // Make sure that Address and ImageSize is correct for the loaded image.
853 if (Address
>= ImageContext
->ImageSize
+ TeStrippedOffset
) {
854 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
858 return (CHAR8
*)((UINTN
) ImageContext
->ImageAddress
+ Address
- TeStrippedOffset
);
862 Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().
864 If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of
865 ImageContext as the relocation base address. Otherwise, use the DestinationAddress field
866 of ImageContext as the relocation base address. The caller must allocate the relocation
867 fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.
869 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress,
870 ImageSize, DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders,
871 DebugDirectoryEntryRva, EntryPoint, FixupDataSize, CodeView, PdbPointer, and FixupData of
872 the ImageContext structure must be valid prior to invoking this service.
874 If ImageContext is NULL, then ASSERT().
876 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
877 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
878 prior to transferring control to a PE/COFF image that is loaded using this library.
880 @param ImageContext The pointer to the image context structure that describes the PE/COFF
881 image that is being relocated.
883 @retval RETURN_SUCCESS The PE/COFF image was relocated.
884 Extended status information is in the ImageError field of ImageContext.
885 @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.
886 Extended status information is in the ImageError field of ImageContext.
887 @retval RETURN_UNSUPPORTED A relocation record type is not supported.
888 Extended status information is in the ImageError field of ImageContext.
893 PeCoffLoaderRelocateImage (
894 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
897 RETURN_STATUS Status
;
898 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
899 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
901 EFI_IMAGE_BASE_RELOCATION
*RelocBaseOrg
;
902 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
903 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
912 PHYSICAL_ADDRESS BaseAddress
;
913 UINT32 NumberOfRvaAndSizes
;
914 UINT32 TeStrippedOffset
;
916 ASSERT (ImageContext
!= NULL
);
921 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
924 // If there are no relocation entries, then we are done
926 if (ImageContext
->RelocationsStripped
) {
927 // Applies additional environment specific actions to relocate fixups
928 // to a PE/COFF image if needed
929 PeCoffLoaderRelocateImageExtraAction (ImageContext
);
930 return RETURN_SUCCESS
;
934 // If the destination address is not 0, use that rather than the
935 // image address as the relocation target.
937 if (ImageContext
->DestinationAddress
!= 0) {
938 BaseAddress
= ImageContext
->DestinationAddress
;
940 BaseAddress
= ImageContext
->ImageAddress
;
943 if (!(ImageContext
->IsTeImage
)) {
944 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
945 TeStrippedOffset
= 0;
947 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
951 Adjust
= (UINT64
)BaseAddress
- Hdr
.Pe32
->OptionalHeader
.ImageBase
;
953 Hdr
.Pe32
->OptionalHeader
.ImageBase
= (UINT32
)BaseAddress
;
956 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
957 RelocDir
= &Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
962 Adjust
= (UINT64
) BaseAddress
- Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
964 Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
= (UINT64
)BaseAddress
;
967 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
968 RelocDir
= &Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
972 // Find the relocation block
973 // Per the PE/COFF spec, you can't assume that a given data directory
974 // is present in the image. You have to check the NumberOfRvaAndSizes in
975 // the optional header to verify a desired directory entry is there.
977 if ((NumberOfRvaAndSizes
< EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
)) {
981 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
982 TeStrippedOffset
= (UINT32
)Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
983 Adjust
= (UINT64
) (BaseAddress
- (Hdr
.Te
->ImageBase
+ TeStrippedOffset
));
985 Hdr
.Te
->ImageBase
= (UINT64
) (BaseAddress
- TeStrippedOffset
);
989 // Find the relocation block
991 RelocDir
= &Hdr
.Te
->DataDirectory
[0];
994 if ((RelocDir
!= NULL
) && (RelocDir
->Size
> 0)) {
995 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
, TeStrippedOffset
);
996 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) PeCoffLoaderImageAddress (ImageContext
,
997 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1,
1000 if (RelocBase
== NULL
|| RelocBaseEnd
== NULL
|| (UINTN
) RelocBaseEnd
< (UINTN
) RelocBase
) {
1001 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1002 return RETURN_LOAD_ERROR
;
1006 // Set base and end to bypass processing below.
1008 RelocBase
= RelocBaseEnd
= NULL
;
1010 RelocBaseOrg
= RelocBase
;
1013 // If Adjust is not zero, then apply fix ups to the image
1017 // Run the relocation information and apply the fixups
1019 FixupData
= ImageContext
->FixupData
;
1020 while ((UINTN
) RelocBase
< (UINTN
) RelocBaseEnd
) {
1022 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
1024 // Add check for RelocBase->SizeOfBlock field.
1026 if (RelocBase
->SizeOfBlock
== 0) {
1027 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1028 return RETURN_LOAD_ERROR
;
1030 if ((UINTN
)RelocBase
> MAX_ADDRESS
- RelocBase
->SizeOfBlock
) {
1031 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1032 return RETURN_LOAD_ERROR
;
1035 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
1036 if ((UINTN
)RelocEnd
> (UINTN
)RelocBaseOrg
+ RelocDir
->Size
) {
1037 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1038 return RETURN_LOAD_ERROR
;
1040 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
, TeStrippedOffset
);
1041 if (FixupBase
== NULL
) {
1042 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1043 return RETURN_LOAD_ERROR
;
1047 // Run this relocation record
1049 while ((UINTN
) Reloc
< (UINTN
) RelocEnd
) {
1050 Fixup
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
+ (*Reloc
& 0xFFF), TeStrippedOffset
);
1051 if (Fixup
== NULL
) {
1052 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1053 return RETURN_LOAD_ERROR
;
1055 switch ((*Reloc
) >> 12) {
1056 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
1059 case EFI_IMAGE_REL_BASED_HIGH
:
1060 Fixup16
= (UINT16
*) Fixup
;
1061 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
1062 if (FixupData
!= NULL
) {
1063 *(UINT16
*) FixupData
= *Fixup16
;
1064 FixupData
= FixupData
+ sizeof (UINT16
);
1068 case EFI_IMAGE_REL_BASED_LOW
:
1069 Fixup16
= (UINT16
*) Fixup
;
1070 *Fixup16
= (UINT16
) (*Fixup16
+ (UINT16
) Adjust
);
1071 if (FixupData
!= NULL
) {
1072 *(UINT16
*) FixupData
= *Fixup16
;
1073 FixupData
= FixupData
+ sizeof (UINT16
);
1077 case EFI_IMAGE_REL_BASED_HIGHLOW
:
1078 Fixup32
= (UINT32
*) Fixup
;
1079 *Fixup32
= *Fixup32
+ (UINT32
) Adjust
;
1080 if (FixupData
!= NULL
) {
1081 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
1082 *(UINT32
*)FixupData
= *Fixup32
;
1083 FixupData
= FixupData
+ sizeof (UINT32
);
1087 case EFI_IMAGE_REL_BASED_DIR64
:
1088 Fixup64
= (UINT64
*) Fixup
;
1089 *Fixup64
= *Fixup64
+ (UINT64
) Adjust
;
1090 if (FixupData
!= NULL
) {
1091 FixupData
= ALIGN_POINTER (FixupData
, sizeof(UINT64
));
1092 *(UINT64
*)(FixupData
) = *Fixup64
;
1093 FixupData
= FixupData
+ sizeof(UINT64
);
1099 // The common code does not handle some of the stranger IPF relocations
1100 // PeCoffLoaderRelocateImageEx () adds support for these complex fixups
1101 // on IPF and is a No-Op on other architectures.
1103 Status
= PeCoffLoaderRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
1104 if (RETURN_ERROR (Status
)) {
1105 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1111 // Next relocation record
1119 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
1121 ASSERT ((UINTN
)FixupData
<= (UINTN
)ImageContext
->FixupData
+ ImageContext
->FixupDataSize
);
1124 // Adjust the EntryPoint to match the linked-to address
1126 if (ImageContext
->DestinationAddress
!= 0) {
1127 ImageContext
->EntryPoint
-= (UINT64
) ImageContext
->ImageAddress
;
1128 ImageContext
->EntryPoint
+= (UINT64
) ImageContext
->DestinationAddress
;
1132 // Applies additional environment specific actions to relocate fixups
1133 // to a PE/COFF image if needed
1134 PeCoffLoaderRelocateImageExtraAction (ImageContext
);
1136 return RETURN_SUCCESS
;
1140 Loads a PE/COFF image into memory.
1142 Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
1143 specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate
1144 the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
1145 The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.
1146 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress, ImageSize,
1147 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
1148 fields of the ImageContext structure must be valid prior to invoking this service.
1150 If ImageContext is NULL, then ASSERT().
1152 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1153 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1154 prior to transferring control to a PE/COFF image that is loaded using this library.
1156 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1157 image that is being loaded.
1159 @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by
1160 the ImageAddress and ImageSize fields of ImageContext.
1161 Extended status information is in the ImageError field of ImageContext.
1162 @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.
1163 Extended status information is in the ImageError field of ImageContext.
1164 @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.
1165 Extended status information is in the ImageError field of ImageContext.
1166 @retval RETURN_INVALID_PARAMETER The image address is invalid.
1167 Extended status information is in the ImageError field of ImageContext.
1172 PeCoffLoaderLoadImage (
1173 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1176 RETURN_STATUS Status
;
1177 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1178 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
1179 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
1180 EFI_IMAGE_SECTION_HEADER
*Section
;
1181 UINTN NumberOfSections
;
1185 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
1186 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
1188 UINT32 TempDebugEntryRva
;
1189 UINT32 NumberOfRvaAndSizes
;
1190 EFI_IMAGE_RESOURCE_DIRECTORY
*ResourceDirectory
;
1191 EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*ResourceDirectoryEntry
;
1192 EFI_IMAGE_RESOURCE_DIRECTORY_STRING
*ResourceDirectoryString
;
1193 EFI_IMAGE_RESOURCE_DATA_ENTRY
*ResourceDataEntry
;
1196 UINT32 TeStrippedOffset
;
1198 ASSERT (ImageContext
!= NULL
);
1203 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
1206 // Copy the provided context information into our local version, get what we
1207 // can from the original image, and then use that to make sure everything
1210 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
1212 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
1213 if (RETURN_ERROR (Status
)) {
1218 // Make sure there is enough allocated space for the image being loaded
1220 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
1221 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
1222 return RETURN_BUFFER_TOO_SMALL
;
1224 if (ImageContext
->ImageAddress
== 0) {
1226 // Image cannot be loaded into 0 address.
1228 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1229 return RETURN_INVALID_PARAMETER
;
1232 // If there's no relocations, then make sure it's not a runtime driver,
1233 // and that it's being loaded at the linked address.
1235 if (CheckContext
.RelocationsStripped
) {
1237 // If the image does not contain relocations and it is a runtime driver
1238 // then return an error.
1240 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
1241 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
1242 return RETURN_LOAD_ERROR
;
1245 // If the image does not contain relocations, and the requested load address
1246 // is not the linked address, then return an error.
1248 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
1249 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1250 return RETURN_INVALID_PARAMETER
;
1254 // Make sure the allocated space has the proper section alignment
1256 if (!(ImageContext
->IsTeImage
)) {
1257 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
1258 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
1259 return RETURN_INVALID_PARAMETER
;
1263 // Read the entire PE/COFF or TE header into memory
1265 if (!(ImageContext
->IsTeImage
)) {
1266 Status
= ImageContext
->ImageRead (
1267 ImageContext
->Handle
,
1269 &ImageContext
->SizeOfHeaders
,
1270 (VOID
*) (UINTN
) ImageContext
->ImageAddress
1273 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
1275 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
1276 (UINTN
)ImageContext
->ImageAddress
+
1277 ImageContext
->PeCoffHeaderOffset
+
1279 sizeof(EFI_IMAGE_FILE_HEADER
) +
1280 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
1282 NumberOfSections
= (UINTN
) (Hdr
.Pe32
->FileHeader
.NumberOfSections
);
1283 TeStrippedOffset
= 0;
1285 Status
= ImageContext
->ImageRead (
1286 ImageContext
->Handle
,
1288 &ImageContext
->SizeOfHeaders
,
1289 (void *)(UINTN
)ImageContext
->ImageAddress
1292 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
1293 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
1294 (UINTN
)ImageContext
->ImageAddress
+
1295 sizeof(EFI_TE_IMAGE_HEADER
)
1297 NumberOfSections
= (UINTN
) (Hdr
.Te
->NumberOfSections
);
1298 TeStrippedOffset
= (UINT32
) Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
1301 if (RETURN_ERROR (Status
)) {
1302 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1303 return RETURN_LOAD_ERROR
;
1307 // Load each section of the image
1309 Section
= FirstSection
;
1310 for (Index
= 0; Index
< NumberOfSections
; Index
++) {
1314 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
1315 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
1316 Size
= (UINTN
) Section
->SizeOfRawData
;
1320 // Compute sections address
1322 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
, TeStrippedOffset
);
1323 End
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1, TeStrippedOffset
);
1326 // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.
1328 if ((Size
> 0) && ((Base
== NULL
) || (End
== NULL
))) {
1329 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
1330 return RETURN_LOAD_ERROR
;
1333 if (Section
->SizeOfRawData
> 0) {
1334 Status
= ImageContext
->ImageRead (
1335 ImageContext
->Handle
,
1336 Section
->PointerToRawData
- TeStrippedOffset
,
1340 if (RETURN_ERROR (Status
)) {
1341 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1347 // If raw size is less then virtual size, zero fill the remaining
1350 if (Size
< Section
->Misc
.VirtualSize
) {
1351 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
1361 // Get image's entry point
1363 if (!(ImageContext
->IsTeImage
)) {
1365 // Sizes of AddressOfEntryPoint are different so we need to do this safely
1367 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1371 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1373 (UINTN
)Hdr
.Pe32
->OptionalHeader
.AddressOfEntryPoint
,
1380 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1382 (UINTN
)Hdr
.Pe32Plus
->OptionalHeader
.AddressOfEntryPoint
,
1387 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1389 (UINTN
)Hdr
.Te
->AddressOfEntryPoint
,
1395 // Determine the size of the fixup data
1397 // Per the PE/COFF spec, you can't assume that a given data directory
1398 // is present in the image. You have to check the NumberOfRvaAndSizes in
1399 // the optional header to verify a desired directory entry is there.
1401 if (!(ImageContext
->IsTeImage
)) {
1402 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1406 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1407 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1412 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1413 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1417 // Must use UINT64 here, because there might a case that 32bit loader to load 64bit image.
1419 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1420 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINT64
);
1422 ImageContext
->FixupDataSize
= 0;
1425 DirectoryEntry
= &Hdr
.Te
->DataDirectory
[0];
1426 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINT64
);
1429 // Consumer must allocate a buffer for the relocation fixup log.
1430 // Only used for runtime drivers.
1432 ImageContext
->FixupData
= NULL
;
1435 // Load the Codeview information if present
1437 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
1438 DebugEntry
= PeCoffLoaderImageAddress (
1440 ImageContext
->DebugDirectoryEntryRva
,
1443 if (DebugEntry
== NULL
) {
1444 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1445 return RETURN_LOAD_ERROR
;
1448 TempDebugEntryRva
= DebugEntry
->RVA
;
1449 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
1451 if ((UINTN
)Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
1452 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
1454 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
1458 if (TempDebugEntryRva
!= 0) {
1459 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
, TeStrippedOffset
);
1460 if (ImageContext
->CodeView
== NULL
) {
1461 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1462 return RETURN_LOAD_ERROR
;
1465 if (DebugEntry
->RVA
== 0) {
1466 Size
= DebugEntry
->SizeOfData
;
1467 Status
= ImageContext
->ImageRead (
1468 ImageContext
->Handle
,
1469 DebugEntry
->FileOffset
- TeStrippedOffset
,
1471 ImageContext
->CodeView
1474 // Should we apply fix up to this field according to the size difference between PE and TE?
1475 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1476 // in original PE image.
1479 if (RETURN_ERROR (Status
)) {
1480 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1481 return RETURN_LOAD_ERROR
;
1484 DebugEntry
->RVA
= TempDebugEntryRva
;
1487 switch (*(UINT32
*) ImageContext
->CodeView
) {
1488 case CODEVIEW_SIGNATURE_NB10
:
1489 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
)) {
1490 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1491 return RETURN_UNSUPPORTED
;
1493 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1496 case CODEVIEW_SIGNATURE_RSDS
:
1497 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
)) {
1498 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1499 return RETURN_UNSUPPORTED
;
1501 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
1504 case CODEVIEW_SIGNATURE_MTOC
:
1505 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
)) {
1506 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1507 return RETURN_UNSUPPORTED
;
1509 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
);
1519 // Get Image's HII resource section
1521 ImageContext
->HiiResourceData
= 0;
1522 if (!(ImageContext
->IsTeImage
)) {
1523 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1527 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1528 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
];
1533 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1534 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
];
1537 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
&& DirectoryEntry
->Size
!= 0) {
1538 Base
= PeCoffLoaderImageAddress (ImageContext
, DirectoryEntry
->VirtualAddress
, 0);
1540 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) Base
;
1541 Offset
= sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) *
1542 (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1543 if (Offset
> DirectoryEntry
->Size
) {
1544 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1545 return RETURN_UNSUPPORTED
;
1547 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1549 for (Index
= 0; Index
< ResourceDirectory
->NumberOfNamedEntries
; Index
++) {
1550 if (ResourceDirectoryEntry
->u1
.s
.NameIsString
) {
1552 // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.
1554 if (ResourceDirectoryEntry
->u1
.s
.NameOffset
>= DirectoryEntry
->Size
) {
1555 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1556 return RETURN_UNSUPPORTED
;
1558 ResourceDirectoryString
= (EFI_IMAGE_RESOURCE_DIRECTORY_STRING
*) (Base
+ ResourceDirectoryEntry
->u1
.s
.NameOffset
);
1559 String
= &ResourceDirectoryString
->String
[0];
1561 if (ResourceDirectoryString
->Length
== 3 &&
1562 String
[0] == L
'H' &&
1563 String
[1] == L
'I' &&
1564 String
[2] == L
'I') {
1566 // Resource Type "HII" found
1568 if (ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1570 // Move to next level - resource Name
1572 if (ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
>= DirectoryEntry
->Size
) {
1573 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1574 return RETURN_UNSUPPORTED
;
1576 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) (Base
+ ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
);
1577 Offset
= ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
+ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) +
1578 sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) * (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1579 if (Offset
> DirectoryEntry
->Size
) {
1580 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1581 return RETURN_UNSUPPORTED
;
1583 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1585 if (ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1587 // Move to next level - resource Language
1589 if (ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
>= DirectoryEntry
->Size
) {
1590 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1591 return RETURN_UNSUPPORTED
;
1593 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) (Base
+ ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
);
1594 Offset
= ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
+ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) +
1595 sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) * (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1596 if (Offset
> DirectoryEntry
->Size
) {
1597 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1598 return RETURN_UNSUPPORTED
;
1600 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1605 // Now it ought to be resource Data
1607 if (!ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1608 if (ResourceDirectoryEntry
->u2
.OffsetToData
>= DirectoryEntry
->Size
) {
1609 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1610 return RETURN_UNSUPPORTED
;
1612 ResourceDataEntry
= (EFI_IMAGE_RESOURCE_DATA_ENTRY
*) (Base
+ ResourceDirectoryEntry
->u2
.OffsetToData
);
1613 ImageContext
->HiiResourceData
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (ImageContext
, ResourceDataEntry
->OffsetToData
, 0);
1618 ResourceDirectoryEntry
++;
1629 Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI
1632 This function reapplies relocation fixups to the PE/COFF image specified by ImageBase
1633 and ImageSize so the image will execute correctly when the PE/COFF image is mapped
1634 to the address specified by VirtualImageBase. RelocationData must be identical
1635 to the FiuxupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure
1636 after this PE/COFF image was relocated with PeCoffLoaderRelocateImage().
1638 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1639 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1640 prior to transferring control to a PE/COFF image that is loaded using this library.
1642 @param ImageBase The base address of a PE/COFF image that has been loaded
1643 and relocated into system memory.
1644 @param VirtImageBase The request virtual address that the PE/COFF image is to
1646 @param ImageSize The size, in bytes, of the PE/COFF image.
1647 @param RelocationData A pointer to the relocation data that was collected when the PE/COFF
1648 image was relocated using PeCoffLoaderRelocateImage().
1653 PeCoffLoaderRelocateImageForRuntime (
1654 IN PHYSICAL_ADDRESS ImageBase
,
1655 IN PHYSICAL_ADDRESS VirtImageBase
,
1657 IN VOID
*RelocationData
1662 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1663 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1664 UINT32 NumberOfRvaAndSizes
;
1665 EFI_IMAGE_DATA_DIRECTORY
*DataDirectory
;
1666 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
1667 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
1668 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
1669 EFI_IMAGE_BASE_RELOCATION
*RelocBaseOrig
;
1679 RETURN_STATUS Status
;
1680 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
1682 if (RelocationData
== NULL
|| ImageBase
== 0x0 || VirtImageBase
== 0x0) {
1686 OldBase
= (CHAR8
*)((UINTN
)ImageBase
);
1687 NewBase
= (CHAR8
*)((UINTN
)VirtImageBase
);
1688 Adjust
= (UINTN
) NewBase
- (UINTN
) OldBase
;
1690 ImageContext
.ImageAddress
= ImageBase
;
1691 ImageContext
.ImageSize
= ImageSize
;
1694 // Find the image's relocate dir info
1696 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)OldBase
;
1697 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
1699 // Valid DOS header so get address of PE header
1701 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)(((CHAR8
*)DosHdr
) + DosHdr
->e_lfanew
);
1704 // No Dos header so assume image starts with PE header.
1706 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)OldBase
;
1709 if (Hdr
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
1711 // Not a valid PE image so Exit
1716 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1720 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1721 DataDirectory
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[0]);
1726 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1727 DataDirectory
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[0]);
1731 // Find the relocation block
1733 // Per the PE/COFF spec, you can't assume that a given data directory
1734 // is present in the image. You have to check the NumberOfRvaAndSizes in
1735 // the optional header to verify a desired directory entry is there.
1738 RelocBaseEnd
= NULL
;
1739 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1740 RelocDir
= DataDirectory
+ EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
;
1741 if ((RelocDir
!= NULL
) && (RelocDir
->Size
> 0)) {
1742 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) PeCoffLoaderImageAddress (&ImageContext
, RelocDir
->VirtualAddress
, 0);
1743 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) PeCoffLoaderImageAddress (&ImageContext
,
1744 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1,
1748 if (RelocBase
== NULL
|| RelocBaseEnd
== NULL
|| (UINTN
) RelocBaseEnd
< (UINTN
) RelocBase
) {
1750 // relocation block is not valid, just return
1756 // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.
1763 // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.
1765 ASSERT (RelocBase
!= NULL
&& RelocBaseEnd
!= NULL
);
1769 // Run the whole relocation block. And re-fixup data that has not been
1770 // modified. The FixupData is used to see if the image has been modified
1771 // since it was relocated. This is so data sections that have been updated
1772 // by code will not be fixed up, since that would set them back to
1775 FixupData
= RelocationData
;
1776 RelocBaseOrig
= RelocBase
;
1777 while ((UINTN
) RelocBase
< (UINTN
) RelocBaseEnd
) {
1779 // Add check for RelocBase->SizeOfBlock field.
1781 if ((RelocBase
->SizeOfBlock
== 0) || (RelocBase
->SizeOfBlock
> RelocDir
->Size
)) {
1783 // Data invalid, cannot continue to relocate the image, just return.
1788 Reloc
= (UINT16
*) ((UINT8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
1789 RelocEnd
= (UINT16
*) ((UINT8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
1790 if ((UINTN
)RelocEnd
> (UINTN
)RelocBaseOrig
+ RelocDir
->Size
) {
1794 FixupBase
= PeCoffLoaderImageAddress (&ImageContext
, RelocBase
->VirtualAddress
, 0);
1795 if (FixupBase
== NULL
) {
1800 // Run this relocation record
1802 while ((UINTN
) Reloc
< (UINTN
) RelocEnd
) {
1804 Fixup
= PeCoffLoaderImageAddress (&ImageContext
, RelocBase
->VirtualAddress
+ (*Reloc
& 0xFFF), 0);
1805 if (Fixup
== NULL
) {
1808 switch ((*Reloc
) >> 12) {
1810 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
1813 case EFI_IMAGE_REL_BASED_HIGH
:
1814 Fixup16
= (UINT16
*) Fixup
;
1815 if (*(UINT16
*) FixupData
== *Fixup16
) {
1816 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
1819 FixupData
= FixupData
+ sizeof (UINT16
);
1822 case EFI_IMAGE_REL_BASED_LOW
:
1823 Fixup16
= (UINT16
*) Fixup
;
1824 if (*(UINT16
*) FixupData
== *Fixup16
) {
1825 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) Adjust
& 0xffff));
1828 FixupData
= FixupData
+ sizeof (UINT16
);
1831 case EFI_IMAGE_REL_BASED_HIGHLOW
:
1832 Fixup32
= (UINT32
*) Fixup
;
1833 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
1834 if (*(UINT32
*) FixupData
== *Fixup32
) {
1835 *Fixup32
= *Fixup32
+ (UINT32
) Adjust
;
1838 FixupData
= FixupData
+ sizeof (UINT32
);
1841 case EFI_IMAGE_REL_BASED_DIR64
:
1842 Fixup64
= (UINT64
*)Fixup
;
1843 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT64
));
1844 if (*(UINT64
*) FixupData
== *Fixup64
) {
1845 *Fixup64
= *Fixup64
+ (UINT64
)Adjust
;
1848 FixupData
= FixupData
+ sizeof (UINT64
);
1853 // Only Itanium requires ConvertPeImage_Ex
1855 Status
= PeHotRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
1856 if (RETURN_ERROR (Status
)) {
1861 // Next relocation record
1868 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
1875 Reads contents of a PE/COFF image from a buffer in system memory.
1877 This is the default implementation of a PE_COFF_LOADER_READ_FILE function
1878 that assumes FileHandle pointer to the beginning of a PE/COFF image.
1879 This function reads contents of the PE/COFF image that starts at the system memory
1880 address specified by FileHandle. The read operation copies ReadSize bytes from the
1881 PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer.
1882 The size of the buffer actually read is returned in ReadSize.
1884 The caller must make sure the FileOffset and ReadSize within the file scope.
1886 If FileHandle is NULL, then ASSERT().
1887 If ReadSize is NULL, then ASSERT().
1888 If Buffer is NULL, then ASSERT().
1890 @param FileHandle The pointer to base of the input stream
1891 @param FileOffset Offset into the PE/COFF image to begin the read operation.
1892 @param ReadSize On input, the size in bytes of the requested read operation.
1893 On output, the number of bytes actually read.
1894 @param Buffer Output buffer that contains the data read from the PE/COFF image.
1896 @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into
1901 PeCoffLoaderImageReadFromMemory (
1902 IN VOID
*FileHandle
,
1903 IN UINTN FileOffset
,
1904 IN OUT UINTN
*ReadSize
,
1908 ASSERT (ReadSize
!= NULL
);
1909 ASSERT (FileHandle
!= NULL
);
1910 ASSERT (Buffer
!= NULL
);
1912 CopyMem (Buffer
, ((UINT8
*)FileHandle
) + FileOffset
, *ReadSize
);
1913 return RETURN_SUCCESS
;
1917 Unloads a loaded PE/COFF image from memory and releases its taken resource.
1918 Releases any environment specific resources that were allocated when the image
1919 specified by ImageContext was loaded using PeCoffLoaderLoadImage().
1921 For NT32 emulator, the PE/COFF image loaded by system needs to release.
1922 For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded,
1923 this function can simply return RETURN_SUCCESS.
1925 If ImageContext is NULL, then ASSERT().
1927 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1928 image to be unloaded.
1930 @retval RETURN_SUCCESS The PE/COFF image was unloaded successfully.
1934 PeCoffLoaderUnloadImage (
1935 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1939 // Applies additional environment specific actions to unload a
1940 // PE/COFF image if needed
1942 PeCoffLoaderUnloadImageExtraAction (ImageContext
);
1943 return RETURN_SUCCESS
;