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 Retrieves the magic value from the PE/COFF header.
35 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
37 @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32
38 @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+
42 PeCoffLoaderGetPeHeaderMagicValue (
43 IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
47 // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
48 // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
49 // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
50 // then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
52 if (Hdr
.Pe32
->FileHeader
.Machine
== IMAGE_FILE_MACHINE_IA64
&& Hdr
.Pe32
->OptionalHeader
.Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
53 return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
;
56 // Return the magic value from the PC/COFF Optional Header
58 return Hdr
.Pe32
->OptionalHeader
.Magic
;
63 Retrieves the PE or TE Header from a PE/COFF or TE image.
65 Caution: This function may receive untrusted input.
66 PE/COFF image is external input, so this routine will
67 also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
68 SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
70 @param ImageContext The context of the image being loaded.
71 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
73 @retval RETURN_SUCCESS The PE or TE Header is read.
74 @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.
78 PeCoffLoaderGetPeHeader (
79 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
80 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
84 EFI_IMAGE_DOS_HEADER DosHdr
;
88 UINT32 SectionHeaderOffset
;
91 UINTN NumberOfSections
;
92 EFI_IMAGE_SECTION_HEADER SectionHeader
;
95 // Read the DOS image header to check for its existence
97 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
99 Status
= ImageContext
->ImageRead (
100 ImageContext
->Handle
,
105 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
106 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
110 ImageContext
->PeCoffHeaderOffset
= 0;
111 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
113 // DOS image header is present, so read the PE header after the DOS image
116 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
120 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
121 // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
122 // determines if this is a PE32 or PE32+ image. The magic is in the same
123 // location in both images.
125 Size
= sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
);
127 Status
= ImageContext
->ImageRead (
128 ImageContext
->Handle
,
129 ImageContext
->PeCoffHeaderOffset
,
133 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
134 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
139 // Use Signature to figure out if we understand the image format
141 if (Hdr
.Te
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
142 ImageContext
->IsTeImage
= TRUE
;
143 ImageContext
->Machine
= Hdr
.Te
->Machine
;
144 ImageContext
->ImageType
= (UINT16
)(Hdr
.Te
->Subsystem
);
146 // For TeImage, SectionAlignment is undefined to be set to Zero
147 // ImageSize can be calculated.
149 ImageContext
->ImageSize
= 0;
150 ImageContext
->SectionAlignment
= 0;
151 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
)Hdr
.Te
->BaseOfCode
- (UINTN
)Hdr
.Te
->StrippedSize
;
153 } else if (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
) {
154 ImageContext
->IsTeImage
= FALSE
;
155 ImageContext
->Machine
= Hdr
.Pe32
->FileHeader
.Machine
;
157 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
159 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
161 // 1. Check FileHeader.SizeOfOptionalHeader filed.
163 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
< Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) {
164 return RETURN_UNSUPPORTED
;
168 // 2. Check the OptionalHeader.SizeOfHeaders field.
169 // This field will be use like the following mode, so just compare the result.
170 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
172 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1 < Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) {
173 if (Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
< (UINT32
)((UINT8
*)(&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1]) - (UINT8
*) &Hdr
)) {
174 return RETURN_UNSUPPORTED
;
179 // 2.2 Read last byte of Hdr.Pe32.OptionalHeader.SizeOfHeaders from the file.
183 Status
= ImageContext
->ImageRead (
184 ImageContext
->Handle
,
185 Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- 1,
189 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
194 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
195 // Read the last byte to make sure the data is in the image region.
196 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
198 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
< Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) {
199 if (Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
!= 0) {
201 // Check the member data to avoid overflow.
203 if ((UINT32
) (~0) - Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
<
204 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
) {
205 return RETURN_INVALID_PARAMETER
;
209 // Read last byte of section header from file
213 Status
= ImageContext
->ImageRead (
214 ImageContext
->Handle
,
215 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
+
216 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
- 1,
220 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
229 ImageContext
->ImageType
= Hdr
.Pe32
->OptionalHeader
.Subsystem
;
230 ImageContext
->ImageSize
= (UINT64
)Hdr
.Pe32
->OptionalHeader
.SizeOfImage
;
231 ImageContext
->SectionAlignment
= Hdr
.Pe32
->OptionalHeader
.SectionAlignment
;
232 ImageContext
->SizeOfHeaders
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
;
234 } else if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
236 // 1. Check FileHeader.SizeOfOptionalHeader filed.
238 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
< Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
239 return RETURN_UNSUPPORTED
;
243 // 2. Check the OptionalHeader.SizeOfHeaders field.
244 // This field will be use like the following mode, so just compare the result.
245 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
247 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1 < Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
248 if (Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
< (UINT32
)((UINT8
*)(&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
+ 1]) - (UINT8
*) &Hdr
)) {
249 return RETURN_UNSUPPORTED
;
254 // 2.2 Read last byte of Hdr.Pe32Plus.OptionalHeader.SizeOfHeaders from the file.
258 Status
= ImageContext
->ImageRead (
259 ImageContext
->Handle
,
260 Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- 1,
264 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
269 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
270 // Read the last byte to make sure the data is in the image region.
271 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
273 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
< Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
274 if (Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
!= 0) {
276 // Check the member data to avoid overflow.
278 if ((UINT32
) (~0) - Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
<
279 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
) {
280 return RETURN_INVALID_PARAMETER
;
284 // Read last byte of section header from file
288 Status
= ImageContext
->ImageRead (
289 ImageContext
->Handle
,
290 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
+
291 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
- 1,
295 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
304 ImageContext
->ImageType
= Hdr
.Pe32Plus
->OptionalHeader
.Subsystem
;
305 ImageContext
->ImageSize
= (UINT64
) Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
;
306 ImageContext
->SectionAlignment
= Hdr
.Pe32Plus
->OptionalHeader
.SectionAlignment
;
307 ImageContext
->SizeOfHeaders
= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
;
309 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
310 return RETURN_UNSUPPORTED
;
313 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
314 return RETURN_UNSUPPORTED
;
317 if (!PeCoffLoaderImageFormatSupported (ImageContext
->Machine
)) {
319 // If the PE/COFF loader does not support the image type return
320 // unsupported. This library can support lots of types of images
321 // this does not mean the user of this library can call the entry
322 // point of the image.
324 return RETURN_UNSUPPORTED
;
328 // Check each section field.
330 if (ImageContext
->IsTeImage
) {
331 SectionHeaderOffset
= sizeof(EFI_TE_IMAGE_HEADER
);
332 NumberOfSections
= (UINTN
) (Hdr
.Te
->NumberOfSections
);
334 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
335 NumberOfSections
= (UINTN
) (Hdr
.Pe32
->FileHeader
.NumberOfSections
);
338 for (Index
= 0; Index
< NumberOfSections
; Index
++) {
340 // Read section header from file
342 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
344 Status
= ImageContext
->ImageRead (
345 ImageContext
->Handle
,
350 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
354 if (SectionHeader
.SizeOfRawData
> 0) {
356 // Check the member data to avoid overflow.
358 if ((UINT32
) (~0) - SectionHeader
.PointerToRawData
< SectionHeader
.SizeOfRawData
) {
359 return RETURN_INVALID_PARAMETER
;
363 // Base on the ImageRead function to check the section data field.
364 // Read the last byte to make sure the data is in the image region.
368 Status
= ImageContext
->ImageRead (
369 ImageContext
->Handle
,
370 SectionHeader
.PointerToRawData
+ SectionHeader
.SizeOfRawData
- 1,
374 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
380 // Check next section.
382 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
385 return RETURN_SUCCESS
;
390 Retrieves information about a PE/COFF image.
392 Computes the PeCoffHeaderOffset, IsTeImage, ImageType, ImageAddress, ImageSize,
393 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and
394 DebugDirectoryEntryRva fields of the ImageContext structure.
395 If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.
396 If the PE/COFF image accessed through the ImageRead service in the ImageContext
397 structure is not a supported PE/COFF image type, then return RETURN_UNSUPPORTED.
398 If any errors occur while computing the fields of ImageContext,
399 then the error status is returned in the ImageError field of ImageContext.
400 If the image is a TE image, then SectionAlignment is set to 0.
401 The ImageRead and Handle fields of ImageContext structure must be valid prior
402 to invoking this service.
404 Caution: This function may receive untrusted input.
405 PE/COFF image is external input, so this routine will
406 also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
407 SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
409 @param ImageContext The pointer to the image context structure that describes the PE/COFF
410 image that needs to be examined by this function.
412 @retval RETURN_SUCCESS The information on the PE/COFF image was collected.
413 @retval RETURN_INVALID_PARAMETER ImageContext is NULL.
414 @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.
419 PeCoffLoaderGetImageInfo (
420 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
423 RETURN_STATUS Status
;
424 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
425 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
426 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
430 UINTN DebugDirectoryEntryRva
;
431 UINTN DebugDirectoryEntryFileOffset
;
432 UINTN SectionHeaderOffset
;
433 EFI_IMAGE_SECTION_HEADER SectionHeader
;
434 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
435 UINT32 NumberOfRvaAndSizes
;
438 if (ImageContext
== NULL
) {
439 return RETURN_INVALID_PARAMETER
;
444 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
446 Hdr
.Union
= &HdrData
;
447 Status
= PeCoffLoaderGetPeHeader (ImageContext
, Hdr
);
448 if (RETURN_ERROR (Status
)) {
452 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
455 // Retrieve the base address of the image
457 if (!(ImageContext
->IsTeImage
)) {
458 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
462 ImageContext
->ImageAddress
= Hdr
.Pe32
->OptionalHeader
.ImageBase
;
467 ImageContext
->ImageAddress
= Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
470 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
)(Hdr
.Te
->ImageBase
+ Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
474 // Initialize the alternate destination address to 0 indicating that it
475 // should not be used.
477 ImageContext
->DestinationAddress
= 0;
480 // Initialize the debug codeview pointer.
482 ImageContext
->DebugDirectoryEntryRva
= 0;
483 ImageContext
->CodeView
= NULL
;
484 ImageContext
->PdbPointer
= NULL
;
487 // Three cases with regards to relocations:
488 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
489 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
490 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
491 // has no base relocs to apply
492 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
494 // Look at the file header to determine if relocations have been stripped, and
495 // save this information in the image context for later use.
497 if ((!(ImageContext
->IsTeImage
)) && ((Hdr
.Pe32
->FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
498 ImageContext
->RelocationsStripped
= TRUE
;
499 } else if ((ImageContext
->IsTeImage
) && (Hdr
.Te
->DataDirectory
[0].Size
== 0) && (Hdr
.Te
->DataDirectory
[0].VirtualAddress
== 0)) {
500 ImageContext
->RelocationsStripped
= TRUE
;
502 ImageContext
->RelocationsStripped
= FALSE
;
506 // TE Image Relocation Data Directory Entry size is non-zero, but the Relocation Data Directory Virtual Address is zero.
507 // This case is not a valid TE image.
509 if ((ImageContext
->IsTeImage
) && (Hdr
.Te
->DataDirectory
[0].Size
!= 0) && (Hdr
.Te
->DataDirectory
[0].VirtualAddress
== 0)) {
510 return RETURN_INVALID_PARAMETER
;
513 if (!(ImageContext
->IsTeImage
)) {
514 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
518 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
519 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
524 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
525 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
528 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
530 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
533 // Determine the file offset of the debug directory... This means we walk
534 // the sections to find which section contains the RVA of the debug
537 DebugDirectoryEntryFileOffset
= 0;
539 SectionHeaderOffset
= (UINTN
)(
540 ImageContext
->PeCoffHeaderOffset
+
542 sizeof (EFI_IMAGE_FILE_HEADER
) +
543 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
546 for (Index
= 0; Index
< Hdr
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
548 // Read section header from file
550 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
552 Status
= ImageContext
->ImageRead (
553 ImageContext
->Handle
,
558 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
559 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
563 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
564 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
566 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
570 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
573 if (DebugDirectoryEntryFileOffset
!= 0) {
574 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
576 // Read next debug directory entry
578 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
580 Status
= ImageContext
->ImageRead (
581 ImageContext
->Handle
,
582 DebugDirectoryEntryFileOffset
+ Index
,
586 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
587 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
590 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
591 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
592 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
593 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
596 return RETURN_SUCCESS
;
603 DebugDirectoryEntry
= &Hdr
.Te
->DataDirectory
[1];
604 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
605 SectionHeaderOffset
= (UINTN
)(sizeof (EFI_TE_IMAGE_HEADER
));
607 DebugDirectoryEntryFileOffset
= 0;
609 for (Index
= 0; Index
< Hdr
.Te
->NumberOfSections
;) {
611 // Read section header from file
613 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
615 Status
= ImageContext
->ImageRead (
616 ImageContext
->Handle
,
621 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
622 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
626 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
627 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
628 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
629 SectionHeader
.VirtualAddress
+
630 SectionHeader
.PointerToRawData
+
631 sizeof (EFI_TE_IMAGE_HEADER
) -
632 Hdr
.Te
->StrippedSize
;
635 // File offset of the debug directory was found, if this is not the last
636 // section, then skip to the last section for calculating the image size.
638 if (Index
< (UINTN
) Hdr
.Te
->NumberOfSections
- 1) {
639 SectionHeaderOffset
+= (Hdr
.Te
->NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
640 Index
= Hdr
.Te
->NumberOfSections
- 1;
646 // In Te image header there is not a field to describe the ImageSize.
647 // Actually, the ImageSize equals the RVA plus the VirtualSize of
648 // the last section mapped into memory (Must be rounded up to
649 // a multiple of Section Alignment). Per the PE/COFF specification, the
650 // section headers in the Section Table must appear in order of the RVA
651 // values for the corresponding sections. So the ImageSize can be determined
652 // by the RVA and the VirtualSize of the last section header in the
655 if ((++Index
) == (UINTN
)Hdr
.Te
->NumberOfSections
) {
656 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
);
659 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
662 if (DebugDirectoryEntryFileOffset
!= 0) {
663 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
665 // Read next debug directory entry
667 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
669 Status
= ImageContext
->ImageRead (
670 ImageContext
->Handle
,
671 DebugDirectoryEntryFileOffset
+ Index
,
675 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
676 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
680 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
681 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
682 return RETURN_SUCCESS
;
688 return RETURN_SUCCESS
;
693 Converts an image address to the loaded address.
695 @param ImageContext The context of the image being loaded.
696 @param Address The relative virtual address to be converted to the loaded address.
698 @return The converted address or NULL if the address can not be converted.
702 PeCoffLoaderImageAddress (
703 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
708 // Make sure that Address and ImageSize is correct for the loaded image.
710 if (Address
>= ImageContext
->ImageSize
) {
711 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
715 return (CHAR8
*)((UINTN
) ImageContext
->ImageAddress
+ Address
);
719 Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().
721 If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of
722 ImageContext as the relocation base address. Otherwise, use the DestinationAddress field
723 of ImageContext as the relocation base address. The caller must allocate the relocation
724 fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.
726 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress,
727 ImageSize, DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders,
728 DebugDirectoryEntryRva, EntryPoint, FixupDataSize, CodeView, PdbPointer, and FixupData of
729 the ImageContext structure must be valid prior to invoking this service.
731 If ImageContext is NULL, then ASSERT().
733 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
734 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
735 prior to transferring control to a PE/COFF image that is loaded using this library.
737 @param ImageContext The pointer to the image context structure that describes the PE/COFF
738 image that is being relocated.
740 @retval RETURN_SUCCESS The PE/COFF image was relocated.
741 Extended status information is in the ImageError field of ImageContext.
742 @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.
743 Extended status information is in the ImageError field of ImageContext.
744 @retval RETURN_UNSUPPORTED A relocation record type is not supported.
745 Extended status information is in the ImageError field of ImageContext.
750 PeCoffLoaderRelocateImage (
751 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
754 RETURN_STATUS Status
;
755 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
756 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
758 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
759 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
768 PHYSICAL_ADDRESS BaseAddress
;
769 UINT32 NumberOfRvaAndSizes
;
772 ASSERT (ImageContext
!= NULL
);
777 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
780 // If there are no relocation entries, then we are done
782 if (ImageContext
->RelocationsStripped
) {
783 // Applies additional environment specific actions to relocate fixups
784 // to a PE/COFF image if needed
785 PeCoffLoaderRelocateImageExtraAction (ImageContext
);
786 return RETURN_SUCCESS
;
790 // If the destination address is not 0, use that rather than the
791 // image address as the relocation target.
793 if (ImageContext
->DestinationAddress
!= 0) {
794 BaseAddress
= ImageContext
->DestinationAddress
;
796 BaseAddress
= ImageContext
->ImageAddress
;
799 if (!(ImageContext
->IsTeImage
)) {
800 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
802 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
804 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
808 Adjust
= (UINT64
)BaseAddress
- Hdr
.Pe32
->OptionalHeader
.ImageBase
;
810 Hdr
.Pe32
->OptionalHeader
.ImageBase
= (UINT32
)BaseAddress
;
813 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
814 RelocDir
= &Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
819 Adjust
= (UINT64
) BaseAddress
- Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
821 Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
= (UINT64
)BaseAddress
;
824 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
825 RelocDir
= &Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
829 // Find the relocation block
830 // Per the PE/COFF spec, you can't assume that a given data directory
831 // is present in the image. You have to check the NumberOfRvaAndSizes in
832 // the optional header to verify a desired directory entry is there.
835 if ((NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) && (RelocDir
->Size
> 0)) {
836 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
837 RelocBaseEnd
= PeCoffLoaderImageAddress (
839 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
841 if (RelocBase
== NULL
|| RelocBaseEnd
== NULL
) {
842 return RETURN_LOAD_ERROR
;
846 // Set base and end to bypass processing below.
848 RelocBase
= RelocBaseEnd
= NULL
;
851 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
852 Adjust
= (UINT64
) (BaseAddress
- Hdr
.Te
->StrippedSize
+ sizeof (EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->ImageBase
);
854 Hdr
.Te
->ImageBase
= (UINT64
) (BaseAddress
- Hdr
.Te
->StrippedSize
+ sizeof (EFI_TE_IMAGE_HEADER
));
858 // Find the relocation block
860 RelocDir
= &Hdr
.Te
->DataDirectory
[0];
861 if (RelocDir
->Size
> 0) {
862 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(
863 ImageContext
->ImageAddress
+
864 RelocDir
->VirtualAddress
+
865 sizeof(EFI_TE_IMAGE_HEADER
) -
868 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) ((UINTN
) RelocBase
+ (UINTN
) RelocDir
->Size
- 1);
871 // Set base and end to bypass processing below.
873 RelocBase
= RelocBaseEnd
= NULL
;
878 // If Adjust is not zero, then apply fix ups to the image
882 // Run the relocation information and apply the fixups
884 FixupData
= ImageContext
->FixupData
;
885 while (RelocBase
< RelocBaseEnd
) {
887 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
888 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
891 // Make sure RelocEnd is in the Image range.
893 if ((CHAR8
*) RelocEnd
< (CHAR8
*)((UINTN
) ImageContext
->ImageAddress
) ||
894 (CHAR8
*) RelocEnd
> (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+ (UINTN
)ImageContext
->ImageSize
)) {
895 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
896 return RETURN_LOAD_ERROR
;
899 if (!(ImageContext
->IsTeImage
)) {
900 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
);
901 if (FixupBase
== NULL
) {
902 return RETURN_LOAD_ERROR
;
905 FixupBase
= (CHAR8
*)(UINTN
)(ImageContext
->ImageAddress
+
906 RelocBase
->VirtualAddress
+
907 sizeof(EFI_TE_IMAGE_HEADER
) -
913 // Run this relocation record
915 while (Reloc
< RelocEnd
) {
917 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
918 switch ((*Reloc
) >> 12) {
919 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
922 case EFI_IMAGE_REL_BASED_HIGH
:
923 Fixup16
= (UINT16
*) Fixup
;
924 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
925 if (FixupData
!= NULL
) {
926 *(UINT16
*) FixupData
= *Fixup16
;
927 FixupData
= FixupData
+ sizeof (UINT16
);
931 case EFI_IMAGE_REL_BASED_LOW
:
932 Fixup16
= (UINT16
*) Fixup
;
933 *Fixup16
= (UINT16
) (*Fixup16
+ (UINT16
) Adjust
);
934 if (FixupData
!= NULL
) {
935 *(UINT16
*) FixupData
= *Fixup16
;
936 FixupData
= FixupData
+ sizeof (UINT16
);
940 case EFI_IMAGE_REL_BASED_HIGHLOW
:
941 Fixup32
= (UINT32
*) Fixup
;
942 *Fixup32
= *Fixup32
+ (UINT32
) Adjust
;
943 if (FixupData
!= NULL
) {
944 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
945 *(UINT32
*)FixupData
= *Fixup32
;
946 FixupData
= FixupData
+ sizeof (UINT32
);
950 case EFI_IMAGE_REL_BASED_DIR64
:
951 Fixup64
= (UINT64
*) Fixup
;
952 *Fixup64
= *Fixup64
+ (UINT64
) Adjust
;
953 if (FixupData
!= NULL
) {
954 FixupData
= ALIGN_POINTER (FixupData
, sizeof(UINT64
));
955 *(UINT64
*)(FixupData
) = *Fixup64
;
956 FixupData
= FixupData
+ sizeof(UINT64
);
962 // The common code does not handle some of the stranger IPF relocations
963 // PeCoffLoaderRelocateImageEx () adds support for these complex fixups
964 // on IPF and is a No-Op on other architectures.
966 Status
= PeCoffLoaderRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
967 if (RETURN_ERROR (Status
)) {
968 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
974 // Next relocation record
982 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
986 // Adjust the EntryPoint to match the linked-to address
988 if (ImageContext
->DestinationAddress
!= 0) {
989 ImageContext
->EntryPoint
-= (UINT64
) ImageContext
->ImageAddress
;
990 ImageContext
->EntryPoint
+= (UINT64
) ImageContext
->DestinationAddress
;
994 // Applies additional environment specific actions to relocate fixups
995 // to a PE/COFF image if needed
996 PeCoffLoaderRelocateImageExtraAction (ImageContext
);
998 return RETURN_SUCCESS
;
1002 Loads a PE/COFF image into memory.
1004 Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
1005 specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate
1006 the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
1007 The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.
1008 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress, ImageSize,
1009 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
1010 fields of the ImageContext structure must be valid prior to invoking this service.
1012 If ImageContext is NULL, then ASSERT().
1014 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1015 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1016 prior to transferring control to a PE/COFF image that is loaded using this library.
1018 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1019 image that is being loaded.
1021 @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by
1022 the ImageAddress and ImageSize fields of ImageContext.
1023 Extended status information is in the ImageError field of ImageContext.
1024 @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.
1025 Extended status information is in the ImageError field of ImageContext.
1026 @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.
1027 Extended status information is in the ImageError field of ImageContext.
1028 @retval RETURN_INVALID_PARAMETER The image address is invalid.
1029 Extended status information is in the ImageError field of ImageContext.
1034 PeCoffLoaderLoadImage (
1035 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1038 RETURN_STATUS Status
;
1039 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1040 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
1041 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
1042 EFI_IMAGE_SECTION_HEADER
*Section
;
1043 UINTN NumberOfSections
;
1048 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
1049 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
1051 UINT32 TempDebugEntryRva
;
1052 UINT32 NumberOfRvaAndSizes
;
1054 EFI_IMAGE_RESOURCE_DIRECTORY
*ResourceDirectory
;
1055 EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*ResourceDirectoryEntry
;
1056 EFI_IMAGE_RESOURCE_DIRECTORY_STRING
*ResourceDirectoryString
;
1057 EFI_IMAGE_RESOURCE_DATA_ENTRY
*ResourceDataEntry
;
1061 ASSERT (ImageContext
!= NULL
);
1066 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
1069 // Copy the provided context information into our local version, get what we
1070 // can from the original image, and then use that to make sure everything
1073 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
1075 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
1076 if (RETURN_ERROR (Status
)) {
1081 // Make sure there is enough allocated space for the image being loaded
1083 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
1084 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
1085 return RETURN_BUFFER_TOO_SMALL
;
1087 if (ImageContext
->ImageAddress
== 0) {
1089 // Image cannot be loaded into 0 address.
1091 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1092 return RETURN_INVALID_PARAMETER
;
1095 // If there's no relocations, then make sure it's not a runtime driver,
1096 // and that it's being loaded at the linked address.
1098 if (CheckContext
.RelocationsStripped
) {
1100 // If the image does not contain relocations and it is a runtime driver
1101 // then return an error.
1103 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
1104 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
1105 return RETURN_LOAD_ERROR
;
1108 // If the image does not contain relocations, and the requested load address
1109 // is not the linked address, then return an error.
1111 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
1112 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1113 return RETURN_INVALID_PARAMETER
;
1117 // Make sure the allocated space has the proper section alignment
1119 if (!(ImageContext
->IsTeImage
)) {
1120 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
1121 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
1122 return RETURN_INVALID_PARAMETER
;
1126 // Read the entire PE/COFF or TE header into memory
1128 if (!(ImageContext
->IsTeImage
)) {
1129 Status
= ImageContext
->ImageRead (
1130 ImageContext
->Handle
,
1132 &ImageContext
->SizeOfHeaders
,
1133 (VOID
*) (UINTN
) ImageContext
->ImageAddress
1136 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
1138 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
1139 (UINTN
)ImageContext
->ImageAddress
+
1140 ImageContext
->PeCoffHeaderOffset
+
1142 sizeof(EFI_IMAGE_FILE_HEADER
) +
1143 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
1145 NumberOfSections
= (UINTN
) (Hdr
.Pe32
->FileHeader
.NumberOfSections
);
1147 Status
= ImageContext
->ImageRead (
1148 ImageContext
->Handle
,
1150 &ImageContext
->SizeOfHeaders
,
1151 (void *)(UINTN
)ImageContext
->ImageAddress
1154 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
1156 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
1157 (UINTN
)ImageContext
->ImageAddress
+
1158 sizeof(EFI_TE_IMAGE_HEADER
)
1160 NumberOfSections
= (UINTN
) (Hdr
.Te
->NumberOfSections
);
1164 if (RETURN_ERROR (Status
)) {
1165 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1166 return RETURN_LOAD_ERROR
;
1170 // Load each section of the image
1172 Section
= FirstSection
;
1173 for (Index
= 0, MaxEnd
= NULL
; Index
< NumberOfSections
; Index
++) {
1177 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
1178 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
1179 Size
= (UINTN
) Section
->SizeOfRawData
;
1183 // Compute sections address
1185 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
);
1186 End
= PeCoffLoaderImageAddress (
1188 Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1
1192 // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.
1194 if ((Size
> 0) && ((Base
== NULL
) || (End
== NULL
))) {
1195 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
1196 return RETURN_LOAD_ERROR
;
1199 if (ImageContext
->IsTeImage
) {
1200 Base
= (CHAR8
*)((UINTN
) Base
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
)Hdr
.Te
->StrippedSize
);
1201 End
= (CHAR8
*)((UINTN
) End
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
)Hdr
.Te
->StrippedSize
);
1208 if (Section
->SizeOfRawData
> 0) {
1209 if (!(ImageContext
->IsTeImage
)) {
1210 Status
= ImageContext
->ImageRead (
1211 ImageContext
->Handle
,
1212 Section
->PointerToRawData
,
1217 Status
= ImageContext
->ImageRead (
1218 ImageContext
->Handle
,
1219 Section
->PointerToRawData
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
)Hdr
.Te
->StrippedSize
,
1225 if (RETURN_ERROR (Status
)) {
1226 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1232 // If raw size is less then virtual size, zero fill the remaining
1235 if (Size
< Section
->Misc
.VirtualSize
) {
1236 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
1246 // Get image's entry point
1248 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
1249 if (!(ImageContext
->IsTeImage
)) {
1251 // Sizes of AddressOfEntryPoint are different so we need to do this safely
1253 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1257 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1259 (UINTN
)Hdr
.Pe32
->OptionalHeader
.AddressOfEntryPoint
1265 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1267 (UINTN
)Hdr
.Pe32Plus
->OptionalHeader
.AddressOfEntryPoint
1271 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (
1272 (UINTN
)ImageContext
->ImageAddress
+
1273 (UINTN
)Hdr
.Te
->AddressOfEntryPoint
+
1274 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1275 (UINTN
)Hdr
.Te
->StrippedSize
1280 // Determine the size of the fixup data
1282 // Per the PE/COFF spec, you can't assume that a given data directory
1283 // is present in the image. You have to check the NumberOfRvaAndSizes in
1284 // the optional header to verify a desired directory entry is there.
1286 if (!(ImageContext
->IsTeImage
)) {
1287 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1291 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1292 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1297 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1298 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1301 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1302 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1304 ImageContext
->FixupDataSize
= 0;
1307 DirectoryEntry
= &Hdr
.Te
->DataDirectory
[0];
1308 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1311 // Consumer must allocate a buffer for the relocation fixup log.
1312 // Only used for runtime drivers.
1314 ImageContext
->FixupData
= NULL
;
1317 // Load the Codeview information if present
1319 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
1320 if (!(ImageContext
->IsTeImage
)) {
1321 DebugEntry
= PeCoffLoaderImageAddress (
1323 ImageContext
->DebugDirectoryEntryRva
1326 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(UINTN
)(
1327 ImageContext
->ImageAddress
+
1328 ImageContext
->DebugDirectoryEntryRva
+
1329 sizeof(EFI_TE_IMAGE_HEADER
) -
1330 Hdr
.Te
->StrippedSize
1334 if (DebugEntry
!= NULL
) {
1335 TempDebugEntryRva
= DebugEntry
->RVA
;
1336 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
1338 if ((UINTN
)Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
1339 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
1341 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
1345 if (TempDebugEntryRva
!= 0) {
1346 if (!(ImageContext
->IsTeImage
)) {
1347 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
);
1349 ImageContext
->CodeView
= (VOID
*)(
1350 (UINTN
)ImageContext
->ImageAddress
+
1351 (UINTN
)TempDebugEntryRva
+
1352 (UINTN
)sizeof (EFI_TE_IMAGE_HEADER
) -
1353 (UINTN
) Hdr
.Te
->StrippedSize
1357 if (ImageContext
->CodeView
== NULL
) {
1358 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1359 return RETURN_LOAD_ERROR
;
1362 if (DebugEntry
->RVA
== 0) {
1363 Size
= DebugEntry
->SizeOfData
;
1364 if (!(ImageContext
->IsTeImage
)) {
1365 Status
= ImageContext
->ImageRead (
1366 ImageContext
->Handle
,
1367 DebugEntry
->FileOffset
,
1369 ImageContext
->CodeView
1372 Status
= ImageContext
->ImageRead (
1373 ImageContext
->Handle
,
1374 DebugEntry
->FileOffset
+ sizeof (EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->StrippedSize
,
1376 ImageContext
->CodeView
1379 // Should we apply fix up to this field according to the size difference between PE and TE?
1380 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1381 // in original PE image.
1385 if (RETURN_ERROR (Status
)) {
1386 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1387 return RETURN_LOAD_ERROR
;
1390 DebugEntry
->RVA
= TempDebugEntryRva
;
1393 switch (*(UINT32
*) ImageContext
->CodeView
) {
1394 case CODEVIEW_SIGNATURE_NB10
:
1395 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1398 case CODEVIEW_SIGNATURE_RSDS
:
1399 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
1402 case CODEVIEW_SIGNATURE_MTOC
:
1403 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
);
1414 // Get Image's HII resource section
1416 ImageContext
->HiiResourceData
= 0;
1417 if (!(ImageContext
->IsTeImage
)) {
1418 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1422 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
];
1427 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
];
1430 if (DirectoryEntry
->Size
!= 0) {
1431 Base
= PeCoffLoaderImageAddress (ImageContext
, DirectoryEntry
->VirtualAddress
);
1433 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) Base
;
1434 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1436 for (Index
= 0; Index
< ResourceDirectory
->NumberOfNamedEntries
; Index
++) {
1437 if (ResourceDirectoryEntry
->u1
.s
.NameIsString
) {
1439 // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.
1441 if (ResourceDirectoryEntry
->u1
.s
.NameOffset
>= DirectoryEntry
->Size
) {
1444 ResourceDirectoryString
= (EFI_IMAGE_RESOURCE_DIRECTORY_STRING
*) (Base
+ ResourceDirectoryEntry
->u1
.s
.NameOffset
);
1445 String
= &ResourceDirectoryString
->String
[0];
1447 if (ResourceDirectoryString
->Length
== 3 &&
1448 String
[0] == L
'H' &&
1449 String
[1] == L
'I' &&
1450 String
[2] == L
'I') {
1452 // Resource Type "HII" found
1454 if (ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1456 // Move to next level - resource Name
1458 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) (Base
+ ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
);
1459 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1461 if (ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1463 // Move to next level - resource Language
1465 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) (Base
+ ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
);
1466 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1471 // Now it ought to be resource Data
1473 if (!ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1474 ResourceDataEntry
= (EFI_IMAGE_RESOURCE_DATA_ENTRY
*) (Base
+ ResourceDirectoryEntry
->u2
.OffsetToData
);
1475 ImageContext
->HiiResourceData
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (ImageContext
, ResourceDataEntry
->OffsetToData
);
1480 ResourceDirectoryEntry
++;
1491 Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI
1494 This function reapplies relocation fixups to the PE/COFF image specified by ImageBase
1495 and ImageSize so the image will execute correctly when the PE/COFF image is mapped
1496 to the address specified by VirtualImageBase. RelocationData must be identical
1497 to the FiuxupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure
1498 after this PE/COFF image was relocated with PeCoffLoaderRelocateImage().
1500 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1501 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1502 prior to transferring control to a PE/COFF image that is loaded using this library.
1504 @param ImageBase The base address of a PE/COFF image that has been loaded
1505 and relocated into system memory.
1506 @param VirtImageBase The request virtual address that the PE/COFF image is to
1508 @param ImageSize The size, in bytes, of the PE/COFF image.
1509 @param RelocationData A pointer to the relocation data that was collected when the PE/COFF
1510 image was relocated using PeCoffLoaderRelocateImage().
1515 PeCoffLoaderRelocateImageForRuntime (
1516 IN PHYSICAL_ADDRESS ImageBase
,
1517 IN PHYSICAL_ADDRESS VirtImageBase
,
1519 IN VOID
*RelocationData
1524 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1525 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1526 UINT32 NumberOfRvaAndSizes
;
1527 EFI_IMAGE_DATA_DIRECTORY
*DataDirectory
;
1528 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
1529 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
1530 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
1540 RETURN_STATUS Status
;
1543 OldBase
= (CHAR8
*)((UINTN
)ImageBase
);
1544 NewBase
= (CHAR8
*)((UINTN
)VirtImageBase
);
1545 Adjust
= (UINTN
) NewBase
- (UINTN
) OldBase
;
1548 // Find the image's relocate dir info
1550 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)OldBase
;
1551 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
1553 // Valid DOS header so get address of PE header
1555 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)(((CHAR8
*)DosHdr
) + DosHdr
->e_lfanew
);
1558 // No Dos header so assume image starts with PE header.
1560 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)OldBase
;
1563 if (Hdr
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
1565 // Not a valid PE image so Exit
1570 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
1572 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1576 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1577 DataDirectory
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[0]);
1582 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1583 DataDirectory
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[0]);
1587 // Find the relocation block
1589 // Per the PE/COFF spec, you can't assume that a given data directory
1590 // is present in the image. You have to check the NumberOfRvaAndSizes in
1591 // the optional header to verify a desired directory entry is there.
1593 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1594 RelocDir
= DataDirectory
+ EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
;
1595 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(ImageBase
+ RelocDir
->VirtualAddress
);
1596 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(ImageBase
+ RelocDir
->VirtualAddress
+ RelocDir
->Size
);
1599 // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.
1606 // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.
1608 ASSERT (RelocBase
!= NULL
&& RelocBaseEnd
!= NULL
);
1611 // Run the whole relocation block. And re-fixup data that has not been
1612 // modified. The FixupData is used to see if the image has been modified
1613 // since it was relocated. This is so data sections that have been updated
1614 // by code will not be fixed up, since that would set them back to
1617 FixupData
= RelocationData
;
1618 while (RelocBase
< RelocBaseEnd
) {
1620 // Add check for RelocBase->SizeOfBlock field.
1622 if ((RelocBase
->SizeOfBlock
== 0) || (RelocBase
->SizeOfBlock
> RelocDir
->Size
)) {
1624 // Data invalid, cannot continue to relocate the image, just return.
1629 Reloc
= (UINT16
*) ((UINT8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
1630 RelocEnd
= (UINT16
*) ((UINT8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
1631 FixupBase
= (CHAR8
*) ((UINTN
)ImageBase
) + RelocBase
->VirtualAddress
;
1634 // Run this relocation record
1636 while (Reloc
< RelocEnd
) {
1638 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
1639 switch ((*Reloc
) >> 12) {
1641 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
1644 case EFI_IMAGE_REL_BASED_HIGH
:
1645 Fixup16
= (UINT16
*) Fixup
;
1646 if (*(UINT16
*) FixupData
== *Fixup16
) {
1647 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
1650 FixupData
= FixupData
+ sizeof (UINT16
);
1653 case EFI_IMAGE_REL_BASED_LOW
:
1654 Fixup16
= (UINT16
*) Fixup
;
1655 if (*(UINT16
*) FixupData
== *Fixup16
) {
1656 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) Adjust
& 0xffff));
1659 FixupData
= FixupData
+ sizeof (UINT16
);
1662 case EFI_IMAGE_REL_BASED_HIGHLOW
:
1663 Fixup32
= (UINT32
*) Fixup
;
1664 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
1665 if (*(UINT32
*) FixupData
== *Fixup32
) {
1666 *Fixup32
= *Fixup32
+ (UINT32
) Adjust
;
1669 FixupData
= FixupData
+ sizeof (UINT32
);
1672 case EFI_IMAGE_REL_BASED_DIR64
:
1673 Fixup64
= (UINT64
*)Fixup
;
1674 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT64
));
1675 if (*(UINT64
*) FixupData
== *Fixup64
) {
1676 *Fixup64
= *Fixup64
+ (UINT64
)Adjust
;
1679 FixupData
= FixupData
+ sizeof (UINT64
);
1682 case EFI_IMAGE_REL_BASED_HIGHADJ
:
1684 // Not valid Relocation type for UEFI image, ASSERT
1691 // Only Itanium requires ConvertPeImage_Ex
1693 Status
= PeHotRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
1694 if (RETURN_ERROR (Status
)) {
1699 // Next relocation record
1706 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
1712 Reads contents of a PE/COFF image from a buffer in system memory.
1714 This is the default implementation of a PE_COFF_LOADER_READ_FILE function
1715 that assumes FileHandle pointer to the beginning of a PE/COFF image.
1716 This function reads contents of the PE/COFF image that starts at the system memory
1717 address specified by FileHandle. The read operation copies ReadSize bytes from the
1718 PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer.
1719 The size of the buffer actually read is returned in ReadSize.
1721 If FileHandle is NULL, then ASSERT().
1722 If ReadSize is NULL, then ASSERT().
1723 If Buffer is NULL, then ASSERT().
1725 @param FileHandle The pointer to base of the input stream
1726 @param FileOffset Offset into the PE/COFF image to begin the read operation.
1727 @param ReadSize On input, the size in bytes of the requested read operation.
1728 On output, the number of bytes actually read.
1729 @param Buffer Output buffer that contains the data read from the PE/COFF image.
1731 @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into
1736 PeCoffLoaderImageReadFromMemory (
1737 IN VOID
*FileHandle
,
1738 IN UINTN FileOffset
,
1739 IN OUT UINTN
*ReadSize
,
1743 ASSERT (ReadSize
!= NULL
);
1744 ASSERT (FileHandle
!= NULL
);
1745 ASSERT (Buffer
!= NULL
);
1747 CopyMem (Buffer
, ((UINT8
*)FileHandle
) + FileOffset
, *ReadSize
);
1748 return RETURN_SUCCESS
;
1752 Unloads a loaded PE/COFF image from memory and releases its taken resource.
1753 Releases any environment specific resources that were allocated when the image
1754 specified by ImageContext was loaded using PeCoffLoaderLoadImage().
1756 For NT32 emulator, the PE/COFF image loaded by system needs to release.
1757 For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded,
1758 this function can simply return RETURN_SUCCESS.
1760 If ImageContext is NULL, then ASSERT().
1762 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1763 image to be unloaded.
1765 @retval RETURN_SUCCESS The PE/COFF image was unloaded successfully.
1769 PeCoffLoaderUnloadImage (
1770 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1774 // Applies additional environment specific actions to unload a
1775 // PE/COFF image if needed
1777 PeCoffLoaderUnloadImageExtraAction (ImageContext
);
1778 return RETURN_SUCCESS
;