diff options
Diffstat (limited to 'MdePkg/Library/BasePeCoffLib/BasePeCoff.c')
-rw-r--r-- | MdePkg/Library/BasePeCoffLib/BasePeCoff.c | 718 |
1 files changed, 511 insertions, 207 deletions
diff --git a/MdePkg/Library/BasePeCoffLib/BasePeCoff.c b/MdePkg/Library/BasePeCoffLib/BasePeCoff.c index 6b8adc1fd6..1e8f573009 100644 --- a/MdePkg/Library/BasePeCoffLib/BasePeCoff.c +++ b/MdePkg/Library/BasePeCoffLib/BasePeCoff.c @@ -1,6 +1,9 @@ /** @file
Tiano PE/COFF loader.
+ This PE/COFF loader supports loading any PE32 or PE32+ image type, but
+ only supports relocating IA32, X64, IPF, and EBC images.
+
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
@@ -14,8 +17,10 @@ **/
+
/**
- Performs an Itanium-based specific relocation fixup.
+ Performs an Itanium-based specific relocation fixup and is a no-op on other
+ instruction sets.
@param Reloc Pointer to the relocation record.
@param Fixup Pointer to the address to fix up.
@@ -34,33 +39,68 @@ PeCoffLoaderRelocateImageEx ( );
+/**
+ Performs an Itanium-based specific re-relocation fixup and is a no-op on other
+ instruction sets. This is used to re-relocated the image into the EFI virtual
+ space for runtime calls.
+
+ @param Reloc Pointer to the relocation record.
+ @param Fixup Pointer to the address to fix up.
+ @param FixupData Pointer to a buffer to log the fixups.
+ @param Adjust The offset to adjust the fixup.
+
+ @return Status code.
+
+**/
+RETURN_STATUS
+PeHotRelocateImageEx (
+ IN UINT16 *Reloc,
+ IN OUT CHAR8 *Fixup,
+ IN OUT CHAR8 **FixupData,
+ IN UINT64 Adjust
+ );
+
+
+/**
+ Returns TRUE if the machine type of PE/COFF image is supported. Supported
+ does not mean the image can be executed it means the PE/COFF loader supports
+ loading and relocating of the image type. It's up to the caller to support
+ the entry point.
+
+ @param Machine Machine type from the PE Header.
+
+ @return TRUE if this PE/COFF loader can load the image
+
+**/
+BOOLEAN
+PeCoffLoaderImageFormatSupported (
+ IN UINT16 Machine
+ );
+
+
/**
Retrieves the PE or TE Header from a PE/COFF or TE image.
@param ImageContext The context of the image being loaded.
- @param PeHdr The buffer in which to return the PE header.
- @param TeHdr The buffer in which to return the TE header.
+ @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
@retval RETURN_SUCCESS The PE or TE Header is read.
@retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.
**/
-STATIC
RETURN_STATUS
PeCoffLoaderGetPeHeader (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
- OUT EFI_IMAGE_NT_HEADERS *PeHdr,
- OUT EFI_TE_IMAGE_HEADER *TeHdr
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
+ OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
)
{
RETURN_STATUS Status;
EFI_IMAGE_DOS_HEADER DosHdr;
UINTN Size;
- ImageContext->IsTeImage = FALSE;
//
- // Read the DOS image headers
+ // Read the DOS image header to check for it's existance
//
Size = sizeof (EFI_IMAGE_DOS_HEADER);
Status = ImageContext->ImageRead (
@@ -77,93 +117,85 @@ PeCoffLoaderGetPeHeader ( ImageContext->PeCoffHeaderOffset = 0;
if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {
//
- // DOS image header is present, so read the PE header after the DOS image header
+ // DOS image header is present, so read the PE header after the DOS image
+ // header
//
ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;
}
+
//
- // Read the PE/COFF Header
+ // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
+ // data, but that should not hurt anythine. Hdr.Pe32->OptionalHeader.Magic
+ // determins if this is a PE32 or PE32+ image. The magic is in the same
+ // location in both images.
//
- Size = sizeof (EFI_IMAGE_NT_HEADERS);
+ Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
Status = ImageContext->ImageRead (
ImageContext->Handle,
ImageContext->PeCoffHeaderOffset,
&Size,
- PeHdr
+ Hdr.Pe32
);
if (RETURN_ERROR (Status)) {
ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
return Status;
}
+
//
- // Check the PE/COFF Header Signature. If not, then try to read a TE header
+ // Use Signature to figure out if we understand the image format
//
- if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {
- Size = sizeof (EFI_TE_IMAGE_HEADER);
- Status = ImageContext->ImageRead (
- ImageContext->Handle,
- 0,
- &Size,
- TeHdr
- );
- if (TeHdr->Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) {
- return RETURN_UNSUPPORTED;
- }
-
- ImageContext->IsTeImage = TRUE;
- }
-
- return RETURN_SUCCESS;
-}
-
-/**
- Checks the PE or TE header of a PE/COFF or TE image to determine if it supported.
-
- @param ImageContext The context of the image being loaded.
- @param PeHdr The buffer in which to return the PE header.
- @param TeHdr The buffer in which to return the TE header.
+ if (Hdr.Pe32->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ ImageContext->IsTeImage = TRUE;
+ ImageContext->Machine = Hdr.Te->Machine;
+ ImageContext->ImageType = (UINT16)(Hdr.Te->Subsystem);
+ ImageContext->ImageSize = 0;
+ ImageContext->SectionAlignment = 4096;
+ ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;
- @retval RETURN_SUCCESS The PE/COFF or TE image is supported.
- @retval RETURN_UNSUPPORTED The PE/COFF or TE image is not supported.
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
+ ImageContext->IsTeImage = FALSE;
+ ImageContext->Machine = Hdr.Pe32->FileHeader.Machine;
+
+ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ ImageContext->ImageType = Hdr.Pe32->OptionalHeader.Subsystem;
+ ImageContext->ImageSize = (UINT64)Hdr.Pe32->OptionalHeader.SizeOfImage;
+ ImageContext->SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;
+ ImageContext->SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
-**/
-STATIC
-RETURN_STATUS
-PeCoffLoaderCheckImageType (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
- IN EFI_IMAGE_NT_HEADERS *PeHdr,
- IN EFI_TE_IMAGE_HEADER *TeHdr
- )
-{
- //
- // See if the machine type is supported. We support a native machine type (IA-32/Itanium-based)
- // and the machine type for the Virtual Machine.
- //
- if (ImageContext->IsTeImage == FALSE) {
- ImageContext->Machine = PeHdr->FileHeader.Machine;
+ } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ //
+ // Use PE32+ offset
+ //
+ ImageContext->ImageType = Hdr.Pe32Plus->OptionalHeader.Subsystem;
+ ImageContext->ImageSize = (UINT64) Hdr.Pe32Plus->OptionalHeader.SizeOfImage;
+ ImageContext->SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
+ ImageContext->SizeOfHeaders = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
+ } else {
+ ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;
+ return RETURN_UNSUPPORTED;
+ }
} else {
- ImageContext->Machine = TeHdr->Machine;
- }
-
- if (!(EFI_IMAGE_MACHINE_TYPE_SUPPORTED (ImageContext->Machine))) {
ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;
return RETURN_UNSUPPORTED;
}
- //
- // See if the image type is supported. We support EFI Applications,
- // EFI Boot Service Drivers, and EFI Runtime Drivers.
- //
- if (ImageContext->IsTeImage == FALSE) {
- ImageContext->ImageType = PeHdr->OptionalHeader.Subsystem;
- } else {
- ImageContext->ImageType = (UINT16) (TeHdr->Subsystem);
+ if (!PeCoffLoaderImageFormatSupported (ImageContext->Machine)) {
+ //
+ // If the PE/COFF loader does not support the image type return
+ // unsupported. This library can suport lots of types of images
+ // this does not mean the user of this library can call the entry
+ // point of the image.
+ //
+ return RETURN_UNSUPPORTED;
}
-
return RETURN_SUCCESS;
}
+
/**
Retrieves information about a PE/COFF image.
@@ -189,17 +221,18 @@ PeCoffLoaderGetImageInfo ( IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
)
{
- RETURN_STATUS Status;
- EFI_IMAGE_NT_HEADERS PeHdr;
- EFI_TE_IMAGE_HEADER TeHdr;
- EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;
- UINTN Size;
- UINTN Index;
- UINTN DebugDirectoryEntryRva;
- UINTN DebugDirectoryEntryFileOffset;
- UINTN SectionHeaderOffset;
- EFI_IMAGE_SECTION_HEADER SectionHeader;
- EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;
+ RETURN_STATUS Status;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;
+ UINTN Size;
+ UINTN Index;
+ UINTN DebugDirectoryEntryRva;
+ UINTN DebugDirectoryEntryFileOffset;
+ UINTN SectionHeaderOffset;
+ EFI_IMAGE_SECTION_HEADER SectionHeader;
+ EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;
+ UINT32 NumberOfRvaAndSizes;
if (NULL == ImageContext) {
return RETURN_INVALID_PARAMETER;
@@ -209,25 +242,31 @@ PeCoffLoaderGetImageInfo ( //
ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
- Status = PeCoffLoaderGetPeHeader (ImageContext, &PeHdr, &TeHdr);
- if (RETURN_ERROR (Status)) {
- return Status;
- }
- //
- // Verify machine type
- //
- Status = PeCoffLoaderCheckImageType (ImageContext, &PeHdr, &TeHdr);
+ Hdr.Union = &HdrData;
+ Status = PeCoffLoaderGetPeHeader (ImageContext, Hdr);
if (RETURN_ERROR (Status)) {
return Status;
}
+
//
// Retrieve the base address of the image
//
if (!(ImageContext->IsTeImage)) {
- ImageContext->ImageAddress = PeHdr.OptionalHeader.ImageBase;
+ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ ImageContext->ImageAddress = Hdr.Pe32->OptionalHeader.ImageBase;
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ ImageContext->ImageAddress = Hdr.Pe32Plus->OptionalHeader.ImageBase;
+ }
} else {
- ImageContext->ImageAddress = (PHYSICAL_ADDRESS) (TeHdr.ImageBase);
+ ImageContext->ImageAddress = (PHYSICAL_ADDRESS)(Hdr.Te->ImageBase);
}
+
//
// Initialize the alternate destination address to 0 indicating that it
// should not be used.
@@ -251,23 +290,28 @@ PeCoffLoaderGetImageInfo ( // Look at the file header to determine if relocations have been stripped, and
// save this info in the image context for later use.
//
- if ((!(ImageContext->IsTeImage)) && ((PeHdr.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {
+ if ((!(ImageContext->IsTeImage)) && ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {
ImageContext->RelocationsStripped = TRUE;
} else {
ImageContext->RelocationsStripped = FALSE;
}
if (!(ImageContext->IsTeImage)) {
- ImageContext->ImageSize = (UINT64) PeHdr.OptionalHeader.SizeOfImage;
- ImageContext->SectionAlignment = PeHdr.OptionalHeader.SectionAlignment;
- ImageContext->SizeOfHeaders = PeHdr.OptionalHeader.SizeOfHeaders;
-
- //
- // Modify ImageSize to contain .PDB file name if required and initialize
- // PdbRVA field...
- //
- if (PeHdr.OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
- DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(PeHdr.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
+ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+ DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
+ }
+
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
@@ -282,10 +326,10 @@ PeCoffLoaderGetImageInfo ( ImageContext->PeCoffHeaderOffset +
sizeof (UINT32) +
sizeof (EFI_IMAGE_FILE_HEADER) +
- PeHdr.FileHeader.SizeOfOptionalHeader
+ Hdr.Pe32->FileHeader.SizeOfOptionalHeader
);
- for (Index = 0; Index < PeHdr.FileHeader.NumberOfSections; Index++) {
+ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
//
// Read section header from file
//
@@ -303,8 +347,8 @@ PeCoffLoaderGetImageInfo ( if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
- DebugDirectoryEntryFileOffset =
- DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
+
+ DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
break;
}
@@ -340,17 +384,14 @@ PeCoffLoaderGetImageInfo ( }
}
} else {
- ImageContext->ImageSize = 0;
- ImageContext->SectionAlignment = 4096;
- ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) TeHdr.BaseOfCode - (UINTN) TeHdr.StrippedSize;
- DebugDirectoryEntry = &TeHdr.DataDirectory[1];
+ DebugDirectoryEntry = &Hdr.Te->DataDirectory[1];
DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
- SectionHeaderOffset = (UINTN) (sizeof (EFI_TE_IMAGE_HEADER));
+ SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));
DebugDirectoryEntryFileOffset = 0;
- for (Index = 0; Index < TeHdr.NumberOfSections;) {
+ for (Index = 0; Index < Hdr.Te->NumberOfSections;) {
//
// Read section header from file
//
@@ -372,15 +413,15 @@ PeCoffLoaderGetImageInfo ( SectionHeader.VirtualAddress +
SectionHeader.PointerToRawData +
sizeof (EFI_TE_IMAGE_HEADER) -
- TeHdr.StrippedSize;
+ Hdr.Te->StrippedSize;
//
// File offset of the debug directory was found, if this is not the last
// section, then skip to the last section for calculating the image size.
//
- if (Index < (UINTN) TeHdr.NumberOfSections - 1) {
- SectionHeaderOffset += (TeHdr.NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);
- Index = TeHdr.NumberOfSections - 1;
+ if (Index < (UINTN) Hdr.Te->NumberOfSections - 1) {
+ SectionHeaderOffset += (Hdr.Te->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);
+ Index = Hdr.Te->NumberOfSections - 1;
continue;
}
}
@@ -395,7 +436,7 @@ PeCoffLoaderGetImageInfo ( // by the RVA and the VirtualSize of the last section header in the
// Section Table.
//
- if ((++Index) == (UINTN) TeHdr.NumberOfSections) {
+ if ((++Index) == (UINTN)Hdr.Te->NumberOfSections) {
ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize +
ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1);
}
@@ -431,6 +472,7 @@ PeCoffLoaderGetImageInfo ( return RETURN_SUCCESS;
}
+
/**
Converts an image address to the loaded address.
@@ -440,19 +482,13 @@ PeCoffLoaderGetImageInfo ( @return The converted address or NULL if the address can not be converted.
**/
-STATIC
VOID *
PeCoffLoaderImageAddress (
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
IN UINTN Address
)
{
- if (Address >= ImageContext->ImageSize) {
- ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
- return NULL;
- }
-
- return (CHAR8 *) ((UINTN) ImageContext->ImageAddress + Address);
+ return (CHAR8 *)((UINTN) ImageContext->ImageAddress + Address);
}
/**
@@ -481,26 +517,25 @@ PeCoffLoaderRelocateImage ( IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
)
{
- RETURN_STATUS Status;
- EFI_IMAGE_NT_HEADERS *PeHdr;
- EFI_TE_IMAGE_HEADER *TeHdr;
- EFI_IMAGE_DATA_DIRECTORY *RelocDir;
- UINT64 Adjust;
- EFI_IMAGE_BASE_RELOCATION *RelocBase;
- EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
- UINT16 *Reloc;
- UINT16 *RelocEnd;
- CHAR8 *Fixup;
- CHAR8 *FixupBase;
- UINT16 *F16;
- UINT32 *F32;
- CHAR8 *FixupData;
- PHYSICAL_ADDRESS BaseAddress;
+ RETURN_STATUS Status;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ EFI_IMAGE_DATA_DIRECTORY *RelocDir;
+ UINT64 Adjust;
+ EFI_IMAGE_BASE_RELOCATION *RelocBase;
+ EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
+ UINT16 *Reloc;
+ UINT16 *RelocEnd;
+ CHAR8 *Fixup;
+ CHAR8 *FixupBase;
+ UINT16 *F16;
+ UINT32 *F32;
+ UINT64 *F64;
+ CHAR8 *FixupData;
+ PHYSICAL_ADDRESS BaseAddress;
+ UINT32 NumberOfRvaAndSizes;
ASSERT (ImageContext != NULL);
- PeHdr = NULL;
- TeHdr = NULL;
//
// Assume success
//
@@ -524,21 +559,35 @@ PeCoffLoaderRelocateImage ( }
if (!(ImageContext->IsTeImage)) {
- PeHdr = (EFI_IMAGE_NT_HEADERS *)((UINTN)ImageContext->ImageAddress +
- ImageContext->PeCoffHeaderOffset);
-
- Adjust = (UINT64) BaseAddress - PeHdr->OptionalHeader.ImageBase;
- PeHdr->OptionalHeader.ImageBase = (UINTN)BaseAddress;
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
+ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ Adjust = (UINT64)BaseAddress - Hdr.Pe32->OptionalHeader.ImageBase;
+ Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress;
+
+ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+ RelocDir = &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ Adjust = (UINT64) BaseAddress - Hdr.Pe32Plus->OptionalHeader.ImageBase;
+ Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress;
+
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ RelocDir = &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
+ }
//
// Find the relocation block
- //
// Per the PE/COFF spec, you can't assume that a given data directory
// is present in the image. You have to check the NumberOfRvaAndSizes in
// the optional header to verify a desired directory entry is there.
//
- if (PeHdr->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
- RelocDir = &PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
+
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);
RelocBaseEnd = PeCoffLoaderImageAddress (
ImageContext,
@@ -551,19 +600,19 @@ PeCoffLoaderRelocateImage ( RelocBase = RelocBaseEnd = 0;
}
} else {
- TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
- Adjust = (UINT64) (BaseAddress - TeHdr->ImageBase);
- TeHdr->ImageBase = (UINT64) (BaseAddress);
+ Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
+ Adjust = (UINT64) (BaseAddress - Hdr.Te->ImageBase);
+ Hdr.Te->ImageBase = (UINT64) (BaseAddress);
//
// Find the relocation block
//
- RelocDir = &TeHdr->DataDirectory[0];
+ RelocDir = &Hdr.Te->DataDirectory[0];
RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(
ImageContext->ImageAddress +
RelocDir->VirtualAddress +
sizeof(EFI_TE_IMAGE_HEADER) -
- TeHdr->StrippedSize
+ Hdr.Te->StrippedSize
);
RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);
}
@@ -582,7 +631,7 @@ PeCoffLoaderRelocateImage ( FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +
RelocBase->VirtualAddress +
sizeof(EFI_TE_IMAGE_HEADER) -
- TeHdr->StrippedSize
+ Hdr.Te->StrippedSize
);
}
@@ -626,21 +675,27 @@ PeCoffLoaderRelocateImage ( *F32 = *F32 + (UINT32) Adjust;
if (FixupData != NULL) {
FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
- *(UINT32 *) FixupData = *F32;
+ *(UINT32 *)FixupData = *F32;
FixupData = FixupData + sizeof (UINT32);
}
break;
- case EFI_IMAGE_REL_BASED_HIGHADJ:
- //
- // Return the same EFI_UNSUPPORTED return code as
- // PeCoffLoaderRelocateImageEx() returns if it does not recognize
- // the relocation type.
- //
- ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
- return RETURN_UNSUPPORTED;
+ case EFI_IMAGE_REL_BASED_DIR64:
+ F64 = (UINT64 *) Fixup;
+ *F64 = *F64 + (UINT64) Adjust;
+ if (FixupData != NULL) {
+ FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));
+ *(UINT64 *)(FixupData) = *F64;
+ FixupData = FixupData + sizeof(UINT64);
+ }
+ break;
default:
+ //
+ // The common code does not handle some of the stranger IPF relocations
+ // PeCoffLoaderRelocateImageEx () addes support for these complex fixups
+ // on IPF and is a No-Op on other archtiectures.
+ //
Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
if (RETURN_ERROR (Status)) {
ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
@@ -693,8 +748,7 @@ PeCoffLoaderLoadImage ( )
{
RETURN_STATUS Status;
- EFI_IMAGE_NT_HEADERS *PeHdr;
- EFI_TE_IMAGE_HEADER *TeHdr;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;
EFI_IMAGE_SECTION_HEADER *FirstSection;
EFI_IMAGE_SECTION_HEADER *Section;
@@ -707,12 +761,10 @@ PeCoffLoaderLoadImage ( EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
UINTN Size;
UINT32 TempDebugEntryRva;
+ UINT32 NumberOfRvaAndSizes;
ASSERT (ImageContext != NULL);
- PeHdr = NULL;
- TeHdr = NULL;
-
//
// Assume success
//
@@ -786,32 +838,31 @@ PeCoffLoaderLoadImage ( (VOID *) (UINTN) ImageContext->ImageAddress
);
- PeHdr = (EFI_IMAGE_NT_HEADERS *)
- ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
(UINTN)ImageContext->ImageAddress +
ImageContext->PeCoffHeaderOffset +
sizeof(UINT32) +
sizeof(EFI_IMAGE_FILE_HEADER) +
- PeHdr->FileHeader.SizeOfOptionalHeader
+ Hdr.Pe32->FileHeader.SizeOfOptionalHeader
);
- NumberOfSections = (UINTN) (PeHdr->FileHeader.NumberOfSections);
+ NumberOfSections = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);
} else {
Status = ImageContext->ImageRead (
ImageContext->Handle,
0,
&ImageContext->SizeOfHeaders,
- (void *) (UINTN) ImageContext->ImageAddress
+ (void *)(UINTN)ImageContext->ImageAddress
);
- TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
+ Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
- (UINTN)ImageContext->ImageAddress +
- sizeof(EFI_TE_IMAGE_HEADER)
- );
- NumberOfSections = (UINTN) (TeHdr->NumberOfSections);
+ (UINTN)ImageContext->ImageAddress +
+ sizeof(EFI_TE_IMAGE_HEADER)
+ );
+ NumberOfSections = (UINTN) (Hdr.Te->NumberOfSections);
}
@@ -835,8 +886,8 @@ PeCoffLoaderLoadImage ( Section->VirtualAddress + Section->Misc.VirtualSize - 1
);
if (ImageContext->IsTeImage) {
- Base = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
- End = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
+ Base = (CHAR8 *)((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);
+ End = (CHAR8 *)((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);
}
if (End > MaxEnd) {
@@ -869,7 +920,7 @@ PeCoffLoaderLoadImage ( } else {
Status = ImageContext->ImageRead (
ImageContext->Handle,
- Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize,
+ Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize,
&Size,
Base
);
@@ -899,17 +950,33 @@ PeCoffLoaderLoadImage ( // Get image's entry point
//
if (!(ImageContext->IsTeImage)) {
- ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (
- ImageContext,
- PeHdr->OptionalHeader.AddressOfEntryPoint
- );
+ //
+ // Sizes of AddressOfEntryPoint are different so we need to do this safely
+ //
+ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
+ ImageContext,
+ (UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint
+ );
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
+ ImageContext,
+ (UINTN)Hdr.Pe32Plus->OptionalHeader.AddressOfEntryPoint
+ );
+ }
} else {
ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (
- (UINTN)ImageContext->ImageAddress +
- (UINTN)TeHdr->AddressOfEntryPoint +
- (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
- (UINTN) TeHdr->StrippedSize
- );
+ (UINTN)ImageContext->ImageAddress +
+ (UINTN)Hdr.Te->AddressOfEntryPoint +
+ (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
+ (UINTN)Hdr.Te->StrippedSize
+ );
}
//
@@ -920,15 +987,27 @@ PeCoffLoaderLoadImage ( // the optional header to verify a desired directory entry is there.
//
if (!(ImageContext->IsTeImage)) {
- if (PeHdr->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
- DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)
- &PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
+ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+ DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
+ }
+
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
} else {
ImageContext->FixupDataSize = 0;
}
} else {
- DirectoryEntry = &TeHdr->DataDirectory[0];
+ DirectoryEntry = &Hdr.Te->DataDirectory[0];
ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
}
//
@@ -948,18 +1027,18 @@ PeCoffLoaderLoadImage ( );
} else {
DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(
- ImageContext->ImageAddress +
- ImageContext->DebugDirectoryEntryRva +
- sizeof(EFI_TE_IMAGE_HEADER) -
- TeHdr->StrippedSize
- );
+ ImageContext->ImageAddress +
+ ImageContext->DebugDirectoryEntryRva +
+ sizeof(EFI_TE_IMAGE_HEADER) -
+ Hdr.Te->StrippedSize
+ );
}
if (DebugEntry != NULL) {
TempDebugEntryRva = DebugEntry->RVA;
if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {
Section--;
- if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) {
+ if ((UINTN)Section->SizeOfRawData < Section->Misc.VirtualSize) {
TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
} else {
TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
@@ -971,11 +1050,11 @@ PeCoffLoaderLoadImage ( ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);
} else {
ImageContext->CodeView = (VOID *)(
- (UINTN)ImageContext->ImageAddress +
- (UINTN)TempDebugEntryRva +
- (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
- (UINTN) TeHdr->StrippedSize
- );
+ (UINTN)ImageContext->ImageAddress +
+ (UINTN)TempDebugEntryRva +
+ (UINTN)sizeof (EFI_TE_IMAGE_HEADER) -
+ (UINTN) Hdr.Te->StrippedSize
+ );
}
if (ImageContext->CodeView == NULL) {
@@ -995,7 +1074,7 @@ PeCoffLoaderLoadImage ( } else {
Status = ImageContext->ImageRead (
ImageContext->Handle,
- DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize,
+ DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize,
&Size,
ImageContext->CodeView
);
@@ -1016,11 +1095,11 @@ PeCoffLoaderLoadImage ( switch (*(UINT32 *) ImageContext->CodeView) {
case CODEVIEW_SIGNATURE_NB10:
- ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
+ ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
break;
case CODEVIEW_SIGNATURE_RSDS:
- ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
+ ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
break;
default:
@@ -1032,3 +1111,228 @@ PeCoffLoaderLoadImage ( return Status;
}
+
+
+/**
+ Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI
+ runtime.
+
+ PE_COFF_LOADER_IMAGE_CONTEXT.FixupData stores information needed to reapply
+ the fixups with a virtual mapping.
+
+
+ @param ImageBase Base address of relocated image
+ @param VirtImageBase Virtual mapping for ImageBase
+ @param ImageSize Size of the image to relocate
+ @param RelocationData Location to place results of read
+
+**/
+VOID
+EFIAPI
+PeCoffLoaderRelocateImageForRuntime (
+ IN PHYSICAL_ADDRESS ImageBase,
+ IN PHYSICAL_ADDRESS VirtImageBase,
+ IN UINTN ImageSize,
+ IN VOID *RelocationData
+ )
+{
+ CHAR8 *OldBase;
+ CHAR8 *NewBase;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ UINT32 NumberOfRvaAndSizes;
+ EFI_IMAGE_DATA_DIRECTORY *DataDirectory;
+ EFI_IMAGE_DATA_DIRECTORY *RelocDir;
+ EFI_IMAGE_BASE_RELOCATION *RelocBase;
+ EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
+ UINT16 *Reloc;
+ UINT16 *RelocEnd;
+ CHAR8 *Fixup;
+ CHAR8 *FixupBase;
+ UINT16 *F16;
+ UINT32 *F32;
+ UINT64 *F64;
+ CHAR8 *FixupData;
+ UINTN Adjust;
+ RETURN_STATUS Status;
+
+ OldBase = (CHAR8 *)((UINTN)ImageBase);
+ NewBase = (CHAR8 *)((UINTN)VirtImageBase);
+ Adjust = (UINTN) NewBase - (UINTN) OldBase;
+
+ //
+ // Find the image's relocate dir info
+ //
+ DosHdr = (EFI_IMAGE_DOS_HEADER *)OldBase;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ //
+ // Valid DOS header so get address of PE header
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(((CHAR8 *)DosHdr) + DosHdr->e_lfanew);
+ } else {
+ //
+ // No Dos header so assume image starts with PE header.
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)OldBase;
+ }
+
+ if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+ //
+ // Not a valid PE image so Exit
+ //
+ return ;
+ }
+
+ //
+ // Get some data from the PE type dependent data
+ //
+ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+ DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
+ }
+
+ //
+ // Find the relocation block
+ //
+ // Per the PE/COFF spec, you can't assume that a given data directory
+ // is present in the image. You have to check the NumberOfRvaAndSizes in
+ // the optional header to verify a desired directory entry is there.
+ //
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
+ RelocDir = DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;
+ RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress);
+ RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress + RelocDir->Size);
+ } else {
+ //
+ // Cannot find relocations, cannot continue
+ //
+ ASSERT (FALSE);
+ return ;
+ }
+
+ ASSERT (RelocBase != NULL && RelocBaseEnd != NULL);
+
+ //
+ // Run the whole relocation block. And re-fixup data that has not been
+ // modified. The FixupData is used to see if the image has been modified
+ // since it was relocated. This is so data sections that have been updated
+ // by code will not be fixed up, since that would set them back to
+ // defaults.
+ //
+ FixupData = RelocationData;
+ while (RelocBase < RelocBaseEnd) {
+
+ Reloc = (UINT16 *) ((UINT8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
+ RelocEnd = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock);
+ FixupBase = (CHAR8 *) ((UINTN)ImageBase) + RelocBase->VirtualAddress;
+
+ //
+ // Run this relocation record
+ //
+ while (Reloc < RelocEnd) {
+
+ Fixup = FixupBase + (*Reloc & 0xFFF);
+ switch ((*Reloc) >> 12) {
+
+ case EFI_IMAGE_REL_BASED_ABSOLUTE:
+ break;
+
+ case EFI_IMAGE_REL_BASED_HIGH:
+ F16 = (UINT16 *) Fixup;
+ if (*(UINT16 *) FixupData == *F16) {
+ *F16 = (UINT16) ((*F16 << 16) + ((UINT16) Adjust & 0xffff));
+ }
+
+ FixupData = FixupData + sizeof (UINT16);
+ break;
+
+ case EFI_IMAGE_REL_BASED_LOW:
+ F16 = (UINT16 *) Fixup;
+ if (*(UINT16 *) FixupData == *F16) {
+ *F16 = (UINT16) (*F16 + ((UINT16) Adjust & 0xffff));
+ }
+
+ FixupData = FixupData + sizeof (UINT16);
+ break;
+
+ case EFI_IMAGE_REL_BASED_HIGHLOW:
+ F32 = (UINT32 *) Fixup;
+ FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
+ if (*(UINT32 *) FixupData == *F32) {
+ *F32 = *F32 + (UINT32) Adjust;
+ }
+
+ FixupData = FixupData + sizeof (UINT32);
+ break;
+
+ case EFI_IMAGE_REL_BASED_DIR64:
+ F64 = (UINT64 *)Fixup;
+ FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));
+ if (*(UINT32 *) FixupData == *F64) {
+ *F64 = *F64 + (UINT64)Adjust;
+ }
+ break;
+
+ case EFI_IMAGE_REL_BASED_HIGHADJ:
+ //
+ // Not implemented, but not used in EFI 1.0
+ //
+ ASSERT (FALSE);
+ break;
+
+ default:
+ //
+ // Only Itanium requires ConvertPeImage_Ex
+ //
+ Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
+ if (RETURN_ERROR (Status)) {
+ return ;
+ }
+ }
+ //
+ // Next relocation record
+ //
+ Reloc += 1;
+ }
+ //
+ // next reloc block
+ //
+ RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
+ }
+}
+
+
+/**
+ ImageRead function that operates on a memory buffer whos base is passed into
+ FileHandle.
+
+ @param FileHandle Ponter to baes of the input stream
+ @param FileOffset Offset to the start of the buffer
+ @param ReadSize Number of bytes to copy into the buffer
+ @param Buffer Location to place results of read
+
+ @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into
+ the buffer.
+**/
+RETURN_STATUS
+EFIAPI
+PeCoffLoaderImageReadFromMemory (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+ CopyMem (Buffer, ((UINT8 *)FileHandle) + FileOffset, *ReadSize);
+ return RETURN_SUCCESS;
+}
+
|