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
;
90 UINT32 HeaderWithoutDataDir
;
92 UINTN NumberOfSections
;
93 EFI_IMAGE_SECTION_HEADER SectionHeader
;
96 // Read the DOS image header to check for its existence
98 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
100 Status
= ImageContext
->ImageRead (
101 ImageContext
->Handle
,
106 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
107 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
108 if (Size
!= ReadSize
) {
109 Status
= RETURN_UNSUPPORTED
;
114 ImageContext
->PeCoffHeaderOffset
= 0;
115 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
117 // DOS image header is present, so read the PE header after the DOS image
120 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
124 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
125 // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
126 // determines if this is a PE32 or PE32+ image. The magic is in the same
127 // location in both images.
129 Size
= sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION
);
131 Status
= ImageContext
->ImageRead (
132 ImageContext
->Handle
,
133 ImageContext
->PeCoffHeaderOffset
,
137 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
138 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
139 if (Size
!= ReadSize
) {
140 Status
= RETURN_UNSUPPORTED
;
146 // Use Signature to figure out if we understand the image format
148 if (Hdr
.Te
->Signature
== EFI_TE_IMAGE_HEADER_SIGNATURE
) {
149 ImageContext
->IsTeImage
= TRUE
;
150 ImageContext
->Machine
= Hdr
.Te
->Machine
;
151 ImageContext
->ImageType
= (UINT16
)(Hdr
.Te
->Subsystem
);
153 // For TeImage, SectionAlignment is undefined to be set to Zero
154 // ImageSize can be calculated.
156 ImageContext
->ImageSize
= 0;
157 ImageContext
->SectionAlignment
= 0;
158 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
)Hdr
.Te
->BaseOfCode
- (UINTN
)Hdr
.Te
->StrippedSize
;
160 } else if (Hdr
.Pe32
->Signature
== EFI_IMAGE_NT_SIGNATURE
) {
161 ImageContext
->IsTeImage
= FALSE
;
162 ImageContext
->Machine
= Hdr
.Pe32
->FileHeader
.Machine
;
164 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
166 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
168 // 1. Check OptionalHeader.NumberOfRvaAndSizes filed.
170 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
< Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) {
171 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
172 return RETURN_UNSUPPORTED
;
176 // 2. Check the FileHeader.SizeOfOptionalHeader field.
177 // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
178 // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
180 HeaderWithoutDataDir
= sizeof (EFI_IMAGE_OPTIONAL_HEADER32
) - sizeof (EFI_IMAGE_DATA_DIRECTORY
) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
;
181 if (((UINT32
)Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
- HeaderWithoutDataDir
) !=
182 Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
* sizeof (EFI_IMAGE_DATA_DIRECTORY
)) {
183 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
184 return RETURN_UNSUPPORTED
;
187 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
189 // 3. Check the FileHeader.NumberOfSections field.
191 if ((Hdr
.Pe32
->OptionalHeader
.SizeOfImage
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
<= Hdr
.Pe32
->FileHeader
.NumberOfSections
) {
192 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
193 return RETURN_UNSUPPORTED
;
197 // 4. Check the OptionalHeader.SizeOfHeaders field.
199 if ((Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
< (UINT32
)Hdr
.Pe32
->FileHeader
.NumberOfSections
) {
200 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
201 return RETURN_UNSUPPORTED
;
205 // 4.2 Read last byte of Hdr.Pe32.OptionalHeader.SizeOfHeaders from the file.
209 Status
= ImageContext
->ImageRead (
210 ImageContext
->Handle
,
211 Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
- 1,
215 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
216 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
217 if (Size
!= ReadSize
) {
218 Status
= RETURN_UNSUPPORTED
;
224 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
225 // Read the last byte to make sure the data is in the image region.
226 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
228 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
< Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
) {
229 if (Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
!= 0) {
231 // Check the member data to avoid overflow.
233 if ((UINT32
) (~0) - Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
<
234 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
) {
235 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
236 return RETURN_UNSUPPORTED
;
240 // Read last byte of section header from file
244 Status
= ImageContext
->ImageRead (
245 ImageContext
->Handle
,
246 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
+
247 Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
- 1,
251 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
252 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
253 if (Size
!= ReadSize
) {
254 Status
= RETURN_UNSUPPORTED
;
264 ImageContext
->ImageType
= Hdr
.Pe32
->OptionalHeader
.Subsystem
;
265 ImageContext
->ImageSize
= (UINT64
)Hdr
.Pe32
->OptionalHeader
.SizeOfImage
;
266 ImageContext
->SectionAlignment
= Hdr
.Pe32
->OptionalHeader
.SectionAlignment
;
267 ImageContext
->SizeOfHeaders
= Hdr
.Pe32
->OptionalHeader
.SizeOfHeaders
;
269 } else if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
271 // 1. Check FileHeader.NumberOfRvaAndSizes filed.
273 if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
< Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
274 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
275 return RETURN_UNSUPPORTED
;
278 // 2. Check the FileHeader.SizeOfOptionalHeader field.
279 // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
280 // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
282 HeaderWithoutDataDir
= sizeof (EFI_IMAGE_OPTIONAL_HEADER64
) - sizeof (EFI_IMAGE_DATA_DIRECTORY
) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES
;
283 if (((UINT32
)Hdr
.Pe32Plus
->FileHeader
.SizeOfOptionalHeader
- HeaderWithoutDataDir
) !=
284 Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
* sizeof (EFI_IMAGE_DATA_DIRECTORY
)) {
285 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
286 return RETURN_UNSUPPORTED
;
289 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32Plus
->FileHeader
.SizeOfOptionalHeader
;
291 // 3. Check the FileHeader.NumberOfSections field.
293 if ((Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
<= Hdr
.Pe32Plus
->FileHeader
.NumberOfSections
) {
294 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
295 return RETURN_UNSUPPORTED
;
299 // 4. Check the OptionalHeader.SizeOfHeaders field.
301 if ((Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- SectionHeaderOffset
) / EFI_IMAGE_SIZEOF_SECTION_HEADER
< (UINT32
)Hdr
.Pe32Plus
->FileHeader
.NumberOfSections
) {
302 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
303 return RETURN_UNSUPPORTED
;
307 // 4.2 Read last byte of Hdr.Pe32Plus.OptionalHeader.SizeOfHeaders from the file.
311 Status
= ImageContext
->ImageRead (
312 ImageContext
->Handle
,
313 Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
- 1,
317 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
318 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
319 if (Size
!= ReadSize
) {
320 Status
= RETURN_UNSUPPORTED
;
326 // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
327 // Read the last byte to make sure the data is in the image region.
328 // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
330 if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
< Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
) {
331 if (Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
!= 0) {
333 // Check the member data to avoid overflow.
335 if ((UINT32
) (~0) - Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
<
336 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
) {
337 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
338 return RETURN_UNSUPPORTED
;
342 // Read last byte of section header from file
346 Status
= ImageContext
->ImageRead (
347 ImageContext
->Handle
,
348 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].VirtualAddress
+
349 Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY
].Size
- 1,
353 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
354 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
355 if (Size
!= ReadSize
) {
356 Status
= RETURN_UNSUPPORTED
;
366 ImageContext
->ImageType
= Hdr
.Pe32Plus
->OptionalHeader
.Subsystem
;
367 ImageContext
->ImageSize
= (UINT64
) Hdr
.Pe32Plus
->OptionalHeader
.SizeOfImage
;
368 ImageContext
->SectionAlignment
= Hdr
.Pe32Plus
->OptionalHeader
.SectionAlignment
;
369 ImageContext
->SizeOfHeaders
= Hdr
.Pe32Plus
->OptionalHeader
.SizeOfHeaders
;
371 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
372 return RETURN_UNSUPPORTED
;
375 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
376 return RETURN_UNSUPPORTED
;
379 if (!PeCoffLoaderImageFormatSupported (ImageContext
->Machine
)) {
381 // If the PE/COFF loader does not support the image type return
382 // unsupported. This library can support lots of types of images
383 // this does not mean the user of this library can call the entry
384 // point of the image.
386 return RETURN_UNSUPPORTED
;
390 // Check each section field.
392 if (ImageContext
->IsTeImage
) {
393 SectionHeaderOffset
= sizeof(EFI_TE_IMAGE_HEADER
);
394 NumberOfSections
= (UINTN
) (Hdr
.Te
->NumberOfSections
);
396 SectionHeaderOffset
= ImageContext
->PeCoffHeaderOffset
+ sizeof (UINT32
) + sizeof (EFI_IMAGE_FILE_HEADER
) + Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
;
397 NumberOfSections
= (UINTN
) (Hdr
.Pe32
->FileHeader
.NumberOfSections
);
400 for (Index
= 0; Index
< NumberOfSections
; Index
++) {
402 // Read section header from file
404 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
406 Status
= ImageContext
->ImageRead (
407 ImageContext
->Handle
,
412 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
413 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
414 if (Size
!= ReadSize
) {
415 Status
= RETURN_UNSUPPORTED
;
420 if (SectionHeader
.SizeOfRawData
> 0) {
422 // Section data should bigger than the Pe header.
424 if (SectionHeader
.VirtualAddress
< ImageContext
->SizeOfHeaders
||
425 SectionHeader
.PointerToRawData
< ImageContext
->SizeOfHeaders
) {
426 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
427 return RETURN_UNSUPPORTED
;
431 // Check the member data to avoid overflow.
433 if ((UINT32
) (~0) - SectionHeader
.PointerToRawData
< SectionHeader
.SizeOfRawData
) {
434 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
435 return RETURN_UNSUPPORTED
;
439 // Base on the ImageRead function to check the section data field.
440 // Read the last byte to make sure the data is in the image region.
444 Status
= ImageContext
->ImageRead (
445 ImageContext
->Handle
,
446 SectionHeader
.PointerToRawData
+ SectionHeader
.SizeOfRawData
- 1,
450 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
451 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
452 if (Size
!= ReadSize
) {
453 Status
= RETURN_UNSUPPORTED
;
460 // Check next section.
462 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
465 return RETURN_SUCCESS
;
470 Retrieves information about a PE/COFF image.
472 Computes the PeCoffHeaderOffset, IsTeImage, ImageType, ImageAddress, ImageSize,
473 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and
474 DebugDirectoryEntryRva fields of the ImageContext structure.
475 If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.
476 If the PE/COFF image accessed through the ImageRead service in the ImageContext
477 structure is not a supported PE/COFF image type, then return RETURN_UNSUPPORTED.
478 If any errors occur while computing the fields of ImageContext,
479 then the error status is returned in the ImageError field of ImageContext.
480 If the image is a TE image, then SectionAlignment is set to 0.
481 The ImageRead and Handle fields of ImageContext structure must be valid prior
482 to invoking this service.
484 Caution: This function may receive untrusted input.
485 PE/COFF image is external input, so this routine will
486 also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
487 SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
489 @param ImageContext The pointer to the image context structure that describes the PE/COFF
490 image that needs to be examined by this function.
492 @retval RETURN_SUCCESS The information on the PE/COFF image was collected.
493 @retval RETURN_INVALID_PARAMETER ImageContext is NULL.
494 @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.
499 PeCoffLoaderGetImageInfo (
500 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
503 RETURN_STATUS Status
;
504 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData
;
505 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
506 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
510 UINTN DebugDirectoryEntryRva
;
511 UINTN DebugDirectoryEntryFileOffset
;
512 UINTN SectionHeaderOffset
;
513 EFI_IMAGE_SECTION_HEADER SectionHeader
;
514 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
515 UINT32 NumberOfRvaAndSizes
;
518 if (ImageContext
== NULL
) {
519 return RETURN_INVALID_PARAMETER
;
524 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
526 Hdr
.Union
= &HdrData
;
527 Status
= PeCoffLoaderGetPeHeader (ImageContext
, Hdr
);
528 if (RETURN_ERROR (Status
)) {
532 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
535 // Retrieve the base address of the image
537 if (!(ImageContext
->IsTeImage
)) {
538 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
542 ImageContext
->ImageAddress
= Hdr
.Pe32
->OptionalHeader
.ImageBase
;
547 ImageContext
->ImageAddress
= Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
550 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
)(Hdr
.Te
->ImageBase
+ Hdr
.Te
->StrippedSize
- sizeof (EFI_TE_IMAGE_HEADER
));
554 // Initialize the alternate destination address to 0 indicating that it
555 // should not be used.
557 ImageContext
->DestinationAddress
= 0;
560 // Initialize the debug codeview pointer.
562 ImageContext
->DebugDirectoryEntryRva
= 0;
563 ImageContext
->CodeView
= NULL
;
564 ImageContext
->PdbPointer
= NULL
;
567 // Three cases with regards to relocations:
568 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
569 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
570 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
571 // has no base relocs to apply
572 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
574 // Look at the file header to determine if relocations have been stripped, and
575 // save this information in the image context for later use.
577 if ((!(ImageContext
->IsTeImage
)) && ((Hdr
.Pe32
->FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
578 ImageContext
->RelocationsStripped
= TRUE
;
579 } else if ((ImageContext
->IsTeImage
) && (Hdr
.Te
->DataDirectory
[0].Size
== 0) && (Hdr
.Te
->DataDirectory
[0].VirtualAddress
== 0)) {
580 ImageContext
->RelocationsStripped
= TRUE
;
582 ImageContext
->RelocationsStripped
= FALSE
;
586 // TE Image Relocation Data Directory Entry size is non-zero, but the Relocation Data Directory Virtual Address is zero.
587 // This case is not a valid TE image.
589 if ((ImageContext
->IsTeImage
) && (Hdr
.Te
->DataDirectory
[0].Size
!= 0) && (Hdr
.Te
->DataDirectory
[0].VirtualAddress
== 0)) {
590 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
591 return RETURN_UNSUPPORTED
;
594 if (!(ImageContext
->IsTeImage
)) {
595 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
599 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
600 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
605 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
606 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
609 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
611 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
614 // Determine the file offset of the debug directory... This means we walk
615 // the sections to find which section contains the RVA of the debug
618 DebugDirectoryEntryFileOffset
= 0;
620 SectionHeaderOffset
= (UINTN
)(
621 ImageContext
->PeCoffHeaderOffset
+
623 sizeof (EFI_IMAGE_FILE_HEADER
) +
624 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
627 for (Index
= 0; Index
< Hdr
.Pe32
->FileHeader
.NumberOfSections
; Index
++) {
629 // Read section header from file
631 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
633 Status
= ImageContext
->ImageRead (
634 ImageContext
->Handle
,
639 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
640 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
641 if (Size
!= ReadSize
) {
642 Status
= RETURN_UNSUPPORTED
;
647 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
648 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
650 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
654 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
657 if (DebugDirectoryEntryFileOffset
!= 0) {
658 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
660 // Read next debug directory entry
662 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
664 Status
= ImageContext
->ImageRead (
665 ImageContext
->Handle
,
666 DebugDirectoryEntryFileOffset
+ Index
,
670 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
671 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
672 if (Size
!= ReadSize
) {
673 Status
= RETURN_UNSUPPORTED
;
679 // From PeCoff spec, when DebugEntry.RVA == 0 means this debug info will not load into memory.
680 // Here we will always load EFI_IMAGE_DEBUG_TYPE_CODEVIEW type debug info. so need adjust the
681 // ImageContext->ImageSize when DebugEntry.RVA == 0.
683 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
684 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
685 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
686 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
689 return RETURN_SUCCESS
;
696 DebugDirectoryEntry
= &Hdr
.Te
->DataDirectory
[1];
697 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
698 SectionHeaderOffset
= (UINTN
)(sizeof (EFI_TE_IMAGE_HEADER
));
700 DebugDirectoryEntryFileOffset
= 0;
702 for (Index
= 0; Index
< Hdr
.Te
->NumberOfSections
;) {
704 // Read section header from file
706 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
708 Status
= ImageContext
->ImageRead (
709 ImageContext
->Handle
,
714 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
715 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
716 if (Size
!= ReadSize
) {
717 Status
= RETURN_UNSUPPORTED
;
722 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
723 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
724 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
725 SectionHeader
.VirtualAddress
+
726 SectionHeader
.PointerToRawData
+
727 sizeof (EFI_TE_IMAGE_HEADER
) -
728 Hdr
.Te
->StrippedSize
;
731 // File offset of the debug directory was found, if this is not the last
732 // section, then skip to the last section for calculating the image size.
734 if (Index
< (UINTN
) Hdr
.Te
->NumberOfSections
- 1) {
735 SectionHeaderOffset
+= (Hdr
.Te
->NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
736 Index
= Hdr
.Te
->NumberOfSections
- 1;
742 // In Te image header there is not a field to describe the ImageSize.
743 // Actually, the ImageSize equals the RVA plus the VirtualSize of
744 // the last section mapped into memory (Must be rounded up to
745 // a multiple of Section Alignment). Per the PE/COFF specification, the
746 // section headers in the Section Table must appear in order of the RVA
747 // values for the corresponding sections. So the ImageSize can be determined
748 // by the RVA and the VirtualSize of the last section header in the
751 if ((++Index
) == (UINTN
)Hdr
.Te
->NumberOfSections
) {
752 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
);
755 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
758 if (DebugDirectoryEntryFileOffset
!= 0) {
759 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
+= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
)) {
761 // Read next debug directory entry
763 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
765 Status
= ImageContext
->ImageRead (
766 ImageContext
->Handle
,
767 DebugDirectoryEntryFileOffset
+ Index
,
771 if (RETURN_ERROR (Status
) || (Size
!= ReadSize
)) {
772 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
773 if (Size
!= ReadSize
) {
774 Status
= RETURN_UNSUPPORTED
;
779 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
780 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
);
781 return RETURN_SUCCESS
;
787 return RETURN_SUCCESS
;
792 Converts an image address to the loaded address.
794 @param ImageContext The context of the image being loaded.
795 @param Address The relative virtual address to be converted to the loaded address.
797 @return The converted address or NULL if the address can not be converted.
801 PeCoffLoaderImageAddress (
802 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
807 // Make sure that Address and ImageSize is correct for the loaded image.
809 if (Address
>= ImageContext
->ImageSize
) {
810 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
814 return (CHAR8
*)((UINTN
) ImageContext
->ImageAddress
+ Address
);
818 Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().
820 If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of
821 ImageContext as the relocation base address. Otherwise, use the DestinationAddress field
822 of ImageContext as the relocation base address. The caller must allocate the relocation
823 fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.
825 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress,
826 ImageSize, DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders,
827 DebugDirectoryEntryRva, EntryPoint, FixupDataSize, CodeView, PdbPointer, and FixupData of
828 the ImageContext structure must be valid prior to invoking this service.
830 If ImageContext is NULL, then ASSERT().
832 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
833 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
834 prior to transferring control to a PE/COFF image that is loaded using this library.
836 @param ImageContext The pointer to the image context structure that describes the PE/COFF
837 image that is being relocated.
839 @retval RETURN_SUCCESS The PE/COFF image was relocated.
840 Extended status information is in the ImageError field of ImageContext.
841 @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.
842 Extended status information is in the ImageError field of ImageContext.
843 @retval RETURN_UNSUPPORTED A relocation record type is not supported.
844 Extended status information is in the ImageError field of ImageContext.
849 PeCoffLoaderRelocateImage (
850 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
853 RETURN_STATUS Status
;
854 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
855 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
857 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
858 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
867 PHYSICAL_ADDRESS BaseAddress
;
868 UINT32 NumberOfRvaAndSizes
;
871 ASSERT (ImageContext
!= NULL
);
876 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
879 // If there are no relocation entries, then we are done
881 if (ImageContext
->RelocationsStripped
) {
882 // Applies additional environment specific actions to relocate fixups
883 // to a PE/COFF image if needed
884 PeCoffLoaderRelocateImageExtraAction (ImageContext
);
885 return RETURN_SUCCESS
;
889 // If the destination address is not 0, use that rather than the
890 // image address as the relocation target.
892 if (ImageContext
->DestinationAddress
!= 0) {
893 BaseAddress
= ImageContext
->DestinationAddress
;
895 BaseAddress
= ImageContext
->ImageAddress
;
898 if (!(ImageContext
->IsTeImage
)) {
899 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
901 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
903 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
907 Adjust
= (UINT64
)BaseAddress
- Hdr
.Pe32
->OptionalHeader
.ImageBase
;
909 Hdr
.Pe32
->OptionalHeader
.ImageBase
= (UINT32
)BaseAddress
;
912 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
913 RelocDir
= &Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
918 Adjust
= (UINT64
) BaseAddress
- Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
;
920 Hdr
.Pe32Plus
->OptionalHeader
.ImageBase
= (UINT64
)BaseAddress
;
923 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
924 RelocDir
= &Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
928 // Find the relocation block
929 // Per the PE/COFF spec, you can't assume that a given data directory
930 // is present in the image. You have to check the NumberOfRvaAndSizes in
931 // the optional header to verify a desired directory entry is there.
934 if ((NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) && (RelocDir
->Size
> 0)) {
935 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
936 RelocBaseEnd
= PeCoffLoaderImageAddress (
938 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
940 if (RelocBase
== NULL
|| RelocBaseEnd
== NULL
) {
941 return RETURN_LOAD_ERROR
;
945 // Set base and end to bypass processing below.
947 RelocBase
= RelocBaseEnd
= NULL
;
950 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
951 Adjust
= (UINT64
) (BaseAddress
- Hdr
.Te
->StrippedSize
+ sizeof (EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->ImageBase
);
953 Hdr
.Te
->ImageBase
= (UINT64
) (BaseAddress
- Hdr
.Te
->StrippedSize
+ sizeof (EFI_TE_IMAGE_HEADER
));
957 // Find the relocation block
959 RelocDir
= &Hdr
.Te
->DataDirectory
[0];
960 if (RelocDir
->Size
> 0) {
961 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(
962 ImageContext
->ImageAddress
+
963 RelocDir
->VirtualAddress
+
964 sizeof(EFI_TE_IMAGE_HEADER
) -
967 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) ((UINTN
) RelocBase
+ (UINTN
) RelocDir
->Size
- 1);
970 // Set base and end to bypass processing below.
972 RelocBase
= RelocBaseEnd
= NULL
;
977 // If Adjust is not zero, then apply fix ups to the image
981 // Run the relocation information and apply the fixups
983 FixupData
= ImageContext
->FixupData
;
984 while (RelocBase
< RelocBaseEnd
) {
986 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
987 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
990 // Make sure RelocEnd is in the Image range.
992 if ((CHAR8
*) RelocEnd
< (CHAR8
*)((UINTN
) ImageContext
->ImageAddress
) ||
993 (CHAR8
*) RelocEnd
> (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+ (UINTN
)ImageContext
->ImageSize
)) {
994 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
995 return RETURN_LOAD_ERROR
;
998 if (!(ImageContext
->IsTeImage
)) {
999 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
);
1000 if (FixupBase
== NULL
) {
1001 return RETURN_LOAD_ERROR
;
1004 FixupBase
= (CHAR8
*)(UINTN
)(ImageContext
->ImageAddress
+
1005 RelocBase
->VirtualAddress
+
1006 sizeof(EFI_TE_IMAGE_HEADER
) -
1007 Hdr
.Te
->StrippedSize
1012 // Run this relocation record
1014 while (Reloc
< RelocEnd
) {
1016 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
1017 switch ((*Reloc
) >> 12) {
1018 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
1021 case EFI_IMAGE_REL_BASED_HIGH
:
1022 Fixup16
= (UINT16
*) Fixup
;
1023 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
1024 if (FixupData
!= NULL
) {
1025 *(UINT16
*) FixupData
= *Fixup16
;
1026 FixupData
= FixupData
+ sizeof (UINT16
);
1030 case EFI_IMAGE_REL_BASED_LOW
:
1031 Fixup16
= (UINT16
*) Fixup
;
1032 *Fixup16
= (UINT16
) (*Fixup16
+ (UINT16
) Adjust
);
1033 if (FixupData
!= NULL
) {
1034 *(UINT16
*) FixupData
= *Fixup16
;
1035 FixupData
= FixupData
+ sizeof (UINT16
);
1039 case EFI_IMAGE_REL_BASED_HIGHLOW
:
1040 Fixup32
= (UINT32
*) Fixup
;
1041 *Fixup32
= *Fixup32
+ (UINT32
) Adjust
;
1042 if (FixupData
!= NULL
) {
1043 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
1044 *(UINT32
*)FixupData
= *Fixup32
;
1045 FixupData
= FixupData
+ sizeof (UINT32
);
1049 case EFI_IMAGE_REL_BASED_DIR64
:
1050 Fixup64
= (UINT64
*) Fixup
;
1051 *Fixup64
= *Fixup64
+ (UINT64
) Adjust
;
1052 if (FixupData
!= NULL
) {
1053 FixupData
= ALIGN_POINTER (FixupData
, sizeof(UINT64
));
1054 *(UINT64
*)(FixupData
) = *Fixup64
;
1055 FixupData
= FixupData
+ sizeof(UINT64
);
1061 // The common code does not handle some of the stranger IPF relocations
1062 // PeCoffLoaderRelocateImageEx () adds support for these complex fixups
1063 // on IPF and is a No-Op on other architectures.
1065 Status
= PeCoffLoaderRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
1066 if (RETURN_ERROR (Status
)) {
1067 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
1073 // Next relocation record
1081 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
1085 // Adjust the EntryPoint to match the linked-to address
1087 if (ImageContext
->DestinationAddress
!= 0) {
1088 ImageContext
->EntryPoint
-= (UINT64
) ImageContext
->ImageAddress
;
1089 ImageContext
->EntryPoint
+= (UINT64
) ImageContext
->DestinationAddress
;
1093 // Applies additional environment specific actions to relocate fixups
1094 // to a PE/COFF image if needed
1095 PeCoffLoaderRelocateImageExtraAction (ImageContext
);
1097 return RETURN_SUCCESS
;
1101 Loads a PE/COFF image into memory.
1103 Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
1104 specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate
1105 the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
1106 The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.
1107 The ImageRead, Handle, PeCoffHeaderOffset, IsTeImage, Machine, ImageType, ImageAddress, ImageSize,
1108 DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
1109 fields of the ImageContext structure must be valid prior to invoking this service.
1111 If ImageContext is NULL, then ASSERT().
1113 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1114 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1115 prior to transferring control to a PE/COFF image that is loaded using this library.
1117 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1118 image that is being loaded.
1120 @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by
1121 the ImageAddress and ImageSize fields of ImageContext.
1122 Extended status information is in the ImageError field of ImageContext.
1123 @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.
1124 Extended status information is in the ImageError field of ImageContext.
1125 @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.
1126 Extended status information is in the ImageError field of ImageContext.
1127 @retval RETURN_INVALID_PARAMETER The image address is invalid.
1128 Extended status information is in the ImageError field of ImageContext.
1133 PeCoffLoaderLoadImage (
1134 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1137 RETURN_STATUS Status
;
1138 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1139 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
1140 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
1141 EFI_IMAGE_SECTION_HEADER
*Section
;
1142 UINTN NumberOfSections
;
1146 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
1147 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
1149 UINT32 TempDebugEntryRva
;
1150 UINT32 NumberOfRvaAndSizes
;
1152 EFI_IMAGE_RESOURCE_DIRECTORY
*ResourceDirectory
;
1153 EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*ResourceDirectoryEntry
;
1154 EFI_IMAGE_RESOURCE_DIRECTORY_STRING
*ResourceDirectoryString
;
1155 EFI_IMAGE_RESOURCE_DATA_ENTRY
*ResourceDataEntry
;
1160 ASSERT (ImageContext
!= NULL
);
1165 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
1168 // Copy the provided context information into our local version, get what we
1169 // can from the original image, and then use that to make sure everything
1172 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
1174 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
1175 if (RETURN_ERROR (Status
)) {
1180 // Make sure there is enough allocated space for the image being loaded
1182 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
1183 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
1184 return RETURN_BUFFER_TOO_SMALL
;
1186 if (ImageContext
->ImageAddress
== 0) {
1188 // Image cannot be loaded into 0 address.
1190 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1191 return RETURN_INVALID_PARAMETER
;
1194 // If there's no relocations, then make sure it's not a runtime driver,
1195 // and that it's being loaded at the linked address.
1197 if (CheckContext
.RelocationsStripped
) {
1199 // If the image does not contain relocations and it is a runtime driver
1200 // then return an error.
1202 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
1203 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
1204 return RETURN_LOAD_ERROR
;
1207 // If the image does not contain relocations, and the requested load address
1208 // is not the linked address, then return an error.
1210 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
1211 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
1212 return RETURN_INVALID_PARAMETER
;
1216 // Make sure the allocated space has the proper section alignment
1218 if (!(ImageContext
->IsTeImage
)) {
1219 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
1220 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
1221 return RETURN_INVALID_PARAMETER
;
1225 // Read the entire PE/COFF or TE header into memory
1227 if (!(ImageContext
->IsTeImage
)) {
1228 Status
= ImageContext
->ImageRead (
1229 ImageContext
->Handle
,
1231 &ImageContext
->SizeOfHeaders
,
1232 (VOID
*) (UINTN
) ImageContext
->ImageAddress
1235 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
1237 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
1238 (UINTN
)ImageContext
->ImageAddress
+
1239 ImageContext
->PeCoffHeaderOffset
+
1241 sizeof(EFI_IMAGE_FILE_HEADER
) +
1242 Hdr
.Pe32
->FileHeader
.SizeOfOptionalHeader
1244 NumberOfSections
= (UINTN
) (Hdr
.Pe32
->FileHeader
.NumberOfSections
);
1246 Status
= ImageContext
->ImageRead (
1247 ImageContext
->Handle
,
1249 &ImageContext
->SizeOfHeaders
,
1250 (void *)(UINTN
)ImageContext
->ImageAddress
1253 Hdr
.Te
= (EFI_TE_IMAGE_HEADER
*)(UINTN
)(ImageContext
->ImageAddress
);
1255 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
1256 (UINTN
)ImageContext
->ImageAddress
+
1257 sizeof(EFI_TE_IMAGE_HEADER
)
1259 NumberOfSections
= (UINTN
) (Hdr
.Te
->NumberOfSections
);
1263 if (RETURN_ERROR (Status
)) {
1264 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1265 return RETURN_LOAD_ERROR
;
1269 // Load each section of the image
1271 Section
= FirstSection
;
1272 for (Index
= 0; Index
< NumberOfSections
; Index
++) {
1276 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
1277 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
1278 Size
= (UINTN
) Section
->SizeOfRawData
;
1282 // Compute sections address
1284 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
);
1285 End
= PeCoffLoaderImageAddress (
1287 Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1
1291 // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.
1293 if ((Size
> 0) && ((Base
== NULL
) || (End
== NULL
))) {
1294 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
1295 return RETURN_LOAD_ERROR
;
1298 if (ImageContext
->IsTeImage
) {
1299 Base
= (CHAR8
*)((UINTN
) Base
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
)Hdr
.Te
->StrippedSize
);
1300 End
= (CHAR8
*)((UINTN
) End
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
)Hdr
.Te
->StrippedSize
);
1303 if (Section
->SizeOfRawData
> 0) {
1304 if (!(ImageContext
->IsTeImage
)) {
1305 Status
= ImageContext
->ImageRead (
1306 ImageContext
->Handle
,
1307 Section
->PointerToRawData
,
1312 Status
= ImageContext
->ImageRead (
1313 ImageContext
->Handle
,
1314 Section
->PointerToRawData
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
)Hdr
.Te
->StrippedSize
,
1320 if (RETURN_ERROR (Status
)) {
1321 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1327 // If raw size is less then virtual size, zero fill the remaining
1330 if (Size
< Section
->Misc
.VirtualSize
) {
1331 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
1341 // Get image's entry point
1343 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
1344 if (!(ImageContext
->IsTeImage
)) {
1346 // Sizes of AddressOfEntryPoint are different so we need to do this safely
1348 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1352 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1354 (UINTN
)Hdr
.Pe32
->OptionalHeader
.AddressOfEntryPoint
1360 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
)(UINTN
)PeCoffLoaderImageAddress (
1362 (UINTN
)Hdr
.Pe32Plus
->OptionalHeader
.AddressOfEntryPoint
1366 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (
1367 (UINTN
)ImageContext
->ImageAddress
+
1368 (UINTN
)Hdr
.Te
->AddressOfEntryPoint
+
1369 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
1370 (UINTN
)Hdr
.Te
->StrippedSize
1375 // Determine the size of the fixup data
1377 // Per the PE/COFF spec, you can't assume that a given data directory
1378 // is present in the image. You have to check the NumberOfRvaAndSizes in
1379 // the optional header to verify a desired directory entry is there.
1381 if (!(ImageContext
->IsTeImage
)) {
1382 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1386 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1387 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1392 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1393 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
1396 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1397 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1399 ImageContext
->FixupDataSize
= 0;
1402 DirectoryEntry
= &Hdr
.Te
->DataDirectory
[0];
1403 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
1406 // Consumer must allocate a buffer for the relocation fixup log.
1407 // Only used for runtime drivers.
1409 ImageContext
->FixupData
= NULL
;
1412 // Load the Codeview information if present
1414 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
1415 if (!(ImageContext
->IsTeImage
)) {
1416 DebugEntry
= PeCoffLoaderImageAddress (
1418 ImageContext
->DebugDirectoryEntryRva
1421 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(UINTN
)(
1422 ImageContext
->ImageAddress
+
1423 ImageContext
->DebugDirectoryEntryRva
+
1424 sizeof(EFI_TE_IMAGE_HEADER
) -
1425 Hdr
.Te
->StrippedSize
1429 if (DebugEntry
!= NULL
) {
1430 TempDebugEntryRva
= DebugEntry
->RVA
;
1431 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
1433 if ((UINTN
)Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
1434 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
1436 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
1440 if (TempDebugEntryRva
!= 0) {
1441 if (!(ImageContext
->IsTeImage
)) {
1442 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
);
1444 ImageContext
->CodeView
= (VOID
*)(
1445 (UINTN
)ImageContext
->ImageAddress
+
1446 (UINTN
)TempDebugEntryRva
+
1447 (UINTN
)sizeof (EFI_TE_IMAGE_HEADER
) -
1448 (UINTN
) Hdr
.Te
->StrippedSize
1452 if (ImageContext
->CodeView
== NULL
) {
1453 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1454 return RETURN_LOAD_ERROR
;
1457 if (DebugEntry
->RVA
== 0) {
1458 Size
= DebugEntry
->SizeOfData
;
1459 if (!(ImageContext
->IsTeImage
)) {
1460 Status
= ImageContext
->ImageRead (
1461 ImageContext
->Handle
,
1462 DebugEntry
->FileOffset
,
1464 ImageContext
->CodeView
1467 Status
= ImageContext
->ImageRead (
1468 ImageContext
->Handle
,
1469 DebugEntry
->FileOffset
+ sizeof (EFI_TE_IMAGE_HEADER
) - Hdr
.Te
->StrippedSize
,
1471 ImageContext
->CodeView
1474 // Should we apply fix up to this field according to the size difference between PE and TE?
1475 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1476 // in original PE image.
1480 if (RETURN_ERROR (Status
)) {
1481 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1482 return RETURN_LOAD_ERROR
;
1485 DebugEntry
->RVA
= TempDebugEntryRva
;
1488 switch (*(UINT32
*) ImageContext
->CodeView
) {
1489 case CODEVIEW_SIGNATURE_NB10
:
1490 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
)) {
1491 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1492 return RETURN_UNSUPPORTED
;
1494 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1497 case CODEVIEW_SIGNATURE_RSDS
:
1498 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
)) {
1499 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1500 return RETURN_UNSUPPORTED
;
1502 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);
1505 case CODEVIEW_SIGNATURE_MTOC
:
1506 if (DebugEntry
->SizeOfData
< sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
)) {
1507 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1508 return RETURN_UNSUPPORTED
;
1510 ImageContext
->PdbPointer
= (CHAR8
*)ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY
);
1521 // Get Image's HII resource section
1523 ImageContext
->HiiResourceData
= 0;
1524 if (!(ImageContext
->IsTeImage
)) {
1525 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1529 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1530 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
];
1535 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1536 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)&Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
];
1539 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE
&& DirectoryEntry
->Size
!= 0) {
1540 Base
= PeCoffLoaderImageAddress (ImageContext
, DirectoryEntry
->VirtualAddress
);
1542 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) Base
;
1543 Offset
= sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) *
1544 (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1545 if (Offset
> DirectoryEntry
->Size
) {
1546 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1547 return RETURN_UNSUPPORTED
;
1549 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1551 for (Index
= 0; Index
< ResourceDirectory
->NumberOfNamedEntries
; Index
++) {
1552 if (ResourceDirectoryEntry
->u1
.s
.NameIsString
) {
1554 // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.
1556 if (ResourceDirectoryEntry
->u1
.s
.NameOffset
>= DirectoryEntry
->Size
) {
1557 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1558 return RETURN_UNSUPPORTED
;
1560 ResourceDirectoryString
= (EFI_IMAGE_RESOURCE_DIRECTORY_STRING
*) (Base
+ ResourceDirectoryEntry
->u1
.s
.NameOffset
);
1561 String
= &ResourceDirectoryString
->String
[0];
1563 if (ResourceDirectoryString
->Length
== 3 &&
1564 String
[0] == L
'H' &&
1565 String
[1] == L
'I' &&
1566 String
[2] == L
'I') {
1568 // Resource Type "HII" found
1570 if (ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1572 // Move to next level - resource Name
1574 if (ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
>= DirectoryEntry
->Size
) {
1575 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1576 return RETURN_UNSUPPORTED
;
1578 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) (Base
+ ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
);
1579 Offset
= ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
+ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) +
1580 sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) * (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1581 if (Offset
> DirectoryEntry
->Size
) {
1582 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1583 return RETURN_UNSUPPORTED
;
1585 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1587 if (ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1589 // Move to next level - resource Language
1591 if (ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
>= DirectoryEntry
->Size
) {
1592 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1593 return RETURN_UNSUPPORTED
;
1595 ResourceDirectory
= (EFI_IMAGE_RESOURCE_DIRECTORY
*) (Base
+ ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
);
1596 Offset
= ResourceDirectoryEntry
->u2
.s
.OffsetToDirectory
+ sizeof (EFI_IMAGE_RESOURCE_DIRECTORY
) +
1597 sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
) * (ResourceDirectory
->NumberOfNamedEntries
+ ResourceDirectory
->NumberOfIdEntries
);
1598 if (Offset
> DirectoryEntry
->Size
) {
1599 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1600 return RETURN_UNSUPPORTED
;
1602 ResourceDirectoryEntry
= (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY
*) (ResourceDirectory
+ 1);
1607 // Now it ought to be resource Data
1609 if (!ResourceDirectoryEntry
->u2
.s
.DataIsDirectory
) {
1610 if (ResourceDirectoryEntry
->u2
.OffsetToData
>= DirectoryEntry
->Size
) {
1611 ImageContext
->ImageError
= IMAGE_ERROR_UNSUPPORTED
;
1612 return RETURN_UNSUPPORTED
;
1614 ResourceDataEntry
= (EFI_IMAGE_RESOURCE_DATA_ENTRY
*) (Base
+ ResourceDirectoryEntry
->u2
.OffsetToData
);
1615 ImageContext
->HiiResourceData
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (ImageContext
, ResourceDataEntry
->OffsetToData
);
1620 ResourceDirectoryEntry
++;
1631 Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI
1634 This function reapplies relocation fixups to the PE/COFF image specified by ImageBase
1635 and ImageSize so the image will execute correctly when the PE/COFF image is mapped
1636 to the address specified by VirtualImageBase. RelocationData must be identical
1637 to the FiuxupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure
1638 after this PE/COFF image was relocated with PeCoffLoaderRelocateImage().
1640 Note that if the platform does not maintain coherency between the instruction cache(s) and the data
1641 cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
1642 prior to transferring control to a PE/COFF image that is loaded using this library.
1644 @param ImageBase The base address of a PE/COFF image that has been loaded
1645 and relocated into system memory.
1646 @param VirtImageBase The request virtual address that the PE/COFF image is to
1648 @param ImageSize The size, in bytes, of the PE/COFF image.
1649 @param RelocationData A pointer to the relocation data that was collected when the PE/COFF
1650 image was relocated using PeCoffLoaderRelocateImage().
1655 PeCoffLoaderRelocateImageForRuntime (
1656 IN PHYSICAL_ADDRESS ImageBase
,
1657 IN PHYSICAL_ADDRESS VirtImageBase
,
1659 IN VOID
*RelocationData
1664 EFI_IMAGE_DOS_HEADER
*DosHdr
;
1665 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
;
1666 UINT32 NumberOfRvaAndSizes
;
1667 EFI_IMAGE_DATA_DIRECTORY
*DataDirectory
;
1668 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
1669 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
1670 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
1680 RETURN_STATUS Status
;
1683 OldBase
= (CHAR8
*)((UINTN
)ImageBase
);
1684 NewBase
= (CHAR8
*)((UINTN
)VirtImageBase
);
1685 Adjust
= (UINTN
) NewBase
- (UINTN
) OldBase
;
1688 // Find the image's relocate dir info
1690 DosHdr
= (EFI_IMAGE_DOS_HEADER
*)OldBase
;
1691 if (DosHdr
->e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
1693 // Valid DOS header so get address of PE header
1695 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)(((CHAR8
*)DosHdr
) + DosHdr
->e_lfanew
);
1698 // No Dos header so assume image starts with PE header.
1700 Hdr
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*)OldBase
;
1703 if (Hdr
.Pe32
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
1705 // Not a valid PE image so Exit
1710 Magic
= PeCoffLoaderGetPeHeaderMagicValue (Hdr
);
1712 if (Magic
== EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
) {
1716 NumberOfRvaAndSizes
= Hdr
.Pe32
->OptionalHeader
.NumberOfRvaAndSizes
;
1717 DataDirectory
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32
->OptionalHeader
.DataDirectory
[0]);
1722 NumberOfRvaAndSizes
= Hdr
.Pe32Plus
->OptionalHeader
.NumberOfRvaAndSizes
;
1723 DataDirectory
= (EFI_IMAGE_DATA_DIRECTORY
*)&(Hdr
.Pe32Plus
->OptionalHeader
.DataDirectory
[0]);
1727 // Find the relocation block
1729 // Per the PE/COFF spec, you can't assume that a given data directory
1730 // is present in the image. You have to check the NumberOfRvaAndSizes in
1731 // the optional header to verify a desired directory entry is there.
1733 if (NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
1734 RelocDir
= DataDirectory
+ EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
;
1735 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(ImageBase
+ RelocDir
->VirtualAddress
);
1736 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(ImageBase
+ RelocDir
->VirtualAddress
+ RelocDir
->Size
);
1739 // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.
1746 // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.
1748 ASSERT (RelocBase
!= NULL
&& RelocBaseEnd
!= NULL
);
1751 // Run the whole relocation block. And re-fixup data that has not been
1752 // modified. The FixupData is used to see if the image has been modified
1753 // since it was relocated. This is so data sections that have been updated
1754 // by code will not be fixed up, since that would set them back to
1757 FixupData
= RelocationData
;
1758 while (RelocBase
< RelocBaseEnd
) {
1760 // Add check for RelocBase->SizeOfBlock field.
1762 if ((RelocBase
->SizeOfBlock
== 0) || (RelocBase
->SizeOfBlock
> RelocDir
->Size
)) {
1764 // Data invalid, cannot continue to relocate the image, just return.
1769 Reloc
= (UINT16
*) ((UINT8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
1770 RelocEnd
= (UINT16
*) ((UINT8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
1771 FixupBase
= (CHAR8
*) ((UINTN
)ImageBase
) + RelocBase
->VirtualAddress
;
1774 // Run this relocation record
1776 while (Reloc
< RelocEnd
) {
1778 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
1779 switch ((*Reloc
) >> 12) {
1781 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
1784 case EFI_IMAGE_REL_BASED_HIGH
:
1785 Fixup16
= (UINT16
*) Fixup
;
1786 if (*(UINT16
*) FixupData
== *Fixup16
) {
1787 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) ((UINT32
) Adjust
>> 16)));
1790 FixupData
= FixupData
+ sizeof (UINT16
);
1793 case EFI_IMAGE_REL_BASED_LOW
:
1794 Fixup16
= (UINT16
*) Fixup
;
1795 if (*(UINT16
*) FixupData
== *Fixup16
) {
1796 *Fixup16
= (UINT16
) (*Fixup16
+ ((UINT16
) Adjust
& 0xffff));
1799 FixupData
= FixupData
+ sizeof (UINT16
);
1802 case EFI_IMAGE_REL_BASED_HIGHLOW
:
1803 Fixup32
= (UINT32
*) Fixup
;
1804 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
1805 if (*(UINT32
*) FixupData
== *Fixup32
) {
1806 *Fixup32
= *Fixup32
+ (UINT32
) Adjust
;
1809 FixupData
= FixupData
+ sizeof (UINT32
);
1812 case EFI_IMAGE_REL_BASED_DIR64
:
1813 Fixup64
= (UINT64
*)Fixup
;
1814 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT64
));
1815 if (*(UINT64
*) FixupData
== *Fixup64
) {
1816 *Fixup64
= *Fixup64
+ (UINT64
)Adjust
;
1819 FixupData
= FixupData
+ sizeof (UINT64
);
1822 case EFI_IMAGE_REL_BASED_HIGHADJ
:
1824 // Not valid Relocation type for UEFI image, ASSERT
1831 // Only Itanium requires ConvertPeImage_Ex
1833 Status
= PeHotRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
1834 if (RETURN_ERROR (Status
)) {
1839 // Next relocation record
1846 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
1852 Reads contents of a PE/COFF image from a buffer in system memory.
1854 This is the default implementation of a PE_COFF_LOADER_READ_FILE function
1855 that assumes FileHandle pointer to the beginning of a PE/COFF image.
1856 This function reads contents of the PE/COFF image that starts at the system memory
1857 address specified by FileHandle. The read operation copies ReadSize bytes from the
1858 PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer.
1859 The size of the buffer actually read is returned in ReadSize.
1861 The caller must make sure the FileOffset and ReadSize within the file scope.
1863 If FileHandle is NULL, then ASSERT().
1864 If ReadSize is NULL, then ASSERT().
1865 If Buffer is NULL, then ASSERT().
1867 @param FileHandle The pointer to base of the input stream
1868 @param FileOffset Offset into the PE/COFF image to begin the read operation.
1869 @param ReadSize On input, the size in bytes of the requested read operation.
1870 On output, the number of bytes actually read.
1871 @param Buffer Output buffer that contains the data read from the PE/COFF image.
1873 @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into
1878 PeCoffLoaderImageReadFromMemory (
1879 IN VOID
*FileHandle
,
1880 IN UINTN FileOffset
,
1881 IN OUT UINTN
*ReadSize
,
1885 ASSERT (ReadSize
!= NULL
);
1886 ASSERT (FileHandle
!= NULL
);
1887 ASSERT (Buffer
!= NULL
);
1889 CopyMem (Buffer
, ((UINT8
*)FileHandle
) + FileOffset
, *ReadSize
);
1890 return RETURN_SUCCESS
;
1894 Unloads a loaded PE/COFF image from memory and releases its taken resource.
1895 Releases any environment specific resources that were allocated when the image
1896 specified by ImageContext was loaded using PeCoffLoaderLoadImage().
1898 For NT32 emulator, the PE/COFF image loaded by system needs to release.
1899 For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded,
1900 this function can simply return RETURN_SUCCESS.
1902 If ImageContext is NULL, then ASSERT().
1904 @param ImageContext The pointer to the image context structure that describes the PE/COFF
1905 image to be unloaded.
1907 @retval RETURN_SUCCESS The PE/COFF image was unloaded successfully.
1911 PeCoffLoaderUnloadImage (
1912 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1916 // Applies additional environment specific actions to unload a
1917 // PE/COFF image if needed
1919 PeCoffLoaderUnloadImageExtraAction (ImageContext
);
1920 return RETURN_SUCCESS
;