4 Copyright (c) 2006, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 Module Name: PeCoffLoader.c
18 Performs an Itanium-based specific relocation fixup.
20 @param Reloc Pointer to the relocation record.
21 @param Fixup Pointer to the address to fix up.
22 @param FixupData Pointer to a buffer to log the fixups.
23 @param Adjust The offset to adjust the fixup.
29 PeCoffLoaderRelocateImageEx (
32 IN OUT CHAR8
**FixupData
,
39 Retrieves the PE or TE Header from a PE/COFF or TE image.
41 @param ImageContext The context of the image being loaded.
42 @param PeHdr The buffer in which to return the PE header.
43 @param TeHdr The buffer in which to return the TE header.
45 @retval RETURN_SUCCESS The PE or TE Header is read.
46 @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.
51 PeCoffLoaderGetPeHeader (
52 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
53 OUT EFI_IMAGE_NT_HEADERS
*PeHdr
,
54 OUT EFI_TE_IMAGE_HEADER
*TeHdr
58 EFI_IMAGE_DOS_HEADER DosHdr
;
61 ImageContext
->IsTeImage
= FALSE
;
63 // Read the DOS image headers
65 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
66 Status
= ImageContext
->ImageRead (
72 if (RETURN_ERROR (Status
)) {
73 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
77 ImageContext
->PeCoffHeaderOffset
= 0;
78 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
80 // DOS image header is present, so read the PE header after the DOS image header
82 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
85 // Read the PE/COFF Header
87 Size
= sizeof (EFI_IMAGE_NT_HEADERS
);
88 Status
= ImageContext
->ImageRead (
90 ImageContext
->PeCoffHeaderOffset
,
94 if (RETURN_ERROR (Status
)) {
95 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
99 // Check the PE/COFF Header Signature. If not, then try to read a TE header
101 if (PeHdr
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
102 Size
= sizeof (EFI_TE_IMAGE_HEADER
);
103 Status
= ImageContext
->ImageRead (
104 ImageContext
->Handle
,
109 if (TeHdr
->Signature
!= EFI_TE_IMAGE_HEADER_SIGNATURE
) {
110 return RETURN_UNSUPPORTED
;
113 ImageContext
->IsTeImage
= TRUE
;
116 return RETURN_SUCCESS
;
120 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported.
122 @param ImageContext The context of the image being loaded.
123 @param PeHdr The buffer in which to return the PE header.
124 @param TeHdr The buffer in which to return the TE header.
126 @retval RETURN_SUCCESS The PE/COFF or TE image is supported.
127 @retval RETURN_UNSUPPORTED The PE/COFF or TE image is not supported.
132 PeCoffLoaderCheckImageType (
133 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
134 IN EFI_IMAGE_NT_HEADERS
*PeHdr
,
135 IN EFI_TE_IMAGE_HEADER
*TeHdr
139 // See if the machine type is supported. We support a native machine type (IA-32/Itanium-based)
140 // and the machine type for the Virtual Machine.
142 if (ImageContext
->IsTeImage
== FALSE
) {
143 ImageContext
->Machine
= PeHdr
->FileHeader
.Machine
;
145 ImageContext
->Machine
= TeHdr
->Machine
;
148 if (!(EFI_IMAGE_MACHINE_TYPE_SUPPORTED (ImageContext
->Machine
))) {
149 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
150 return RETURN_UNSUPPORTED
;
154 // See if the image type is supported. We support EFI Applications,
155 // EFI Boot Service Drivers, and EFI Runtime Drivers.
157 if (ImageContext
->IsTeImage
== FALSE
) {
158 ImageContext
->ImageType
= PeHdr
->OptionalHeader
.Subsystem
;
160 ImageContext
->ImageType
= (UINT16
) (TeHdr
->Subsystem
);
164 return RETURN_SUCCESS
;
168 Retrieves information about a PE/COFF image.
170 Computes the PeCoffHeaderOffset, ImageAddress, ImageSize, DestinationAddress, CodeView,
171 PdbPointer, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
172 fields of the ImageContext structure. If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.
173 If the PE/COFF image accessed through the ImageRead service in the ImageContext structure is not
174 a supported PE/COFF image type, then return RETURN_UNSUPPORTED. If any errors occur while
175 computing the fields of ImageContext, then the error status is returned in the ImageError field of
178 @param ImageContext Pointer to the image context structure that describes the PE/COFF
179 image that needs to be examined by this function.
181 @retval RETURN_SUCCESS The information on the PE/COFF image was collected.
182 @retval RETURN_INVALID_PARAMETER ImageContext is NULL.
183 @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.
188 PeCoffLoaderGetImageInfo (
189 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
192 RETURN_STATUS Status
;
193 EFI_IMAGE_NT_HEADERS PeHdr
;
194 EFI_TE_IMAGE_HEADER TeHdr
;
195 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
198 UINTN DebugDirectoryEntryRva
;
199 UINTN DebugDirectoryEntryFileOffset
;
200 UINTN SectionHeaderOffset
;
201 EFI_IMAGE_SECTION_HEADER SectionHeader
;
202 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
204 if (NULL
== ImageContext
) {
205 return RETURN_INVALID_PARAMETER
;
210 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
212 Status
= PeCoffLoaderGetPeHeader (ImageContext
, &PeHdr
, &TeHdr
);
213 if (RETURN_ERROR (Status
)) {
217 // Verify machine type
219 Status
= PeCoffLoaderCheckImageType (ImageContext
, &PeHdr
, &TeHdr
);
220 if (RETURN_ERROR (Status
)) {
224 // Retrieve the base address of the image
226 if (!(ImageContext
->IsTeImage
)) {
227 ImageContext
->ImageAddress
= PeHdr
.OptionalHeader
.ImageBase
;
229 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) (TeHdr
.ImageBase
);
232 // Initialize the alternate destination address to 0 indicating that it
233 // should not be used.
235 ImageContext
->DestinationAddress
= 0;
238 // Initialize the codeview pointer.
240 ImageContext
->CodeView
= NULL
;
241 ImageContext
->PdbPointer
= NULL
;
244 // Three cases with regards to relocations:
245 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
246 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
247 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
248 // has no base relocs to apply
249 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
251 // Look at the file header to determine if relocations have been stripped, and
252 // save this info in the image context for later use.
254 if ((!(ImageContext
->IsTeImage
)) && ((PeHdr
.FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
255 ImageContext
->RelocationsStripped
= TRUE
;
257 ImageContext
->RelocationsStripped
= FALSE
;
260 if (!(ImageContext
->IsTeImage
)) {
261 ImageContext
->ImageSize
= (UINT64
) PeHdr
.OptionalHeader
.SizeOfImage
;
262 ImageContext
->SectionAlignment
= PeHdr
.OptionalHeader
.SectionAlignment
;
263 ImageContext
->SizeOfHeaders
= PeHdr
.OptionalHeader
.SizeOfHeaders
;
266 // Modify ImageSize to contain .PDB file name if required and initialize
269 if (PeHdr
.OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
270 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(PeHdr
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
272 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
275 // Determine the file offset of the debug directory... This means we walk
276 // the sections to find which section contains the RVA of the debug
279 DebugDirectoryEntryFileOffset
= 0;
281 SectionHeaderOffset
= (UINTN
)(
282 ImageContext
->PeCoffHeaderOffset
+
284 sizeof (EFI_IMAGE_FILE_HEADER
) +
285 PeHdr
.FileHeader
.SizeOfOptionalHeader
288 for (Index
= 0; Index
< PeHdr
.FileHeader
.NumberOfSections
; Index
++) {
290 // Read section header from file
292 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
293 Status
= ImageContext
->ImageRead (
294 ImageContext
->Handle
,
299 if (RETURN_ERROR (Status
)) {
300 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
304 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
305 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
306 DebugDirectoryEntryFileOffset
=
307 DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
311 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
314 if (DebugDirectoryEntryFileOffset
!= 0) {
315 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
++) {
317 // Read next debug directory entry
319 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
320 Status
= ImageContext
->ImageRead (
321 ImageContext
->Handle
,
322 DebugDirectoryEntryFileOffset
,
326 if (RETURN_ERROR (Status
)) {
327 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
331 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
332 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
));
333 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
334 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
337 return RETURN_SUCCESS
;
343 ImageContext
->ImageSize
= 0;
344 ImageContext
->SectionAlignment
= 4096;
345 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
) TeHdr
.BaseOfCode
- (UINTN
) TeHdr
.StrippedSize
;
347 DebugDirectoryEntry
= &TeHdr
.DataDirectory
[1];
348 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
349 SectionHeaderOffset
= (UINTN
) (sizeof (EFI_TE_IMAGE_HEADER
));
351 DebugDirectoryEntryFileOffset
= 0;
353 for (Index
= 0; Index
< TeHdr
.NumberOfSections
;) {
355 // Read section header from file
357 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
358 Status
= ImageContext
->ImageRead (
359 ImageContext
->Handle
,
364 if (RETURN_ERROR (Status
)) {
365 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
369 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
370 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
371 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
372 SectionHeader
.VirtualAddress
+
373 SectionHeader
.PointerToRawData
+
374 sizeof (EFI_TE_IMAGE_HEADER
) -
378 // File offset of the debug directory was found, if this is not the last
379 // section, then skip to the last section for calculating the image size.
381 if (Index
< (UINTN
) TeHdr
.NumberOfSections
- 1) {
382 SectionHeaderOffset
+= (TeHdr
.NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
383 Index
= TeHdr
.NumberOfSections
- 1;
389 // In Te image header there is not a field to describe the ImageSize.
390 // Actually, the ImageSize equals the RVA plus the VirtualSize of
391 // the last section mapped into memory (Must be rounded up to
392 // a mulitple of Section Alignment). Per the PE/COFF specification, the
393 // section headers in the Section Table must appear in order of the RVA
394 // values for the corresponding sections. So the ImageSize can be determined
395 // by the RVA and the VirtualSize of the last section header in the
398 if ((++Index
) == (UINTN
) TeHdr
.NumberOfSections
) {
399 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
+
400 ImageContext
->SectionAlignment
- 1) & ~(ImageContext
->SectionAlignment
- 1);
403 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
406 if (DebugDirectoryEntryFileOffset
!= 0) {
407 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
++) {
409 // Read next debug directory entry
411 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
412 Status
= ImageContext
->ImageRead (
413 ImageContext
->Handle
,
414 DebugDirectoryEntryFileOffset
,
418 if (RETURN_ERROR (Status
)) {
419 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
423 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
424 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
));
425 return RETURN_SUCCESS
;
431 return RETURN_SUCCESS
;
435 Converts an image address to the loaded address.
437 @param ImageContext The context of the image being loaded.
438 @param Address The address to be converted to the loaded address.
440 @return The converted address or NULL if the address can not be converted.
445 PeCoffLoaderImageAddress (
446 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
450 if (Address
>= ImageContext
->ImageSize
) {
451 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
455 return (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
+ Address
);
459 Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().
461 If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of
462 ImageContext as the relocation base address. Otherwise, use the DestinationAddress field
463 of ImageContext as the relocation base address. The caller must allocate the relocation
464 fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.
465 If ImageContext is NULL, then ASSERT().
467 @param ImageContext Pointer to the image context structure that describes the PE/COFF
468 image that is being relocated.
470 @retval RETURN_SUCCESS The PE/COFF image was relocated.
471 Extended status information is in the ImageError field of ImageContext.
472 @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.
473 Extended status information is in the ImageError field of ImageContext.
474 @retval RETURN_UNSUPPORTED A relocation record type is not supported.
475 Extended status information is in the ImageError field of ImageContext.
480 PeCoffLoaderRelocateImage (
481 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
484 RETURN_STATUS Status
;
485 EFI_IMAGE_NT_HEADERS
*PeHdr
;
486 EFI_TE_IMAGE_HEADER
*TeHdr
;
487 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
489 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
490 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
498 PHYSICAL_ADDRESS BaseAddress
;
500 ASSERT (ImageContext
!= NULL
);
507 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
510 // If there are no relocation entries, then we are done
512 if (ImageContext
->RelocationsStripped
) {
513 return RETURN_SUCCESS
;
517 // If the destination address is not 0, use that rather than the
518 // image address as the relocation target.
520 if (ImageContext
->DestinationAddress
!= 0) {
521 BaseAddress
= ImageContext
->DestinationAddress
;
523 BaseAddress
= ImageContext
->ImageAddress
;
526 if (!(ImageContext
->IsTeImage
)) {
527 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)((UINTN
)ImageContext
->ImageAddress
+
528 ImageContext
->PeCoffHeaderOffset
);
530 Adjust
= (UINT64
) BaseAddress
- PeHdr
->OptionalHeader
.ImageBase
;
531 PeHdr
->OptionalHeader
.ImageBase
= (UINTN
)BaseAddress
;
534 // Find the relocation block
536 // Per the PE/COFF spec, you can't assume that a given data directory
537 // is present in the image. You have to check the NumberOfRvaAndSizes in
538 // the optional header to verify a desired directory entry is there.
540 if (PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
541 RelocDir
= &PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
542 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
543 RelocBaseEnd
= PeCoffLoaderImageAddress (
545 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
549 // Set base and end to bypass processing below.
551 RelocBase
= RelocBaseEnd
= 0;
554 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
555 Adjust
= (UINT64
) (BaseAddress
- TeHdr
->ImageBase
);
556 TeHdr
->ImageBase
= (UINT64
) (BaseAddress
);
559 // Find the relocation block
561 RelocDir
= &TeHdr
->DataDirectory
[0];
562 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(
563 ImageContext
->ImageAddress
+
564 RelocDir
->VirtualAddress
+
565 sizeof(EFI_TE_IMAGE_HEADER
) -
568 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) ((UINTN
) RelocBase
+ (UINTN
) RelocDir
->Size
- 1);
572 // Run the relocation information and apply the fixups
574 FixupData
= ImageContext
->FixupData
;
575 while (RelocBase
< RelocBaseEnd
) {
577 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
578 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
579 if (!(ImageContext
->IsTeImage
)) {
580 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
);
582 FixupBase
= (CHAR8
*)(UINTN
)(ImageContext
->ImageAddress
+
583 RelocBase
->VirtualAddress
+
584 sizeof(EFI_TE_IMAGE_HEADER
) -
589 if ((CHAR8
*) RelocEnd
< (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
) ||
590 (CHAR8
*) RelocEnd
> (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+
591 (UINTN
)ImageContext
->ImageSize
)) {
592 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
593 return RETURN_LOAD_ERROR
;
597 // Run this relocation record
599 while (Reloc
< RelocEnd
) {
601 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
602 switch ((*Reloc
) >> 12) {
603 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
606 case EFI_IMAGE_REL_BASED_HIGH
:
607 F16
= (UINT16
*) Fixup
;
608 *F16
= (UINT16
) ((*F16
<< 16) + (UINT16
) Adjust
);
609 if (FixupData
!= NULL
) {
610 *(UINT16
*) FixupData
= *F16
;
611 FixupData
= FixupData
+ sizeof (UINT16
);
615 case EFI_IMAGE_REL_BASED_LOW
:
616 F16
= (UINT16
*) Fixup
;
617 *F16
= (UINT16
) (*F16
+ (UINT16
) Adjust
);
618 if (FixupData
!= NULL
) {
619 *(UINT16
*) FixupData
= *F16
;
620 FixupData
= FixupData
+ sizeof (UINT16
);
624 case EFI_IMAGE_REL_BASED_HIGHLOW
:
625 F32
= (UINT32
*) Fixup
;
626 *F32
= *F32
+ (UINT32
) Adjust
;
627 if (FixupData
!= NULL
) {
628 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
629 *(UINT32
*) FixupData
= *F32
;
630 FixupData
= FixupData
+ sizeof (UINT32
);
634 case EFI_IMAGE_REL_BASED_HIGHADJ
:
636 // Return the same EFI_UNSUPPORTED return code as
637 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
638 // the relocation type.
640 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
641 return RETURN_UNSUPPORTED
;
644 Status
= PeCoffLoaderRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
645 if (RETURN_ERROR (Status
)) {
646 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
652 // Next relocation record
660 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
663 return RETURN_SUCCESS
;
667 Loads a PE/COFF image into memory.
669 Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
670 specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate
671 the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
672 The EntryPoint, FixupDataSize, CodeView, and PdbPointer fields of ImageContext are computed.
673 If ImageContext is NULL, then ASSERT().
675 @param ImageContext Pointer to the image context structure that describes the PE/COFF
676 image that is being loaded.
678 @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by
679 the ImageAddress and ImageSize fields of ImageContext.
680 Extended status information is in the ImageError field of ImageContext.
681 @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.
682 Extended status information is in the ImageError field of ImageContext.
683 @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.
684 Extended status information is in the ImageError field of ImageContext.
685 @retval RETURN_INVALID_PARAMETER The image address is invalid.
686 Extended status information is in the ImageError field of ImageContext.
691 PeCoffLoaderLoadImage (
692 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
695 RETURN_STATUS Status
;
696 EFI_IMAGE_NT_HEADERS
*PeHdr
;
697 EFI_TE_IMAGE_HEADER
*TeHdr
;
698 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
699 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
700 EFI_IMAGE_SECTION_HEADER
*Section
;
701 UINTN NumberOfSections
;
706 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
707 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
709 UINT32 TempDebugEntryRva
;
711 ASSERT (ImageContext
!= NULL
);
719 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
722 // Copy the provided context info into our local version, get what we
723 // can from the original image, and then use that to make sure everything
726 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
728 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
729 if (RETURN_ERROR (Status
)) {
734 // Make sure there is enough allocated space for the image being loaded
736 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
737 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
738 return RETURN_BUFFER_TOO_SMALL
;
740 if (ImageContext
->ImageAddress
== 0) {
742 // Image cannot be loaded into 0 address.
744 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
745 return RETURN_INVALID_PARAMETER
;
748 // If there's no relocations, then make sure it's not a runtime driver,
749 // and that it's being loaded at the linked address.
751 if (CheckContext
.RelocationsStripped
) {
753 // If the image does not contain relocations and it is a runtime driver
754 // then return an error.
756 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
757 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
758 return RETURN_LOAD_ERROR
;
761 // If the image does not contain relocations, and the requested load address
762 // is not the linked address, then return an error.
764 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
765 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
766 return RETURN_INVALID_PARAMETER
;
770 // Make sure the allocated space has the proper section alignment
772 if (!(ImageContext
->IsTeImage
)) {
773 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
774 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
775 return RETURN_INVALID_PARAMETER
;
779 // Read the entire PE/COFF or TE header into memory
781 if (!(ImageContext
->IsTeImage
)) {
782 Status
= ImageContext
->ImageRead (
783 ImageContext
->Handle
,
785 &ImageContext
->SizeOfHeaders
,
786 (VOID
*) (UINTN
) ImageContext
->ImageAddress
789 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)
790 ((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
792 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
793 (UINTN
)ImageContext
->ImageAddress
+
794 ImageContext
->PeCoffHeaderOffset
+
796 sizeof(EFI_IMAGE_FILE_HEADER
) +
797 PeHdr
->FileHeader
.SizeOfOptionalHeader
799 NumberOfSections
= (UINTN
) (PeHdr
->FileHeader
.NumberOfSections
);
801 Status
= ImageContext
->ImageRead (
802 ImageContext
->Handle
,
804 &ImageContext
->SizeOfHeaders
,
805 (void *) (UINTN
) ImageContext
->ImageAddress
808 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
810 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
811 (UINTN
)ImageContext
->ImageAddress
+
812 sizeof(EFI_TE_IMAGE_HEADER
)
814 NumberOfSections
= (UINTN
) (TeHdr
->NumberOfSections
);
818 if (RETURN_ERROR (Status
)) {
819 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
820 return RETURN_LOAD_ERROR
;
824 // Load each section of the image
826 Section
= FirstSection
;
827 for (Index
= 0, MaxEnd
= NULL
; Index
< NumberOfSections
; Index
++) {
830 // Compute sections address
832 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
);
833 End
= PeCoffLoaderImageAddress (
835 Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1
837 if (ImageContext
->IsTeImage
) {
838 Base
= (CHAR8
*) ((UINTN
) Base
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
839 End
= (CHAR8
*) ((UINTN
) End
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
846 // If the base start or end address resolved to 0, then fail.
848 if ((Base
== NULL
) || (End
== NULL
)) {
849 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
850 return RETURN_LOAD_ERROR
;
856 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
857 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
858 Size
= (UINTN
) Section
->SizeOfRawData
;
861 if (Section
->SizeOfRawData
) {
862 if (!(ImageContext
->IsTeImage
)) {
863 Status
= ImageContext
->ImageRead (
864 ImageContext
->Handle
,
865 Section
->PointerToRawData
,
870 Status
= ImageContext
->ImageRead (
871 ImageContext
->Handle
,
872 Section
->PointerToRawData
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
,
878 if (RETURN_ERROR (Status
)) {
879 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
885 // If raw size is less then virt size, zero fill the remaining
888 if (Size
< Section
->Misc
.VirtualSize
) {
889 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
899 // Get image's entry point
901 if (!(ImageContext
->IsTeImage
)) {
902 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (
904 PeHdr
->OptionalHeader
.AddressOfEntryPoint
907 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (
908 (UINTN
)ImageContext
->ImageAddress
+
909 (UINTN
)TeHdr
->AddressOfEntryPoint
+
910 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
911 (UINTN
) TeHdr
->StrippedSize
916 // Determine the size of the fixup data
918 // Per the PE/COFF spec, you can't assume that a given data directory
919 // is present in the image. You have to check the NumberOfRvaAndSizes in
920 // the optional header to verify a desired directory entry is there.
922 if (!(ImageContext
->IsTeImage
)) {
923 if (PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
924 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
925 &PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
926 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
928 ImageContext
->FixupDataSize
= 0;
931 DirectoryEntry
= &TeHdr
->DataDirectory
[0];
932 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
935 // Consumer must allocate a buffer for the relocation fixup log.
936 // Only used for runtime drivers.
938 ImageContext
->FixupData
= NULL
;
941 // Load the Codeview info if present
943 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
944 if (!(ImageContext
->IsTeImage
)) {
945 DebugEntry
= PeCoffLoaderImageAddress (
947 ImageContext
->DebugDirectoryEntryRva
950 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(UINTN
)(
951 ImageContext
->ImageAddress
+
952 ImageContext
->DebugDirectoryEntryRva
+
953 sizeof(EFI_TE_IMAGE_HEADER
) -
958 if (DebugEntry
!= NULL
) {
959 TempDebugEntryRva
= DebugEntry
->RVA
;
960 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
962 if ((UINTN
) Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
963 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
965 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
969 if (TempDebugEntryRva
!= 0) {
970 if (!(ImageContext
->IsTeImage
)) {
971 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
);
973 ImageContext
->CodeView
= (VOID
*)(
974 (UINTN
)ImageContext
->ImageAddress
+
975 (UINTN
)TempDebugEntryRva
+
976 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
977 (UINTN
) TeHdr
->StrippedSize
981 if (ImageContext
->CodeView
== NULL
) {
982 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
983 return RETURN_LOAD_ERROR
;
986 if (DebugEntry
->RVA
== 0) {
987 Size
= DebugEntry
->SizeOfData
;
988 if (!(ImageContext
->IsTeImage
)) {
989 Status
= ImageContext
->ImageRead (
990 ImageContext
->Handle
,
991 DebugEntry
->FileOffset
,
993 ImageContext
->CodeView
996 Status
= ImageContext
->ImageRead (
997 ImageContext
->Handle
,
998 DebugEntry
->FileOffset
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHdr
->StrippedSize
,
1000 ImageContext
->CodeView
1003 // Should we apply fix up to this field according to the size difference between PE and TE?
1004 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1005 // in original PE image.
1009 if (RETURN_ERROR (Status
)) {
1010 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1011 return RETURN_LOAD_ERROR
;
1014 DebugEntry
->RVA
= TempDebugEntryRva
;
1017 switch (*(UINT32
*) ImageContext
->CodeView
) {
1018 case CODEVIEW_SIGNATURE_NB10
:
1019 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1022 case CODEVIEW_SIGNATURE_RSDS
:
1023 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);