/** @file\r
Tiano PE/COFF loader.\r
\r
+ This PE/COFF loader supports loading any PE32 or PE32+ image type, but\r
+ only supports relocating IA32, X64, IPF, and EBC images.\r
+\r
Copyright (c) 2006, Intel Corporation\r
All rights reserved. This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
\r
**/\r
\r
+#include "BasePeCoffLibInternals.h"\r
\r
+/**\r
+ Retrieves the magic value from the PE/COFF header.\r
\r
+ @param Hdr The buffer in which to return the PE32, PE32+, or TE header.\r
\r
-STATIC\r
-RETURN_STATUS\r
-PeCoffLoaderGetPeHeader (\r
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
- OUT EFI_IMAGE_NT_HEADERS *PeHdr,\r
- OUT EFI_TE_IMAGE_HEADER *TeHdr\r
- );\r
-\r
-STATIC\r
-RETURN_STATUS\r
-PeCoffLoaderCheckImageType (\r
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
- IN EFI_IMAGE_NT_HEADERS *PeHdr,\r
- IN EFI_TE_IMAGE_HEADER *TeHdr\r
- );\r
-\r
-STATIC\r
-VOID *\r
-PeCoffLoaderImageAddress (\r
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
- IN UINTN Address\r
- );\r
-\r
-RETURN_STATUS\r
-PeCoffLoaderRelocateImageEx (\r
- IN UINT16 *Reloc,\r
- IN OUT CHAR8 *Fixup,\r
- IN OUT CHAR8 **FixupData,\r
- IN UINT64 Adjust\r
- );\r
+ @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32\r
+ @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+\r
\r
+**/\r
+UINT16\r
+PeCoffLoaderGetPeHeaderMagicValue (\r
+ IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr\r
+ )\r
+{\r
+ //\r
+ // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value \r
+ // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the \r
+ // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
+ // then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
+ //\r
+ if (Hdr.Pe32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
+ }\r
+ //\r
+ // Return the magic value from the PC/COFF Optional Header\r
+ //\r
+ return Hdr.Pe32->OptionalHeader.Magic;\r
+}\r
\r
\r
/**\r
Retrieves the PE or TE Header from a PE/COFF or TE image.\r
\r
- @param ImageContext The context of the image being loaded.\r
- \r
- @param PeHdr The buffer in which to return the PE header.\r
- \r
- @param TeHdr The buffer in which to return the TE header.\r
+ @param ImageContext The context of the image being loaded.\r
+ @param Hdr The buffer in which to return the PE32, PE32+, or TE header.\r
\r
- @return\r
- RETURN_SUCCESS if the PE or TE Header is read,\r
- Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.\r
+ @retval RETURN_SUCCESS The PE or TE Header is read.\r
+ @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.\r
\r
**/\r
-STATIC\r
RETURN_STATUS\r
PeCoffLoaderGetPeHeader (\r
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
- OUT EFI_IMAGE_NT_HEADERS *PeHdr,\r
- OUT EFI_TE_IMAGE_HEADER *TeHdr\r
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
+ OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr\r
)\r
{\r
- RETURN_STATUS Status;\r
+ RETURN_STATUS Status;\r
EFI_IMAGE_DOS_HEADER DosHdr;\r
UINTN Size;\r
+ UINT16 Magic;\r
\r
- ImageContext->IsTeImage = FALSE;\r
//\r
- // Read the DOS image headers\r
+ // Read the DOS image header to check for it's existance\r
//\r
Size = sizeof (EFI_IMAGE_DOS_HEADER);\r
Status = ImageContext->ImageRead (\r
- ImageContext->Handle,\r
- 0,\r
- &Size,\r
- &DosHdr\r
- );\r
+ ImageContext->Handle,\r
+ 0,\r
+ &Size,\r
+ &DosHdr\r
+ );\r
if (RETURN_ERROR (Status)) {\r
ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
return Status;\r
ImageContext->PeCoffHeaderOffset = 0;\r
if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
//\r
- // DOS image header is present, so read the PE header after the DOS image header\r
+ // DOS image header is present, so read the PE header after the DOS image\r
+ // header\r
//\r
ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;\r
}\r
+\r
//\r
- // Read the PE/COFF Header\r
+ // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much\r
+ // data, but that should not hurt anythine. Hdr.Pe32->OptionalHeader.Magic\r
+ // determins if this is a PE32 or PE32+ image. The magic is in the same\r
+ // location in both images.\r
//\r
- Size = sizeof (EFI_IMAGE_NT_HEADERS);\r
+ Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);\r
Status = ImageContext->ImageRead (\r
- ImageContext->Handle,\r
- ImageContext->PeCoffHeaderOffset,\r
- &Size,\r
- PeHdr\r
- );\r
+ ImageContext->Handle,\r
+ ImageContext->PeCoffHeaderOffset,\r
+ &Size,\r
+ Hdr.Pe32\r
+ );\r
if (RETURN_ERROR (Status)) {\r
ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
return Status;\r
}\r
+\r
//\r
- // Check the PE/COFF Header Signature. If not, then try to read a TE header\r
+ // Use Signature to figure out if we understand the image format\r
//\r
- if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
- Size = sizeof (EFI_TE_IMAGE_HEADER);\r
- Status = ImageContext->ImageRead (\r
- ImageContext->Handle,\r
- 0,\r
- &Size,\r
- TeHdr\r
- );\r
- if (TeHdr->Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
- return RETURN_UNSUPPORTED;\r
- }\r
-\r
- ImageContext->IsTeImage = TRUE;\r
- }\r
-\r
- return RETURN_SUCCESS;\r
-}\r
+ if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
+ ImageContext->IsTeImage = TRUE;\r
+ ImageContext->Machine = Hdr.Te->Machine;\r
+ ImageContext->ImageType = (UINT16)(Hdr.Te->Subsystem);\r
+ ImageContext->ImageSize = 0;\r
+ ImageContext->SectionAlignment = 4096;\r
+ ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;\r
\r
-/**\r
- Checks the PE or TE header of a PE/COFF or TE image to determine if it supported.\r
+ } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
+ ImageContext->IsTeImage = FALSE;\r
+ ImageContext->Machine = Hdr.Pe32->FileHeader.Machine;\r
\r
- @param ImageContext The context of the image being loaded.\r
- \r
- @param PeHdr The buffer in which to return the PE header.\r
- \r
- @param TeHdr The buffer in which to return the TE header.\r
+ Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);\r
\r
- @retval RETURN_SUCCESS if the PE/COFF or TE image is supported\r
- @retval RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported.\r
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ //\r
+ // Use PE32 offset\r
+ //\r
+ ImageContext->ImageType = Hdr.Pe32->OptionalHeader.Subsystem;\r
+ ImageContext->ImageSize = (UINT64)Hdr.Pe32->OptionalHeader.SizeOfImage;\r
+ ImageContext->SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;\r
+ ImageContext->SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
\r
-**/\r
-STATIC\r
-RETURN_STATUS\r
-PeCoffLoaderCheckImageType (\r
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
- IN EFI_IMAGE_NT_HEADERS *PeHdr,\r
- IN EFI_TE_IMAGE_HEADER *TeHdr\r
- )\r
-{\r
- //\r
- // See if the machine type is supported. We support a native machine type (IA-32/Itanium-based)\r
- // and the machine type for the Virtual Machine.\r
- //\r
- if (ImageContext->IsTeImage == FALSE) {\r
- ImageContext->Machine = PeHdr->FileHeader.Machine;\r
+ } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
+ //\r
+ // Use PE32+ offset\r
+ //\r
+ ImageContext->ImageType = Hdr.Pe32Plus->OptionalHeader.Subsystem;\r
+ ImageContext->ImageSize = (UINT64) Hdr.Pe32Plus->OptionalHeader.SizeOfImage;\r
+ ImageContext->SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;\r
+ ImageContext->SizeOfHeaders = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;\r
+ } else {\r
+ ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
} else {\r
- ImageContext->Machine = TeHdr->Machine;\r
- }\r
-\r
- if (!(EFI_IMAGE_MACHINE_TYPE_SUPPORTED (ImageContext->Machine))) {\r
ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;\r
return RETURN_UNSUPPORTED;\r
}\r
\r
- //\r
- // See if the image type is supported. We support EFI Applications,\r
- // EFI Boot Service Drivers, and EFI Runtime Drivers.\r
- //\r
- if (ImageContext->IsTeImage == FALSE) {\r
- ImageContext->ImageType = PeHdr->OptionalHeader.Subsystem;\r
- } else {\r
- ImageContext->ImageType = (UINT16) (TeHdr->Subsystem);\r
+ if (!PeCoffLoaderImageFormatSupported (ImageContext->Machine)) {\r
+ //\r
+ // If the PE/COFF loader does not support the image type return\r
+ // unsupported. This library can suport lots of types of images\r
+ // this does not mean the user of this library can call the entry\r
+ // point of the image.\r
+ //\r
+ return RETURN_UNSUPPORTED;\r
}\r
\r
-\r
return RETURN_SUCCESS;\r
}\r
\r
+\r
/**\r
- Retrieves information on a PE/COFF image.\r
+ Retrieves information about a PE/COFF image.\r
\r
- @param This Calling context\r
- @param ImageContext The context of the image being loaded\r
+ Computes the PeCoffHeaderOffset, ImageAddress, ImageSize, DestinationAddress, CodeView,\r
+ PdbPointer, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva\r
+ fields of the ImageContext structure. If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.\r
+ If the PE/COFF image accessed through the ImageRead service in the ImageContext structure is not\r
+ a supported PE/COFF image type, then return RETURN_UNSUPPORTED. If any errors occur while\r
+ computing the fields of ImageContext, then the error status is returned in the ImageError field of\r
+ ImageContext.\r
\r
- @retval RETURN_SUCCESS The information on the PE/COFF image was collected.\r
- @retval RETURN_INVALID_PARAMETER ImageContext is NULL.\r
- @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.\r
- @retval Otherwise The error status from reading the PE/COFF image using the\r
- ImageContext->ImageRead() function\r
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF\r
+ image that needs to be examined by this function.\r
+\r
+ @retval RETURN_SUCCESS The information on the PE/COFF image was collected.\r
+ @retval RETURN_INVALID_PARAMETER ImageContext is NULL.\r
+ @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.\r
\r
**/\r
RETURN_STATUS\r
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
)\r
{\r
- RETURN_STATUS Status;\r
- EFI_IMAGE_NT_HEADERS PeHdr;\r
- EFI_TE_IMAGE_HEADER TeHdr;\r
- EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;\r
- UINTN Size;\r
- UINTN Index;\r
- UINTN DebugDirectoryEntryRva;\r
- UINTN DebugDirectoryEntryFileOffset;\r
- UINTN SectionHeaderOffset;\r
- EFI_IMAGE_SECTION_HEADER SectionHeader;\r
- EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;\r
+ RETURN_STATUS Status;\r
+ EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;\r
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
+ EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;\r
+ UINTN Size;\r
+ UINTN Index;\r
+ UINTN DebugDirectoryEntryRva;\r
+ UINTN DebugDirectoryEntryFileOffset;\r
+ UINTN SectionHeaderOffset;\r
+ EFI_IMAGE_SECTION_HEADER SectionHeader;\r
+ EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;\r
+ UINT32 NumberOfRvaAndSizes;\r
+ UINT16 Magic;\r
\r
if (NULL == ImageContext) {\r
return RETURN_INVALID_PARAMETER;\r
//\r
ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
\r
- Status = PeCoffLoaderGetPeHeader (ImageContext, &PeHdr, &TeHdr);\r
- if (RETURN_ERROR (Status)) {\r
- return Status;\r
- }\r
- //\r
- // Verify machine type\r
- //\r
- Status = PeCoffLoaderCheckImageType (ImageContext, &PeHdr, &TeHdr);\r
+ Hdr.Union = &HdrData;\r
+ Status = PeCoffLoaderGetPeHeader (ImageContext, Hdr);\r
if (RETURN_ERROR (Status)) {\r
return Status;\r
}\r
+\r
+ Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);\r
+\r
//\r
// Retrieve the base address of the image\r
//\r
if (!(ImageContext->IsTeImage)) {\r
- ImageContext->ImageAddress = PeHdr.OptionalHeader.ImageBase;\r
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ //\r
+ // Use PE32 offset\r
+ //\r
+ ImageContext->ImageAddress = Hdr.Pe32->OptionalHeader.ImageBase;\r
+ } else {\r
+ //\r
+ // Use PE32+ offset\r
+ //\r
+ ImageContext->ImageAddress = Hdr.Pe32Plus->OptionalHeader.ImageBase;\r
+ }\r
} else {\r
- ImageContext->ImageAddress = (PHYSICAL_ADDRESS) (TeHdr.ImageBase);\r
+ ImageContext->ImageAddress = (PHYSICAL_ADDRESS)(Hdr.Te->ImageBase + Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));\r
}\r
+\r
//\r
// Initialize the alternate destination address to 0 indicating that it\r
// should not be used.\r
// Look at the file header to determine if relocations have been stripped, and\r
// save this info in the image context for later use.\r
//\r
- if ((!(ImageContext->IsTeImage)) && ((PeHdr.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {\r
+ if ((!(ImageContext->IsTeImage)) && ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {\r
ImageContext->RelocationsStripped = TRUE;\r
} else {\r
ImageContext->RelocationsStripped = FALSE;\r
}\r
\r
if (!(ImageContext->IsTeImage)) {\r
- ImageContext->ImageSize = (UINT64) PeHdr.OptionalHeader.SizeOfImage;\r
- ImageContext->SectionAlignment = PeHdr.OptionalHeader.SectionAlignment;\r
- ImageContext->SizeOfHeaders = PeHdr.OptionalHeader.SizeOfHeaders;\r
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ //\r
+ // Use PE32 offset\r
+ //\r
+ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
+ DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
+ } else {\r
+ //\r
+ // Use PE32+ offset\r
+ //\r
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
+ DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
+ }\r
\r
- //\r
- // Modify ImageSize to contain .PDB file name if required and initialize\r
- // PdbRVA field...\r
- //\r
- if (PeHdr.OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
- DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(PeHdr.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
\r
DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
\r
\r
SectionHeaderOffset = (UINTN)(\r
ImageContext->PeCoffHeaderOffset +\r
- sizeof (UINT32) + \r
- sizeof (EFI_IMAGE_FILE_HEADER) + \r
- PeHdr.FileHeader.SizeOfOptionalHeader\r
+ sizeof (UINT32) +\r
+ sizeof (EFI_IMAGE_FILE_HEADER) +\r
+ Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
);\r
\r
- for (Index = 0; Index < PeHdr.FileHeader.NumberOfSections; Index++) {\r
+ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
//\r
// Read section header from file\r
//\r
\r
if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
- DebugDirectoryEntryFileOffset =\r
- DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;\r
+\r
+ DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;\r
break;\r
}\r
\r
}\r
\r
if (DebugDirectoryEntryFileOffset != 0) {\r
- for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {\r
+ for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {\r
//\r
// Read next debug directory entry\r
//\r
ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
return Status;\r
}\r
-\r
if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
- ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));\r
+ ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);\r
if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {\r
ImageContext->ImageSize += DebugEntry.SizeOfData;\r
}\r
}\r
}\r
} else {\r
- ImageContext->ImageSize = 0;\r
- ImageContext->SectionAlignment = 4096;\r
- ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) TeHdr.BaseOfCode - (UINTN) TeHdr.StrippedSize;\r
\r
- DebugDirectoryEntry = &TeHdr.DataDirectory[1];\r
+ DebugDirectoryEntry = &Hdr.Te->DataDirectory[1];\r
DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
- SectionHeaderOffset = (UINTN) (sizeof (EFI_TE_IMAGE_HEADER));\r
+ SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));\r
\r
DebugDirectoryEntryFileOffset = 0;\r
\r
- for (Index = 0; Index < TeHdr.NumberOfSections;) {\r
+ for (Index = 0; Index < Hdr.Te->NumberOfSections;) {\r
//\r
// Read section header from file\r
//\r
- Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
+ Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
Status = ImageContext->ImageRead (\r
ImageContext->Handle,\r
SectionHeaderOffset,\r
if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -\r
- SectionHeader.VirtualAddress +\r
- SectionHeader.PointerToRawData +\r
- sizeof (EFI_TE_IMAGE_HEADER) -\r
- TeHdr.StrippedSize;\r
+ SectionHeader.VirtualAddress +\r
+ SectionHeader.PointerToRawData +\r
+ sizeof (EFI_TE_IMAGE_HEADER) -\r
+ Hdr.Te->StrippedSize;\r
\r
//\r
// File offset of the debug directory was found, if this is not the last\r
// section, then skip to the last section for calculating the image size.\r
//\r
- if (Index < (UINTN) TeHdr.NumberOfSections - 1) {\r
- SectionHeaderOffset += (TeHdr.NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);\r
- Index = TeHdr.NumberOfSections - 1;\r
+ if (Index < (UINTN) Hdr.Te->NumberOfSections - 1) {\r
+ SectionHeaderOffset += (Hdr.Te->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);\r
+ Index = Hdr.Te->NumberOfSections - 1;\r
continue;\r
}\r
}\r
\r
//\r
// In Te image header there is not a field to describe the ImageSize.\r
- // Actually, the ImageSize equals the RVA plus the VirtualSize of \r
- // the last section mapped into memory (Must be rounded up to \r
+ // Actually, the ImageSize equals the RVA plus the VirtualSize of\r
+ // the last section mapped into memory (Must be rounded up to\r
// a mulitple of Section Alignment). Per the PE/COFF specification, the\r
// section headers in the Section Table must appear in order of the RVA\r
// values for the corresponding sections. So the ImageSize can be determined\r
// by the RVA and the VirtualSize of the last section header in the\r
// Section Table.\r
//\r
- if ((++Index) == (UINTN) TeHdr.NumberOfSections) {\r
+ if ((++Index) == (UINTN)Hdr.Te->NumberOfSections) {\r
ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize +\r
ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1);\r
}\r
}\r
\r
if (DebugDirectoryEntryFileOffset != 0) {\r
- for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {\r
+ for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {\r
//\r
// Read next debug directory entry\r
//\r
}\r
\r
if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
- ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));\r
+ ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);\r
return RETURN_SUCCESS;\r
}\r
}\r
return RETURN_SUCCESS;\r
}\r
\r
+\r
/**\r
Converts an image address to the loaded address.\r
\r
- @param ImageContext The context of the image being loaded.\r
- \r
- @param Address The address to be converted to the loaded address.\r
+ @param ImageContext The context of the image being loaded.\r
+ @param Address The address to be converted to the loaded address.\r
\r
- @return NULL if the address can not be converted, otherwise, the converted address\r
+ @return The converted address or NULL if the address can not be converted.\r
\r
**/\r
-STATIC\r
VOID *\r
PeCoffLoaderImageAddress (\r
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
IN UINTN Address\r
)\r
{\r
+ //\r
+ // @bug Check to make sure ImageSize is correct for the relocated image.\r
+ // it may only work for the file we start with and not the relocated image\r
+ //\r
if (Address >= ImageContext->ImageSize) {\r
ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
return NULL;\r
}\r
\r
- return (CHAR8 *) ((UINTN) ImageContext->ImageAddress + Address);\r
+ return (CHAR8 *)((UINTN) ImageContext->ImageAddress + Address);\r
}\r
\r
/**\r
- Relocates a PE/COFF image in memory.\r
+ Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().\r
+\r
+ If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of\r
+ ImageContext as the relocation base address. Otherwise, use the DestinationAddress field\r
+ of ImageContext as the relocation base address. The caller must allocate the relocation\r
+ fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.\r
+ If ImageContext is NULL, then ASSERT().\r
\r
- @param This Calling context.\r
- \r
- @param ImageContext Contains information on the loaded image to relocate.\r
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF\r
+ image that is being relocated.\r
\r
- @retval RETURN_SUCCESS if the PE/COFF image was relocated.\r
- @retval RETURN_LOAD_ERROR if the image is not a valid PE/COFF image.\r
- @retval RETURN_UNSUPPORTED not support.\r
+ @retval RETURN_SUCCESS The PE/COFF image was relocated.\r
+ Extended status information is in the ImageError field of ImageContext.\r
+ @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.\r
+ Extended status information is in the ImageError field of ImageContext.\r
+ @retval RETURN_UNSUPPORTED A relocation record type is not supported.\r
+ Extended status information is in the ImageError field of ImageContext.\r
\r
**/\r
RETURN_STATUS\r
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
)\r
{\r
- RETURN_STATUS Status;\r
- EFI_IMAGE_NT_HEADERS *PeHdr;\r
- EFI_TE_IMAGE_HEADER *TeHdr;\r
- EFI_IMAGE_DATA_DIRECTORY *RelocDir;\r
- UINT64 Adjust;\r
- EFI_IMAGE_BASE_RELOCATION *RelocBase;\r
- EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;\r
- UINT16 *Reloc;\r
- UINT16 *RelocEnd;\r
- CHAR8 *Fixup;\r
- CHAR8 *FixupBase;\r
- UINT16 *F16;\r
- UINT32 *F32;\r
- CHAR8 *FixupData;\r
- PHYSICAL_ADDRESS BaseAddress;\r
-\r
- PeHdr = NULL;\r
- TeHdr = NULL;\r
+ RETURN_STATUS Status;\r
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
+ EFI_IMAGE_DATA_DIRECTORY *RelocDir;\r
+ UINT64 Adjust;\r
+ EFI_IMAGE_BASE_RELOCATION *RelocBase;\r
+ EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;\r
+ UINT16 *Reloc;\r
+ UINT16 *RelocEnd;\r
+ CHAR8 *Fixup;\r
+ CHAR8 *FixupBase;\r
+ UINT16 *F16;\r
+ UINT32 *F32;\r
+ UINT64 *F64;\r
+ CHAR8 *FixupData;\r
+ PHYSICAL_ADDRESS BaseAddress;\r
+ UINT32 NumberOfRvaAndSizes;\r
+ UINT16 Magic;\r
+\r
+ ASSERT (ImageContext != NULL);\r
+\r
//\r
// Assume success\r
//\r
// If the destination address is not 0, use that rather than the\r
// image address as the relocation target.\r
//\r
- if (ImageContext->DestinationAddress) {\r
+ if (ImageContext->DestinationAddress != 0) {\r
BaseAddress = ImageContext->DestinationAddress;\r
- } else {\r
+ } else if (!(ImageContext->IsTeImage)) {\r
BaseAddress = ImageContext->ImageAddress;\r
+ } else {\r
+ Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);\r
+ BaseAddress = ImageContext->ImageAddress + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize; \r
}\r
\r
if (!(ImageContext->IsTeImage)) {\r
- PeHdr = (EFI_IMAGE_NT_HEADERS *)((UINTN)ImageContext->ImageAddress + \r
- ImageContext->PeCoffHeaderOffset);\r
- Adjust = (UINT64) BaseAddress - PeHdr->OptionalHeader.ImageBase;\r
- PeHdr->OptionalHeader.ImageBase = (UINTN)BaseAddress;\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r
+\r
+ Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);\r
+\r
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ //\r
+ // Use PE32 offset\r
+ //\r
+ Adjust = (UINT64)BaseAddress - Hdr.Pe32->OptionalHeader.ImageBase;\r
+ Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress;\r
+\r
+ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
+ RelocDir = &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
+ } else {\r
+ //\r
+ // Use PE32+ offset\r
+ //\r
+ Adjust = (UINT64) BaseAddress - Hdr.Pe32Plus->OptionalHeader.ImageBase;\r
+ Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress;\r
+\r
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
+ RelocDir = &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
+ }\r
\r
//\r
// Find the relocation block\r
- //\r
// Per the PE/COFF spec, you can't assume that a given data directory\r
// is present in the image. You have to check the NumberOfRvaAndSizes in\r
// the optional header to verify a desired directory entry is there.\r
//\r
- if (PeHdr->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
- RelocDir = &PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
+\r
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);\r
RelocBaseEnd = PeCoffLoaderImageAddress (\r
ImageContext,\r
RelocBase = RelocBaseEnd = 0;\r
}\r
} else {\r
- TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);\r
- Adjust = (UINT64) (BaseAddress - TeHdr->ImageBase);\r
- TeHdr->ImageBase = (UINT64) (BaseAddress);\r
+ Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);\r
+ Adjust = (UINT64) (BaseAddress - Hdr.Te->ImageBase);\r
+ Hdr.Te->ImageBase = (UINT64) (BaseAddress);\r
\r
//\r
// Find the relocation block\r
//\r
- RelocDir = &TeHdr->DataDirectory[0];\r
+ RelocDir = &Hdr.Te->DataDirectory[0];\r
RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(\r
- ImageContext->ImageAddress + \r
- RelocDir->VirtualAddress +\r
- sizeof(EFI_TE_IMAGE_HEADER) - \r
- TeHdr->StrippedSize\r
- );\r
+ ImageContext->ImageAddress +\r
+ RelocDir->VirtualAddress +\r
+ sizeof(EFI_TE_IMAGE_HEADER) -\r
+ Hdr.Te->StrippedSize\r
+ );\r
RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);\r
}\r
- \r
+\r
//\r
// Run the relocation information and apply the fixups\r
//\r
FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);\r
} else {\r
FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +\r
- RelocBase->VirtualAddress +\r
- sizeof(EFI_TE_IMAGE_HEADER) - \r
- TeHdr->StrippedSize\r
- );\r
+ RelocBase->VirtualAddress +\r
+ sizeof(EFI_TE_IMAGE_HEADER) -\r
+ Hdr.Te->StrippedSize\r
+ );\r
}\r
\r
if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||\r
- (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + \r
+ (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress +\r
(UINTN)ImageContext->ImageSize)) {\r
ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
return RETURN_LOAD_ERROR;\r
\r
case EFI_IMAGE_REL_BASED_HIGH:\r
F16 = (UINT16 *) Fixup;\r
- *F16 = (UINT16) ((*F16 << 16) + (UINT16) Adjust);\r
+ *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));\r
if (FixupData != NULL) {\r
*(UINT16 *) FixupData = *F16;\r
FixupData = FixupData + sizeof (UINT16);\r
*F32 = *F32 + (UINT32) Adjust;\r
if (FixupData != NULL) {\r
FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
- *(UINT32 *) FixupData = *F32;\r
+ *(UINT32 *)FixupData = *F32;\r
FixupData = FixupData + sizeof (UINT32);\r
}\r
break;\r
\r
- case EFI_IMAGE_REL_BASED_HIGHADJ:\r
- //\r
- // Return the same EFI_UNSUPPORTED return code as\r
- // PeCoffLoaderRelocateImageEx() returns if it does not recognize\r
- // the relocation type.\r
- //\r
- ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
- return RETURN_UNSUPPORTED;\r
+ case EFI_IMAGE_REL_BASED_DIR64:\r
+ F64 = (UINT64 *) Fixup;\r
+ *F64 = *F64 + (UINT64) Adjust;\r
+ if (FixupData != NULL) {\r
+ FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));\r
+ *(UINT64 *)(FixupData) = *F64;\r
+ FixupData = FixupData + sizeof(UINT64);\r
+ }\r
+ break;\r
\r
default:\r
+ //\r
+ // The common code does not handle some of the stranger IPF relocations\r
+ // PeCoffLoaderRelocateImageEx () addes support for these complex fixups\r
+ // on IPF and is a No-Op on other archtiectures.\r
+ //\r
Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);\r
if (RETURN_ERROR (Status)) {\r
ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
/**\r
Loads a PE/COFF image into memory.\r
\r
- @param This Calling context.\r
- \r
- @param ImageContext Contains information on image to load into memory.\r
-\r
- @retval RETURN_SUCCESS if the PE/COFF image was loaded.\r
- @retval RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer.\r
- @retval RETURN_LOAD_ERROR if the image is a runtime driver with no relocations.\r
- @retval RETURN_INVALID_PARAMETER if the image address is invalid.\r
+ Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer\r
+ specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate\r
+ the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.\r
+ The EntryPoint, FixupDataSize, CodeView, and PdbPointer fields of ImageContext are computed.\r
+ If ImageContext is NULL, then ASSERT().\r
+\r
+ @param ImageContext Pointer to the image context structure that describes the PE/COFF\r
+ image that is being loaded.\r
+\r
+ @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by\r
+ the ImageAddress and ImageSize fields of ImageContext.\r
+ Extended status information is in the ImageError field of ImageContext.\r
+ @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.\r
+ Extended status information is in the ImageError field of ImageContext.\r
+ @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.\r
+ Extended status information is in the ImageError field of ImageContext.\r
+ @retval RETURN_INVALID_PARAMETER The image address is invalid.\r
+ Extended status information is in the ImageError field of ImageContext.\r
\r
**/\r
RETURN_STATUS\r
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
)\r
{\r
- RETURN_STATUS Status;\r
- EFI_IMAGE_NT_HEADERS *PeHdr;\r
- EFI_TE_IMAGE_HEADER *TeHdr;\r
- PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;\r
+ RETURN_STATUS Status;\r
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
+ PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;\r
EFI_IMAGE_SECTION_HEADER *FirstSection;\r
EFI_IMAGE_SECTION_HEADER *Section;\r
UINTN NumberOfSections;\r
EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
UINTN Size;\r
UINT32 TempDebugEntryRva;\r
+ UINT32 NumberOfRvaAndSizes;\r
+ UINT16 Magic;\r
+\r
+ ASSERT (ImageContext != NULL);\r
\r
- PeHdr = NULL;\r
- TeHdr = NULL;\r
//\r
// Assume success\r
//\r
ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;\r
return RETURN_BUFFER_TOO_SMALL;\r
}\r
-\r
+ if (ImageContext->ImageAddress == 0) {\r
+ //\r
+ // Image cannot be loaded into 0 address.\r
+ //\r
+ ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
+ return RETURN_INVALID_PARAMETER;\r
+ }\r
//\r
// If there's no relocations, then make sure it's not a runtime driver,\r
// and that it's being loaded at the linked address.\r
(VOID *) (UINTN) ImageContext->ImageAddress\r
);\r
\r
- PeHdr = (EFI_IMAGE_NT_HEADERS *)\r
- ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r
\r
FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
(UINTN)ImageContext->ImageAddress +\r
ImageContext->PeCoffHeaderOffset +\r
- sizeof(UINT32) + \r
- sizeof(EFI_IMAGE_FILE_HEADER) + \r
- PeHdr->FileHeader.SizeOfOptionalHeader\r
+ sizeof(UINT32) +\r
+ sizeof(EFI_IMAGE_FILE_HEADER) +\r
+ Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
);\r
- NumberOfSections = (UINTN) (PeHdr->FileHeader.NumberOfSections);\r
+ NumberOfSections = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);\r
} else {\r
Status = ImageContext->ImageRead (\r
ImageContext->Handle,\r
0,\r
&ImageContext->SizeOfHeaders,\r
- (void *) (UINTN) ImageContext->ImageAddress\r
+ (void *)(UINTN)ImageContext->ImageAddress\r
);\r
\r
- TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);\r
+ Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);\r
\r
FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
- (UINTN)ImageContext->ImageAddress +\r
- sizeof(EFI_TE_IMAGE_HEADER)\r
- );\r
- NumberOfSections = (UINTN) (TeHdr->NumberOfSections);\r
+ (UINTN)ImageContext->ImageAddress +\r
+ sizeof(EFI_TE_IMAGE_HEADER)\r
+ );\r
+ NumberOfSections = (UINTN) (Hdr.Te->NumberOfSections);\r
\r
}\r
\r
Section->VirtualAddress + Section->Misc.VirtualSize - 1\r
);\r
if (ImageContext->IsTeImage) {\r
- Base = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);\r
- End = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);\r
+ Base = (CHAR8 *)((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);\r
+ End = (CHAR8 *)((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);\r
}\r
\r
if (End > MaxEnd) {\r
} else {\r
Status = ImageContext->ImageRead (\r
ImageContext->Handle,\r
- Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize,\r
+ Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize,\r
&Size,\r
Base\r
);\r
//\r
// Get image's entry point\r
//\r
+ Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);\r
if (!(ImageContext->IsTeImage)) {\r
- ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (\r
- ImageContext,\r
- PeHdr->OptionalHeader.AddressOfEntryPoint\r
- );\r
+ //\r
+ // Sizes of AddressOfEntryPoint are different so we need to do this safely\r
+ //\r
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ //\r
+ // Use PE32 offset\r
+ //\r
+ ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (\r
+ ImageContext,\r
+ (UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint\r
+ );\r
+ } else {\r
+ //\r
+ // Use PE32+ offset\r
+ //\r
+ ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (\r
+ ImageContext,\r
+ (UINTN)Hdr.Pe32Plus->OptionalHeader.AddressOfEntryPoint\r
+ );\r
+ }\r
} else {\r
ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (\r
- (UINTN)ImageContext->ImageAddress +\r
- (UINTN)TeHdr->AddressOfEntryPoint +\r
- (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r
- (UINTN) TeHdr->StrippedSize\r
- );\r
+ (UINTN)ImageContext->ImageAddress +\r
+ (UINTN)Hdr.Te->AddressOfEntryPoint +\r
+ (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r
+ (UINTN)Hdr.Te->StrippedSize\r
+ );\r
}\r
\r
//\r
// the optional header to verify a desired directory entry is there.\r
//\r
if (!(ImageContext->IsTeImage)) {\r
- if (PeHdr->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
- DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)\r
- &PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ //\r
+ // Use PE32 offset\r
+ //\r
+ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
+ DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
+ } else {\r
+ //\r
+ // Use PE32+ offset\r
+ //\r
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
+ DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
+ }\r
+\r
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
} else {\r
ImageContext->FixupDataSize = 0;\r
}\r
} else {\r
- DirectoryEntry = &TeHdr->DataDirectory[0];\r
+ DirectoryEntry = &Hdr.Te->DataDirectory[0];\r
ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
}\r
//\r
);\r
} else {\r
DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(\r
- ImageContext->ImageAddress +\r
- ImageContext->DebugDirectoryEntryRva +\r
- sizeof(EFI_TE_IMAGE_HEADER) -\r
- TeHdr->StrippedSize\r
- );\r
+ ImageContext->ImageAddress +\r
+ ImageContext->DebugDirectoryEntryRva +\r
+ sizeof(EFI_TE_IMAGE_HEADER) -\r
+ Hdr.Te->StrippedSize\r
+ );\r
}\r
\r
if (DebugEntry != NULL) {\r
TempDebugEntryRva = DebugEntry->RVA;\r
if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {\r
Section--;\r
- if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) {\r
+ if ((UINTN)Section->SizeOfRawData < Section->Misc.VirtualSize) {\r
TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;\r
} else {\r
TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;\r
ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);\r
} else {\r
ImageContext->CodeView = (VOID *)(\r
- (UINTN)ImageContext->ImageAddress +\r
- (UINTN)TempDebugEntryRva +\r
- (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r
- (UINTN) TeHdr->StrippedSize\r
- );\r
+ (UINTN)ImageContext->ImageAddress +\r
+ (UINTN)TempDebugEntryRva +\r
+ (UINTN)sizeof (EFI_TE_IMAGE_HEADER) -\r
+ (UINTN) Hdr.Te->StrippedSize\r
+ );\r
}\r
\r
if (ImageContext->CodeView == NULL) {\r
} else {\r
Status = ImageContext->ImageRead (\r
ImageContext->Handle,\r
- DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize,\r
+ DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize,\r
&Size,\r
ImageContext->CodeView\r
);\r
\r
switch (*(UINT32 *) ImageContext->CodeView) {\r
case CODEVIEW_SIGNATURE_NB10:\r
- ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
+ ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
break;\r
\r
case CODEVIEW_SIGNATURE_RSDS:\r
- ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
+ ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
break;\r
\r
default:\r
\r
return Status;\r
}\r
+\r
+\r
+/**\r
+ Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI\r
+ runtime.\r
+\r
+ PE_COFF_LOADER_IMAGE_CONTEXT.FixupData stores information needed to reapply\r
+ the fixups with a virtual mapping.\r
+\r
+\r
+ @param ImageBase Base address of relocated image\r
+ @param VirtImageBase Virtual mapping for ImageBase\r
+ @param ImageSize Size of the image to relocate\r
+ @param RelocationData Location to place results of read\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PeCoffLoaderRelocateImageForRuntime (\r
+ IN PHYSICAL_ADDRESS ImageBase,\r
+ IN PHYSICAL_ADDRESS VirtImageBase,\r
+ IN UINTN ImageSize,\r
+ IN VOID *RelocationData\r
+ )\r
+{\r
+ CHAR8 *OldBase;\r
+ CHAR8 *NewBase;\r
+ EFI_IMAGE_DOS_HEADER *DosHdr;\r
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
+ UINT32 NumberOfRvaAndSizes;\r
+ EFI_IMAGE_DATA_DIRECTORY *DataDirectory;\r
+ EFI_IMAGE_DATA_DIRECTORY *RelocDir;\r
+ EFI_IMAGE_BASE_RELOCATION *RelocBase;\r
+ EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;\r
+ UINT16 *Reloc;\r
+ UINT16 *RelocEnd;\r
+ CHAR8 *Fixup;\r
+ CHAR8 *FixupBase;\r
+ UINT16 *F16;\r
+ UINT32 *F32;\r
+ UINT64 *F64;\r
+ CHAR8 *FixupData;\r
+ UINTN Adjust;\r
+ RETURN_STATUS Status;\r
+ UINT16 Magic;\r
+\r
+ OldBase = (CHAR8 *)((UINTN)ImageBase);\r
+ NewBase = (CHAR8 *)((UINTN)VirtImageBase);\r
+ Adjust = (UINTN) NewBase - (UINTN) OldBase;\r
+\r
+ //\r
+ // Find the image's relocate dir info\r
+ //\r
+ DosHdr = (EFI_IMAGE_DOS_HEADER *)OldBase;\r
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
+ //\r
+ // Valid DOS header so get address of PE header\r
+ //\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(((CHAR8 *)DosHdr) + DosHdr->e_lfanew);\r
+ } else {\r
+ //\r
+ // No Dos header so assume image starts with PE header.\r
+ //\r
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)OldBase;\r
+ }\r
+\r
+ if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
+ //\r
+ // Not a valid PE image so Exit\r
+ //\r
+ return ;\r
+ }\r
+\r
+ Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);\r
+\r
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+ //\r
+ // Use PE32 offset\r
+ //\r
+ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
+ DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[0]);\r
+ } else {\r
+ //\r
+ // Use PE32+ offset\r
+ //\r
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
+ DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[0]);\r
+ }\r
+\r
+ //\r
+ // Find the relocation block\r
+ //\r
+ // Per the PE/COFF spec, you can't assume that a given data directory\r
+ // is present in the image. You have to check the NumberOfRvaAndSizes in\r
+ // the optional header to verify a desired directory entry is there.\r
+ //\r
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
+ RelocDir = DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;\r
+ RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress);\r
+ RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress + RelocDir->Size);\r
+ } else {\r
+ //\r
+ // Cannot find relocations, cannot continue\r
+ //\r
+ ASSERT (FALSE);\r
+ return ;\r
+ }\r
+\r
+ ASSERT (RelocBase != NULL && RelocBaseEnd != NULL);\r
+\r
+ //\r
+ // Run the whole relocation block. And re-fixup data that has not been\r
+ // modified. The FixupData is used to see if the image has been modified\r
+ // since it was relocated. This is so data sections that have been updated\r
+ // by code will not be fixed up, since that would set them back to\r
+ // defaults.\r
+ //\r
+ FixupData = RelocationData;\r
+ while (RelocBase < RelocBaseEnd) {\r
+\r
+ Reloc = (UINT16 *) ((UINT8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
+ RelocEnd = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock);\r
+ FixupBase = (CHAR8 *) ((UINTN)ImageBase) + RelocBase->VirtualAddress;\r
+\r
+ //\r
+ // Run this relocation record\r
+ //\r
+ while (Reloc < RelocEnd) {\r
+\r
+ Fixup = FixupBase + (*Reloc & 0xFFF);\r
+ switch ((*Reloc) >> 12) {\r
+\r
+ case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
+ break;\r
+\r
+ case EFI_IMAGE_REL_BASED_HIGH:\r
+ F16 = (UINT16 *) Fixup;\r
+ if (*(UINT16 *) FixupData == *F16) {\r
+ *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));\r
+ }\r
+\r
+ FixupData = FixupData + sizeof (UINT16);\r
+ break;\r
+\r
+ case EFI_IMAGE_REL_BASED_LOW:\r
+ F16 = (UINT16 *) Fixup;\r
+ if (*(UINT16 *) FixupData == *F16) {\r
+ *F16 = (UINT16) (*F16 + ((UINT16) Adjust & 0xffff));\r
+ }\r
+\r
+ FixupData = FixupData + sizeof (UINT16);\r
+ break;\r
+\r
+ case EFI_IMAGE_REL_BASED_HIGHLOW:\r
+ F32 = (UINT32 *) Fixup;\r
+ FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
+ if (*(UINT32 *) FixupData == *F32) {\r
+ *F32 = *F32 + (UINT32) Adjust;\r
+ }\r
+\r
+ FixupData = FixupData + sizeof (UINT32);\r
+ break;\r
+\r
+ case EFI_IMAGE_REL_BASED_DIR64:\r
+ F64 = (UINT64 *)Fixup;\r
+ FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));\r
+ if (*(UINT64 *) FixupData == *F64) {\r
+ *F64 = *F64 + (UINT64)Adjust;\r
+ }\r
+\r
+ FixupData = FixupData + sizeof (UINT64);\r
+ break;\r
+\r
+ case EFI_IMAGE_REL_BASED_HIGHADJ:\r
+ //\r
+ // Not implemented, but not used in EFI 1.0\r
+ //\r
+ ASSERT (FALSE);\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // Only Itanium requires ConvertPeImage_Ex\r
+ //\r
+ Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);\r
+ if (RETURN_ERROR (Status)) {\r
+ return ;\r
+ }\r
+ }\r
+ //\r
+ // Next relocation record\r
+ //\r
+ Reloc += 1;\r
+ }\r
+ //\r
+ // next reloc block\r
+ //\r
+ RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ ImageRead function that operates on a memory buffer whos base is passed into\r
+ FileHandle.\r
+\r
+ @param FileHandle Ponter to baes of the input stream\r
+ @param FileOffset Offset to the start of the buffer\r
+ @param ReadSize Number of bytes to copy into the buffer\r
+ @param Buffer Location to place results of read\r
+\r
+ @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into\r
+ the buffer.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+PeCoffLoaderImageReadFromMemory (\r
+ IN VOID *FileHandle,\r
+ IN UINTN FileOffset,\r
+ IN OUT UINTN *ReadSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ CopyMem (Buffer, ((UINT8 *)FileHandle) + FileOffset, *ReadSize);\r
+ return RETURN_SUCCESS;\r
+}\r
+\r