]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OldMdePkg/Library/BasePeCoffLib/BasePeCoff.c
Moved the MdePkg to OldMdePkg so that new code in MdePkg does not break existing...
[mirror_edk2.git] / OldMdePkg / Library / BasePeCoffLib / BasePeCoff.c
diff --git a/OldMdePkg/Library/BasePeCoffLib/BasePeCoff.c b/OldMdePkg/Library/BasePeCoffLib/BasePeCoff.c
new file mode 100644 (file)
index 0000000..ad3635f
--- /dev/null
@@ -0,0 +1,1333 @@
+/** @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
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+  Module Name:  PeCoffLoader.c\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
+  @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
+  @param  Hdr             The buffer in which to return the PE32, PE32+, or TE header.\r
+\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
+RETURN_STATUS\r
+PeCoffLoaderGetPeHeader (\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
+  EFI_IMAGE_DOS_HEADER  DosHdr;\r
+  UINTN                 Size;\r
+  UINT16                Magic;\r
+\r
+  //\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
+  if (RETURN_ERROR (Status)) {\r
+    ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+    return Status;\r
+  }\r
+\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\r
+    // header\r
+    //\r
+    ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;\r
+  }\r
+\r
+  //\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_OPTIONAL_HEADER_UNION);\r
+  Status = ImageContext->ImageRead (\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
+  // Use Signature to figure out if we understand the image format\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
+  } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE)  {\r
+    ImageContext->IsTeImage = FALSE;\r
+    ImageContext->Machine = Hdr.Pe32->FileHeader.Machine;\r
+\r
+    Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);\r
+\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
+    } 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->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\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
+  return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Retrieves information about a PE/COFF image.\r
+\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
+  @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
+EFIAPI\r
+PeCoffLoaderGetImageInfo (\r
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT           *ImageContext\r
+  )\r
+{\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
+  //\r
+  // Assume success\r
+  //\r
+  ImageContext->ImageError  = IMAGE_ERROR_SUCCESS;\r
+\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
+    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)(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
+  //\r
+  ImageContext->DestinationAddress = 0;\r
+\r
+  //\r
+  // Initialize the codeview pointer.\r
+  //\r
+  ImageContext->CodeView    = NULL;\r
+  ImageContext->PdbPointer  = NULL;\r
+\r
+  //\r
+  // Three cases with regards to relocations:\r
+  // - Image has base relocs, RELOCS_STRIPPED==0    => image is relocatable\r
+  // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable\r
+  // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but\r
+  //   has no base relocs to apply\r
+  // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.\r
+  //\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)) && ((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
+    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
+    if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
+\r
+      DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
+\r
+      //\r
+      // Determine the file offset of the debug directory...  This means we walk\r
+      // the sections to find which section contains the RVA of the debug\r
+      // directory\r
+      //\r
+      DebugDirectoryEntryFileOffset = 0;\r
+\r
+      SectionHeaderOffset = (UINTN)(\r
+                               ImageContext->PeCoffHeaderOffset +\r
+                               sizeof (UINT32) +\r
+                               sizeof (EFI_IMAGE_FILE_HEADER) +\r
+                               Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
+                               );\r
+\r
+      for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
+        //\r
+        // Read section header from file\r
+        //\r
+        Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
+        Status = ImageContext->ImageRead (\r
+                                 ImageContext->Handle,\r
+                                 SectionHeaderOffset,\r
+                                 &Size,\r
+                                 &SectionHeader\r
+                                 );\r
+        if (RETURN_ERROR (Status)) {\r
+          ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+          return Status;\r
+        }\r
+\r
+        if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
+            DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
+\r
+          DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;\r
+          break;\r
+        }\r
+\r
+        SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
+      }\r
+\r
+      if (DebugDirectoryEntryFileOffset != 0) {\r
+        for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {\r
+          //\r
+          // Read next debug directory entry\r
+          //\r
+          Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
+          Status = ImageContext->ImageRead (\r
+                                   ImageContext->Handle,\r
+                                   DebugDirectoryEntryFileOffset,\r
+                                   &Size,\r
+                                   &DebugEntry\r
+                                   );\r
+          if (RETURN_ERROR (Status)) {\r
+            ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+            return Status;\r
+          }\r
+          if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
+            ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);\r
+            if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {\r
+              ImageContext->ImageSize += DebugEntry.SizeOfData;\r
+            }\r
+\r
+            return RETURN_SUCCESS;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  } else {\r
+\r
+    DebugDirectoryEntry             = &Hdr.Te->DataDirectory[1];\r
+    DebugDirectoryEntryRva          = DebugDirectoryEntry->VirtualAddress;\r
+    SectionHeaderOffset             = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));\r
+\r
+    DebugDirectoryEntryFileOffset   = 0;\r
+\r
+    for (Index = 0; Index < Hdr.Te->NumberOfSections;) {\r
+      //\r
+      // Read section header from file\r
+      //\r
+      Size   = sizeof (EFI_IMAGE_SECTION_HEADER);\r
+      Status = ImageContext->ImageRead (\r
+                               ImageContext->Handle,\r
+                               SectionHeaderOffset,\r
+                               &Size,\r
+                               &SectionHeader\r
+                               );\r
+      if (RETURN_ERROR (Status)) {\r
+        ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+        return Status;\r
+      }\r
+\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
+                                        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) 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
+      // 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)Hdr.Te->NumberOfSections) {\r
+        ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize +\r
+                                   ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1);\r
+      }\r
+\r
+      SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
+    }\r
+\r
+    if (DebugDirectoryEntryFileOffset != 0) {\r
+      for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {\r
+        //\r
+        // Read next debug directory entry\r
+        //\r
+        Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
+        Status = ImageContext->ImageRead (\r
+                                 ImageContext->Handle,\r
+                                 DebugDirectoryEntryFileOffset,\r
+                                 &Size,\r
+                                 &DebugEntry\r
+                                 );\r
+        if (RETURN_ERROR (Status)) {\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);\r
+          return RETURN_SUCCESS;\r
+        }\r
+      }\r
+    }\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
+  @param  Address       The address to be converted to the loaded address.\r
+\r
+  @return The converted address or NULL if the address can not be converted.\r
+\r
+**/\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
+}\r
+\r
+/**\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  ImageContext        Pointer to the image context structure that describes the PE/COFF\r
+                              image that is being relocated.\r
+\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
+EFIAPI\r
+PeCoffLoaderRelocateImage (\r
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext\r
+  )\r
+{\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
+  ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
+\r
+  //\r
+  // If there are no relocation entries, then we are done\r
+  //\r
+  if (ImageContext->RelocationsStripped) {\r
+    return RETURN_SUCCESS;\r
+  }\r
+\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 != 0) {\r
+    BaseAddress = ImageContext->DestinationAddress;\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
+    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
+    // 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
+\r
+    if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
+      RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);\r
+      RelocBaseEnd = PeCoffLoaderImageAddress (\r
+                      ImageContext,\r
+                      RelocDir->VirtualAddress + RelocDir->Size - 1\r
+                      );\r
+    } else {\r
+      //\r
+      // Set base and end to bypass processing below.\r
+      //\r
+      RelocBase = RelocBaseEnd = 0;\r
+    }\r
+  } else {\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 = &Hdr.Te->DataDirectory[0];\r
+    RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(\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
+  // Run the relocation information and apply the fixups\r
+  //\r
+  FixupData = ImageContext->FixupData;\r
+  while (RelocBase < RelocBaseEnd) {\r
+\r
+    Reloc     = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
+    RelocEnd  = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);\r
+    if (!(ImageContext->IsTeImage)) {\r
+      FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);\r
+    } else {\r
+      FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +\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
+          (UINTN)ImageContext->ImageSize)) {\r
+      ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
+      return RETURN_LOAD_ERROR;\r
+    }\r
+\r
+    //\r
+    // Run this relocation record\r
+    //\r
+    while (Reloc < RelocEnd) {\r
+\r
+      Fixup = FixupBase + (*Reloc & 0xFFF);\r
+      switch ((*Reloc) >> 12) {\r
+      case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
+        break;\r
+\r
+      case EFI_IMAGE_REL_BASED_HIGH:\r
+        F16   = (UINT16 *) Fixup;\r
+        *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));\r
+        if (FixupData != NULL) {\r
+          *(UINT16 *) FixupData = *F16;\r
+          FixupData             = FixupData + sizeof (UINT16);\r
+        }\r
+        break;\r
+\r
+      case EFI_IMAGE_REL_BASED_LOW:\r
+        F16   = (UINT16 *) Fixup;\r
+        *F16  = (UINT16) (*F16 + (UINT16) Adjust);\r
+        if (FixupData != NULL) {\r
+          *(UINT16 *) FixupData = *F16;\r
+          FixupData             = FixupData + sizeof (UINT16);\r
+        }\r
+        break;\r
+\r
+      case EFI_IMAGE_REL_BASED_HIGHLOW:\r
+        F32   = (UINT32 *) Fixup;\r
+        *F32  = *F32 + (UINT32) Adjust;\r
+        if (FixupData != NULL) {\r
+          FixupData             = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
+          *(UINT32 *)FixupData  = *F32;\r
+          FixupData             = FixupData + sizeof (UINT32);\r
+        }\r
+        break;\r
+\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
+          return Status;\r
+        }\r
+      }\r
+\r
+      //\r
+      // Next relocation record\r
+      //\r
+      Reloc += 1;\r
+    }\r
+\r
+    //\r
+    // Next reloc block\r
+    //\r
+    RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r
+  }\r
+\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+  Loads a PE/COFF image into memory.\r
+\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
+EFIAPI\r
+PeCoffLoaderLoadImage (\r
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext\r
+  )\r
+{\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
+  UINTN                                 Index;\r
+  CHAR8                                 *Base;\r
+  CHAR8                                 *End;\r
+  CHAR8                                 *MaxEnd;\r
+  EFI_IMAGE_DATA_DIRECTORY              *DirectoryEntry;\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
+  //\r
+  // Assume success\r
+  //\r
+  ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
+\r
+  //\r
+  // Copy the provided context info into our local version, get what we\r
+  // can from the original image, and then use that to make sure everything\r
+  // is legit.\r
+  //\r
+  CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));\r
+\r
+  Status = PeCoffLoaderGetImageInfo (&CheckContext);\r
+  if (RETURN_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Make sure there is enough allocated space for the image being loaded\r
+  //\r
+  if (ImageContext->ImageSize < CheckContext.ImageSize) {\r
+    ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;\r
+    return RETURN_BUFFER_TOO_SMALL;\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
+  //\r
+  if (CheckContext.RelocationsStripped) {\r
+    //\r
+    // If the image does not contain relocations and it is a runtime driver\r
+    // then return an error.\r
+    //\r
+    if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {\r
+      ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;\r
+      return RETURN_LOAD_ERROR;\r
+    }\r
+    //\r
+    // If the image does not contain relocations, and the requested load address\r
+    // is not the linked address, then return an error.\r
+    //\r
+    if (CheckContext.ImageAddress != ImageContext->ImageAddress) {\r
+      ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
+      return RETURN_INVALID_PARAMETER;\r
+    }\r
+  }\r
+  //\r
+  // Make sure the allocated space has the proper section alignment\r
+  //\r
+  if (!(ImageContext->IsTeImage)) {\r
+    if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {\r
+      ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;\r
+      return RETURN_INVALID_PARAMETER;\r
+    }\r
+  }\r
+  //\r
+  // Read the entire PE/COFF or TE header into memory\r
+  //\r
+  if (!(ImageContext->IsTeImage)) {\r
+    Status = ImageContext->ImageRead (\r
+                            ImageContext->Handle,\r
+                            0,\r
+                            &ImageContext->SizeOfHeaders,\r
+                            (VOID *) (UINTN) ImageContext->ImageAddress\r
+                            );\r
+\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
+                      Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
+      );\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
+                            );\r
+\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) (Hdr.Te->NumberOfSections);\r
+\r
+  }\r
+\r
+  if (RETURN_ERROR (Status)) {\r
+    ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+    return RETURN_LOAD_ERROR;\r
+  }\r
+\r
+  //\r
+  // Load each section of the image\r
+  //\r
+  Section = FirstSection;\r
+  for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {\r
+\r
+    //\r
+    // Compute sections address\r
+    //\r
+    Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);\r
+    End = PeCoffLoaderImageAddress (\r
+            ImageContext,\r
+            Section->VirtualAddress + Section->Misc.VirtualSize - 1\r
+            );\r
+    if (ImageContext->IsTeImage) {\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
+      MaxEnd = End;\r
+    }\r
+    //\r
+    // If the base start or end address resolved to 0, then fail.\r
+    //\r
+    if ((Base == NULL) || (End == NULL)) {\r
+      ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;\r
+      return RETURN_LOAD_ERROR;\r
+    }\r
+\r
+    //\r
+    // Read the section\r
+    //\r
+    Size = (UINTN) Section->Misc.VirtualSize;\r
+    if ((Size == 0) || (Size > Section->SizeOfRawData)) {\r
+      Size = (UINTN) Section->SizeOfRawData;\r
+    }\r
+\r
+    if (Section->SizeOfRawData) {\r
+      if (!(ImageContext->IsTeImage)) {\r
+        Status = ImageContext->ImageRead (\r
+                                ImageContext->Handle,\r
+                                Section->PointerToRawData,\r
+                                &Size,\r
+                                Base\r
+                                );\r
+      } else {\r
+        Status = ImageContext->ImageRead (\r
+                                ImageContext->Handle,\r
+                                Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize,\r
+                                &Size,\r
+                                Base\r
+                                );\r
+      }\r
+\r
+      if (RETURN_ERROR (Status)) {\r
+        ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+        return Status;\r
+      }\r
+    }\r
+\r
+    //\r
+    // If raw size is less then virt size, zero fill the remaining\r
+    //\r
+\r
+    if (Size < Section->Misc.VirtualSize) {\r
+      ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);\r
+    }\r
+\r
+    //\r
+    // Next Section\r
+    //\r
+    Section += 1;\r
+  }\r
+\r
+  //\r
+  // Get image's entry point\r
+  //\r
+  Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);\r
+  if (!(ImageContext->IsTeImage)) {\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)Hdr.Te->AddressOfEntryPoint +\r
+                                (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r
+                                (UINTN)Hdr.Te->StrippedSize\r
+                                );\r
+  }\r
+\r
+  //\r
+  // Determine the size of the fixup data\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 (!(ImageContext->IsTeImage)) {\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              = &Hdr.Te->DataDirectory[0];\r
+    ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
+  }\r
+  //\r
+  // Consumer must allocate a buffer for the relocation fixup log.\r
+  // Only used for runtime drivers.\r
+  //\r
+  ImageContext->FixupData = NULL;\r
+\r
+  //\r
+  // Load the Codeview info if present\r
+  //\r
+  if (ImageContext->DebugDirectoryEntryRva != 0) {\r
+    if (!(ImageContext->IsTeImage)) {\r
+      DebugEntry = PeCoffLoaderImageAddress (\r
+                    ImageContext,\r
+                    ImageContext->DebugDirectoryEntryRva\r
+                    );\r
+    } else {\r
+      DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(\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
+          TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;\r
+        } else {\r
+          TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;\r
+        }\r
+      }\r
+\r
+      if (TempDebugEntryRva != 0) {\r
+        if (!(ImageContext->IsTeImage)) {\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) Hdr.Te->StrippedSize\r
+                                    );\r
+        }\r
+\r
+        if (ImageContext->CodeView == NULL) {\r
+          ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+          return RETURN_LOAD_ERROR;\r
+        }\r
+\r
+        if (DebugEntry->RVA == 0) {\r
+          Size = DebugEntry->SizeOfData;\r
+          if (!(ImageContext->IsTeImage)) {\r
+            Status = ImageContext->ImageRead (\r
+                                    ImageContext->Handle,\r
+                                    DebugEntry->FileOffset,\r
+                                    &Size,\r
+                                    ImageContext->CodeView\r
+                                    );\r
+          } else {\r
+            Status = ImageContext->ImageRead (\r
+                                    ImageContext->Handle,\r
+                                    DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize,\r
+                                    &Size,\r
+                                    ImageContext->CodeView\r
+                                    );\r
+            //\r
+            // Should we apply fix up to this field according to the size difference between PE and TE?\r
+            // Because now we maintain TE header fields unfixed, this field will also remain as they are\r
+            // in original PE image.\r
+            //\r
+          }\r
+\r
+          if (RETURN_ERROR (Status)) {\r
+            ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+            return RETURN_LOAD_ERROR;\r
+          }\r
+\r
+          DebugEntry->RVA = TempDebugEntryRva;\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
+          break;\r
+\r
+        case CODEVIEW_SIGNATURE_RSDS:\r
+          ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
+          break;\r
+\r
+        default:\r
+          break;\r
+        }\r
+      }\r
+    }\r
+  }\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