2 Base PE/COFF loader supports loading any PE32/PE32+ or TE image, but
3 only supports relocating IA32, x64, IPF, and EBC images.
5 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 SPDX-License-Identifier: BSD-2-Clause-Patent
24 #include "BasePeCoffLibInternals.h"
27 Adjust some fields in section header for TE image.
29 @param SectionHeader Pointer to the section header.
30 @param TeStrippedOffset Size adjust for the TE image.
34 PeCoffLoaderAdjustOffsetForTeImage (
35 EFI_IMAGE_SECTION_HEADER
*SectionHeader
,
36 UINT32 TeStrippedOffset
39 SectionHeader
->VirtualAddress
-= TeStrippedOffset
;
40 SectionHeader
->PointerToRawData
-= TeStrippedOffset
;
44 Retrieves the PE or TE Header from a PE/COFF or TE image.
46 Caution: This function may receive untrusted input.
47 PE/COFF image is external input, so this routine will
48 also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
49 SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
51 @param ImageContext The context of the image being loaded.
52 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
54 @retval RETURN_SUCCESS The PE or TE Header is read.
55 @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.
59 PeCoffLoaderGetPeHeader (
60 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
61 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
65 EFI_IMAGE_DOS_HEADER DosHdr
;
68 UINT32 SectionHeaderOffset
;
70 UINT32 HeaderWithoutDataDir
;
72 UINTN NumberOfSections
;
73 EFI_IMAGE_SECTION_HEADER SectionHeader
;
76 // Read the DOS image header to check for its existence
78 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
80 Status
= ImageContext
->ImageRead (
86 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
87 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
88 if (Size
!= ReadSize
) {
89 Status
= RETURN_UNSUPPORTED
;
94 ImageContext
->PeCoffHeaderOffset
= 0;
95 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
97 // DOS image header is present, so read the PE header after the DOS image
100 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
104 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
105 // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
106 // determines if this is a PE32 or PE32+ image. The magic is in the same
107 // location in both images.
109 Size
= sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
);
111 Status
= ImageContext
->ImageRead (
112 ImageContext
->Handle
,
113 ImageContext
->PeCoffHeaderOffset
,
117 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
118 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
119 if (Size
!= ReadSize
) {
120 Status
= RETURN_UNSUPPORTED
;
126 // Use Signature to figure out if we understand the image format
128 if (Hdr
.Te
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
129 ImageContext
->IsTeImage
= TRUE
;
130 ImageContext
->Machine
= Hdr
.Te
->Machine
;
131 ImageContext
->ImageType
= (UINT16
)(Hdr
.Te
->Subsystem
);
133 // For TeImage, SectionAlignment is undefined to be set to Zero
134 // ImageSize can be calculated.
136 ImageContext
->ImageSize
= 0;
137 ImageContext
->SectionAlignment
= 0;
138 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
)Hdr
.Te
->BaseOfCode
- (UINTN
)Hdr
.Te
->StrippedSize
;
141 // Check the StrippedSize.
143 if (sizeof (EFI_TE_IMAGE_HEADER
) >= (UINT32
)Hdr
.Te
->StrippedSize
) {
144 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
145 return RETURN_UNSUPPORTED
;
149 // Check the SizeOfHeaders field.
151 if (Hdr
.Te
->BaseOfCode
<= Hdr
.Te
->StrippedSize
) {
152 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
153 return RETURN_UNSUPPORTED
;
157 // Read last byte of Hdr.Te->SizeOfHeaders from the file.
161 Status
= ImageContext
->ImageRead (
162 ImageContext
->Handle
,
163 ImageContext
->SizeOfHeaders
- 1,
167 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
168 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
169 if (Size
!= ReadSize
) {
170 Status
= RETURN_UNSUPPORTED
;
176 // TE Image Data Directory Entry size is non-zero, but the Data Directory Virtual Address is zero.
177 // This case is not a valid TE image.
179 if ((Hdr
.Te
->DataDirectory
[0].Size
!= 0 && Hdr
.Te
->DataDirectory
[0].VirtualAddress
== 0) ||
180 (Hdr
.Te
->DataDirectory
[1].Size
!= 0 && Hdr
.Te
->DataDirectory
[1].VirtualAddress
== 0)) {
181 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
182 return RETURN_UNSUPPORTED
;
184 } else if (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
) {
185 ImageContext
->IsTeImage
= FALSE
;
186 ImageContext
->Machine
= Hdr
.Pe32
->FileHeader
.Machine
;
188 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
190 // 1. Check OptionalHeader.NumberOfRvaAndSizes filed.
192 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
< Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) {
193 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
194 return RETURN_UNSUPPORTED
;
198 // 2. Check the FileHeader.SizeOfOptionalHeader field.
199 // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
200 // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
202 HeaderWithoutDataDir
= sizeof (EFI_IMAGE_OPTIONAL_HEADER32
) - sizeof (EFI_IMAGE_DATA_DIRECTORY
) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
;
203 if (((UINT32
)Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
- HeaderWithoutDataDir
) !=
204 Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
* sizeof (EFI_IMAGE_DATA_DIRECTORY
)) {
205 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
206 return RETURN_UNSUPPORTED
;
209 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
211 // 3. Check the FileHeader.NumberOfSections field.
213 if (Hdr
.Pe32
->OptionalHeader
.SizeOfImage
<= SectionHeaderOffset
) {
214 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
215 return RETURN_UNSUPPORTED
;
217 if ((Hdr
.Pe32
->OptionalHeader
.SizeOfImage
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
<= Hdr
.Pe32
->FileHeader
.NumberOfSections
) {
218 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
219 return RETURN_UNSUPPORTED
;
223 // 4. Check the OptionalHeader.SizeOfHeaders field.
225 if (Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
<= SectionHeaderOffset
) {
226 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
227 return RETURN_UNSUPPORTED
;
229 if (Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
>= Hdr
.Pe32
->OptionalHeader
.SizeOfImage
) {
230 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
231 return RETURN_UNSUPPORTED
;
233 if ((Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
< (UINT32
)Hdr
.Pe32
->FileHeader
.NumberOfSections
) {
234 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
235 return RETURN_UNSUPPORTED
;
239 // 4.2 Read last byte of Hdr.Pe32.OptionalHeader.SizeOfHeaders from the file.
243 Status
= ImageContext
->ImageRead (
244 ImageContext
->Handle
,
245 Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- 1,
249 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
250 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
251 if (Size
!= ReadSize
) {
252 Status
= RETURN_UNSUPPORTED
;
258 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
259 // Read the last byte to make sure the data is in the image region.
260 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
262 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
< Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) {
263 if (Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
!= 0) {
265 // Check the member data to avoid overflow.
267 if ((UINT32
) (~0) - Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
<
268 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
) {
269 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
270 return RETURN_UNSUPPORTED
;
274 // Read last byte of section header from file
278 Status
= ImageContext
->ImageRead (
279 ImageContext
->Handle
,
280 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
+
281 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
- 1,
285 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
286 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
287 if (Size
!= ReadSize
) {
288 Status
= RETURN_UNSUPPORTED
;
298 ImageContext
->ImageType
= Hdr
.Pe32
->OptionalHeader
.Subsystem
;
299 ImageContext
->ImageSize
= (UINT64
)Hdr
.Pe32
->OptionalHeader
.SizeOfImage
;
300 ImageContext
->SectionAlignment
= Hdr
.Pe32
->OptionalHeader
.SectionAlignment
;
301 ImageContext
->SizeOfHeaders
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
;
303 } else if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
305 // 1. Check FileHeader.NumberOfRvaAndSizes filed.
307 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
< Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
308 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
309 return RETURN_UNSUPPORTED
;
312 // 2. Check the FileHeader.SizeOfOptionalHeader field.
313 // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
314 // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
316 HeaderWithoutDataDir
= sizeof (EFI_IMAGE_OPTIONAL_HEADER64
) - sizeof (EFI_IMAGE_DATA_DIRECTORY
) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
;
317 if (((UINT32
)Hdr
.Pe32Plus
->FileHeader
.SizeOfOptionalHeader
- HeaderWithoutDataDir
) !=
318 Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
* sizeof (EFI_IMAGE_DATA_DIRECTORY
)) {
319 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
320 return RETURN_UNSUPPORTED
;
323 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32Plus
->FileHeader
.SizeOfOptionalHeader
;
325 // 3. Check the FileHeader.NumberOfSections field.
327 if (Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
<= SectionHeaderOffset
) {
328 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
329 return RETURN_UNSUPPORTED
;
331 if ((Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
<= Hdr
.Pe32Plus
->FileHeader
.NumberOfSections
) {
332 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
333 return RETURN_UNSUPPORTED
;
337 // 4. Check the OptionalHeader.SizeOfHeaders field.
339 if (Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
<= SectionHeaderOffset
) {
340 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
341 return RETURN_UNSUPPORTED
;
343 if (Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
>= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
) {
344 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
345 return RETURN_UNSUPPORTED
;
347 if ((Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
< (UINT32
)Hdr
.Pe32Plus
->FileHeader
.NumberOfSections
) {
348 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
349 return RETURN_UNSUPPORTED
;
353 // 4.2 Read last byte of Hdr.Pe32Plus.OptionalHeader.SizeOfHeaders from the file.
357 Status
= ImageContext
->ImageRead (
358 ImageContext
->Handle
,
359 Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- 1,
363 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
364 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
365 if (Size
!= ReadSize
) {
366 Status
= RETURN_UNSUPPORTED
;
372 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
373 // Read the last byte to make sure the data is in the image region.
374 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
376 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
< Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
377 if (Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
!= 0) {
379 // Check the member data to avoid overflow.
381 if ((UINT32
) (~0) - Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
<
382 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
) {
383 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
384 return RETURN_UNSUPPORTED
;
388 // Read last byte of section header from file
392 Status
= ImageContext
->ImageRead (
393 ImageContext
->Handle
,
394 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
+
395 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
- 1,
399 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
400 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
401 if (Size
!= ReadSize
) {
402 Status
= RETURN_UNSUPPORTED
;
412 ImageContext
->ImageType
= Hdr
.Pe32Plus
->OptionalHeader
.Subsystem
;
413 ImageContext
->ImageSize
= (UINT64
) Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
;
414 ImageContext
->SectionAlignment
= Hdr
.Pe32Plus
->OptionalHeader
.SectionAlignment
;
415 ImageContext
->SizeOfHeaders
= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
;
417 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
418 return RETURN_UNSUPPORTED
;
421 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
422 return RETURN_UNSUPPORTED
;
425 if (!PeCoffLoaderImageFormatSupported (ImageContext
->Machine
)) {
427 // If the PE/COFF loader does not support the image type return
428 // unsupported. This library can support lots of types of images
429 // this does not mean the user of this library can call the entry
430 // point of the image.
432 return RETURN_UNSUPPORTED
;
436 // Check each section field.
438 if (ImageContext
->IsTeImage
) {
439 SectionHeaderOffset
= sizeof(EFI_TE_IMAGE_HEADER
);
440 NumberOfSections
= (UINTN
) (Hdr
.Te
->NumberOfSections
);
442 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
443 NumberOfSections
= (UINTN
) (Hdr
.Pe32
->FileHeader
.NumberOfSections
);
446 for (Index
= 0; Index
< NumberOfSections
; Index
++) {
448 // Read section header from file
450 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
452 Status
= ImageContext
->ImageRead (
453 ImageContext
->Handle
,
458 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
459 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
460 if (Size
!= ReadSize
) {
461 Status
= RETURN_UNSUPPORTED
;
467 // Adjust some field in Section Header for TE image.
469 if (ImageContext
->IsTeImage
) {
470 PeCoffLoaderAdjustOffsetForTeImage (&SectionHeader
, (UINT32
)Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
473 if (SectionHeader
.SizeOfRawData
> 0) {
475 // Section data should bigger than the Pe header.
477 if (SectionHeader
.VirtualAddress
< ImageContext
->SizeOfHeaders
||
478 SectionHeader
.PointerToRawData
< ImageContext
->SizeOfHeaders
) {
479 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
480 return RETURN_UNSUPPORTED
;
484 // Check the member data to avoid overflow.
486 if ((UINT32
) (~0) - SectionHeader
.PointerToRawData
< SectionHeader
.SizeOfRawData
) {
487 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
488 return RETURN_UNSUPPORTED
;
492 // Base on the ImageRead function to check the section data field.
493 // Read the last byte to make sure the data is in the image region.
497 Status
= ImageContext
->ImageRead (
498 ImageContext
->Handle
,
499 SectionHeader
.PointerToRawData
+ SectionHeader
.SizeOfRawData
- 1,
503 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
504 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
505 if (Size
!= ReadSize
) {
506 Status
= RETURN_UNSUPPORTED
;
513 // Check next section.
515 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
518 return RETURN_SUCCESS
;
523 Retrieves information about a PE/COFF image.
525 Computes the PeCoffHeaderOffset, IsTeImage, ImageType, ImageAddress, ImageSize,
526 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and
527 DebugDirectoryEntryRva fields of the ImageContext structure.
528 If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.
529 If the PE/COFF image accessed through the ImageRead service in the ImageContext
530 structure is not a supported PE/COFF image type, then return RETURN_UNSUPPORTED.
531 If any errors occur while computing the fields of ImageContext,
532 then the error status is returned in the ImageError field of ImageContext.
533 If the image is a TE image, then SectionAlignment is set to 0.
534 The ImageRead and Handle fields of ImageContext structure must be valid prior
535 to invoking this service.
537 Caution: This function may receive untrusted input.
538 PE/COFF image is external input, so this routine will
539 also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
540 SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
542 @param ImageContext The pointer to the image context structure that describes the PE/COFF
543 image that needs to be examined by this function.
545 @retval RETURN_SUCCESS The information on the PE/COFF image was collected.
546 @retval RETURN_INVALID_PARAMETER ImageContext is NULL.
547 @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.
552 PeCoffLoaderGetImageInfo (
553 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
556 RETURN_STATUS Status
;
557 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
558 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
559 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
563 UINTN DebugDirectoryEntryRva
;
564 UINTN DebugDirectoryEntryFileOffset
;
565 UINTN SectionHeaderOffset
;
566 EFI_IMAGE_SECTION_HEADER SectionHeader
;
567 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
568 UINT32 NumberOfRvaAndSizes
;
569 UINT32 TeStrippedOffset
;
571 if (ImageContext
== NULL
) {
572 return RETURN_INVALID_PARAMETER
;
577 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
579 Hdr
.Union
= &HdrData
;
580 Status
= PeCoffLoaderGetPeHeader (ImageContext
, Hdr
);
581 if (RETURN_ERROR (Status
)) {
586 // Retrieve the base address of the image
588 if (!(ImageContext
->IsTeImage
)) {
589 TeStrippedOffset
= 0;
590 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
594 ImageContext
->ImageAddress
= Hdr
.Pe32
->OptionalHeader
.ImageBase
;
599 ImageContext
->ImageAddress
= Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
602 TeStrippedOffset
= (UINT32
)Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
603 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
)(Hdr
.Te
->ImageBase
+ TeStrippedOffset
);
607 // Initialize the alternate destination address to 0 indicating that it
608 // should not be used.
610 ImageContext
->DestinationAddress
= 0;
613 // Initialize the debug codeview pointer.
615 ImageContext
->DebugDirectoryEntryRva
= 0;
616 ImageContext
->CodeView
= NULL
;
617 ImageContext
->PdbPointer
= NULL
;
620 // Three cases with regards to relocations:
621 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
622 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
623 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
624 // has no base relocs to apply
625 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
627 // Look at the file header to determine if relocations have been stripped, and
628 // save this information in the image context for later use.
630 if ((!(ImageContext
->IsTeImage
)) && ((Hdr
.Pe32
->FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
631 ImageContext
->RelocationsStripped
= TRUE
;
632 } else if ((ImageContext
->IsTeImage
) && (Hdr
.Te
->DataDirectory
[0].Size
== 0) && (Hdr
.Te
->DataDirectory
[0].VirtualAddress
== 0)) {
633 ImageContext
->RelocationsStripped
= TRUE
;
635 ImageContext
->RelocationsStripped
= FALSE
;
638 if (!(ImageContext
->IsTeImage
)) {
639 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
643 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
644 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
649 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
650 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
653 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
655 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
658 // Determine the file offset of the debug directory... This means we walk
659 // the sections to find which section contains the RVA of the debug
662 DebugDirectoryEntryFileOffset
= 0;
664 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+
666 sizeof (EFI_IMAGE_FILE_HEADER
) +
667 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
669 for (Index
= 0; Index
< Hdr
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
671 // Read section header from file
673 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
675 Status
= ImageContext
->ImageRead (
676 ImageContext
->Handle
,
681 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
682 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
683 if (Size
!= ReadSize
) {
684 Status
= RETURN_UNSUPPORTED
;
689 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
690 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
692 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
696 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
699 if (DebugDirectoryEntryFileOffset
!= 0) {
700 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
702 // Read next debug directory entry
704 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
706 Status
= ImageContext
->ImageRead (
707 ImageContext
->Handle
,
708 DebugDirectoryEntryFileOffset
+ Index
,
712 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
713 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
714 if (Size
!= ReadSize
) {
715 Status
= RETURN_UNSUPPORTED
;
721 // From PeCoff spec, when DebugEntry.RVA == 0 means this debug info will not load into memory.
722 // Here we will always load EFI_IMAGE_DEBUG_TYPE_CODEVIEW type debug info. so need adjust the
723 // ImageContext->ImageSize when DebugEntry.RVA == 0.
725 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
726 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
727 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
728 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
731 return RETURN_SUCCESS
;
738 DebugDirectoryEntry
= &Hdr
.Te
->DataDirectory
[1];
739 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
740 SectionHeaderOffset
= (UINTN
)(sizeof (EFI_TE_IMAGE_HEADER
));
742 DebugDirectoryEntryFileOffset
= 0;
744 for (Index
= 0; Index
< Hdr
.Te
->NumberOfSections
;) {
746 // Read section header from file
748 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
750 Status
= ImageContext
->ImageRead (
751 ImageContext
->Handle
,
756 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
757 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
758 if (Size
!= ReadSize
) {
759 Status
= RETURN_UNSUPPORTED
;
764 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
765 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
766 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
767 SectionHeader
.VirtualAddress
+
768 SectionHeader
.PointerToRawData
-
772 // File offset of the debug directory was found, if this is not the last
773 // section, then skip to the last section for calculating the image size.
775 if (Index
< (UINTN
) Hdr
.Te
->NumberOfSections
- 1) {
776 SectionHeaderOffset
+= (Hdr
.Te
->NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
777 Index
= Hdr
.Te
->NumberOfSections
- 1;
783 // In Te image header there is not a field to describe the ImageSize.
784 // Actually, the ImageSize equals the RVA plus the VirtualSize of
785 // the last section mapped into memory (Must be rounded up to
786 // a multiple of Section Alignment). Per the PE/COFF specification, the
787 // section headers in the Section Table must appear in order of the RVA
788 // values for the corresponding sections. So the ImageSize can be determined
789 // by the RVA and the VirtualSize of the last section header in the
792 if ((++Index
) == (UINTN
)Hdr
.Te
->NumberOfSections
) {
793 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) - TeStrippedOffset
;
796 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
799 if (DebugDirectoryEntryFileOffset
!= 0) {
800 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
802 // Read next debug directory entry
804 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
806 Status
= ImageContext
->ImageRead (
807 ImageContext
->Handle
,
808 DebugDirectoryEntryFileOffset
+ Index
,
812 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
813 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
814 if (Size
!= ReadSize
) {
815 Status
= RETURN_UNSUPPORTED
;
820 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
821 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
822 return RETURN_SUCCESS
;
828 return RETURN_SUCCESS
;
833 Converts an image address to the loaded address.
835 @param ImageContext The context of the image being loaded.
836 @param Address The address to be converted to the loaded address.
837 @param TeStrippedOffset Stripped offset for TE image.
839 @return The converted address or NULL if the address can not be converted.
843 PeCoffLoaderImageAddress (
844 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
846 IN UINTN TeStrippedOffset
850 // Make sure that Address and ImageSize is correct for the loaded image.
852 if (Address
>= ImageContext
->ImageSize
+ TeStrippedOffset
) {
853 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
857 return (CHAR8
*)((UINTN
) ImageContext
->ImageAddress
+ Address
- TeStrippedOffset
);
861 Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().
863 If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of
864 ImageContext as the relocation base address. Otherwise, use the DestinationAddress field
865 of ImageContext as the relocation base address. The caller must allocate the relocation
866 fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.
868 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress,
869 ImageSize, DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders,
870 DebugDirectoryEntryRva, EntryPoint, FixupDataSize, CodeView, PdbPointer, and FixupData of
871 the ImageContext structure must be valid prior to invoking this service.
873 If ImageContext is NULL, then ASSERT().
875 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
876 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
877 prior to transferring control to a PE/COFF image that is loaded using this library.
879 @param ImageContext The pointer to the image context structure that describes the PE/COFF
880 image that is being relocated.
882 @retval RETURN_SUCCESS The PE/COFF image was relocated.
883 Extended status information is in the ImageError field of ImageContext.
884 @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.
885 Extended status information is in the ImageError field of ImageContext.
886 @retval RETURN_UNSUPPORTED A relocation record type is not supported.
887 Extended status information is in the ImageError field of ImageContext.
892 PeCoffLoaderRelocateImage (
893 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
896 RETURN_STATUS Status
;
897 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
898 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
900 EFI_IMAGE_BASE_RELOCATION
*RelocBaseOrg
;
901 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
902 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
911 PHYSICAL_ADDRESS BaseAddress
;
912 UINT32 NumberOfRvaAndSizes
;
913 UINT32 TeStrippedOffset
;
915 ASSERT (ImageContext
!= NULL
);
920 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
923 // If there are no relocation entries, then we are done
925 if (ImageContext
->RelocationsStripped
) {
926 // Applies additional environment specific actions to relocate fixups
927 // to a PE/COFF image if needed
928 PeCoffLoaderRelocateImageExtraAction (ImageContext
);
929 return RETURN_SUCCESS
;
933 // If the destination address is not 0, use that rather than the
934 // image address as the relocation target.
936 if (ImageContext
->DestinationAddress
!= 0) {
937 BaseAddress
= ImageContext
->DestinationAddress
;
939 BaseAddress
= ImageContext
->ImageAddress
;
942 if (!(ImageContext
->IsTeImage
)) {
943 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
944 TeStrippedOffset
= 0;
946 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
950 Adjust
= (UINT64
)BaseAddress
- Hdr
.Pe32
->OptionalHeader
.ImageBase
;
952 Hdr
.Pe32
->OptionalHeader
.ImageBase
= (UINT32
)BaseAddress
;
955 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
956 RelocDir
= &Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
961 Adjust
= (UINT64
) BaseAddress
- Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
963 Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
= (UINT64
)BaseAddress
;
966 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
967 RelocDir
= &Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
971 // Find the relocation block
972 // Per the PE/COFF spec, you can't assume that a given data directory
973 // is present in the image. You have to check the NumberOfRvaAndSizes in
974 // the optional header to verify a desired directory entry is there.
976 if ((NumberOfRvaAndSizes
< EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
)) {
980 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
981 TeStrippedOffset
= (UINT32
)Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
982 Adjust
= (UINT64
) (BaseAddress
- (Hdr
.Te
->ImageBase
+ TeStrippedOffset
));
984 Hdr
.Te
->ImageBase
= (UINT64
) (BaseAddress
- TeStrippedOffset
);
988 // Find the relocation block
990 RelocDir
= &Hdr
.Te
->DataDirectory
[0];
993 if ((RelocDir
!= NULL
) && (RelocDir
->Size
> 0)) {
994 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
, TeStrippedOffset
);
995 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) PeCoffLoaderImageAddress (ImageContext
,
996 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1,
999 if (RelocBase
== NULL
|| RelocBaseEnd
== NULL
|| (UINTN
) RelocBaseEnd
< (UINTN
) RelocBase
) {
1000 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1001 return RETURN_LOAD_ERROR
;
1005 // Set base and end to bypass processing below.
1007 RelocBase
= RelocBaseEnd
= NULL
;
1009 RelocBaseOrg
= RelocBase
;
1012 // If Adjust is not zero, then apply fix ups to the image
1016 // Run the relocation information and apply the fixups
1018 FixupData
= ImageContext
->FixupData
;
1019 while ((UINTN
) RelocBase
< (UINTN
) RelocBaseEnd
) {
1021 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
1023 // Add check for RelocBase->SizeOfBlock field.
1025 if (RelocBase
->SizeOfBlock
== 0) {
1026 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1027 return RETURN_LOAD_ERROR
;
1029 if ((UINTN
)RelocBase
> MAX_ADDRESS
- RelocBase
->SizeOfBlock
) {
1030 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1031 return RETURN_LOAD_ERROR
;
1034 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
1035 if ((UINTN
)RelocEnd
> (UINTN
)RelocBaseOrg
+ RelocDir
->Size
) {
1036 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1037 return RETURN_LOAD_ERROR
;
1039 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
, TeStrippedOffset
);
1040 if (FixupBase
== NULL
) {
1041 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1042 return RETURN_LOAD_ERROR
;
1046 // Run this relocation record
1048 while ((UINTN
) Reloc
< (UINTN
) RelocEnd
) {
1049 Fixup
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
+ (*Reloc
& 0xFFF), TeStrippedOffset
);
1050 if (Fixup
== NULL
) {
1051 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1052 return RETURN_LOAD_ERROR
;
1054 switch ((*Reloc
) >> 12) {
1055 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
1058 case EFI_IMAGE_REL_BASED_HIGH
:
1059 Fixup16
= (UINT16
*) Fixup
;
1060 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
1061 if (FixupData
!= NULL
) {
1062 *(UINT16
*) FixupData
= *Fixup16
;
1063 FixupData
= FixupData
+ sizeof (UINT16
);
1067 case EFI_IMAGE_REL_BASED_LOW
:
1068 Fixup16
= (UINT16
*) Fixup
;
1069 *Fixup16
= (UINT16
) (*Fixup16
+ (UINT16
) Adjust
);
1070 if (FixupData
!= NULL
) {
1071 *(UINT16
*) FixupData
= *Fixup16
;
1072 FixupData
= FixupData
+ sizeof (UINT16
);
1076 case EFI_IMAGE_REL_BASED_HIGHLOW
:
1077 Fixup32
= (UINT32
*) Fixup
;
1078 *Fixup32
= *Fixup32
+ (UINT32
) Adjust
;
1079 if (FixupData
!= NULL
) {
1080 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
1081 *(UINT32
*)FixupData
= *Fixup32
;
1082 FixupData
= FixupData
+ sizeof (UINT32
);
1086 case EFI_IMAGE_REL_BASED_DIR64
:
1087 Fixup64
= (UINT64
*) Fixup
;
1088 *Fixup64
= *Fixup64
+ (UINT64
) Adjust
;
1089 if (FixupData
!= NULL
) {
1090 FixupData
= ALIGN_POINTER (FixupData
, sizeof(UINT64
));
1091 *(UINT64
*)(FixupData
) = *Fixup64
;
1092 FixupData
= FixupData
+ sizeof(UINT64
);
1098 // The common code does not handle some of the stranger IPF relocations
1099 // PeCoffLoaderRelocateImageEx () adds support for these complex fixups
1100 // on IPF and is a No-Op on other architectures.
1102 Status
= PeCoffLoaderRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
1103 if (RETURN_ERROR (Status
)) {
1104 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1110 // Next relocation record
1118 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
1120 ASSERT ((UINTN
)FixupData
<= (UINTN
)ImageContext
->FixupData
+ ImageContext
->FixupDataSize
);
1123 // Adjust the EntryPoint to match the linked-to address
1125 if (ImageContext
->DestinationAddress
!= 0) {
1126 ImageContext
->EntryPoint
-= (UINT64
) ImageContext
->ImageAddress
;
1127 ImageContext
->EntryPoint
+= (UINT64
) ImageContext
->DestinationAddress
;
1131 // Applies additional environment specific actions to relocate fixups
1132 // to a PE/COFF image if needed
1133 PeCoffLoaderRelocateImageExtraAction (ImageContext
);
1135 return RETURN_SUCCESS
;
1139 Loads a PE/COFF image into memory.
1141 Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
1142 specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate
1143 the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
1144 The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.
1145 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress, ImageSize,
1146 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
1147 fields of the ImageContext structure must be valid prior to invoking this service.
1149 If ImageContext is NULL, then ASSERT().
1151 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1152 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1153 prior to transferring control to a PE/COFF image that is loaded using this library.
1155 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1156 image that is being loaded.
1158 @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by
1159 the ImageAddress and ImageSize fields of ImageContext.
1160 Extended status information is in the ImageError field of ImageContext.
1161 @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.
1162 Extended status information is in the ImageError field of ImageContext.
1163 @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.
1164 Extended status information is in the ImageError field of ImageContext.
1165 @retval RETURN_INVALID_PARAMETER The image address is invalid.
1166 Extended status information is in the ImageError field of ImageContext.
1171 PeCoffLoaderLoadImage (
1172 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1175 RETURN_STATUS Status
;
1176 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1177 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
1178 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
1179 EFI_IMAGE_SECTION_HEADER
*Section
;
1180 UINTN NumberOfSections
;
1184 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
1185 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
1187 UINT32 TempDebugEntryRva
;
1188 UINT32 NumberOfRvaAndSizes
;
1189 EFI_IMAGE_RESOURCE_DIRECTORY
*ResourceDirectory
;
1190 EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*ResourceDirectoryEntry
;
1191 EFI_IMAGE_RESOURCE_DIRECTORY_STRING
*ResourceDirectoryString
;
1192 EFI_IMAGE_RESOURCE_DATA_ENTRY
*ResourceDataEntry
;
1195 UINT32 TeStrippedOffset
;
1197 ASSERT (ImageContext
!= NULL
);
1202 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
1205 // Copy the provided context information into our local version, get what we
1206 // can from the original image, and then use that to make sure everything
1209 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
1211 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
1212 if (RETURN_ERROR (Status
)) {
1217 // Make sure there is enough allocated space for the image being loaded
1219 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
1220 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
1221 return RETURN_BUFFER_TOO_SMALL
;
1223 if (ImageContext
->ImageAddress
== 0) {
1225 // Image cannot be loaded into 0 address.
1227 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1228 return RETURN_INVALID_PARAMETER
;
1231 // If there's no relocations, then make sure it's not a runtime driver,
1232 // and that it's being loaded at the linked address.
1234 if (CheckContext
.RelocationsStripped
) {
1236 // If the image does not contain relocations and it is a runtime driver
1237 // then return an error.
1239 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
1240 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
1241 return RETURN_LOAD_ERROR
;
1244 // If the image does not contain relocations, and the requested load address
1245 // is not the linked address, then return an error.
1247 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
1248 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1249 return RETURN_INVALID_PARAMETER
;
1253 // Make sure the allocated space has the proper section alignment
1255 if (!(ImageContext
->IsTeImage
)) {
1256 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
1257 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
1258 return RETURN_INVALID_PARAMETER
;
1262 // Read the entire PE/COFF or TE header into memory
1264 if (!(ImageContext
->IsTeImage
)) {
1265 Status
= ImageContext
->ImageRead (
1266 ImageContext
->Handle
,
1268 &ImageContext
->SizeOfHeaders
,
1269 (VOID
*) (UINTN
) ImageContext
->ImageAddress
1272 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
1274 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
1275 (UINTN
)ImageContext
->ImageAddress
+
1276 ImageContext
->PeCoffHeaderOffset
+
1278 sizeof(EFI_IMAGE_FILE_HEADER
) +
1279 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
1281 NumberOfSections
= (UINTN
) (Hdr
.Pe32
->FileHeader
.NumberOfSections
);
1282 TeStrippedOffset
= 0;
1284 Status
= ImageContext
->ImageRead (
1285 ImageContext
->Handle
,
1287 &ImageContext
->SizeOfHeaders
,
1288 (void *)(UINTN
)ImageContext
->ImageAddress
1291 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
1292 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
1293 (UINTN
)ImageContext
->ImageAddress
+
1294 sizeof(EFI_TE_IMAGE_HEADER
)
1296 NumberOfSections
= (UINTN
) (Hdr
.Te
->NumberOfSections
);
1297 TeStrippedOffset
= (UINT32
) Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
1300 if (RETURN_ERROR (Status
)) {
1301 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1302 return RETURN_LOAD_ERROR
;
1306 // Load each section of the image
1308 Section
= FirstSection
;
1309 for (Index
= 0; Index
< NumberOfSections
; Index
++) {
1313 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
1314 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
1315 Size
= (UINTN
) Section
->SizeOfRawData
;
1319 // Compute sections address
1321 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
, TeStrippedOffset
);
1322 End
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1, TeStrippedOffset
);
1325 // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.
1327 if ((Size
> 0) && ((Base
== NULL
) || (End
== NULL
))) {
1328 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
1329 return RETURN_LOAD_ERROR
;
1332 if (Section
->SizeOfRawData
> 0) {
1333 Status
= ImageContext
->ImageRead (
1334 ImageContext
->Handle
,
1335 Section
->PointerToRawData
- TeStrippedOffset
,
1339 if (RETURN_ERROR (Status
)) {
1340 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1346 // If raw size is less then virtual size, zero fill the remaining
1349 if (Size
< Section
->Misc
.VirtualSize
) {
1350 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
1360 // Get image's entry point
1362 if (!(ImageContext
->IsTeImage
)) {
1364 // Sizes of AddressOfEntryPoint are different so we need to do this safely
1366 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1370 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1372 (UINTN
)Hdr
.Pe32
->OptionalHeader
.AddressOfEntryPoint
,
1379 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1381 (UINTN
)Hdr
.Pe32Plus
->OptionalHeader
.AddressOfEntryPoint
,
1386 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1388 (UINTN
)Hdr
.Te
->AddressOfEntryPoint
,
1394 // Determine the size of the fixup data
1396 // Per the PE/COFF spec, you can't assume that a given data directory
1397 // is present in the image. You have to check the NumberOfRvaAndSizes in
1398 // the optional header to verify a desired directory entry is there.
1400 if (!(ImageContext
->IsTeImage
)) {
1401 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1405 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1406 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1411 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1412 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1416 // Must use UINT64 here, because there might a case that 32bit loader to load 64bit image.
1418 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1419 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINT64
);
1421 ImageContext
->FixupDataSize
= 0;
1424 DirectoryEntry
= &Hdr
.Te
->DataDirectory
[0];
1425 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINT64
);
1428 // Consumer must allocate a buffer for the relocation fixup log.
1429 // Only used for runtime drivers.
1431 ImageContext
->FixupData
= NULL
;
1434 // Load the Codeview information if present
1436 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
1437 DebugEntry
= PeCoffLoaderImageAddress (
1439 ImageContext
->DebugDirectoryEntryRva
,
1442 if (DebugEntry
== NULL
) {
1443 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1444 return RETURN_LOAD_ERROR
;
1447 TempDebugEntryRva
= DebugEntry
->RVA
;
1448 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
1450 if ((UINTN
)Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
1451 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
1453 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
1457 if (TempDebugEntryRva
!= 0) {
1458 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
, TeStrippedOffset
);
1459 if (ImageContext
->CodeView
== NULL
) {
1460 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1461 return RETURN_LOAD_ERROR
;
1464 if (DebugEntry
->RVA
== 0) {
1465 Size
= DebugEntry
->SizeOfData
;
1466 Status
= ImageContext
->ImageRead (
1467 ImageContext
->Handle
,
1468 DebugEntry
->FileOffset
- TeStrippedOffset
,
1470 ImageContext
->CodeView
1473 // Should we apply fix up to this field according to the size difference between PE and TE?
1474 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1475 // in original PE image.
1478 if (RETURN_ERROR (Status
)) {
1479 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1480 return RETURN_LOAD_ERROR
;
1483 DebugEntry
->RVA
= TempDebugEntryRva
;
1486 switch (*(UINT32
*) ImageContext
->CodeView
) {
1487 case CODEVIEW_SIGNATURE_NB10
:
1488 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
)) {
1489 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1490 return RETURN_UNSUPPORTED
;
1492 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1495 case CODEVIEW_SIGNATURE_RSDS
:
1496 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
)) {
1497 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1498 return RETURN_UNSUPPORTED
;
1500 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
1503 case CODEVIEW_SIGNATURE_MTOC
:
1504 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
)) {
1505 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1506 return RETURN_UNSUPPORTED
;
1508 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
);
1518 // Get Image's HII resource section
1520 ImageContext
->HiiResourceData
= 0;
1521 if (!(ImageContext
->IsTeImage
)) {
1522 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1526 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1527 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
];
1532 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1533 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
];
1536 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
&& DirectoryEntry
->Size
!= 0) {
1537 Base
= PeCoffLoaderImageAddress (ImageContext
, DirectoryEntry
->VirtualAddress
, 0);
1539 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) Base
;
1540 Offset
= sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) *
1541 (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1542 if (Offset
> DirectoryEntry
->Size
) {
1543 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1544 return RETURN_UNSUPPORTED
;
1546 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1548 for (Index
= 0; Index
< ResourceDirectory
->NumberOfNamedEntries
; Index
++) {
1549 if (ResourceDirectoryEntry
->u1
.s
.NameIsString
) {
1551 // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.
1553 if (ResourceDirectoryEntry
->u1
.s
.NameOffset
>= DirectoryEntry
->Size
) {
1554 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1555 return RETURN_UNSUPPORTED
;
1557 ResourceDirectoryString
= (EFI_IMAGE_RESOURCE_DIRECTORY_STRING
*) (Base
+ ResourceDirectoryEntry
->u1
.s
.NameOffset
);
1558 String
= &ResourceDirectoryString
->String
[0];
1560 if (ResourceDirectoryString
->Length
== 3 &&
1561 String
[0] == L
'H' &&
1562 String
[1] == L
'I' &&
1563 String
[2] == L
'I') {
1565 // Resource Type "HII" found
1567 if (ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1569 // Move to next level - resource Name
1571 if (ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
>= DirectoryEntry
->Size
) {
1572 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1573 return RETURN_UNSUPPORTED
;
1575 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) (Base
+ ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
);
1576 Offset
= ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
+ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) +
1577 sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) * (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1578 if (Offset
> DirectoryEntry
->Size
) {
1579 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1580 return RETURN_UNSUPPORTED
;
1582 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1584 if (ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1586 // Move to next level - resource Language
1588 if (ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
>= DirectoryEntry
->Size
) {
1589 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1590 return RETURN_UNSUPPORTED
;
1592 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) (Base
+ ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
);
1593 Offset
= ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
+ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) +
1594 sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) * (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1595 if (Offset
> DirectoryEntry
->Size
) {
1596 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1597 return RETURN_UNSUPPORTED
;
1599 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1604 // Now it ought to be resource Data
1606 if (!ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1607 if (ResourceDirectoryEntry
->u2
.OffsetToData
>= DirectoryEntry
->Size
) {
1608 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1609 return RETURN_UNSUPPORTED
;
1611 ResourceDataEntry
= (EFI_IMAGE_RESOURCE_DATA_ENTRY
*) (Base
+ ResourceDirectoryEntry
->u2
.OffsetToData
);
1612 ImageContext
->HiiResourceData
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (ImageContext
, ResourceDataEntry
->OffsetToData
, 0);
1617 ResourceDirectoryEntry
++;
1628 Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI
1631 This function reapplies relocation fixups to the PE/COFF image specified by ImageBase
1632 and ImageSize so the image will execute correctly when the PE/COFF image is mapped
1633 to the address specified by VirtualImageBase. RelocationData must be identical
1634 to the FiuxupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure
1635 after this PE/COFF image was relocated with PeCoffLoaderRelocateImage().
1637 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1638 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1639 prior to transferring control to a PE/COFF image that is loaded using this library.
1641 @param ImageBase The base address of a PE/COFF image that has been loaded
1642 and relocated into system memory.
1643 @param VirtImageBase The request virtual address that the PE/COFF image is to
1645 @param ImageSize The size, in bytes, of the PE/COFF image.
1646 @param RelocationData A pointer to the relocation data that was collected when the PE/COFF
1647 image was relocated using PeCoffLoaderRelocateImage().
1652 PeCoffLoaderRelocateImageForRuntime (
1653 IN PHYSICAL_ADDRESS ImageBase
,
1654 IN PHYSICAL_ADDRESS VirtImageBase
,
1656 IN VOID
*RelocationData
1661 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1662 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1663 UINT32 NumberOfRvaAndSizes
;
1664 EFI_IMAGE_DATA_DIRECTORY
*DataDirectory
;
1665 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
1666 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
1667 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
1668 EFI_IMAGE_BASE_RELOCATION
*RelocBaseOrig
;
1678 RETURN_STATUS Status
;
1679 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
1681 if (RelocationData
== NULL
|| ImageBase
== 0x0 || VirtImageBase
== 0x0) {
1685 OldBase
= (CHAR8
*)((UINTN
)ImageBase
);
1686 NewBase
= (CHAR8
*)((UINTN
)VirtImageBase
);
1687 Adjust
= (UINTN
) NewBase
- (UINTN
) OldBase
;
1689 ImageContext
.ImageAddress
= ImageBase
;
1690 ImageContext
.ImageSize
= ImageSize
;
1693 // Find the image's relocate dir info
1695 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)OldBase
;
1696 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
1698 // Valid DOS header so get address of PE header
1700 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)(((CHAR8
*)DosHdr
) + DosHdr
->e_lfanew
);
1703 // No Dos header so assume image starts with PE header.
1705 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)OldBase
;
1708 if (Hdr
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
1710 // Not a valid PE image so Exit
1715 if (Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1719 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1720 DataDirectory
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[0]);
1725 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1726 DataDirectory
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[0]);
1730 // Find the relocation block
1732 // Per the PE/COFF spec, you can't assume that a given data directory
1733 // is present in the image. You have to check the NumberOfRvaAndSizes in
1734 // the optional header to verify a desired directory entry is there.
1737 RelocBaseEnd
= NULL
;
1738 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1739 RelocDir
= DataDirectory
+ EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
;
1740 if ((RelocDir
!= NULL
) && (RelocDir
->Size
> 0)) {
1741 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) PeCoffLoaderImageAddress (&ImageContext
, RelocDir
->VirtualAddress
, 0);
1742 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) PeCoffLoaderImageAddress (&ImageContext
,
1743 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1,
1747 if (RelocBase
== NULL
|| RelocBaseEnd
== NULL
|| (UINTN
) RelocBaseEnd
< (UINTN
) RelocBase
) {
1749 // relocation block is not valid, just return
1755 // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.
1762 // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.
1764 ASSERT (RelocBase
!= NULL
&& RelocBaseEnd
!= NULL
);
1768 // Run the whole relocation block. And re-fixup data that has not been
1769 // modified. The FixupData is used to see if the image has been modified
1770 // since it was relocated. This is so data sections that have been updated
1771 // by code will not be fixed up, since that would set them back to
1774 FixupData
= RelocationData
;
1775 RelocBaseOrig
= RelocBase
;
1776 while ((UINTN
) RelocBase
< (UINTN
) RelocBaseEnd
) {
1778 // Add check for RelocBase->SizeOfBlock field.
1780 if ((RelocBase
->SizeOfBlock
== 0) || (RelocBase
->SizeOfBlock
> RelocDir
->Size
)) {
1782 // Data invalid, cannot continue to relocate the image, just return.
1787 Reloc
= (UINT16
*) ((UINT8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
1788 RelocEnd
= (UINT16
*) ((UINT8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
1789 if ((UINTN
)RelocEnd
> (UINTN
)RelocBaseOrig
+ RelocDir
->Size
) {
1793 FixupBase
= PeCoffLoaderImageAddress (&ImageContext
, RelocBase
->VirtualAddress
, 0);
1794 if (FixupBase
== NULL
) {
1799 // Run this relocation record
1801 while ((UINTN
) Reloc
< (UINTN
) RelocEnd
) {
1803 Fixup
= PeCoffLoaderImageAddress (&ImageContext
, RelocBase
->VirtualAddress
+ (*Reloc
& 0xFFF), 0);
1804 if (Fixup
== NULL
) {
1807 switch ((*Reloc
) >> 12) {
1809 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
1812 case EFI_IMAGE_REL_BASED_HIGH
:
1813 Fixup16
= (UINT16
*) Fixup
;
1814 if (*(UINT16
*) FixupData
== *Fixup16
) {
1815 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
1818 FixupData
= FixupData
+ sizeof (UINT16
);
1821 case EFI_IMAGE_REL_BASED_LOW
:
1822 Fixup16
= (UINT16
*) Fixup
;
1823 if (*(UINT16
*) FixupData
== *Fixup16
) {
1824 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) Adjust
& 0xffff));
1827 FixupData
= FixupData
+ sizeof (UINT16
);
1830 case EFI_IMAGE_REL_BASED_HIGHLOW
:
1831 Fixup32
= (UINT32
*) Fixup
;
1832 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
1833 if (*(UINT32
*) FixupData
== *Fixup32
) {
1834 *Fixup32
= *Fixup32
+ (UINT32
) Adjust
;
1837 FixupData
= FixupData
+ sizeof (UINT32
);
1840 case EFI_IMAGE_REL_BASED_DIR64
:
1841 Fixup64
= (UINT64
*)Fixup
;
1842 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT64
));
1843 if (*(UINT64
*) FixupData
== *Fixup64
) {
1844 *Fixup64
= *Fixup64
+ (UINT64
)Adjust
;
1847 FixupData
= FixupData
+ sizeof (UINT64
);
1852 // Only Itanium requires ConvertPeImage_Ex
1854 Status
= PeHotRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
1855 if (RETURN_ERROR (Status
)) {
1860 // Next relocation record
1867 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
1874 Reads contents of a PE/COFF image from a buffer in system memory.
1876 This is the default implementation of a PE_COFF_LOADER_READ_FILE function
1877 that assumes FileHandle pointer to the beginning of a PE/COFF image.
1878 This function reads contents of the PE/COFF image that starts at the system memory
1879 address specified by FileHandle. The read operation copies ReadSize bytes from the
1880 PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer.
1881 The size of the buffer actually read is returned in ReadSize.
1883 The caller must make sure the FileOffset and ReadSize within the file scope.
1885 If FileHandle is NULL, then ASSERT().
1886 If ReadSize is NULL, then ASSERT().
1887 If Buffer is NULL, then ASSERT().
1889 @param FileHandle The pointer to base of the input stream
1890 @param FileOffset Offset into the PE/COFF image to begin the read operation.
1891 @param ReadSize On input, the size in bytes of the requested read operation.
1892 On output, the number of bytes actually read.
1893 @param Buffer Output buffer that contains the data read from the PE/COFF image.
1895 @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into
1900 PeCoffLoaderImageReadFromMemory (
1901 IN VOID
*FileHandle
,
1902 IN UINTN FileOffset
,
1903 IN OUT UINTN
*ReadSize
,
1907 ASSERT (ReadSize
!= NULL
);
1908 ASSERT (FileHandle
!= NULL
);
1909 ASSERT (Buffer
!= NULL
);
1911 CopyMem (Buffer
, ((UINT8
*)FileHandle
) + FileOffset
, *ReadSize
);
1912 return RETURN_SUCCESS
;
1916 Unloads a loaded PE/COFF image from memory and releases its taken resource.
1917 Releases any environment specific resources that were allocated when the image
1918 specified by ImageContext was loaded using PeCoffLoaderLoadImage().
1920 For NT32 emulator, the PE/COFF image loaded by system needs to release.
1921 For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded,
1922 this function can simply return RETURN_SUCCESS.
1924 If ImageContext is NULL, then ASSERT().
1926 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1927 image to be unloaded.
1929 @retval RETURN_SUCCESS The PE/COFF image was unloaded successfully.
1933 PeCoffLoaderUnloadImage (
1934 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1938 // Applies additional environment specific actions to unload a
1939 // PE/COFF image if needed
1941 PeCoffLoaderUnloadImageExtraAction (ImageContext
);
1942 return RETURN_SUCCESS
;