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 - 2012, 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
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
<= Hdr
.Pe32
->FileHeader
.NumberOfSections
) {
253 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
254 return RETURN_UNSUPPORTED
;
258 // 4. Check the OptionalHeader.SizeOfHeaders field.
260 if ((Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
< (UINT32
)Hdr
.Pe32
->FileHeader
.NumberOfSections
) {
261 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
262 return RETURN_UNSUPPORTED
;
266 // 4.2 Read last byte of Hdr.Pe32.OptionalHeader.SizeOfHeaders from the file.
270 Status
= ImageContext
->ImageRead (
271 ImageContext
->Handle
,
272 Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- 1,
276 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
277 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
278 if (Size
!= ReadSize
) {
279 Status
= RETURN_UNSUPPORTED
;
285 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
286 // Read the last byte to make sure the data is in the image region.
287 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
289 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
< Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) {
290 if (Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
!= 0) {
292 // Check the member data to avoid overflow.
294 if ((UINT32
) (~0) - Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
<
295 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
) {
296 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
297 return RETURN_UNSUPPORTED
;
301 // Read last byte of section header from file
305 Status
= ImageContext
->ImageRead (
306 ImageContext
->Handle
,
307 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
+
308 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
- 1,
312 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
313 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
314 if (Size
!= ReadSize
) {
315 Status
= RETURN_UNSUPPORTED
;
325 ImageContext
->ImageType
= Hdr
.Pe32
->OptionalHeader
.Subsystem
;
326 ImageContext
->ImageSize
= (UINT64
)Hdr
.Pe32
->OptionalHeader
.SizeOfImage
;
327 ImageContext
->SectionAlignment
= Hdr
.Pe32
->OptionalHeader
.SectionAlignment
;
328 ImageContext
->SizeOfHeaders
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
;
330 } else if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
332 // 1. Check FileHeader.NumberOfRvaAndSizes filed.
334 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
< Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
335 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
336 return RETURN_UNSUPPORTED
;
339 // 2. Check the FileHeader.SizeOfOptionalHeader field.
340 // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
341 // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
343 HeaderWithoutDataDir
= sizeof (EFI_IMAGE_OPTIONAL_HEADER64
) - sizeof (EFI_IMAGE_DATA_DIRECTORY
) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
;
344 if (((UINT32
)Hdr
.Pe32Plus
->FileHeader
.SizeOfOptionalHeader
- HeaderWithoutDataDir
) !=
345 Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
* sizeof (EFI_IMAGE_DATA_DIRECTORY
)) {
346 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
347 return RETURN_UNSUPPORTED
;
350 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32Plus
->FileHeader
.SizeOfOptionalHeader
;
352 // 3. Check the FileHeader.NumberOfSections field.
354 if ((Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
<= Hdr
.Pe32Plus
->FileHeader
.NumberOfSections
) {
355 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
356 return RETURN_UNSUPPORTED
;
360 // 4. Check the OptionalHeader.SizeOfHeaders field.
362 if ((Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
< (UINT32
)Hdr
.Pe32Plus
->FileHeader
.NumberOfSections
) {
363 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
364 return RETURN_UNSUPPORTED
;
368 // 4.2 Read last byte of Hdr.Pe32Plus.OptionalHeader.SizeOfHeaders from the file.
372 Status
= ImageContext
->ImageRead (
373 ImageContext
->Handle
,
374 Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- 1,
378 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
379 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
380 if (Size
!= ReadSize
) {
381 Status
= RETURN_UNSUPPORTED
;
387 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
388 // Read the last byte to make sure the data is in the image region.
389 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
391 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
< Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
392 if (Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
!= 0) {
394 // Check the member data to avoid overflow.
396 if ((UINT32
) (~0) - Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
<
397 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
) {
398 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
399 return RETURN_UNSUPPORTED
;
403 // Read last byte of section header from file
407 Status
= ImageContext
->ImageRead (
408 ImageContext
->Handle
,
409 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
+
410 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
- 1,
414 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
415 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
416 if (Size
!= ReadSize
) {
417 Status
= RETURN_UNSUPPORTED
;
427 ImageContext
->ImageType
= Hdr
.Pe32Plus
->OptionalHeader
.Subsystem
;
428 ImageContext
->ImageSize
= (UINT64
) Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
;
429 ImageContext
->SectionAlignment
= Hdr
.Pe32Plus
->OptionalHeader
.SectionAlignment
;
430 ImageContext
->SizeOfHeaders
= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
;
432 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
433 return RETURN_UNSUPPORTED
;
436 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
437 return RETURN_UNSUPPORTED
;
440 if (!PeCoffLoaderImageFormatSupported (ImageContext
->Machine
)) {
442 // If the PE/COFF loader does not support the image type return
443 // unsupported. This library can support lots of types of images
444 // this does not mean the user of this library can call the entry
445 // point of the image.
447 return RETURN_UNSUPPORTED
;
451 // Check each section field.
453 if (ImageContext
->IsTeImage
) {
454 SectionHeaderOffset
= sizeof(EFI_TE_IMAGE_HEADER
);
455 NumberOfSections
= (UINTN
) (Hdr
.Te
->NumberOfSections
);
457 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
458 NumberOfSections
= (UINTN
) (Hdr
.Pe32
->FileHeader
.NumberOfSections
);
461 for (Index
= 0; Index
< NumberOfSections
; Index
++) {
463 // Read section header from file
465 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
467 Status
= ImageContext
->ImageRead (
468 ImageContext
->Handle
,
473 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
474 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
475 if (Size
!= ReadSize
) {
476 Status
= RETURN_UNSUPPORTED
;
482 // Adjust some field in Section Header for TE image.
484 if (ImageContext
->IsTeImage
) {
485 PeCoffLoaderAdjustOffsetForTeImage (&SectionHeader
, (UINT32
)Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
488 if (SectionHeader
.SizeOfRawData
> 0) {
490 // Section data should bigger than the Pe header.
492 if (SectionHeader
.VirtualAddress
< ImageContext
->SizeOfHeaders
||
493 SectionHeader
.PointerToRawData
< ImageContext
->SizeOfHeaders
) {
494 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
495 return RETURN_UNSUPPORTED
;
499 // Check the member data to avoid overflow.
501 if ((UINT32
) (~0) - SectionHeader
.PointerToRawData
< SectionHeader
.SizeOfRawData
) {
502 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
503 return RETURN_UNSUPPORTED
;
507 // Base on the ImageRead function to check the section data field.
508 // Read the last byte to make sure the data is in the image region.
512 Status
= ImageContext
->ImageRead (
513 ImageContext
->Handle
,
514 SectionHeader
.PointerToRawData
+ SectionHeader
.SizeOfRawData
- 1,
518 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
519 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
520 if (Size
!= ReadSize
) {
521 Status
= RETURN_UNSUPPORTED
;
528 // Check next section.
530 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
533 return RETURN_SUCCESS
;
538 Retrieves information about a PE/COFF image.
540 Computes the PeCoffHeaderOffset, IsTeImage, ImageType, ImageAddress, ImageSize,
541 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and
542 DebugDirectoryEntryRva fields of the ImageContext structure.
543 If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.
544 If the PE/COFF image accessed through the ImageRead service in the ImageContext
545 structure is not a supported PE/COFF image type, then return RETURN_UNSUPPORTED.
546 If any errors occur while computing the fields of ImageContext,
547 then the error status is returned in the ImageError field of ImageContext.
548 If the image is a TE image, then SectionAlignment is set to 0.
549 The ImageRead and Handle fields of ImageContext structure must be valid prior
550 to invoking this service.
552 Caution: This function may receive untrusted input.
553 PE/COFF image is external input, so this routine will
554 also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
555 SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
557 @param ImageContext The pointer to the image context structure that describes the PE/COFF
558 image that needs to be examined by this function.
560 @retval RETURN_SUCCESS The information on the PE/COFF image was collected.
561 @retval RETURN_INVALID_PARAMETER ImageContext is NULL.
562 @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.
567 PeCoffLoaderGetImageInfo (
568 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
571 RETURN_STATUS Status
;
572 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
573 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
574 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
578 UINTN DebugDirectoryEntryRva
;
579 UINTN DebugDirectoryEntryFileOffset
;
580 UINTN SectionHeaderOffset
;
581 EFI_IMAGE_SECTION_HEADER SectionHeader
;
582 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
583 UINT32 NumberOfRvaAndSizes
;
585 UINT32 TeStrippedOffset
;
587 if (ImageContext
== NULL
) {
588 return RETURN_INVALID_PARAMETER
;
593 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
595 Hdr
.Union
= &HdrData
;
596 Status
= PeCoffLoaderGetPeHeader (ImageContext
, Hdr
);
597 if (RETURN_ERROR (Status
)) {
601 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
604 // Retrieve the base address of the image
606 if (!(ImageContext
->IsTeImage
)) {
607 TeStrippedOffset
= 0;
608 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
612 ImageContext
->ImageAddress
= Hdr
.Pe32
->OptionalHeader
.ImageBase
;
617 ImageContext
->ImageAddress
= Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
620 TeStrippedOffset
= (UINT32
)Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
621 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
)(Hdr
.Te
->ImageBase
+ TeStrippedOffset
);
625 // Initialize the alternate destination address to 0 indicating that it
626 // should not be used.
628 ImageContext
->DestinationAddress
= 0;
631 // Initialize the debug codeview pointer.
633 ImageContext
->DebugDirectoryEntryRva
= 0;
634 ImageContext
->CodeView
= NULL
;
635 ImageContext
->PdbPointer
= NULL
;
638 // Three cases with regards to relocations:
639 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
640 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
641 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
642 // has no base relocs to apply
643 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
645 // Look at the file header to determine if relocations have been stripped, and
646 // save this information in the image context for later use.
648 if ((!(ImageContext
->IsTeImage
)) && ((Hdr
.Pe32
->FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
649 ImageContext
->RelocationsStripped
= TRUE
;
650 } else if ((ImageContext
->IsTeImage
) && (Hdr
.Te
->DataDirectory
[0].Size
== 0) && (Hdr
.Te
->DataDirectory
[0].VirtualAddress
== 0)) {
651 ImageContext
->RelocationsStripped
= TRUE
;
653 ImageContext
->RelocationsStripped
= FALSE
;
656 if (!(ImageContext
->IsTeImage
)) {
657 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
661 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
662 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
667 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
668 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
671 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
673 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
676 // Determine the file offset of the debug directory... This means we walk
677 // the sections to find which section contains the RVA of the debug
680 DebugDirectoryEntryFileOffset
= 0;
682 SectionHeaderOffset
= (UINTN
)(
683 ImageContext
->PeCoffHeaderOffset
+
685 sizeof (EFI_IMAGE_FILE_HEADER
) +
686 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
689 for (Index
= 0; Index
< Hdr
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
691 // Read section header from file
693 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
695 Status
= ImageContext
->ImageRead (
696 ImageContext
->Handle
,
701 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
702 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
703 if (Size
!= ReadSize
) {
704 Status
= RETURN_UNSUPPORTED
;
709 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
710 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
712 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
716 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
719 if (DebugDirectoryEntryFileOffset
!= 0) {
720 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
722 // Read next debug directory entry
724 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
726 Status
= ImageContext
->ImageRead (
727 ImageContext
->Handle
,
728 DebugDirectoryEntryFileOffset
+ Index
,
732 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
733 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
734 if (Size
!= ReadSize
) {
735 Status
= RETURN_UNSUPPORTED
;
741 // From PeCoff spec, when DebugEntry.RVA == 0 means this debug info will not load into memory.
742 // Here we will always load EFI_IMAGE_DEBUG_TYPE_CODEVIEW type debug info. so need adjust the
743 // ImageContext->ImageSize when DebugEntry.RVA == 0.
745 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
746 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
747 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
748 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
751 return RETURN_SUCCESS
;
758 DebugDirectoryEntry
= &Hdr
.Te
->DataDirectory
[1];
759 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
760 SectionHeaderOffset
= (UINTN
)(sizeof (EFI_TE_IMAGE_HEADER
));
762 DebugDirectoryEntryFileOffset
= 0;
764 for (Index
= 0; Index
< Hdr
.Te
->NumberOfSections
;) {
766 // Read section header from file
768 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
770 Status
= ImageContext
->ImageRead (
771 ImageContext
->Handle
,
776 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
777 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
778 if (Size
!= ReadSize
) {
779 Status
= RETURN_UNSUPPORTED
;
784 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
785 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
786 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
787 SectionHeader
.VirtualAddress
+
788 SectionHeader
.PointerToRawData
-
792 // File offset of the debug directory was found, if this is not the last
793 // section, then skip to the last section for calculating the image size.
795 if (Index
< (UINTN
) Hdr
.Te
->NumberOfSections
- 1) {
796 SectionHeaderOffset
+= (Hdr
.Te
->NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
797 Index
= Hdr
.Te
->NumberOfSections
- 1;
803 // In Te image header there is not a field to describe the ImageSize.
804 // Actually, the ImageSize equals the RVA plus the VirtualSize of
805 // the last section mapped into memory (Must be rounded up to
806 // a multiple of Section Alignment). Per the PE/COFF specification, the
807 // section headers in the Section Table must appear in order of the RVA
808 // values for the corresponding sections. So the ImageSize can be determined
809 // by the RVA and the VirtualSize of the last section header in the
812 if ((++Index
) == (UINTN
)Hdr
.Te
->NumberOfSections
) {
813 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) - TeStrippedOffset
;
816 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
819 if (DebugDirectoryEntryFileOffset
!= 0) {
820 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
822 // Read next debug directory entry
824 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
826 Status
= ImageContext
->ImageRead (
827 ImageContext
->Handle
,
828 DebugDirectoryEntryFileOffset
+ Index
,
832 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
833 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
834 if (Size
!= ReadSize
) {
835 Status
= RETURN_UNSUPPORTED
;
840 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
841 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
842 return RETURN_SUCCESS
;
848 return RETURN_SUCCESS
;
853 Converts an image address to the loaded address.
855 @param ImageContext The context of the image being loaded.
856 @param Address The address to be converted to the loaded address.
857 @param TeStrippedOffset Stripped offset for TE image.
859 @return The converted address or NULL if the address can not be converted.
863 PeCoffLoaderImageAddress (
864 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
866 IN UINTN TeStrippedOffset
870 // Make sure that Address and ImageSize is correct for the loaded image.
872 if (Address
>= ImageContext
->ImageSize
+ TeStrippedOffset
) {
873 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
877 return (CHAR8
*)((UINTN
) ImageContext
->ImageAddress
+ Address
- TeStrippedOffset
);
881 Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().
883 If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of
884 ImageContext as the relocation base address. Otherwise, use the DestinationAddress field
885 of ImageContext as the relocation base address. The caller must allocate the relocation
886 fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.
888 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress,
889 ImageSize, DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders,
890 DebugDirectoryEntryRva, EntryPoint, FixupDataSize, CodeView, PdbPointer, and FixupData of
891 the ImageContext structure must be valid prior to invoking this service.
893 If ImageContext is NULL, then ASSERT().
895 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
896 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
897 prior to transferring control to a PE/COFF image that is loaded using this library.
899 @param ImageContext The pointer to the image context structure that describes the PE/COFF
900 image that is being relocated.
902 @retval RETURN_SUCCESS The PE/COFF image was relocated.
903 Extended status information is in the ImageError field of ImageContext.
904 @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.
905 Extended status information is in the ImageError field of ImageContext.
906 @retval RETURN_UNSUPPORTED A relocation record type is not supported.
907 Extended status information is in the ImageError field of ImageContext.
912 PeCoffLoaderRelocateImage (
913 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
916 RETURN_STATUS Status
;
917 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
918 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
920 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
921 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
930 PHYSICAL_ADDRESS BaseAddress
;
931 UINT32 NumberOfRvaAndSizes
;
933 UINT32 TeStrippedOffset
;
935 ASSERT (ImageContext
!= NULL
);
940 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
943 // If there are no relocation entries, then we are done
945 if (ImageContext
->RelocationsStripped
) {
946 // Applies additional environment specific actions to relocate fixups
947 // to a PE/COFF image if needed
948 PeCoffLoaderRelocateImageExtraAction (ImageContext
);
949 return RETURN_SUCCESS
;
953 // If the destination address is not 0, use that rather than the
954 // image address as the relocation target.
956 if (ImageContext
->DestinationAddress
!= 0) {
957 BaseAddress
= ImageContext
->DestinationAddress
;
959 BaseAddress
= ImageContext
->ImageAddress
;
962 if (!(ImageContext
->IsTeImage
)) {
963 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
964 TeStrippedOffset
= 0;
965 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
967 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
971 Adjust
= (UINT64
)BaseAddress
- Hdr
.Pe32
->OptionalHeader
.ImageBase
;
973 Hdr
.Pe32
->OptionalHeader
.ImageBase
= (UINT32
)BaseAddress
;
976 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
977 RelocDir
= &Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
982 Adjust
= (UINT64
) BaseAddress
- Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
984 Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
= (UINT64
)BaseAddress
;
987 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
988 RelocDir
= &Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
992 // Find the relocation block
993 // Per the PE/COFF spec, you can't assume that a given data directory
994 // is present in the image. You have to check the NumberOfRvaAndSizes in
995 // the optional header to verify a desired directory entry is there.
997 if ((NumberOfRvaAndSizes
< EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
)) {
1001 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
1002 TeStrippedOffset
= (UINT32
)Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
1003 Adjust
= (UINT64
) (BaseAddress
- (Hdr
.Te
->ImageBase
+ TeStrippedOffset
));
1005 Hdr
.Te
->ImageBase
= (UINT64
) (BaseAddress
- TeStrippedOffset
);
1009 // Find the relocation block
1011 RelocDir
= &Hdr
.Te
->DataDirectory
[0];
1014 if ((RelocDir
!= NULL
) && (RelocDir
->Size
> 0)) {
1015 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
, TeStrippedOffset
);
1016 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) PeCoffLoaderImageAddress (ImageContext
,
1017 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1,
1020 if (RelocBase
== NULL
|| RelocBaseEnd
== NULL
) {
1021 return RETURN_LOAD_ERROR
;
1025 // Set base and end to bypass processing below.
1027 RelocBase
= RelocBaseEnd
= NULL
;
1031 // If Adjust is not zero, then apply fix ups to the image
1035 // Run the relocation information and apply the fixups
1037 FixupData
= ImageContext
->FixupData
;
1038 while (RelocBase
< RelocBaseEnd
) {
1040 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
1042 // Add check for RelocBase->SizeOfBlock field.
1044 if ((RelocBase
->SizeOfBlock
== 0) || (RelocBase
->SizeOfBlock
> RelocDir
->Size
)) {
1045 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1046 return RETURN_LOAD_ERROR
;
1049 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
1050 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
, TeStrippedOffset
);
1051 if (FixupBase
== NULL
) {
1052 return RETURN_LOAD_ERROR
;
1056 // Run this relocation record
1058 while (Reloc
< RelocEnd
) {
1060 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
1061 switch ((*Reloc
) >> 12) {
1062 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
1065 case EFI_IMAGE_REL_BASED_HIGH
:
1066 Fixup16
= (UINT16
*) Fixup
;
1067 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
1068 if (FixupData
!= NULL
) {
1069 *(UINT16
*) FixupData
= *Fixup16
;
1070 FixupData
= FixupData
+ sizeof (UINT16
);
1074 case EFI_IMAGE_REL_BASED_LOW
:
1075 Fixup16
= (UINT16
*) Fixup
;
1076 *Fixup16
= (UINT16
) (*Fixup16
+ (UINT16
) Adjust
);
1077 if (FixupData
!= NULL
) {
1078 *(UINT16
*) FixupData
= *Fixup16
;
1079 FixupData
= FixupData
+ sizeof (UINT16
);
1083 case EFI_IMAGE_REL_BASED_HIGHLOW
:
1084 Fixup32
= (UINT32
*) Fixup
;
1085 *Fixup32
= *Fixup32
+ (UINT32
) Adjust
;
1086 if (FixupData
!= NULL
) {
1087 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
1088 *(UINT32
*)FixupData
= *Fixup32
;
1089 FixupData
= FixupData
+ sizeof (UINT32
);
1093 case EFI_IMAGE_REL_BASED_DIR64
:
1094 Fixup64
= (UINT64
*) Fixup
;
1095 *Fixup64
= *Fixup64
+ (UINT64
) Adjust
;
1096 if (FixupData
!= NULL
) {
1097 FixupData
= ALIGN_POINTER (FixupData
, sizeof(UINT64
));
1098 *(UINT64
*)(FixupData
) = *Fixup64
;
1099 FixupData
= FixupData
+ sizeof(UINT64
);
1105 // The common code does not handle some of the stranger IPF relocations
1106 // PeCoffLoaderRelocateImageEx () adds support for these complex fixups
1107 // on IPF and is a No-Op on other architectures.
1109 Status
= PeCoffLoaderRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
1110 if (RETURN_ERROR (Status
)) {
1111 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1117 // Next relocation record
1125 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
1129 // Adjust the EntryPoint to match the linked-to address
1131 if (ImageContext
->DestinationAddress
!= 0) {
1132 ImageContext
->EntryPoint
-= (UINT64
) ImageContext
->ImageAddress
;
1133 ImageContext
->EntryPoint
+= (UINT64
) ImageContext
->DestinationAddress
;
1137 // Applies additional environment specific actions to relocate fixups
1138 // to a PE/COFF image if needed
1139 PeCoffLoaderRelocateImageExtraAction (ImageContext
);
1141 return RETURN_SUCCESS
;
1145 Loads a PE/COFF image into memory.
1147 Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
1148 specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate
1149 the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
1150 The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.
1151 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress, ImageSize,
1152 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
1153 fields of the ImageContext structure must be valid prior to invoking this service.
1155 If ImageContext is NULL, then ASSERT().
1157 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1158 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1159 prior to transferring control to a PE/COFF image that is loaded using this library.
1161 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1162 image that is being loaded.
1164 @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by
1165 the ImageAddress and ImageSize fields of ImageContext.
1166 Extended status information is in the ImageError field of ImageContext.
1167 @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.
1168 Extended status information is in the ImageError field of ImageContext.
1169 @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.
1170 Extended status information is in the ImageError field of ImageContext.
1171 @retval RETURN_INVALID_PARAMETER The image address is invalid.
1172 Extended status information is in the ImageError field of ImageContext.
1177 PeCoffLoaderLoadImage (
1178 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1181 RETURN_STATUS Status
;
1182 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1183 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
1184 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
1185 EFI_IMAGE_SECTION_HEADER
*Section
;
1186 UINTN NumberOfSections
;
1190 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
1191 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
1193 UINT32 TempDebugEntryRva
;
1194 UINT32 NumberOfRvaAndSizes
;
1196 EFI_IMAGE_RESOURCE_DIRECTORY
*ResourceDirectory
;
1197 EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*ResourceDirectoryEntry
;
1198 EFI_IMAGE_RESOURCE_DIRECTORY_STRING
*ResourceDirectoryString
;
1199 EFI_IMAGE_RESOURCE_DATA_ENTRY
*ResourceDataEntry
;
1202 UINT32 TeStrippedOffset
;
1204 ASSERT (ImageContext
!= NULL
);
1209 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
1212 // Copy the provided context information into our local version, get what we
1213 // can from the original image, and then use that to make sure everything
1216 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
1218 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
1219 if (RETURN_ERROR (Status
)) {
1224 // Make sure there is enough allocated space for the image being loaded
1226 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
1227 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
1228 return RETURN_BUFFER_TOO_SMALL
;
1230 if (ImageContext
->ImageAddress
== 0) {
1232 // Image cannot be loaded into 0 address.
1234 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1235 return RETURN_INVALID_PARAMETER
;
1238 // If there's no relocations, then make sure it's not a runtime driver,
1239 // and that it's being loaded at the linked address.
1241 if (CheckContext
.RelocationsStripped
) {
1243 // If the image does not contain relocations and it is a runtime driver
1244 // then return an error.
1246 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
1247 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
1248 return RETURN_LOAD_ERROR
;
1251 // If the image does not contain relocations, and the requested load address
1252 // is not the linked address, then return an error.
1254 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
1255 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1256 return RETURN_INVALID_PARAMETER
;
1260 // Make sure the allocated space has the proper section alignment
1262 if (!(ImageContext
->IsTeImage
)) {
1263 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
1264 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
1265 return RETURN_INVALID_PARAMETER
;
1269 // Read the entire PE/COFF or TE header into memory
1271 if (!(ImageContext
->IsTeImage
)) {
1272 Status
= ImageContext
->ImageRead (
1273 ImageContext
->Handle
,
1275 &ImageContext
->SizeOfHeaders
,
1276 (VOID
*) (UINTN
) ImageContext
->ImageAddress
1279 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
1281 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
1282 (UINTN
)ImageContext
->ImageAddress
+
1283 ImageContext
->PeCoffHeaderOffset
+
1285 sizeof(EFI_IMAGE_FILE_HEADER
) +
1286 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
1288 NumberOfSections
= (UINTN
) (Hdr
.Pe32
->FileHeader
.NumberOfSections
);
1289 TeStrippedOffset
= 0;
1291 Status
= ImageContext
->ImageRead (
1292 ImageContext
->Handle
,
1294 &ImageContext
->SizeOfHeaders
,
1295 (void *)(UINTN
)ImageContext
->ImageAddress
1298 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
1299 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
1300 (UINTN
)ImageContext
->ImageAddress
+
1301 sizeof(EFI_TE_IMAGE_HEADER
)
1303 NumberOfSections
= (UINTN
) (Hdr
.Te
->NumberOfSections
);
1304 TeStrippedOffset
= (UINT32
) Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
);
1307 if (RETURN_ERROR (Status
)) {
1308 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1309 return RETURN_LOAD_ERROR
;
1313 // Load each section of the image
1315 Section
= FirstSection
;
1316 for (Index
= 0; Index
< NumberOfSections
; Index
++) {
1320 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
1321 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
1322 Size
= (UINTN
) Section
->SizeOfRawData
;
1326 // Compute sections address
1328 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
, TeStrippedOffset
);
1329 End
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1, TeStrippedOffset
);
1332 // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.
1334 if ((Size
> 0) && ((Base
== NULL
) || (End
== NULL
))) {
1335 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
1336 return RETURN_LOAD_ERROR
;
1339 if (Section
->SizeOfRawData
> 0) {
1340 Status
= ImageContext
->ImageRead (
1341 ImageContext
->Handle
,
1342 Section
->PointerToRawData
- TeStrippedOffset
,
1346 if (RETURN_ERROR (Status
)) {
1347 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1353 // If raw size is less then virtual size, zero fill the remaining
1356 if (Size
< Section
->Misc
.VirtualSize
) {
1357 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
1367 // Get image's entry point
1369 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
1370 if (!(ImageContext
->IsTeImage
)) {
1372 // Sizes of AddressOfEntryPoint are different so we need to do this safely
1374 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1378 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1380 (UINTN
)Hdr
.Pe32
->OptionalHeader
.AddressOfEntryPoint
,
1387 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1389 (UINTN
)Hdr
.Pe32Plus
->OptionalHeader
.AddressOfEntryPoint
,
1394 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1396 (UINTN
)Hdr
.Te
->AddressOfEntryPoint
,
1402 // Determine the size of the fixup data
1404 // Per the PE/COFF spec, you can't assume that a given data directory
1405 // is present in the image. You have to check the NumberOfRvaAndSizes in
1406 // the optional header to verify a desired directory entry is there.
1408 if (!(ImageContext
->IsTeImage
)) {
1409 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1413 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1414 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1419 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1420 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1423 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1424 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1426 ImageContext
->FixupDataSize
= 0;
1429 DirectoryEntry
= &Hdr
.Te
->DataDirectory
[0];
1430 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1433 // Consumer must allocate a buffer for the relocation fixup log.
1434 // Only used for runtime drivers.
1436 ImageContext
->FixupData
= NULL
;
1439 // Load the Codeview information if present
1441 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
1442 DebugEntry
= PeCoffLoaderImageAddress (
1444 ImageContext
->DebugDirectoryEntryRva
,
1447 if (DebugEntry
== NULL
) {
1448 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1449 return RETURN_LOAD_ERROR
;
1452 TempDebugEntryRva
= DebugEntry
->RVA
;
1453 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
1455 if ((UINTN
)Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
1456 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
1458 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
1462 if (TempDebugEntryRva
!= 0) {
1463 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
, TeStrippedOffset
);
1464 if (ImageContext
->CodeView
== NULL
) {
1465 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1466 return RETURN_LOAD_ERROR
;
1469 if (DebugEntry
->RVA
== 0) {
1470 Size
= DebugEntry
->SizeOfData
;
1471 Status
= ImageContext
->ImageRead (
1472 ImageContext
->Handle
,
1473 DebugEntry
->FileOffset
- TeStrippedOffset
,
1475 ImageContext
->CodeView
1478 // Should we apply fix up to this field according to the size difference between PE and TE?
1479 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1480 // in original PE image.
1483 if (RETURN_ERROR (Status
)) {
1484 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1485 return RETURN_LOAD_ERROR
;
1488 DebugEntry
->RVA
= TempDebugEntryRva
;
1491 switch (*(UINT32
*) ImageContext
->CodeView
) {
1492 case CODEVIEW_SIGNATURE_NB10
:
1493 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
)) {
1494 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1495 return RETURN_UNSUPPORTED
;
1497 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1500 case CODEVIEW_SIGNATURE_RSDS
:
1501 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
)) {
1502 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1503 return RETURN_UNSUPPORTED
;
1505 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
1508 case CODEVIEW_SIGNATURE_MTOC
:
1509 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
)) {
1510 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1511 return RETURN_UNSUPPORTED
;
1513 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
);
1523 // Get Image's HII resource section
1525 ImageContext
->HiiResourceData
= 0;
1526 if (!(ImageContext
->IsTeImage
)) {
1527 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1531 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1532 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
];
1537 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1538 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
];
1541 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
&& DirectoryEntry
->Size
!= 0) {
1542 Base
= PeCoffLoaderImageAddress (ImageContext
, DirectoryEntry
->VirtualAddress
, 0);
1544 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) Base
;
1545 Offset
= sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) *
1546 (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1547 if (Offset
> DirectoryEntry
->Size
) {
1548 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1549 return RETURN_UNSUPPORTED
;
1551 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1553 for (Index
= 0; Index
< ResourceDirectory
->NumberOfNamedEntries
; Index
++) {
1554 if (ResourceDirectoryEntry
->u1
.s
.NameIsString
) {
1556 // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.
1558 if (ResourceDirectoryEntry
->u1
.s
.NameOffset
>= DirectoryEntry
->Size
) {
1559 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1560 return RETURN_UNSUPPORTED
;
1562 ResourceDirectoryString
= (EFI_IMAGE_RESOURCE_DIRECTORY_STRING
*) (Base
+ ResourceDirectoryEntry
->u1
.s
.NameOffset
);
1563 String
= &ResourceDirectoryString
->String
[0];
1565 if (ResourceDirectoryString
->Length
== 3 &&
1566 String
[0] == L
'H' &&
1567 String
[1] == L
'I' &&
1568 String
[2] == L
'I') {
1570 // Resource Type "HII" found
1572 if (ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1574 // Move to next level - resource Name
1576 if (ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
>= DirectoryEntry
->Size
) {
1577 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1578 return RETURN_UNSUPPORTED
;
1580 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) (Base
+ ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
);
1581 Offset
= ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
+ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) +
1582 sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) * (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1583 if (Offset
> DirectoryEntry
->Size
) {
1584 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1585 return RETURN_UNSUPPORTED
;
1587 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1589 if (ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1591 // Move to next level - resource Language
1593 if (ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
>= DirectoryEntry
->Size
) {
1594 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1595 return RETURN_UNSUPPORTED
;
1597 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) (Base
+ ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
);
1598 Offset
= ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
+ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) +
1599 sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) * (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1600 if (Offset
> DirectoryEntry
->Size
) {
1601 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1602 return RETURN_UNSUPPORTED
;
1604 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1609 // Now it ought to be resource Data
1611 if (!ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1612 if (ResourceDirectoryEntry
->u2
.OffsetToData
>= DirectoryEntry
->Size
) {
1613 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1614 return RETURN_UNSUPPORTED
;
1616 ResourceDataEntry
= (EFI_IMAGE_RESOURCE_DATA_ENTRY
*) (Base
+ ResourceDirectoryEntry
->u2
.OffsetToData
);
1617 ImageContext
->HiiResourceData
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (ImageContext
, ResourceDataEntry
->OffsetToData
, 0);
1622 ResourceDirectoryEntry
++;
1633 Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI
1636 This function reapplies relocation fixups to the PE/COFF image specified by ImageBase
1637 and ImageSize so the image will execute correctly when the PE/COFF image is mapped
1638 to the address specified by VirtualImageBase. RelocationData must be identical
1639 to the FiuxupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure
1640 after this PE/COFF image was relocated with PeCoffLoaderRelocateImage().
1642 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1643 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1644 prior to transferring control to a PE/COFF image that is loaded using this library.
1646 @param ImageBase The base address of a PE/COFF image that has been loaded
1647 and relocated into system memory.
1648 @param VirtImageBase The request virtual address that the PE/COFF image is to
1650 @param ImageSize The size, in bytes, of the PE/COFF image.
1651 @param RelocationData A pointer to the relocation data that was collected when the PE/COFF
1652 image was relocated using PeCoffLoaderRelocateImage().
1657 PeCoffLoaderRelocateImageForRuntime (
1658 IN PHYSICAL_ADDRESS ImageBase
,
1659 IN PHYSICAL_ADDRESS VirtImageBase
,
1661 IN VOID
*RelocationData
1666 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1667 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1668 UINT32 NumberOfRvaAndSizes
;
1669 EFI_IMAGE_DATA_DIRECTORY
*DataDirectory
;
1670 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
1671 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
1672 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
1682 RETURN_STATUS Status
;
1685 OldBase
= (CHAR8
*)((UINTN
)ImageBase
);
1686 NewBase
= (CHAR8
*)((UINTN
)VirtImageBase
);
1687 Adjust
= (UINTN
) NewBase
- (UINTN
) OldBase
;
1690 // Find the image's relocate dir info
1692 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)OldBase
;
1693 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
1695 // Valid DOS header so get address of PE header
1697 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)(((CHAR8
*)DosHdr
) + DosHdr
->e_lfanew
);
1700 // No Dos header so assume image starts with PE header.
1702 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)OldBase
;
1705 if (Hdr
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
1707 // Not a valid PE image so Exit
1712 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
1714 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1718 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1719 DataDirectory
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[0]);
1724 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1725 DataDirectory
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[0]);
1729 // Find the relocation block
1731 // Per the PE/COFF spec, you can't assume that a given data directory
1732 // is present in the image. You have to check the NumberOfRvaAndSizes in
1733 // the optional header to verify a desired directory entry is there.
1735 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1736 RelocDir
= DataDirectory
+ EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
;
1737 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(ImageBase
+ RelocDir
->VirtualAddress
);
1738 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(ImageBase
+ RelocDir
->VirtualAddress
+ RelocDir
->Size
);
1741 // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.
1748 // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.
1750 ASSERT (RelocBase
!= NULL
&& RelocBaseEnd
!= NULL
);
1753 // Run the whole relocation block. And re-fixup data that has not been
1754 // modified. The FixupData is used to see if the image has been modified
1755 // since it was relocated. This is so data sections that have been updated
1756 // by code will not be fixed up, since that would set them back to
1759 FixupData
= RelocationData
;
1760 while (RelocBase
< RelocBaseEnd
) {
1762 // Add check for RelocBase->SizeOfBlock field.
1764 if ((RelocBase
->SizeOfBlock
== 0) || (RelocBase
->SizeOfBlock
> RelocDir
->Size
)) {
1766 // Data invalid, cannot continue to relocate the image, just return.
1771 Reloc
= (UINT16
*) ((UINT8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
1772 RelocEnd
= (UINT16
*) ((UINT8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
1773 FixupBase
= (CHAR8
*) ((UINTN
)ImageBase
) + RelocBase
->VirtualAddress
;
1776 // Run this relocation record
1778 while (Reloc
< RelocEnd
) {
1780 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
1781 switch ((*Reloc
) >> 12) {
1783 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
1786 case EFI_IMAGE_REL_BASED_HIGH
:
1787 Fixup16
= (UINT16
*) Fixup
;
1788 if (*(UINT16
*) FixupData
== *Fixup16
) {
1789 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
1792 FixupData
= FixupData
+ sizeof (UINT16
);
1795 case EFI_IMAGE_REL_BASED_LOW
:
1796 Fixup16
= (UINT16
*) Fixup
;
1797 if (*(UINT16
*) FixupData
== *Fixup16
) {
1798 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) Adjust
& 0xffff));
1801 FixupData
= FixupData
+ sizeof (UINT16
);
1804 case EFI_IMAGE_REL_BASED_HIGHLOW
:
1805 Fixup32
= (UINT32
*) Fixup
;
1806 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
1807 if (*(UINT32
*) FixupData
== *Fixup32
) {
1808 *Fixup32
= *Fixup32
+ (UINT32
) Adjust
;
1811 FixupData
= FixupData
+ sizeof (UINT32
);
1814 case EFI_IMAGE_REL_BASED_DIR64
:
1815 Fixup64
= (UINT64
*)Fixup
;
1816 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT64
));
1817 if (*(UINT64
*) FixupData
== *Fixup64
) {
1818 *Fixup64
= *Fixup64
+ (UINT64
)Adjust
;
1821 FixupData
= FixupData
+ sizeof (UINT64
);
1826 // Only Itanium requires ConvertPeImage_Ex
1828 Status
= PeHotRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
1829 if (RETURN_ERROR (Status
)) {
1834 // Next relocation record
1841 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
1847 Reads contents of a PE/COFF image from a buffer in system memory.
1849 This is the default implementation of a PE_COFF_LOADER_READ_FILE function
1850 that assumes FileHandle pointer to the beginning of a PE/COFF image.
1851 This function reads contents of the PE/COFF image that starts at the system memory
1852 address specified by FileHandle. The read operation copies ReadSize bytes from the
1853 PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer.
1854 The size of the buffer actually read is returned in ReadSize.
1856 The caller must make sure the FileOffset and ReadSize within the file scope.
1858 If FileHandle is NULL, then ASSERT().
1859 If ReadSize is NULL, then ASSERT().
1860 If Buffer is NULL, then ASSERT().
1862 @param FileHandle The pointer to base of the input stream
1863 @param FileOffset Offset into the PE/COFF image to begin the read operation.
1864 @param ReadSize On input, the size in bytes of the requested read operation.
1865 On output, the number of bytes actually read.
1866 @param Buffer Output buffer that contains the data read from the PE/COFF image.
1868 @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into
1873 PeCoffLoaderImageReadFromMemory (
1874 IN VOID
*FileHandle
,
1875 IN UINTN FileOffset
,
1876 IN OUT UINTN
*ReadSize
,
1880 ASSERT (ReadSize
!= NULL
);
1881 ASSERT (FileHandle
!= NULL
);
1882 ASSERT (Buffer
!= NULL
);
1884 CopyMem (Buffer
, ((UINT8
*)FileHandle
) + FileOffset
, *ReadSize
);
1885 return RETURN_SUCCESS
;
1889 Unloads a loaded PE/COFF image from memory and releases its taken resource.
1890 Releases any environment specific resources that were allocated when the image
1891 specified by ImageContext was loaded using PeCoffLoaderLoadImage().
1893 For NT32 emulator, the PE/COFF image loaded by system needs to release.
1894 For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded,
1895 this function can simply return RETURN_SUCCESS.
1897 If ImageContext is NULL, then ASSERT().
1899 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1900 image to be unloaded.
1902 @retval RETURN_SUCCESS The PE/COFF image was unloaded successfully.
1906 PeCoffLoaderUnloadImage (
1907 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1911 // Applies additional environment specific actions to unload a
1912 // PE/COFF image if needed
1914 PeCoffLoaderUnloadImageExtraAction (ImageContext
);
1915 return RETURN_SUCCESS
;