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 - 2014, Intel Corporation. All rights reserved.<BR>
19 Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
20 This program and the accompanying materials
21 are licensed and made available under the terms and conditions of the BSD License
22 which accompanies this distribution. The full text of the license may be found at
23 http://opensource.org/licenses/bsd-license.php.
25 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
26 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
30 #include "BasePeCoffLibInternals.h"
33 Adjust some fields in section header for TE image.
35 @param SectionHeader Pointer to the section header.
36 @param TeStrippedOffset Size adjust for the TE image.
40 PeCoffLoaderAdjustOffsetForTeImage (
41 EFI_IMAGE_SECTION_HEADER
*SectionHeader
,
42 UINT32 TeStrippedOffset
45 SectionHeader
->VirtualAddress
-= TeStrippedOffset
;
46 SectionHeader
->PointerToRawData
-= TeStrippedOffset
;
50 Retrieves the magic value from the PE/COFF header.
52 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
54 @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32
55 @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+
59 PeCoffLoaderGetPeHeaderMagicValue (
60 IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
64 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
65 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
66 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
67 // then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
69 if (Hdr
.Pe32
->FileHeader
.Machine
== IMAGE_FILE_MACHINE_IA64
&& Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
70 return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
73 // Return the magic value from the PC/COFF Optional Header
75 return Hdr
.Pe32
->OptionalHeader
.Magic
;
80 Retrieves the PE or TE Header from a PE/COFF or TE image.
82 Caution: This function may receive untrusted input.
83 PE/COFF image is external input, so this routine will
84 also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
85 SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
87 @param ImageContext The context of the image being loaded.
88 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
90 @retval RETURN_SUCCESS The PE or TE Header is read.
91 @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.
95 PeCoffLoaderGetPeHeader (
96 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
97 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
100 RETURN_STATUS Status
;
101 EFI_IMAGE_DOS_HEADER DosHdr
;
105 UINT32 SectionHeaderOffset
;
107 UINT32 HeaderWithoutDataDir
;
109 UINTN NumberOfSections
;
110 EFI_IMAGE_SECTION_HEADER SectionHeader
;
113 // Read the DOS image header to check for its existence
115 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
117 Status
= ImageContext
->ImageRead (
118 ImageContext
->Handle
,
123 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
124 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
125 if (Size
!= ReadSize
) {
126 Status
= RETURN_UNSUPPORTED
;
131 ImageContext
->PeCoffHeaderOffset
= 0;
132 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
134 // DOS image header is present, so read the PE header after the DOS image
137 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
141 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
142 // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
143 // determines if this is a PE32 or PE32+ image. The magic is in the same
144 // location in both images.
146 Size
= sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
);
148 Status
= ImageContext
->ImageRead (
149 ImageContext
->Handle
,
150 ImageContext
->PeCoffHeaderOffset
,
154 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
155 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
156 if (Size
!= ReadSize
) {
157 Status
= RETURN_UNSUPPORTED
;
163 // Use Signature to figure out if we understand the image format
165 if (Hdr
.Te
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
166 ImageContext
->IsTeImage
= TRUE
;
167 ImageContext
->Machine
= Hdr
.Te
->Machine
;
168 ImageContext
->ImageType
= (UINT16
)(Hdr
.Te
->Subsystem
);
170 // For TeImage, SectionAlignment is undefined to be set to Zero
171 // ImageSize can be calculated.
173 ImageContext
->ImageSize
= 0;
174 ImageContext
->SectionAlignment
= 0;
175 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
)Hdr
.Te
->BaseOfCode
- (UINTN
)Hdr
.Te
->StrippedSize
;
178 // Check the StrippedSize.
180 if (sizeof (EFI_TE_IMAGE_HEADER
) >= (UINT32
)Hdr
.Te
->StrippedSize
) {
181 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
182 return RETURN_UNSUPPORTED
;
186 // Check the SizeOfHeaders field.
188 if (Hdr
.Te
->BaseOfCode
<= Hdr
.Te
->StrippedSize
) {
189 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
190 return RETURN_UNSUPPORTED
;
194 // Read last byte of Hdr.Te->SizeOfHeaders from the file.
198 Status
= ImageContext
->ImageRead (
199 ImageContext
->Handle
,
200 ImageContext
->SizeOfHeaders
- 1,
204 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
205 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
206 if (Size
!= ReadSize
) {
207 Status
= RETURN_UNSUPPORTED
;
213 // TE Image Data Directory Entry size is non-zero, but the Data Directory Virtual Address is zero.
214 // This case is not a valid TE image.
216 if ((Hdr
.Te
->DataDirectory
[0].Size
!= 0 && Hdr
.Te
->DataDirectory
[0].VirtualAddress
== 0) ||
217 (Hdr
.Te
->DataDirectory
[1].Size
!= 0 && Hdr
.Te
->DataDirectory
[1].VirtualAddress
== 0)) {
218 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
219 return RETURN_UNSUPPORTED
;
221 } else if (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
) {
222 ImageContext
->IsTeImage
= FALSE
;
223 ImageContext
->Machine
= Hdr
.Pe32
->FileHeader
.Machine
;
225 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
227 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
229 // 1. Check OptionalHeader.NumberOfRvaAndSizes filed.
231 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
< Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) {
232 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
233 return RETURN_UNSUPPORTED
;
237 // 2. Check the FileHeader.SizeOfOptionalHeader field.
238 // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
239 // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
241 HeaderWithoutDataDir
= sizeof (EFI_IMAGE_OPTIONAL_HEADER32
) - sizeof (EFI_IMAGE_DATA_DIRECTORY
) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
;
242 if (((UINT32
)Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
- HeaderWithoutDataDir
) !=
243 Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
* sizeof (EFI_IMAGE_DATA_DIRECTORY
)) {
244 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
245 return RETURN_UNSUPPORTED
;
248 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
250 // 3. Check the FileHeader.NumberOfSections field.
252 if (Hdr
.Pe32
->OptionalHeader
.SizeOfImage
<= SectionHeaderOffset
) {
253 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
254 return RETURN_UNSUPPORTED
;
256 if ((Hdr
.Pe32
->OptionalHeader
.SizeOfImage
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
<= Hdr
.Pe32
->FileHeader
.NumberOfSections
) {
257 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
258 return RETURN_UNSUPPORTED
;
262 // 4. Check the OptionalHeader.SizeOfHeaders field.
264 if (Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
<= SectionHeaderOffset
) {
265 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
266 return RETURN_UNSUPPORTED
;
268 if (Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
>= Hdr
.Pe32
->OptionalHeader
.SizeOfImage
) {
269 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
270 return RETURN_UNSUPPORTED
;
272 if ((Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
< (UINT32
)Hdr
.Pe32
->FileHeader
.NumberOfSections
) {
273 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
274 return RETURN_UNSUPPORTED
;
278 // 4.2 Read last byte of Hdr.Pe32.OptionalHeader.SizeOfHeaders from the file.
282 Status
= ImageContext
->ImageRead (
283 ImageContext
->Handle
,
284 Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- 1,
288 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
289 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
290 if (Size
!= ReadSize
) {
291 Status
= RETURN_UNSUPPORTED
;
297 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
298 // Read the last byte to make sure the data is in the image region.
299 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
301 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
< Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) {
302 if (Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
!= 0) {
304 // Check the member data to avoid overflow.
306 if ((UINT32
) (~0) - Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
<
307 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
) {
308 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
309 return RETURN_UNSUPPORTED
;
313 // Read last byte of section header from file
317 Status
= ImageContext
->ImageRead (
318 ImageContext
->Handle
,
319 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
+
320 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
- 1,
324 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
325 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
326 if (Size
!= ReadSize
) {
327 Status
= RETURN_UNSUPPORTED
;
337 ImageContext
->ImageType
= Hdr
.Pe32
->OptionalHeader
.Subsystem
;
338 ImageContext
->ImageSize
= (UINT64
)Hdr
.Pe32
->OptionalHeader
.SizeOfImage
;
339 ImageContext
->SectionAlignment
= Hdr
.Pe32
->OptionalHeader
.SectionAlignment
;
340 ImageContext
->SizeOfHeaders
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
;
342 } else if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
344 // 1. Check FileHeader.NumberOfRvaAndSizes filed.
346 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
< Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
347 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
348 return RETURN_UNSUPPORTED
;
351 // 2. Check the FileHeader.SizeOfOptionalHeader field.
352 // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
353 // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
355 HeaderWithoutDataDir
= sizeof (EFI_IMAGE_OPTIONAL_HEADER64
) - sizeof (EFI_IMAGE_DATA_DIRECTORY
) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
;
356 if (((UINT32
)Hdr
.Pe32Plus
->FileHeader
.SizeOfOptionalHeader
- HeaderWithoutDataDir
) !=
357 Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
* sizeof (EFI_IMAGE_DATA_DIRECTORY
)) {
358 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
359 return RETURN_UNSUPPORTED
;
362 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32Plus
->FileHeader
.SizeOfOptionalHeader
;
364 // 3. Check the FileHeader.NumberOfSections field.
366 if (Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
<= SectionHeaderOffset
) {
367 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
368 return RETURN_UNSUPPORTED
;
370 if ((Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
<= Hdr
.Pe32Plus
->FileHeader
.NumberOfSections
) {
371 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
372 return RETURN_UNSUPPORTED
;
376 // 4. Check the OptionalHeader.SizeOfHeaders field.
378 if (Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
<= SectionHeaderOffset
) {
379 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
380 return RETURN_UNSUPPORTED
;
382 if (Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
>= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
) {
383 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
384 return RETURN_UNSUPPORTED
;
386 if ((Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
< (UINT32
)Hdr
.Pe32Plus
->FileHeader
.NumberOfSections
) {
387 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
388 return RETURN_UNSUPPORTED
;
392 // 4.2 Read last byte of Hdr.Pe32Plus.OptionalHeader.SizeOfHeaders from the file.
396 Status
= ImageContext
->ImageRead (
397 ImageContext
->Handle
,
398 Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- 1,
402 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
403 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
404 if (Size
!= ReadSize
) {
405 Status
= RETURN_UNSUPPORTED
;
411 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
412 // Read the last byte to make sure the data is in the image region.
413 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
415 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
< Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
416 if (Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
!= 0) {
418 // Check the member data to avoid overflow.
420 if ((UINT32
) (~0) - Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
<
421 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
) {
422 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
423 return RETURN_UNSUPPORTED
;
427 // Read last byte of section header from file
431 Status
= ImageContext
->ImageRead (
432 ImageContext
->Handle
,
433 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
+
434 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
- 1,
438 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
439 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
440 if (Size
!= ReadSize
) {
441 Status
= RETURN_UNSUPPORTED
;
451 ImageContext
->ImageType
= Hdr
.Pe32Plus
->OptionalHeader
.Subsystem
;
452 ImageContext
->ImageSize
= (UINT64
) Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
;
453 ImageContext
->SectionAlignment
= Hdr
.Pe32Plus
->OptionalHeader
.SectionAlignment
;
454 ImageContext
->SizeOfHeaders
= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
;
456 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
457 return RETURN_UNSUPPORTED
;
460 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
461 return RETURN_UNSUPPORTED
;
464 if (!PeCoffLoaderImageFormatSupported (ImageContext
->Machine
)) {
466 // If the PE/COFF loader does not support the image type return
467 // unsupported. This library can support lots of types of images
468 // this does not mean the user of this library can call the entry
469 // point of the image.
471 return RETURN_UNSUPPORTED
;
475 // Check each section field.
477 if (ImageContext
->IsTeImage
) {
478 SectionHeaderOffset
= sizeof(EFI_TE_IMAGE_HEADER
);
479 NumberOfSections
= (UINTN
) (Hdr
.Te
->NumberOfSections
);
481 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
482 NumberOfSections
= (UINTN
) (Hdr
.Pe32
->FileHeader
.NumberOfSections
);
485 for (Index
= 0; Index
< NumberOfSections
; Index
++) {
487 // Read section header from file
489 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
491 Status
= ImageContext
->ImageRead (
492 ImageContext
->Handle
,
497 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
498 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
499 if (Size
!= ReadSize
) {
500 Status
= RETURN_UNSUPPORTED
;
506 // Adjust some field in Section Header for TE image.
508 if (ImageContext
->IsTeImage
) {
509 PeCoffLoaderAdjustOffsetForTeImage (&SectionHeader
, (UINT32
)Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
512 if (SectionHeader
.SizeOfRawData
> 0) {
514 // Section data should bigger than the Pe header.
516 if (SectionHeader
.VirtualAddress
< ImageContext
->SizeOfHeaders
||
517 SectionHeader
.PointerToRawData
< ImageContext
->SizeOfHeaders
) {
518 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
519 return RETURN_UNSUPPORTED
;
523 // Check the member data to avoid overflow.
525 if ((UINT32
) (~0) - SectionHeader
.PointerToRawData
< SectionHeader
.SizeOfRawData
) {
526 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
527 return RETURN_UNSUPPORTED
;
531 // Base on the ImageRead function to check the section data field.
532 // Read the last byte to make sure the data is in the image region.
536 Status
= ImageContext
->ImageRead (
537 ImageContext
->Handle
,
538 SectionHeader
.PointerToRawData
+ SectionHeader
.SizeOfRawData
- 1,
542 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
543 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
544 if (Size
!= ReadSize
) {
545 Status
= RETURN_UNSUPPORTED
;
552 // Check next section.
554 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
557 return RETURN_SUCCESS
;
562 Retrieves information about a PE/COFF image.
564 Computes the PeCoffHeaderOffset, IsTeImage, ImageType, ImageAddress, ImageSize,
565 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and
566 DebugDirectoryEntryRva fields of the ImageContext structure.
567 If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.
568 If the PE/COFF image accessed through the ImageRead service in the ImageContext
569 structure is not a supported PE/COFF image type, then return RETURN_UNSUPPORTED.
570 If any errors occur while computing the fields of ImageContext,
571 then the error status is returned in the ImageError field of ImageContext.
572 If the image is a TE image, then SectionAlignment is set to 0.
573 The ImageRead and Handle fields of ImageContext structure must be valid prior
574 to invoking this service.
576 Caution: This function may receive untrusted input.
577 PE/COFF image is external input, so this routine will
578 also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
579 SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
581 @param ImageContext The pointer to the image context structure that describes the PE/COFF
582 image that needs to be examined by this function.
584 @retval RETURN_SUCCESS The information on the PE/COFF image was collected.
585 @retval RETURN_INVALID_PARAMETER ImageContext is NULL.
586 @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.
591 PeCoffLoaderGetImageInfo (
592 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
595 RETURN_STATUS Status
;
596 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
597 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
598 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
602 UINTN DebugDirectoryEntryRva
;
603 UINTN DebugDirectoryEntryFileOffset
;
604 UINTN SectionHeaderOffset
;
605 EFI_IMAGE_SECTION_HEADER SectionHeader
;
606 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
607 UINT32 NumberOfRvaAndSizes
;
609 UINT32 TeStrippedOffset
;
611 if (ImageContext
== NULL
) {
612 return RETURN_INVALID_PARAMETER
;
617 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
619 Hdr
.Union
= &HdrData
;
620 Status
= PeCoffLoaderGetPeHeader (ImageContext
, Hdr
);
621 if (RETURN_ERROR (Status
)) {
625 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
628 // Retrieve the base address of the image
630 if (!(ImageContext
->IsTeImage
)) {
631 TeStrippedOffset
= 0;
632 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
636 ImageContext
->ImageAddress
= Hdr
.Pe32
->OptionalHeader
.ImageBase
;
641 ImageContext
->ImageAddress
= Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
644 TeStrippedOffset
= (UINT32
)Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
645 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
)(Hdr
.Te
->ImageBase
+ TeStrippedOffset
);
649 // Initialize the alternate destination address to 0 indicating that it
650 // should not be used.
652 ImageContext
->DestinationAddress
= 0;
655 // Initialize the debug codeview pointer.
657 ImageContext
->DebugDirectoryEntryRva
= 0;
658 ImageContext
->CodeView
= NULL
;
659 ImageContext
->PdbPointer
= NULL
;
662 // Three cases with regards to relocations:
663 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
664 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
665 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
666 // has no base relocs to apply
667 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
669 // Look at the file header to determine if relocations have been stripped, and
670 // save this information in the image context for later use.
672 if ((!(ImageContext
->IsTeImage
)) && ((Hdr
.Pe32
->FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
673 ImageContext
->RelocationsStripped
= TRUE
;
674 } else if ((ImageContext
->IsTeImage
) && (Hdr
.Te
->DataDirectory
[0].Size
== 0) && (Hdr
.Te
->DataDirectory
[0].VirtualAddress
== 0)) {
675 ImageContext
->RelocationsStripped
= TRUE
;
677 ImageContext
->RelocationsStripped
= FALSE
;
680 if (!(ImageContext
->IsTeImage
)) {
681 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
685 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
686 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
691 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
692 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
695 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
697 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
700 // Determine the file offset of the debug directory... This means we walk
701 // the sections to find which section contains the RVA of the debug
704 DebugDirectoryEntryFileOffset
= 0;
706 SectionHeaderOffset
= (UINTN
)(
707 ImageContext
->PeCoffHeaderOffset
+
709 sizeof (EFI_IMAGE_FILE_HEADER
) +
710 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
713 for (Index
= 0; Index
< Hdr
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
715 // Read section header from file
717 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
719 Status
= ImageContext
->ImageRead (
720 ImageContext
->Handle
,
725 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
726 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
727 if (Size
!= ReadSize
) {
728 Status
= RETURN_UNSUPPORTED
;
733 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
734 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
736 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
740 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
743 if (DebugDirectoryEntryFileOffset
!= 0) {
744 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
746 // Read next debug directory entry
748 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
750 Status
= ImageContext
->ImageRead (
751 ImageContext
->Handle
,
752 DebugDirectoryEntryFileOffset
+ Index
,
756 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
757 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
758 if (Size
!= ReadSize
) {
759 Status
= RETURN_UNSUPPORTED
;
765 // From PeCoff spec, when DebugEntry.RVA == 0 means this debug info will not load into memory.
766 // Here we will always load EFI_IMAGE_DEBUG_TYPE_CODEVIEW type debug info. so need adjust the
767 // ImageContext->ImageSize when DebugEntry.RVA == 0.
769 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
770 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
771 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
772 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
775 return RETURN_SUCCESS
;
782 DebugDirectoryEntry
= &Hdr
.Te
->DataDirectory
[1];
783 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
784 SectionHeaderOffset
= (UINTN
)(sizeof (EFI_TE_IMAGE_HEADER
));
786 DebugDirectoryEntryFileOffset
= 0;
788 for (Index
= 0; Index
< Hdr
.Te
->NumberOfSections
;) {
790 // Read section header from file
792 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
794 Status
= ImageContext
->ImageRead (
795 ImageContext
->Handle
,
800 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
801 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
802 if (Size
!= ReadSize
) {
803 Status
= RETURN_UNSUPPORTED
;
808 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
809 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
810 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
811 SectionHeader
.VirtualAddress
+
812 SectionHeader
.PointerToRawData
-
816 // File offset of the debug directory was found, if this is not the last
817 // section, then skip to the last section for calculating the image size.
819 if (Index
< (UINTN
) Hdr
.Te
->NumberOfSections
- 1) {
820 SectionHeaderOffset
+= (Hdr
.Te
->NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
821 Index
= Hdr
.Te
->NumberOfSections
- 1;
827 // In Te image header there is not a field to describe the ImageSize.
828 // Actually, the ImageSize equals the RVA plus the VirtualSize of
829 // the last section mapped into memory (Must be rounded up to
830 // a multiple of Section Alignment). Per the PE/COFF specification, the
831 // section headers in the Section Table must appear in order of the RVA
832 // values for the corresponding sections. So the ImageSize can be determined
833 // by the RVA and the VirtualSize of the last section header in the
836 if ((++Index
) == (UINTN
)Hdr
.Te
->NumberOfSections
) {
837 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) - TeStrippedOffset
;
840 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
843 if (DebugDirectoryEntryFileOffset
!= 0) {
844 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
846 // Read next debug directory entry
848 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
850 Status
= ImageContext
->ImageRead (
851 ImageContext
->Handle
,
852 DebugDirectoryEntryFileOffset
+ Index
,
856 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
857 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
858 if (Size
!= ReadSize
) {
859 Status
= RETURN_UNSUPPORTED
;
864 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
865 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
866 return RETURN_SUCCESS
;
872 return RETURN_SUCCESS
;
877 Converts an image address to the loaded address.
879 @param ImageContext The context of the image being loaded.
880 @param Address The address to be converted to the loaded address.
881 @param TeStrippedOffset Stripped offset for TE image.
883 @return The converted address or NULL if the address can not be converted.
887 PeCoffLoaderImageAddress (
888 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
890 IN UINTN TeStrippedOffset
894 // Make sure that Address and ImageSize is correct for the loaded image.
896 if (Address
>= ImageContext
->ImageSize
+ TeStrippedOffset
) {
897 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
901 return (CHAR8
*)((UINTN
) ImageContext
->ImageAddress
+ Address
- TeStrippedOffset
);
905 Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().
907 If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of
908 ImageContext as the relocation base address. Otherwise, use the DestinationAddress field
909 of ImageContext as the relocation base address. The caller must allocate the relocation
910 fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.
912 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress,
913 ImageSize, DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders,
914 DebugDirectoryEntryRva, EntryPoint, FixupDataSize, CodeView, PdbPointer, and FixupData of
915 the ImageContext structure must be valid prior to invoking this service.
917 If ImageContext is NULL, then ASSERT().
919 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
920 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
921 prior to transferring control to a PE/COFF image that is loaded using this library.
923 @param ImageContext The pointer to the image context structure that describes the PE/COFF
924 image that is being relocated.
926 @retval RETURN_SUCCESS The PE/COFF image was relocated.
927 Extended status information is in the ImageError field of ImageContext.
928 @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.
929 Extended status information is in the ImageError field of ImageContext.
930 @retval RETURN_UNSUPPORTED A relocation record type is not supported.
931 Extended status information is in the ImageError field of ImageContext.
936 PeCoffLoaderRelocateImage (
937 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
940 RETURN_STATUS Status
;
941 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
942 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
944 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
945 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
954 PHYSICAL_ADDRESS BaseAddress
;
955 UINT32 NumberOfRvaAndSizes
;
957 UINT32 TeStrippedOffset
;
959 ASSERT (ImageContext
!= NULL
);
964 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
967 // If there are no relocation entries, then we are done
969 if (ImageContext
->RelocationsStripped
) {
970 // Applies additional environment specific actions to relocate fixups
971 // to a PE/COFF image if needed
972 PeCoffLoaderRelocateImageExtraAction (ImageContext
);
973 return RETURN_SUCCESS
;
977 // If the destination address is not 0, use that rather than the
978 // image address as the relocation target.
980 if (ImageContext
->DestinationAddress
!= 0) {
981 BaseAddress
= ImageContext
->DestinationAddress
;
983 BaseAddress
= ImageContext
->ImageAddress
;
986 if (!(ImageContext
->IsTeImage
)) {
987 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
988 TeStrippedOffset
= 0;
989 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
991 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
995 Adjust
= (UINT64
)BaseAddress
- Hdr
.Pe32
->OptionalHeader
.ImageBase
;
997 Hdr
.Pe32
->OptionalHeader
.ImageBase
= (UINT32
)BaseAddress
;
1000 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1001 RelocDir
= &Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1006 Adjust
= (UINT64
) BaseAddress
- Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
1008 Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
= (UINT64
)BaseAddress
;
1011 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1012 RelocDir
= &Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1016 // Find the relocation block
1017 // Per the PE/COFF spec, you can't assume that a given data directory
1018 // is present in the image. You have to check the NumberOfRvaAndSizes in
1019 // the optional header to verify a desired directory entry is there.
1021 if ((NumberOfRvaAndSizes
< EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
)) {
1025 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
1026 TeStrippedOffset
= (UINT32
)Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
1027 Adjust
= (UINT64
) (BaseAddress
- (Hdr
.Te
->ImageBase
+ TeStrippedOffset
));
1029 Hdr
.Te
->ImageBase
= (UINT64
) (BaseAddress
- TeStrippedOffset
);
1033 // Find the relocation block
1035 RelocDir
= &Hdr
.Te
->DataDirectory
[0];
1038 if ((RelocDir
!= NULL
) && (RelocDir
->Size
> 0)) {
1039 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
, TeStrippedOffset
);
1040 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) PeCoffLoaderImageAddress (ImageContext
,
1041 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1,
1044 if (RelocBase
== NULL
|| RelocBaseEnd
== NULL
) {
1045 return RETURN_LOAD_ERROR
;
1049 // Set base and end to bypass processing below.
1051 RelocBase
= RelocBaseEnd
= NULL
;
1055 // If Adjust is not zero, then apply fix ups to the image
1059 // Run the relocation information and apply the fixups
1061 FixupData
= ImageContext
->FixupData
;
1062 while (RelocBase
< RelocBaseEnd
) {
1064 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
1066 // Add check for RelocBase->SizeOfBlock field.
1068 if ((RelocBase
->SizeOfBlock
== 0) || (RelocBase
->SizeOfBlock
> RelocDir
->Size
)) {
1069 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1070 return RETURN_LOAD_ERROR
;
1073 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
1074 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
, TeStrippedOffset
);
1075 if (FixupBase
== NULL
) {
1076 return RETURN_LOAD_ERROR
;
1080 // Run this relocation record
1082 while (Reloc
< RelocEnd
) {
1084 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
1085 switch ((*Reloc
) >> 12) {
1086 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
1089 case EFI_IMAGE_REL_BASED_HIGH
:
1090 Fixup16
= (UINT16
*) Fixup
;
1091 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
1092 if (FixupData
!= NULL
) {
1093 *(UINT16
*) FixupData
= *Fixup16
;
1094 FixupData
= FixupData
+ sizeof (UINT16
);
1098 case EFI_IMAGE_REL_BASED_LOW
:
1099 Fixup16
= (UINT16
*) Fixup
;
1100 *Fixup16
= (UINT16
) (*Fixup16
+ (UINT16
) Adjust
);
1101 if (FixupData
!= NULL
) {
1102 *(UINT16
*) FixupData
= *Fixup16
;
1103 FixupData
= FixupData
+ sizeof (UINT16
);
1107 case EFI_IMAGE_REL_BASED_HIGHLOW
:
1108 Fixup32
= (UINT32
*) Fixup
;
1109 *Fixup32
= *Fixup32
+ (UINT32
) Adjust
;
1110 if (FixupData
!= NULL
) {
1111 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
1112 *(UINT32
*)FixupData
= *Fixup32
;
1113 FixupData
= FixupData
+ sizeof (UINT32
);
1117 case EFI_IMAGE_REL_BASED_DIR64
:
1118 Fixup64
= (UINT64
*) Fixup
;
1119 *Fixup64
= *Fixup64
+ (UINT64
) Adjust
;
1120 if (FixupData
!= NULL
) {
1121 FixupData
= ALIGN_POINTER (FixupData
, sizeof(UINT64
));
1122 *(UINT64
*)(FixupData
) = *Fixup64
;
1123 FixupData
= FixupData
+ sizeof(UINT64
);
1129 // The common code does not handle some of the stranger IPF relocations
1130 // PeCoffLoaderRelocateImageEx () adds support for these complex fixups
1131 // on IPF and is a No-Op on other architectures.
1133 Status
= PeCoffLoaderRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
1134 if (RETURN_ERROR (Status
)) {
1135 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1141 // Next relocation record
1149 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
1153 // Adjust the EntryPoint to match the linked-to address
1155 if (ImageContext
->DestinationAddress
!= 0) {
1156 ImageContext
->EntryPoint
-= (UINT64
) ImageContext
->ImageAddress
;
1157 ImageContext
->EntryPoint
+= (UINT64
) ImageContext
->DestinationAddress
;
1161 // Applies additional environment specific actions to relocate fixups
1162 // to a PE/COFF image if needed
1163 PeCoffLoaderRelocateImageExtraAction (ImageContext
);
1165 return RETURN_SUCCESS
;
1169 Loads a PE/COFF image into memory.
1171 Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
1172 specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate
1173 the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
1174 The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.
1175 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress, ImageSize,
1176 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
1177 fields of the ImageContext structure must be valid prior to invoking this service.
1179 If ImageContext is NULL, then ASSERT().
1181 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1182 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1183 prior to transferring control to a PE/COFF image that is loaded using this library.
1185 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1186 image that is being loaded.
1188 @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by
1189 the ImageAddress and ImageSize fields of ImageContext.
1190 Extended status information is in the ImageError field of ImageContext.
1191 @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.
1192 Extended status information is in the ImageError field of ImageContext.
1193 @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.
1194 Extended status information is in the ImageError field of ImageContext.
1195 @retval RETURN_INVALID_PARAMETER The image address is invalid.
1196 Extended status information is in the ImageError field of ImageContext.
1201 PeCoffLoaderLoadImage (
1202 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1205 RETURN_STATUS Status
;
1206 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1207 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
1208 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
1209 EFI_IMAGE_SECTION_HEADER
*Section
;
1210 UINTN NumberOfSections
;
1214 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
1215 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
1217 UINT32 TempDebugEntryRva
;
1218 UINT32 NumberOfRvaAndSizes
;
1220 EFI_IMAGE_RESOURCE_DIRECTORY
*ResourceDirectory
;
1221 EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*ResourceDirectoryEntry
;
1222 EFI_IMAGE_RESOURCE_DIRECTORY_STRING
*ResourceDirectoryString
;
1223 EFI_IMAGE_RESOURCE_DATA_ENTRY
*ResourceDataEntry
;
1226 UINT32 TeStrippedOffset
;
1228 ASSERT (ImageContext
!= NULL
);
1233 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
1236 // Copy the provided context information into our local version, get what we
1237 // can from the original image, and then use that to make sure everything
1240 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
1242 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
1243 if (RETURN_ERROR (Status
)) {
1248 // Make sure there is enough allocated space for the image being loaded
1250 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
1251 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
1252 return RETURN_BUFFER_TOO_SMALL
;
1254 if (ImageContext
->ImageAddress
== 0) {
1256 // Image cannot be loaded into 0 address.
1258 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1259 return RETURN_INVALID_PARAMETER
;
1262 // If there's no relocations, then make sure it's not a runtime driver,
1263 // and that it's being loaded at the linked address.
1265 if (CheckContext
.RelocationsStripped
) {
1267 // If the image does not contain relocations and it is a runtime driver
1268 // then return an error.
1270 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
1271 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
1272 return RETURN_LOAD_ERROR
;
1275 // If the image does not contain relocations, and the requested load address
1276 // is not the linked address, then return an error.
1278 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
1279 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1280 return RETURN_INVALID_PARAMETER
;
1284 // Make sure the allocated space has the proper section alignment
1286 if (!(ImageContext
->IsTeImage
)) {
1287 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
1288 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
1289 return RETURN_INVALID_PARAMETER
;
1293 // Read the entire PE/COFF or TE header into memory
1295 if (!(ImageContext
->IsTeImage
)) {
1296 Status
= ImageContext
->ImageRead (
1297 ImageContext
->Handle
,
1299 &ImageContext
->SizeOfHeaders
,
1300 (VOID
*) (UINTN
) ImageContext
->ImageAddress
1303 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
1305 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
1306 (UINTN
)ImageContext
->ImageAddress
+
1307 ImageContext
->PeCoffHeaderOffset
+
1309 sizeof(EFI_IMAGE_FILE_HEADER
) +
1310 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
1312 NumberOfSections
= (UINTN
) (Hdr
.Pe32
->FileHeader
.NumberOfSections
);
1313 TeStrippedOffset
= 0;
1315 Status
= ImageContext
->ImageRead (
1316 ImageContext
->Handle
,
1318 &ImageContext
->SizeOfHeaders
,
1319 (void *)(UINTN
)ImageContext
->ImageAddress
1322 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
1323 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
1324 (UINTN
)ImageContext
->ImageAddress
+
1325 sizeof(EFI_TE_IMAGE_HEADER
)
1327 NumberOfSections
= (UINTN
) (Hdr
.Te
->NumberOfSections
);
1328 TeStrippedOffset
= (UINT32
) Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
1331 if (RETURN_ERROR (Status
)) {
1332 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1333 return RETURN_LOAD_ERROR
;
1337 // Load each section of the image
1339 Section
= FirstSection
;
1340 for (Index
= 0; Index
< NumberOfSections
; Index
++) {
1344 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
1345 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
1346 Size
= (UINTN
) Section
->SizeOfRawData
;
1350 // Compute sections address
1352 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
, TeStrippedOffset
);
1353 End
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1, TeStrippedOffset
);
1356 // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.
1358 if ((Size
> 0) && ((Base
== NULL
) || (End
== NULL
))) {
1359 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
1360 return RETURN_LOAD_ERROR
;
1363 if (Section
->SizeOfRawData
> 0) {
1364 Status
= ImageContext
->ImageRead (
1365 ImageContext
->Handle
,
1366 Section
->PointerToRawData
- TeStrippedOffset
,
1370 if (RETURN_ERROR (Status
)) {
1371 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1377 // If raw size is less then virtual size, zero fill the remaining
1380 if (Size
< Section
->Misc
.VirtualSize
) {
1381 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
1391 // Get image's entry point
1393 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
1394 if (!(ImageContext
->IsTeImage
)) {
1396 // Sizes of AddressOfEntryPoint are different so we need to do this safely
1398 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1402 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1404 (UINTN
)Hdr
.Pe32
->OptionalHeader
.AddressOfEntryPoint
,
1411 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1413 (UINTN
)Hdr
.Pe32Plus
->OptionalHeader
.AddressOfEntryPoint
,
1418 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1420 (UINTN
)Hdr
.Te
->AddressOfEntryPoint
,
1426 // Determine the size of the fixup data
1428 // Per the PE/COFF spec, you can't assume that a given data directory
1429 // is present in the image. You have to check the NumberOfRvaAndSizes in
1430 // the optional header to verify a desired directory entry is there.
1432 if (!(ImageContext
->IsTeImage
)) {
1433 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1437 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1438 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1443 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1444 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1447 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1448 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1450 ImageContext
->FixupDataSize
= 0;
1453 DirectoryEntry
= &Hdr
.Te
->DataDirectory
[0];
1454 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1457 // Consumer must allocate a buffer for the relocation fixup log.
1458 // Only used for runtime drivers.
1460 ImageContext
->FixupData
= NULL
;
1463 // Load the Codeview information if present
1465 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
1466 DebugEntry
= PeCoffLoaderImageAddress (
1468 ImageContext
->DebugDirectoryEntryRva
,
1471 if (DebugEntry
== NULL
) {
1472 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1473 return RETURN_LOAD_ERROR
;
1476 TempDebugEntryRva
= DebugEntry
->RVA
;
1477 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
1479 if ((UINTN
)Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
1480 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
1482 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
1486 if (TempDebugEntryRva
!= 0) {
1487 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
, TeStrippedOffset
);
1488 if (ImageContext
->CodeView
== NULL
) {
1489 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1490 return RETURN_LOAD_ERROR
;
1493 if (DebugEntry
->RVA
== 0) {
1494 Size
= DebugEntry
->SizeOfData
;
1495 Status
= ImageContext
->ImageRead (
1496 ImageContext
->Handle
,
1497 DebugEntry
->FileOffset
- TeStrippedOffset
,
1499 ImageContext
->CodeView
1502 // Should we apply fix up to this field according to the size difference between PE and TE?
1503 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1504 // in original PE image.
1507 if (RETURN_ERROR (Status
)) {
1508 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1509 return RETURN_LOAD_ERROR
;
1512 DebugEntry
->RVA
= TempDebugEntryRva
;
1515 switch (*(UINT32
*) ImageContext
->CodeView
) {
1516 case CODEVIEW_SIGNATURE_NB10
:
1517 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
)) {
1518 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1519 return RETURN_UNSUPPORTED
;
1521 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1524 case CODEVIEW_SIGNATURE_RSDS
:
1525 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
)) {
1526 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1527 return RETURN_UNSUPPORTED
;
1529 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
1532 case CODEVIEW_SIGNATURE_MTOC
:
1533 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
)) {
1534 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1535 return RETURN_UNSUPPORTED
;
1537 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
);
1547 // Get Image's HII resource section
1549 ImageContext
->HiiResourceData
= 0;
1550 if (!(ImageContext
->IsTeImage
)) {
1551 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1555 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1556 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
];
1561 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1562 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
];
1565 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
&& DirectoryEntry
->Size
!= 0) {
1566 Base
= PeCoffLoaderImageAddress (ImageContext
, DirectoryEntry
->VirtualAddress
, 0);
1568 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) Base
;
1569 Offset
= sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) *
1570 (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1571 if (Offset
> DirectoryEntry
->Size
) {
1572 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1573 return RETURN_UNSUPPORTED
;
1575 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1577 for (Index
= 0; Index
< ResourceDirectory
->NumberOfNamedEntries
; Index
++) {
1578 if (ResourceDirectoryEntry
->u1
.s
.NameIsString
) {
1580 // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.
1582 if (ResourceDirectoryEntry
->u1
.s
.NameOffset
>= DirectoryEntry
->Size
) {
1583 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1584 return RETURN_UNSUPPORTED
;
1586 ResourceDirectoryString
= (EFI_IMAGE_RESOURCE_DIRECTORY_STRING
*) (Base
+ ResourceDirectoryEntry
->u1
.s
.NameOffset
);
1587 String
= &ResourceDirectoryString
->String
[0];
1589 if (ResourceDirectoryString
->Length
== 3 &&
1590 String
[0] == L
'H' &&
1591 String
[1] == L
'I' &&
1592 String
[2] == L
'I') {
1594 // Resource Type "HII" found
1596 if (ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1598 // Move to next level - resource Name
1600 if (ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
>= DirectoryEntry
->Size
) {
1601 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1602 return RETURN_UNSUPPORTED
;
1604 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) (Base
+ ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
);
1605 Offset
= ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
+ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) +
1606 sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) * (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1607 if (Offset
> DirectoryEntry
->Size
) {
1608 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1609 return RETURN_UNSUPPORTED
;
1611 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1613 if (ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1615 // Move to next level - resource Language
1617 if (ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
>= DirectoryEntry
->Size
) {
1618 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1619 return RETURN_UNSUPPORTED
;
1621 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) (Base
+ ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
);
1622 Offset
= ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
+ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) +
1623 sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) * (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1624 if (Offset
> DirectoryEntry
->Size
) {
1625 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1626 return RETURN_UNSUPPORTED
;
1628 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1633 // Now it ought to be resource Data
1635 if (!ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1636 if (ResourceDirectoryEntry
->u2
.OffsetToData
>= DirectoryEntry
->Size
) {
1637 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1638 return RETURN_UNSUPPORTED
;
1640 ResourceDataEntry
= (EFI_IMAGE_RESOURCE_DATA_ENTRY
*) (Base
+ ResourceDirectoryEntry
->u2
.OffsetToData
);
1641 ImageContext
->HiiResourceData
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (ImageContext
, ResourceDataEntry
->OffsetToData
, 0);
1646 ResourceDirectoryEntry
++;
1657 Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI
1660 This function reapplies relocation fixups to the PE/COFF image specified by ImageBase
1661 and ImageSize so the image will execute correctly when the PE/COFF image is mapped
1662 to the address specified by VirtualImageBase. RelocationData must be identical
1663 to the FiuxupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure
1664 after this PE/COFF image was relocated with PeCoffLoaderRelocateImage().
1666 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1667 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1668 prior to transferring control to a PE/COFF image that is loaded using this library.
1670 @param ImageBase The base address of a PE/COFF image that has been loaded
1671 and relocated into system memory.
1672 @param VirtImageBase The request virtual address that the PE/COFF image is to
1674 @param ImageSize The size, in bytes, of the PE/COFF image.
1675 @param RelocationData A pointer to the relocation data that was collected when the PE/COFF
1676 image was relocated using PeCoffLoaderRelocateImage().
1681 PeCoffLoaderRelocateImageForRuntime (
1682 IN PHYSICAL_ADDRESS ImageBase
,
1683 IN PHYSICAL_ADDRESS VirtImageBase
,
1685 IN VOID
*RelocationData
1690 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1691 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1692 UINT32 NumberOfRvaAndSizes
;
1693 EFI_IMAGE_DATA_DIRECTORY
*DataDirectory
;
1694 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
1695 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
1696 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
1706 RETURN_STATUS Status
;
1709 OldBase
= (CHAR8
*)((UINTN
)ImageBase
);
1710 NewBase
= (CHAR8
*)((UINTN
)VirtImageBase
);
1711 Adjust
= (UINTN
) NewBase
- (UINTN
) OldBase
;
1714 // Find the image's relocate dir info
1716 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)OldBase
;
1717 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
1719 // Valid DOS header so get address of PE header
1721 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)(((CHAR8
*)DosHdr
) + DosHdr
->e_lfanew
);
1724 // No Dos header so assume image starts with PE header.
1726 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)OldBase
;
1729 if (Hdr
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
1731 // Not a valid PE image so Exit
1736 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
1738 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1742 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1743 DataDirectory
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[0]);
1748 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1749 DataDirectory
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[0]);
1753 // Find the relocation block
1755 // Per the PE/COFF spec, you can't assume that a given data directory
1756 // is present in the image. You have to check the NumberOfRvaAndSizes in
1757 // the optional header to verify a desired directory entry is there.
1759 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1760 RelocDir
= DataDirectory
+ EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
;
1761 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(ImageBase
+ RelocDir
->VirtualAddress
);
1762 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(ImageBase
+ RelocDir
->VirtualAddress
+ RelocDir
->Size
);
1765 // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.
1772 // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.
1774 ASSERT (RelocBase
!= NULL
&& RelocBaseEnd
!= NULL
);
1777 // Run the whole relocation block. And re-fixup data that has not been
1778 // modified. The FixupData is used to see if the image has been modified
1779 // since it was relocated. This is so data sections that have been updated
1780 // by code will not be fixed up, since that would set them back to
1783 FixupData
= RelocationData
;
1784 while (RelocBase
< RelocBaseEnd
) {
1786 // Add check for RelocBase->SizeOfBlock field.
1788 if ((RelocBase
->SizeOfBlock
== 0) || (RelocBase
->SizeOfBlock
> RelocDir
->Size
)) {
1790 // Data invalid, cannot continue to relocate the image, just return.
1795 Reloc
= (UINT16
*) ((UINT8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
1796 RelocEnd
= (UINT16
*) ((UINT8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
1797 FixupBase
= (CHAR8
*) ((UINTN
)ImageBase
) + RelocBase
->VirtualAddress
;
1800 // Run this relocation record
1802 while (Reloc
< RelocEnd
) {
1804 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
1805 switch ((*Reloc
) >> 12) {
1807 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
1810 case EFI_IMAGE_REL_BASED_HIGH
:
1811 Fixup16
= (UINT16
*) Fixup
;
1812 if (*(UINT16
*) FixupData
== *Fixup16
) {
1813 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
1816 FixupData
= FixupData
+ sizeof (UINT16
);
1819 case EFI_IMAGE_REL_BASED_LOW
:
1820 Fixup16
= (UINT16
*) Fixup
;
1821 if (*(UINT16
*) FixupData
== *Fixup16
) {
1822 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) Adjust
& 0xffff));
1825 FixupData
= FixupData
+ sizeof (UINT16
);
1828 case EFI_IMAGE_REL_BASED_HIGHLOW
:
1829 Fixup32
= (UINT32
*) Fixup
;
1830 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
1831 if (*(UINT32
*) FixupData
== *Fixup32
) {
1832 *Fixup32
= *Fixup32
+ (UINT32
) Adjust
;
1835 FixupData
= FixupData
+ sizeof (UINT32
);
1838 case EFI_IMAGE_REL_BASED_DIR64
:
1839 Fixup64
= (UINT64
*)Fixup
;
1840 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT64
));
1841 if (*(UINT64
*) FixupData
== *Fixup64
) {
1842 *Fixup64
= *Fixup64
+ (UINT64
)Adjust
;
1845 FixupData
= FixupData
+ sizeof (UINT64
);
1850 // Only Itanium requires ConvertPeImage_Ex
1852 Status
= PeHotRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
1853 if (RETURN_ERROR (Status
)) {
1858 // Next relocation record
1865 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
1871 Reads contents of a PE/COFF image from a buffer in system memory.
1873 This is the default implementation of a PE_COFF_LOADER_READ_FILE function
1874 that assumes FileHandle pointer to the beginning of a PE/COFF image.
1875 This function reads contents of the PE/COFF image that starts at the system memory
1876 address specified by FileHandle. The read operation copies ReadSize bytes from the
1877 PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer.
1878 The size of the buffer actually read is returned in ReadSize.
1880 The caller must make sure the FileOffset and ReadSize within the file scope.
1882 If FileHandle is NULL, then ASSERT().
1883 If ReadSize is NULL, then ASSERT().
1884 If Buffer is NULL, then ASSERT().
1886 @param FileHandle The pointer to base of the input stream
1887 @param FileOffset Offset into the PE/COFF image to begin the read operation.
1888 @param ReadSize On input, the size in bytes of the requested read operation.
1889 On output, the number of bytes actually read.
1890 @param Buffer Output buffer that contains the data read from the PE/COFF image.
1892 @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into
1897 PeCoffLoaderImageReadFromMemory (
1898 IN VOID
*FileHandle
,
1899 IN UINTN FileOffset
,
1900 IN OUT UINTN
*ReadSize
,
1904 ASSERT (ReadSize
!= NULL
);
1905 ASSERT (FileHandle
!= NULL
);
1906 ASSERT (Buffer
!= NULL
);
1908 CopyMem (Buffer
, ((UINT8
*)FileHandle
) + FileOffset
, *ReadSize
);
1909 return RETURN_SUCCESS
;
1913 Unloads a loaded PE/COFF image from memory and releases its taken resource.
1914 Releases any environment specific resources that were allocated when the image
1915 specified by ImageContext was loaded using PeCoffLoaderLoadImage().
1917 For NT32 emulator, the PE/COFF image loaded by system needs to release.
1918 For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded,
1919 this function can simply return RETURN_SUCCESS.
1921 If ImageContext is NULL, then ASSERT().
1923 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1924 image to be unloaded.
1926 @retval RETURN_SUCCESS The PE/COFF image was unloaded successfully.
1930 PeCoffLoaderUnloadImage (
1931 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1935 // Applies additional environment specific actions to unload a
1936 // PE/COFF image if needed
1938 PeCoffLoaderUnloadImageExtraAction (ImageContext
);
1939 return RETURN_SUCCESS
;