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
22 PeCoffLoaderGetPeHeader (
23 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
24 OUT EFI_IMAGE_NT_HEADERS
*PeHdr
,
25 OUT EFI_TE_IMAGE_HEADER
*TeHdr
30 PeCoffLoaderCheckImageType (
31 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
32 IN EFI_IMAGE_NT_HEADERS
*PeHdr
,
33 IN EFI_TE_IMAGE_HEADER
*TeHdr
38 PeCoffLoaderImageAddress (
39 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
44 PeCoffLoaderRelocateImageEx (
47 IN OUT CHAR8
**FixupData
,
54 Retrieves the PE or TE Header from a PE/COFF or TE image.
56 @param ImageContext The context of the image being loaded.
57 @param PeHdr The buffer in which to return the PE header.
58 @param TeHdr The buffer in which to return the TE header.
60 @retval RETURN_SUCCESS The PE or TE Header is read.
61 @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.
66 PeCoffLoaderGetPeHeader (
67 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
68 OUT EFI_IMAGE_NT_HEADERS
*PeHdr
,
69 OUT EFI_TE_IMAGE_HEADER
*TeHdr
73 EFI_IMAGE_DOS_HEADER DosHdr
;
76 ImageContext
->IsTeImage
= FALSE
;
78 // Read the DOS image headers
80 Size
= sizeof (EFI_IMAGE_DOS_HEADER
);
81 Status
= ImageContext
->ImageRead (
87 if (RETURN_ERROR (Status
)) {
88 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
92 ImageContext
->PeCoffHeaderOffset
= 0;
93 if (DosHdr
.e_magic
== EFI_IMAGE_DOS_SIGNATURE
) {
95 // DOS image header is present, so read the PE header after the DOS image header
97 ImageContext
->PeCoffHeaderOffset
= DosHdr
.e_lfanew
;
100 // Read the PE/COFF Header
102 Size
= sizeof (EFI_IMAGE_NT_HEADERS
);
103 Status
= ImageContext
->ImageRead (
104 ImageContext
->Handle
,
105 ImageContext
->PeCoffHeaderOffset
,
109 if (RETURN_ERROR (Status
)) {
110 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
114 // Check the PE/COFF Header Signature. If not, then try to read a TE header
116 if (PeHdr
->Signature
!= EFI_IMAGE_NT_SIGNATURE
) {
117 Size
= sizeof (EFI_TE_IMAGE_HEADER
);
118 Status
= ImageContext
->ImageRead (
119 ImageContext
->Handle
,
124 if (TeHdr
->Signature
!= EFI_TE_IMAGE_HEADER_SIGNATURE
) {
125 return RETURN_UNSUPPORTED
;
128 ImageContext
->IsTeImage
= TRUE
;
131 return RETURN_SUCCESS
;
135 Checks the PE or TE header of a PE/COFF or TE image to determine if it supported.
137 @param ImageContext The context of the image being loaded.
138 @param PeHdr The buffer in which to return the PE header.
139 @param TeHdr The buffer in which to return the TE header.
141 @retval RETURN_SUCCESS The PE/COFF or TE image is supported.
142 @retval RETURN_UNSUPPORTED The PE/COFF or TE image is not supported.
147 PeCoffLoaderCheckImageType (
148 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
149 IN EFI_IMAGE_NT_HEADERS
*PeHdr
,
150 IN EFI_TE_IMAGE_HEADER
*TeHdr
154 // See if the machine type is supported. We support a native machine type (IA-32/Itanium-based)
155 // and the machine type for the Virtual Machine.
157 if (ImageContext
->IsTeImage
== FALSE
) {
158 ImageContext
->Machine
= PeHdr
->FileHeader
.Machine
;
160 ImageContext
->Machine
= TeHdr
->Machine
;
163 if (!(EFI_IMAGE_MACHINE_TYPE_SUPPORTED (ImageContext
->Machine
))) {
164 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_MACHINE_TYPE
;
165 return RETURN_UNSUPPORTED
;
169 // See if the image type is supported. We support EFI Applications,
170 // EFI Boot Service Drivers, and EFI Runtime Drivers.
172 if (ImageContext
->IsTeImage
== FALSE
) {
173 ImageContext
->ImageType
= PeHdr
->OptionalHeader
.Subsystem
;
175 ImageContext
->ImageType
= (UINT16
) (TeHdr
->Subsystem
);
179 return RETURN_SUCCESS
;
183 Retrieves information about a PE/COFF image.
185 Computes the PeCoffHeaderOffset, ImageAddress, ImageSize, DestinationAddress, CodeView,
186 PdbPointer, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
187 fields of the ImageContext structure. If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.
188 If the PE/COFF image accessed through the ImageRead service in the ImageContext structure is not
189 a supported PE/COFF image type, then return RETURN_UNSUPPORTED. If any errors occur while
190 computing the fields of ImageContext, then the error status is returned in the ImageError field of
193 @param ImageContext Pointer to the image context structure that describes the PE/COFF
194 image that needs to be examined by this function.
196 @retval RETURN_SUCCESS The information on the PE/COFF image was collected.
197 @retval RETURN_INVALID_PARAMETER ImageContext is NULL.
198 @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.
199 @retval Others The error status from reading the PE/COFF image
200 using the ImageContext->ImageRead() function.
205 PeCoffLoaderGetImageInfo (
206 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
209 RETURN_STATUS Status
;
210 EFI_IMAGE_NT_HEADERS PeHdr
;
211 EFI_TE_IMAGE_HEADER TeHdr
;
212 EFI_IMAGE_DATA_DIRECTORY
*DebugDirectoryEntry
;
215 UINTN DebugDirectoryEntryRva
;
216 UINTN DebugDirectoryEntryFileOffset
;
217 UINTN SectionHeaderOffset
;
218 EFI_IMAGE_SECTION_HEADER SectionHeader
;
219 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry
;
221 if (NULL
== ImageContext
) {
222 return RETURN_INVALID_PARAMETER
;
227 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
229 Status
= PeCoffLoaderGetPeHeader (ImageContext
, &PeHdr
, &TeHdr
);
230 if (RETURN_ERROR (Status
)) {
234 // Verify machine type
236 Status
= PeCoffLoaderCheckImageType (ImageContext
, &PeHdr
, &TeHdr
);
237 if (RETURN_ERROR (Status
)) {
241 // Retrieve the base address of the image
243 if (!(ImageContext
->IsTeImage
)) {
244 ImageContext
->ImageAddress
= PeHdr
.OptionalHeader
.ImageBase
;
246 ImageContext
->ImageAddress
= (PHYSICAL_ADDRESS
) (TeHdr
.ImageBase
);
249 // Initialize the alternate destination address to 0 indicating that it
250 // should not be used.
252 ImageContext
->DestinationAddress
= 0;
255 // Initialize the codeview pointer.
257 ImageContext
->CodeView
= NULL
;
258 ImageContext
->PdbPointer
= NULL
;
261 // Three cases with regards to relocations:
262 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
263 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
264 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
265 // has no base relocs to apply
266 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
268 // Look at the file header to determine if relocations have been stripped, and
269 // save this info in the image context for later use.
271 if ((!(ImageContext
->IsTeImage
)) && ((PeHdr
.FileHeader
.Characteristics
& EFI_IMAGE_FILE_RELOCS_STRIPPED
) != 0)) {
272 ImageContext
->RelocationsStripped
= TRUE
;
274 ImageContext
->RelocationsStripped
= FALSE
;
277 if (!(ImageContext
->IsTeImage
)) {
278 ImageContext
->ImageSize
= (UINT64
) PeHdr
.OptionalHeader
.SizeOfImage
;
279 ImageContext
->SectionAlignment
= PeHdr
.OptionalHeader
.SectionAlignment
;
280 ImageContext
->SizeOfHeaders
= PeHdr
.OptionalHeader
.SizeOfHeaders
;
283 // Modify ImageSize to contain .PDB file name if required and initialize
286 if (PeHdr
.OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
) {
287 DebugDirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*) &(PeHdr
.OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG
]);
289 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
292 // Determine the file offset of the debug directory... This means we walk
293 // the sections to find which section contains the RVA of the debug
296 DebugDirectoryEntryFileOffset
= 0;
298 SectionHeaderOffset
= (UINTN
)(
299 ImageContext
->PeCoffHeaderOffset
+
301 sizeof (EFI_IMAGE_FILE_HEADER
) +
302 PeHdr
.FileHeader
.SizeOfOptionalHeader
305 for (Index
= 0; Index
< PeHdr
.FileHeader
.NumberOfSections
; Index
++) {
307 // Read section header from file
309 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
310 Status
= ImageContext
->ImageRead (
311 ImageContext
->Handle
,
316 if (RETURN_ERROR (Status
)) {
317 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
321 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
322 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
323 DebugDirectoryEntryFileOffset
=
324 DebugDirectoryEntryRva
- SectionHeader
.VirtualAddress
+ SectionHeader
.PointerToRawData
;
328 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
331 if (DebugDirectoryEntryFileOffset
!= 0) {
332 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
++) {
334 // Read next debug directory entry
336 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
337 Status
= ImageContext
->ImageRead (
338 ImageContext
->Handle
,
339 DebugDirectoryEntryFileOffset
,
343 if (RETURN_ERROR (Status
)) {
344 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
348 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
349 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
));
350 if (DebugEntry
.RVA
== 0 && DebugEntry
.FileOffset
!= 0) {
351 ImageContext
->ImageSize
+= DebugEntry
.SizeOfData
;
354 return RETURN_SUCCESS
;
360 ImageContext
->ImageSize
= 0;
361 ImageContext
->SectionAlignment
= 4096;
362 ImageContext
->SizeOfHeaders
= sizeof (EFI_TE_IMAGE_HEADER
) + (UINTN
) TeHdr
.BaseOfCode
- (UINTN
) TeHdr
.StrippedSize
;
364 DebugDirectoryEntry
= &TeHdr
.DataDirectory
[1];
365 DebugDirectoryEntryRva
= DebugDirectoryEntry
->VirtualAddress
;
366 SectionHeaderOffset
= (UINTN
) (sizeof (EFI_TE_IMAGE_HEADER
));
368 DebugDirectoryEntryFileOffset
= 0;
370 for (Index
= 0; Index
< TeHdr
.NumberOfSections
;) {
372 // Read section header from file
374 Size
= sizeof (EFI_IMAGE_SECTION_HEADER
);
375 Status
= ImageContext
->ImageRead (
376 ImageContext
->Handle
,
381 if (RETURN_ERROR (Status
)) {
382 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
386 if (DebugDirectoryEntryRva
>= SectionHeader
.VirtualAddress
&&
387 DebugDirectoryEntryRva
< SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
) {
388 DebugDirectoryEntryFileOffset
= DebugDirectoryEntryRva
-
389 SectionHeader
.VirtualAddress
+
390 SectionHeader
.PointerToRawData
+
391 sizeof (EFI_TE_IMAGE_HEADER
) -
395 // File offset of the debug directory was found, if this is not the last
396 // section, then skip to the last section for calculating the image size.
398 if (Index
< (UINTN
) TeHdr
.NumberOfSections
- 1) {
399 SectionHeaderOffset
+= (TeHdr
.NumberOfSections
- 1 - Index
) * sizeof (EFI_IMAGE_SECTION_HEADER
);
400 Index
= TeHdr
.NumberOfSections
- 1;
406 // In Te image header there is not a field to describe the ImageSize.
407 // Actually, the ImageSize equals the RVA plus the VirtualSize of
408 // the last section mapped into memory (Must be rounded up to
409 // a mulitple of Section Alignment). Per the PE/COFF specification, the
410 // section headers in the Section Table must appear in order of the RVA
411 // values for the corresponding sections. So the ImageSize can be determined
412 // by the RVA and the VirtualSize of the last section header in the
415 if ((++Index
) == (UINTN
) TeHdr
.NumberOfSections
) {
416 ImageContext
->ImageSize
= (SectionHeader
.VirtualAddress
+ SectionHeader
.Misc
.VirtualSize
+
417 ImageContext
->SectionAlignment
- 1) & ~(ImageContext
->SectionAlignment
- 1);
420 SectionHeaderOffset
+= sizeof (EFI_IMAGE_SECTION_HEADER
);
423 if (DebugDirectoryEntryFileOffset
!= 0) {
424 for (Index
= 0; Index
< DebugDirectoryEntry
->Size
; Index
++) {
426 // Read next debug directory entry
428 Size
= sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
);
429 Status
= ImageContext
->ImageRead (
430 ImageContext
->Handle
,
431 DebugDirectoryEntryFileOffset
,
435 if (RETURN_ERROR (Status
)) {
436 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
440 if (DebugEntry
.Type
== EFI_IMAGE_DEBUG_TYPE_CODEVIEW
) {
441 ImageContext
->DebugDirectoryEntryRva
= (UINT32
) (DebugDirectoryEntryRva
+ Index
* sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
));
442 return RETURN_SUCCESS
;
448 return RETURN_SUCCESS
;
452 Converts an image address to the loaded address.
454 @param ImageContext The context of the image being loaded.
455 @param Address The address to be converted to the loaded address.
457 @return The converted address or NULL if the address can not be converted.
462 PeCoffLoaderImageAddress (
463 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
467 if (Address
>= ImageContext
->ImageSize
) {
468 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
472 return (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
+ Address
);
476 Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().
478 If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of
479 ImageContext as the relocation base address. Otherwise, use the DestinationAddress field
480 of ImageContext as the relocation base address. The caller must allocate the relocation
481 fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.
482 If ImageContext is NULL, then ASSERT().
484 @param ImageContext Pointer to the image context structure that describes the PE/COFF
485 image that is being relocated.
487 @retval RETURN_SUCCESS The PE/COFF image was relocated.
488 Extended status information is in the ImageError field of ImageContext.
489 @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.
490 Extended status information is in the ImageError field of ImageContext.
491 @retval RETURN_UNSUPPORTED A relocation record type is not supported.
492 Extended status information is in the ImageError field of ImageContext.
497 PeCoffLoaderRelocateImage (
498 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
501 RETURN_STATUS Status
;
502 EFI_IMAGE_NT_HEADERS
*PeHdr
;
503 EFI_TE_IMAGE_HEADER
*TeHdr
;
504 EFI_IMAGE_DATA_DIRECTORY
*RelocDir
;
506 EFI_IMAGE_BASE_RELOCATION
*RelocBase
;
507 EFI_IMAGE_BASE_RELOCATION
*RelocBaseEnd
;
515 PHYSICAL_ADDRESS BaseAddress
;
517 ASSERT (ImageContext
!= NULL
);
524 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
527 // If there are no relocation entries, then we are done
529 if (ImageContext
->RelocationsStripped
) {
530 return RETURN_SUCCESS
;
534 // If the destination address is not 0, use that rather than the
535 // image address as the relocation target.
537 if (ImageContext
->DestinationAddress
!= 0) {
538 BaseAddress
= ImageContext
->DestinationAddress
;
540 BaseAddress
= ImageContext
->ImageAddress
;
543 if (!(ImageContext
->IsTeImage
)) {
544 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)((UINTN
)ImageContext
->ImageAddress
+
545 ImageContext
->PeCoffHeaderOffset
);
547 Adjust
= (UINT64
) BaseAddress
- PeHdr
->OptionalHeader
.ImageBase
;
548 PeHdr
->OptionalHeader
.ImageBase
= (UINTN
)BaseAddress
;
551 // Find the relocation block
553 // Per the PE/COFF spec, you can't assume that a given data directory
554 // is present in the image. You have to check the NumberOfRvaAndSizes in
555 // the optional header to verify a desired directory entry is there.
557 if (PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
558 RelocDir
= &PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
559 RelocBase
= PeCoffLoaderImageAddress (ImageContext
, RelocDir
->VirtualAddress
);
560 RelocBaseEnd
= PeCoffLoaderImageAddress (
562 RelocDir
->VirtualAddress
+ RelocDir
->Size
- 1
566 // Set base and end to bypass processing below.
568 RelocBase
= RelocBaseEnd
= 0;
571 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
572 Adjust
= (UINT64
) (BaseAddress
- TeHdr
->ImageBase
);
573 TeHdr
->ImageBase
= (UINT64
) (BaseAddress
);
576 // Find the relocation block
578 RelocDir
= &TeHdr
->DataDirectory
[0];
579 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*)(UINTN
)(
580 ImageContext
->ImageAddress
+
581 RelocDir
->VirtualAddress
+
582 sizeof(EFI_TE_IMAGE_HEADER
) -
585 RelocBaseEnd
= (EFI_IMAGE_BASE_RELOCATION
*) ((UINTN
) RelocBase
+ (UINTN
) RelocDir
->Size
- 1);
589 // Run the relocation information and apply the fixups
591 FixupData
= ImageContext
->FixupData
;
592 while (RelocBase
< RelocBaseEnd
) {
594 Reloc
= (UINT16
*) ((CHAR8
*) RelocBase
+ sizeof (EFI_IMAGE_BASE_RELOCATION
));
595 RelocEnd
= (UINT16
*) ((CHAR8
*) RelocBase
+ RelocBase
->SizeOfBlock
);
596 if (!(ImageContext
->IsTeImage
)) {
597 FixupBase
= PeCoffLoaderImageAddress (ImageContext
, RelocBase
->VirtualAddress
);
599 FixupBase
= (CHAR8
*)(UINTN
)(ImageContext
->ImageAddress
+
600 RelocBase
->VirtualAddress
+
601 sizeof(EFI_TE_IMAGE_HEADER
) -
606 if ((CHAR8
*) RelocEnd
< (CHAR8
*) ((UINTN
) ImageContext
->ImageAddress
) ||
607 (CHAR8
*) RelocEnd
> (CHAR8
*)((UINTN
)ImageContext
->ImageAddress
+
608 (UINTN
)ImageContext
->ImageSize
)) {
609 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
610 return RETURN_LOAD_ERROR
;
614 // Run this relocation record
616 while (Reloc
< RelocEnd
) {
618 Fixup
= FixupBase
+ (*Reloc
& 0xFFF);
619 switch ((*Reloc
) >> 12) {
620 case EFI_IMAGE_REL_BASED_ABSOLUTE
:
623 case EFI_IMAGE_REL_BASED_HIGH
:
624 F16
= (UINT16
*) Fixup
;
625 *F16
= (UINT16
) ((*F16
<< 16) + (UINT16
) Adjust
);
626 if (FixupData
!= NULL
) {
627 *(UINT16
*) FixupData
= *F16
;
628 FixupData
= FixupData
+ sizeof (UINT16
);
632 case EFI_IMAGE_REL_BASED_LOW
:
633 F16
= (UINT16
*) Fixup
;
634 *F16
= (UINT16
) (*F16
+ (UINT16
) Adjust
);
635 if (FixupData
!= NULL
) {
636 *(UINT16
*) FixupData
= *F16
;
637 FixupData
= FixupData
+ sizeof (UINT16
);
641 case EFI_IMAGE_REL_BASED_HIGHLOW
:
642 F32
= (UINT32
*) Fixup
;
643 *F32
= *F32
+ (UINT32
) Adjust
;
644 if (FixupData
!= NULL
) {
645 FixupData
= ALIGN_POINTER (FixupData
, sizeof (UINT32
));
646 *(UINT32
*) FixupData
= *F32
;
647 FixupData
= FixupData
+ sizeof (UINT32
);
651 case EFI_IMAGE_REL_BASED_HIGHADJ
:
653 // Return the same EFI_UNSUPPORTED return code as
654 // PeCoffLoaderRelocateImageEx() returns if it does not recognize
655 // the relocation type.
657 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
658 return RETURN_UNSUPPORTED
;
661 Status
= PeCoffLoaderRelocateImageEx (Reloc
, Fixup
, &FixupData
, Adjust
);
662 if (RETURN_ERROR (Status
)) {
663 ImageContext
->ImageError
= IMAGE_ERROR_FAILED_RELOCATION
;
669 // Next relocation record
677 RelocBase
= (EFI_IMAGE_BASE_RELOCATION
*) RelocEnd
;
680 return RETURN_SUCCESS
;
684 Loads a PE/COFF image into memory.
686 Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
687 specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate
688 the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
689 The EntryPoint, FixupDataSize, CodeView, and PdbPointer fields of ImageContext are computed.
691 @param ImageContext Pointer to the image context structure that describes the PE/COFF
692 image that is being loaded.
694 @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by
695 the ImageAddress and ImageSize fields of ImageContext.
696 Extended status information is in the ImageError field of ImageContext.
697 @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.
698 Extended status information is in the ImageError field of ImageContext.
699 @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.
700 Extended status information is in the ImageError field of ImageContext.
701 @retval RETURN_INVALID_PARAMETER The image address is invalid.
702 Extended status information is in the ImageError field of ImageContext.
707 PeCoffLoaderLoadImage (
708 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
711 RETURN_STATUS Status
;
712 EFI_IMAGE_NT_HEADERS
*PeHdr
;
713 EFI_TE_IMAGE_HEADER
*TeHdr
;
714 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext
;
715 EFI_IMAGE_SECTION_HEADER
*FirstSection
;
716 EFI_IMAGE_SECTION_HEADER
*Section
;
717 UINTN NumberOfSections
;
722 EFI_IMAGE_DATA_DIRECTORY
*DirectoryEntry
;
723 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*DebugEntry
;
725 UINT32 TempDebugEntryRva
;
732 ImageContext
->ImageError
= IMAGE_ERROR_SUCCESS
;
735 // Copy the provided context info into our local version, get what we
736 // can from the original image, and then use that to make sure everything
739 CopyMem (&CheckContext
, ImageContext
, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT
));
741 Status
= PeCoffLoaderGetImageInfo (&CheckContext
);
742 if (RETURN_ERROR (Status
)) {
747 // Make sure there is enough allocated space for the image being loaded
749 if (ImageContext
->ImageSize
< CheckContext
.ImageSize
) {
750 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_SIZE
;
751 return RETURN_BUFFER_TOO_SMALL
;
755 // If there's no relocations, then make sure it's not a runtime driver,
756 // and that it's being loaded at the linked address.
758 if (CheckContext
.RelocationsStripped
) {
760 // If the image does not contain relocations and it is a runtime driver
761 // then return an error.
763 if (CheckContext
.ImageType
== EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
) {
764 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
765 return RETURN_LOAD_ERROR
;
768 // If the image does not contain relocations, and the requested load address
769 // is not the linked address, then return an error.
771 if (CheckContext
.ImageAddress
!= ImageContext
->ImageAddress
) {
772 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_IMAGE_ADDRESS
;
773 return RETURN_INVALID_PARAMETER
;
777 // Make sure the allocated space has the proper section alignment
779 if (!(ImageContext
->IsTeImage
)) {
780 if ((ImageContext
->ImageAddress
& (CheckContext
.SectionAlignment
- 1)) != 0) {
781 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SECTION_ALIGNMENT
;
782 return RETURN_INVALID_PARAMETER
;
786 // Read the entire PE/COFF or TE header into memory
788 if (!(ImageContext
->IsTeImage
)) {
789 Status
= ImageContext
->ImageRead (
790 ImageContext
->Handle
,
792 &ImageContext
->SizeOfHeaders
,
793 (VOID
*) (UINTN
) ImageContext
->ImageAddress
796 PeHdr
= (EFI_IMAGE_NT_HEADERS
*)
797 ((UINTN
)ImageContext
->ImageAddress
+ ImageContext
->PeCoffHeaderOffset
);
799 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
800 (UINTN
)ImageContext
->ImageAddress
+
801 ImageContext
->PeCoffHeaderOffset
+
803 sizeof(EFI_IMAGE_FILE_HEADER
) +
804 PeHdr
->FileHeader
.SizeOfOptionalHeader
806 NumberOfSections
= (UINTN
) (PeHdr
->FileHeader
.NumberOfSections
);
808 Status
= ImageContext
->ImageRead (
809 ImageContext
->Handle
,
811 &ImageContext
->SizeOfHeaders
,
812 (void *) (UINTN
) ImageContext
->ImageAddress
815 TeHdr
= (EFI_TE_IMAGE_HEADER
*) (UINTN
) (ImageContext
->ImageAddress
);
817 FirstSection
= (EFI_IMAGE_SECTION_HEADER
*) (
818 (UINTN
)ImageContext
->ImageAddress
+
819 sizeof(EFI_TE_IMAGE_HEADER
)
821 NumberOfSections
= (UINTN
) (TeHdr
->NumberOfSections
);
825 if (RETURN_ERROR (Status
)) {
826 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
827 return RETURN_LOAD_ERROR
;
831 // Load each section of the image
833 Section
= FirstSection
;
834 for (Index
= 0, MaxEnd
= NULL
; Index
< NumberOfSections
; Index
++) {
837 // Compute sections address
839 Base
= PeCoffLoaderImageAddress (ImageContext
, Section
->VirtualAddress
);
840 End
= PeCoffLoaderImageAddress (
842 Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
- 1
844 if (ImageContext
->IsTeImage
) {
845 Base
= (CHAR8
*) ((UINTN
) Base
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
846 End
= (CHAR8
*) ((UINTN
) End
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
);
853 // If the base start or end address resolved to 0, then fail.
855 if ((Base
== NULL
) || (End
== NULL
)) {
856 ImageContext
->ImageError
= IMAGE_ERROR_SECTION_NOT_LOADED
;
857 return RETURN_LOAD_ERROR
;
863 Size
= (UINTN
) Section
->Misc
.VirtualSize
;
864 if ((Size
== 0) || (Size
> Section
->SizeOfRawData
)) {
865 Size
= (UINTN
) Section
->SizeOfRawData
;
868 if (Section
->SizeOfRawData
) {
869 if (!(ImageContext
->IsTeImage
)) {
870 Status
= ImageContext
->ImageRead (
871 ImageContext
->Handle
,
872 Section
->PointerToRawData
,
877 Status
= ImageContext
->ImageRead (
878 ImageContext
->Handle
,
879 Section
->PointerToRawData
+ sizeof (EFI_TE_IMAGE_HEADER
) - (UINTN
) TeHdr
->StrippedSize
,
885 if (RETURN_ERROR (Status
)) {
886 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
892 // If raw size is less then virt size, zero fill the remaining
895 if (Size
< Section
->Misc
.VirtualSize
) {
896 ZeroMem (Base
+ Size
, Section
->Misc
.VirtualSize
- Size
);
906 // Get image's entry point
908 if (!(ImageContext
->IsTeImage
)) {
909 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (UINTN
) PeCoffLoaderImageAddress (
911 PeHdr
->OptionalHeader
.AddressOfEntryPoint
914 ImageContext
->EntryPoint
= (PHYSICAL_ADDRESS
) (
915 (UINTN
)ImageContext
->ImageAddress
+
916 (UINTN
)TeHdr
->AddressOfEntryPoint
+
917 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
918 (UINTN
) TeHdr
->StrippedSize
923 // Determine the size of the fixup data
925 // Per the PE/COFF spec, you can't assume that a given data directory
926 // is present in the image. You have to check the NumberOfRvaAndSizes in
927 // the optional header to verify a desired directory entry is there.
929 if (!(ImageContext
->IsTeImage
)) {
930 if (PeHdr
->OptionalHeader
.NumberOfRvaAndSizes
> EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
) {
931 DirectoryEntry
= (EFI_IMAGE_DATA_DIRECTORY
*)
932 &PeHdr
->OptionalHeader
.DataDirectory
[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC
];
933 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
935 ImageContext
->FixupDataSize
= 0;
938 DirectoryEntry
= &TeHdr
->DataDirectory
[0];
939 ImageContext
->FixupDataSize
= DirectoryEntry
->Size
/ sizeof (UINT16
) * sizeof (UINTN
);
942 // Consumer must allocate a buffer for the relocation fixup log.
943 // Only used for runtime drivers.
945 ImageContext
->FixupData
= NULL
;
948 // Load the Codeview info if present
950 if (ImageContext
->DebugDirectoryEntryRva
!= 0) {
951 if (!(ImageContext
->IsTeImage
)) {
952 DebugEntry
= PeCoffLoaderImageAddress (
954 ImageContext
->DebugDirectoryEntryRva
957 DebugEntry
= (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
*)(UINTN
)(
958 ImageContext
->ImageAddress
+
959 ImageContext
->DebugDirectoryEntryRva
+
960 sizeof(EFI_TE_IMAGE_HEADER
) -
965 if (DebugEntry
!= NULL
) {
966 TempDebugEntryRva
= DebugEntry
->RVA
;
967 if (DebugEntry
->RVA
== 0 && DebugEntry
->FileOffset
!= 0) {
969 if ((UINTN
) Section
->SizeOfRawData
< Section
->Misc
.VirtualSize
) {
970 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->Misc
.VirtualSize
;
972 TempDebugEntryRva
= Section
->VirtualAddress
+ Section
->SizeOfRawData
;
976 if (TempDebugEntryRva
!= 0) {
977 if (!(ImageContext
->IsTeImage
)) {
978 ImageContext
->CodeView
= PeCoffLoaderImageAddress (ImageContext
, TempDebugEntryRva
);
980 ImageContext
->CodeView
= (VOID
*)(
981 (UINTN
)ImageContext
->ImageAddress
+
982 (UINTN
)TempDebugEntryRva
+
983 (UINTN
)sizeof(EFI_TE_IMAGE_HEADER
) -
984 (UINTN
) TeHdr
->StrippedSize
988 if (ImageContext
->CodeView
== NULL
) {
989 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
990 return RETURN_LOAD_ERROR
;
993 if (DebugEntry
->RVA
== 0) {
994 Size
= DebugEntry
->SizeOfData
;
995 if (!(ImageContext
->IsTeImage
)) {
996 Status
= ImageContext
->ImageRead (
997 ImageContext
->Handle
,
998 DebugEntry
->FileOffset
,
1000 ImageContext
->CodeView
1003 Status
= ImageContext
->ImageRead (
1004 ImageContext
->Handle
,
1005 DebugEntry
->FileOffset
+ sizeof (EFI_TE_IMAGE_HEADER
) - TeHdr
->StrippedSize
,
1007 ImageContext
->CodeView
1010 // Should we apply fix up to this field according to the size difference between PE and TE?
1011 // Because now we maintain TE header fields unfixed, this field will also remain as they are
1012 // in original PE image.
1016 if (RETURN_ERROR (Status
)) {
1017 ImageContext
->ImageError
= IMAGE_ERROR_IMAGE_READ
;
1018 return RETURN_LOAD_ERROR
;
1021 DebugEntry
->RVA
= TempDebugEntryRva
;
1024 switch (*(UINT32
*) ImageContext
->CodeView
) {
1025 case CODEVIEW_SIGNATURE_NB10
:
1026 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
);
1029 case CODEVIEW_SIGNATURE_RSDS
:
1030 ImageContext
->PdbPointer
= (CHAR8
*) ImageContext
->CodeView
+ sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY
);