]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdePkg/Library/BasePeCoffLib/BasePeCoff.c
MdePkg: Apply uncrustify changes
[mirror_edk2.git] / MdePkg / Library / BasePeCoffLib / BasePeCoff.c
index c7f33546372863ad1a693de17b516cebd5a014f7..6d8d9faeb86a7be50cdbc74f7bce0f361cc04393 100644 (file)
 /** @file\r
-  Tiano PE/COFF loader.\r
+  Base PE/COFF loader supports loading any PE32/PE32+ or TE image, but\r
+  only supports relocating IA32, x64, IPF, ARM, RISC-V 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
+  Caution: This file requires additional review when modified.\r
+  This library will have external input - PE/COFF image.\r
+  This external input must be validated carefully to avoid security issue like\r
+  buffer overflow, integer overflow.\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
+  The basic guideline is that caller need provide ImageContext->ImageRead () with the\r
+  necessary data range check, to make sure when this library reads PE/COFF image, the\r
+  PE image buffer is always in valid range.\r
+  This library will also do some additional check for PE header fields.\r
 \r
-  Module Name:  PeCoffLoader.c\r
+  PeCoffLoaderGetPeHeader() routine will do basic check for PE/COFF header.\r
+  PeCoffLoaderGetImageInfo() routine will do basic check for whole PE/COFF image.\r
 \r
-**/\r
-\r
-\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
-  );\r
+  Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
+  Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
+  Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\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
-STATIC\r
-VOID                            *\r
-PeCoffLoaderImageAddress (\r
-  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext,\r
-  IN     UINTN                         Address\r
-  );\r
+#include "BasePeCoffLibInternals.h"\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
+/**\r
+  Adjust some fields in section header for TE image.\r
 \r
+  @param  SectionHeader             Pointer to the section header.\r
+  @param  TeStrippedOffset          Size adjust for the TE image.\r
 \r
+**/\r
+VOID\r
+PeCoffLoaderAdjustOffsetForTeImage (\r
+  EFI_IMAGE_SECTION_HEADER  *SectionHeader,\r
+  UINT32                    TeStrippedOffset\r
+  )\r
+{\r
+  SectionHeader->VirtualAddress   -= TeStrippedOffset;\r
+  SectionHeader->PointerToRawData -= TeStrippedOffset;\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
+  Caution: This function may receive untrusted input.\r
+  PE/COFF image is external input, so this routine will\r
+  also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,\r
+  SizeOfHeader, Section Data Region and Security Data Region be in PE image range.\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
-  @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
-  EFI_IMAGE_DOS_HEADER  DosHdr;\r
-  UINTN                 Size;\r
+  RETURN_STATUS             Status;\r
+  EFI_IMAGE_DOS_HEADER      DosHdr;\r
+  UINTN                     Size;\r
+  UINTN                     ReadSize;\r
+  UINT32                    SectionHeaderOffset;\r
+  UINT32                    Index;\r
+  UINT32                    HeaderWithoutDataDir;\r
+  CHAR8                     BufferData;\r
+  UINTN                     NumberOfSections;\r
+  EFI_IMAGE_SECTION_HEADER  SectionHeader;\r
 \r
-  ImageContext->IsTeImage = FALSE;\r
   //\r
-  // Read the DOS image headers\r
+  // Read the DOS image header to check for its existence\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
+  Size     = sizeof (EFI_IMAGE_DOS_HEADER);\r
+  ReadSize = Size;\r
+  Status   = ImageContext->ImageRead (\r
+                             ImageContext->Handle,\r
+                             0,\r
+                             &Size,\r
+                             &DosHdr\r
+                             );\r
+  if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
     ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+    if (Size != ReadSize) {\r
+      Status = RETURN_UNSUPPORTED;\r
+    }\r
+\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 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 anything. Hdr.Pe32->OptionalHeader.Magic\r
+  // determines 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
-  Status = ImageContext->ImageRead (\r
-                          ImageContext->Handle,\r
-                          ImageContext->PeCoffHeaderOffset,\r
-                          &Size,\r
-                          PeHdr\r
-                          );\r
-  if (RETURN_ERROR (Status)) {\r
+  Size     = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);\r
+  ReadSize = Size;\r
+  Status   = ImageContext->ImageRead (\r
+                             ImageContext->Handle,\r
+                             ImageContext->PeCoffHeaderOffset,\r
+                             &Size,\r
+                             Hdr.Pe32\r
+                             );\r
+  if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
     ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+    if (Size != ReadSize) {\r
+      Status = RETURN_UNSUPPORTED;\r
+    }\r
+\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
+  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
+    //\r
+    // For TeImage, SectionAlignment is undefined to be set to Zero\r
+    // ImageSize can be calculated.\r
+    //\r
+    ImageContext->ImageSize        = 0;\r
+    ImageContext->SectionAlignment = 0;\r
+    ImageContext->SizeOfHeaders    = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;\r
+\r
+    //\r
+    // Check the StrippedSize.\r
+    //\r
+    if (sizeof (EFI_TE_IMAGE_HEADER) >= (UINT32)Hdr.Te->StrippedSize) {\r
+      ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
       return RETURN_UNSUPPORTED;\r
     }\r
 \r
-    ImageContext->IsTeImage = TRUE;\r
-  }\r
+    //\r
+    // Check the SizeOfHeaders field.\r
+    //\r
+    if (Hdr.Te->BaseOfCode <= Hdr.Te->StrippedSize) {\r
+      ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
 \r
-  return RETURN_SUCCESS;\r
-}\r
+    //\r
+    // Read last byte of Hdr.Te->SizeOfHeaders from the file.\r
+    //\r
+    Size     = 1;\r
+    ReadSize = Size;\r
+    Status   = ImageContext->ImageRead (\r
+                               ImageContext->Handle,\r
+                               ImageContext->SizeOfHeaders - 1,\r
+                               &Size,\r
+                               &BufferData\r
+                               );\r
+    if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
+      ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+      if (Size != ReadSize) {\r
+        Status = RETURN_UNSUPPORTED;\r
+      }\r
 \r
-/**\r
-  Checks the PE or TE header of a PE/COFF or TE image to determine if it supported.\r
+      return Status;\r
+    }\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
+    //\r
+    // TE Image Data Directory Entry size is non-zero, but the Data Directory Virtual Address is zero.\r
+    // This case is not a valid TE image.\r
+    //\r
+    if (((Hdr.Te->DataDirectory[0].Size != 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) ||\r
+        ((Hdr.Te->DataDirectory[1].Size != 0) && (Hdr.Te->DataDirectory[1].VirtualAddress == 0)))\r
+    {\r
+      ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+  } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
+    ImageContext->IsTeImage = FALSE;\r
+    ImageContext->Machine   = Hdr.Pe32->FileHeader.Machine;\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 (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+      //\r
+      // 1. Check OptionalHeader.NumberOfRvaAndSizes filed.\r
+      //\r
+      if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {\r
+        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+        return RETURN_UNSUPPORTED;\r
+      }\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
+      //\r
+      // 2. Check the FileHeader.SizeOfOptionalHeader field.\r
+      // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so\r
+      // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.\r
+      //\r
+      HeaderWithoutDataDir = sizeof (EFI_IMAGE_OPTIONAL_HEADER32) - sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;\r
+      if (((UINT32)Hdr.Pe32->FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) !=\r
+          Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY))\r
+      {\r
+        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32->FileHeader.SizeOfOptionalHeader;\r
+      //\r
+      // 3. Check the FileHeader.NumberOfSections field.\r
+      //\r
+      if (Hdr.Pe32->OptionalHeader.SizeOfImage <= SectionHeaderOffset) {\r
+        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      if ((Hdr.Pe32->OptionalHeader.SizeOfImage - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER <= Hdr.Pe32->FileHeader.NumberOfSections) {\r
+        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      //\r
+      // 4. Check the OptionalHeader.SizeOfHeaders field.\r
+      //\r
+      if (Hdr.Pe32->OptionalHeader.SizeOfHeaders <= SectionHeaderOffset) {\r
+        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      if (Hdr.Pe32->OptionalHeader.SizeOfHeaders >= Hdr.Pe32->OptionalHeader.SizeOfImage) {\r
+        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      if ((Hdr.Pe32->OptionalHeader.SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER < (UINT32)Hdr.Pe32->FileHeader.NumberOfSections) {\r
+        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      //\r
+      // 4.2 Read last byte of Hdr.Pe32.OptionalHeader.SizeOfHeaders from the file.\r
+      //\r
+      Size     = 1;\r
+      ReadSize = Size;\r
+      Status   = ImageContext->ImageRead (\r
+                                 ImageContext->Handle,\r
+                                 Hdr.Pe32->OptionalHeader.SizeOfHeaders - 1,\r
+                                 &Size,\r
+                                 &BufferData\r
+                                 );\r
+      if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
+        ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+        if (Size != ReadSize) {\r
+          Status = RETURN_UNSUPPORTED;\r
+        }\r
+\r
+        return Status;\r
+      }\r
+\r
+      //\r
+      // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.\r
+      // Read the last byte to make sure the data is in the image region.\r
+      // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.\r
+      //\r
+      if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {\r
+        if (Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size != 0) {\r
+          //\r
+          // Check the member data to avoid overflow.\r
+          //\r
+          if ((UINT32)(~0) - Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress <\r
+              Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size)\r
+          {\r
+            ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+            return RETURN_UNSUPPORTED;\r
+          }\r
+\r
+          //\r
+          // Read last byte of section header from file\r
+          //\r
+          Size     = 1;\r
+          ReadSize = Size;\r
+          Status   = ImageContext->ImageRead (\r
+                                     ImageContext->Handle,\r
+                                     Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +\r
+                                     Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - 1,\r
+                                     &Size,\r
+                                     &BufferData\r
+                                     );\r
+          if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
+            ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+            if (Size != ReadSize) {\r
+              Status = RETURN_UNSUPPORTED;\r
+            }\r
+\r
+            return Status;\r
+          }\r
+        }\r
+      }\r
+\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
+    } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
+      //\r
+      // 1. Check FileHeader.NumberOfRvaAndSizes filed.\r
+      //\r
+      if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {\r
+        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      //\r
+      // 2. Check the FileHeader.SizeOfOptionalHeader field.\r
+      // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so\r
+      // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.\r
+      //\r
+      HeaderWithoutDataDir = sizeof (EFI_IMAGE_OPTIONAL_HEADER64) - sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;\r
+      if (((UINT32)Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) !=\r
+          Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY))\r
+      {\r
+        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader;\r
+      //\r
+      // 3. Check the FileHeader.NumberOfSections field.\r
+      //\r
+      if (Hdr.Pe32Plus->OptionalHeader.SizeOfImage <= SectionHeaderOffset) {\r
+        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      if ((Hdr.Pe32Plus->OptionalHeader.SizeOfImage - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER <= Hdr.Pe32Plus->FileHeader.NumberOfSections) {\r
+        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      //\r
+      // 4. Check the OptionalHeader.SizeOfHeaders field.\r
+      //\r
+      if (Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders <= SectionHeaderOffset) {\r
+        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      if (Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders >= Hdr.Pe32Plus->OptionalHeader.SizeOfImage) {\r
+        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      if ((Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER < (UINT32)Hdr.Pe32Plus->FileHeader.NumberOfSections) {\r
+        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      //\r
+      // 4.2 Read last byte of Hdr.Pe32Plus.OptionalHeader.SizeOfHeaders from the file.\r
+      //\r
+      Size     = 1;\r
+      ReadSize = Size;\r
+      Status   = ImageContext->ImageRead (\r
+                                 ImageContext->Handle,\r
+                                 Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - 1,\r
+                                 &Size,\r
+                                 &BufferData\r
+                                 );\r
+      if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
+        ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+        if (Size != ReadSize) {\r
+          Status = RETURN_UNSUPPORTED;\r
+        }\r
+\r
+        return Status;\r
+      }\r
+\r
+      //\r
+      // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.\r
+      // Read the last byte to make sure the data is in the image region.\r
+      // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.\r
+      //\r
+      if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {\r
+        if (Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size != 0) {\r
+          //\r
+          // Check the member data to avoid overflow.\r
+          //\r
+          if ((UINT32)(~0) - Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress <\r
+              Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size)\r
+          {\r
+            ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+            return RETURN_UNSUPPORTED;\r
+          }\r
+\r
+          //\r
+          // Read last byte of section header from file\r
+          //\r
+          Size     = 1;\r
+          ReadSize = Size;\r
+          Status   = ImageContext->ImageRead (\r
+                                     ImageContext->Handle,\r
+                                     Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +\r
+                                     Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - 1,\r
+                                     &Size,\r
+                                     &BufferData\r
+                                     );\r
+          if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
+            ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+            if (Size != ReadSize) {\r
+              Status = RETURN_UNSUPPORTED;\r
+            }\r
+\r
+            return Status;\r
+          }\r
+        }\r
+      }\r
+\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
+    ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;\r
+    return RETURN_UNSUPPORTED;\r
   }\r
 \r
-  if (!(EFI_IMAGE_MACHINE_TYPE_SUPPORTED (ImageContext->Machine))) {\r
-    ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;\r
+  if (!PeCoffLoaderImageFormatSupported (ImageContext->Machine)) {\r
+    //\r
+    // If the PE/COFF loader does not support the image type return\r
+    // unsupported. This library can support 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
-  // See if the image type is supported.  We support EFI Applications,\r
-  // EFI Boot Service Drivers, and EFI Runtime Drivers.\r
+  // Check each section field.\r
   //\r
-  if (ImageContext->IsTeImage == FALSE) {\r
-    ImageContext->ImageType = PeHdr->OptionalHeader.Subsystem;\r
+  if (ImageContext->IsTeImage) {\r
+    SectionHeaderOffset = sizeof (EFI_TE_IMAGE_HEADER);\r
+    NumberOfSections    = (UINTN)(Hdr.Te->NumberOfSections);\r
   } else {\r
-    ImageContext->ImageType = (UINT16) (TeHdr->Subsystem);\r
+    SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32->FileHeader.SizeOfOptionalHeader;\r
+    NumberOfSections    = (UINTN)(Hdr.Pe32->FileHeader.NumberOfSections);\r
   }\r
 \r
+  for (Index = 0; Index < NumberOfSections; Index++) {\r
+    //\r
+    // Read section header from file\r
+    //\r
+    Size     = sizeof (EFI_IMAGE_SECTION_HEADER);\r
+    ReadSize = Size;\r
+    Status   = ImageContext->ImageRead (\r
+                               ImageContext->Handle,\r
+                               SectionHeaderOffset,\r
+                               &Size,\r
+                               &SectionHeader\r
+                               );\r
+    if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
+      ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+      if (Size != ReadSize) {\r
+        Status = RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Adjust some field in Section Header for TE image.\r
+    //\r
+    if (ImageContext->IsTeImage) {\r
+      PeCoffLoaderAdjustOffsetForTeImage (&SectionHeader, (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));\r
+    }\r
+\r
+    if (SectionHeader.SizeOfRawData > 0) {\r
+      //\r
+      // Section data should bigger than the Pe header.\r
+      //\r
+      if ((SectionHeader.VirtualAddress < ImageContext->SizeOfHeaders) ||\r
+          (SectionHeader.PointerToRawData < ImageContext->SizeOfHeaders))\r
+      {\r
+        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      //\r
+      // Check the member data to avoid overflow.\r
+      //\r
+      if ((UINT32)(~0) - SectionHeader.PointerToRawData < SectionHeader.SizeOfRawData) {\r
+        ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+        return RETURN_UNSUPPORTED;\r
+      }\r
+\r
+      //\r
+      // Base on the ImageRead function to check the section data field.\r
+      // Read the last byte to make sure the data is in the image region.\r
+      //\r
+      Size     = 1;\r
+      ReadSize = Size;\r
+      Status   = ImageContext->ImageRead (\r
+                                 ImageContext->Handle,\r
+                                 SectionHeader.PointerToRawData + SectionHeader.SizeOfRawData - 1,\r
+                                 &Size,\r
+                                 &BufferData\r
+                                 );\r
+      if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
+        ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+        if (Size != ReadSize) {\r
+          Status = RETURN_UNSUPPORTED;\r
+        }\r
+\r
+        return Status;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Check next section.\r
+    //\r
+    SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
+  }\r
 \r
   return RETURN_SUCCESS;\r
 }\r
 \r
 /**\r
-  Retrieves information on a PE/COFF image.\r
-\r
-  @param  This Calling context\r
-  @param  ImageContext The context of the image being loaded\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
+  Retrieves information about a PE/COFF image.\r
+\r
+  Computes the PeCoffHeaderOffset, IsTeImage, ImageType, ImageAddress, ImageSize,\r
+  DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and\r
+  DebugDirectoryEntryRva fields of the ImageContext structure.\r
+  If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.\r
+  If the PE/COFF image accessed through the ImageRead service in the ImageContext\r
+  structure is not a supported PE/COFF image type, then return RETURN_UNSUPPORTED.\r
+  If any errors occur while computing the fields of ImageContext,\r
+  then the error status is returned in the ImageError field of ImageContext.\r
+  If the image is a TE image, then SectionAlignment is set to 0.\r
+  The ImageRead and Handle fields of ImageContext structure must be valid prior\r
+  to invoking this service.\r
+\r
+  Caution: This function may receive untrusted input.\r
+  PE/COFF image is external input, so this routine will\r
+  also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,\r
+  SizeOfHeader, Section Data Region and Security Data Region be in PE image range.\r
+\r
+  @param  ImageContext              The 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
+  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
-\r
-  if (NULL == ImageContext) {\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                                ReadSize;\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
+  UINT32                               TeStrippedOffset;\r
+\r
+  if (ImageContext == NULL) {\r
     return RETURN_INVALID_PARAMETER;\r
   }\r
+\r
   //\r
   // Assume success\r
   //\r
-  ImageContext->ImageError  = IMAGE_ERROR_SUCCESS;\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
   //\r
   // Retrieve the base address of the image\r
   //\r
   if (!(ImageContext->IsTeImage)) {\r
-    ImageContext->ImageAddress = PeHdr.OptionalHeader.ImageBase;\r
+    TeStrippedOffset = 0;\r
+    if (Hdr.Pe32->OptionalHeader.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
+    TeStrippedOffset           = (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);\r
+    ImageContext->ImageAddress = (PHYSICAL_ADDRESS)(Hdr.Te->ImageBase + TeStrippedOffset);\r
   }\r
+\r
   //\r
   // Initialize the alternate destination address to 0 indicating that it\r
   // should not be used.\r
@@ -249,10 +632,11 @@ PeCoffLoaderGetImageInfo (
   ImageContext->DestinationAddress = 0;\r
 \r
   //\r
-  // Initialize the codeview pointer.\r
+  // Initialize the debug codeview pointer.\r
   //\r
-  ImageContext->CodeView    = NULL;\r
-  ImageContext->PdbPointer  = NULL;\r
+  ImageContext->DebugDirectoryEntryRva = 0;\r
+  ImageContext->CodeView               = NULL;\r
+  ImageContext->PdbPointer             = NULL;\r
 \r
   //\r
   // Three cases with regards to relocations:\r
@@ -263,26 +647,32 @@ PeCoffLoaderGetImageInfo (
   // 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
+  // save this information 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 if ((ImageContext->IsTeImage) && (Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 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
-\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 (Hdr.Pe32->OptionalHeader.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
       DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
 \r
       //\r
@@ -292,33 +682,36 @@ PeCoffLoaderGetImageInfo (
       //\r
       DebugDirectoryEntryFileOffset = 0;\r
 \r
-      SectionHeaderOffset = (UINTN)(\r
-                               ImageContext->PeCoffHeaderOffset +\r
-                               sizeof (UINT32) + \r
-                               sizeof (EFI_IMAGE_FILE_HEADER) + \r
-                               PeHdr.FileHeader.SizeOfOptionalHeader\r
-                               );\r
+      SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +\r
+                            sizeof (UINT32) +\r
+                            sizeof (EFI_IMAGE_FILE_HEADER) +\r
+                            Hdr.Pe32->FileHeader.SizeOfOptionalHeader;\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
-        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
+        Size     = sizeof (EFI_IMAGE_SECTION_HEADER);\r
+        ReadSize = Size;\r
+        Status   = ImageContext->ImageRead (\r
+                                   ImageContext->Handle,\r
+                                   SectionHeaderOffset,\r
+                                   &Size,\r
+                                   &SectionHeader\r
+                                   );\r
+        if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
           ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+          if (Size != ReadSize) {\r
+            Status = RETURN_UNSUPPORTED;\r
+          }\r
+\r
           return Status;\r
         }\r
 \r
-        if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
-            DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
-            DebugDirectoryEntryFileOffset =\r
-            DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;\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
@@ -326,25 +719,35 @@ PeCoffLoaderGetImageInfo (
       }\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
-          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
+          Size     = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
+          ReadSize = Size;\r
+          Status   = ImageContext->ImageRead (\r
+                                     ImageContext->Handle,\r
+                                     DebugDirectoryEntryFileOffset + Index,\r
+                                     &Size,\r
+                                     &DebugEntry\r
+                                     );\r
+          if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
             ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+            if (Size != ReadSize) {\r
+              Status = RETURN_UNSUPPORTED;\r
+            }\r
+\r
             return Status;\r
           }\r
 \r
+          //\r
+          // From PeCoff spec, when DebugEntry.RVA == 0 means this debug info will not load into memory.\r
+          // Here we will always load EFI_IMAGE_DEBUG_TYPE_CODEVIEW type debug info. so need adjust the\r
+          // ImageContext->ImageSize when DebugEntry.RVA == 0.\r
+          //\r
           if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
-            ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));\r
-            if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {\r
+            ImageContext->DebugDirectoryEntryRva = (UINT32)(DebugDirectoryEntryRva + Index);\r
+            if ((DebugEntry.RVA == 0) && (DebugEntry.FileOffset != 0)) {\r
               ImageContext->ImageSize += DebugEntry.SizeOfData;\r
             }\r
 \r
@@ -354,88 +757,93 @@ PeCoffLoaderGetImageInfo (
       }\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
+    DebugDirectoryEntry    = &Hdr.Te->DataDirectory[1];\r
+    DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
+    SectionHeaderOffset    = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));\r
 \r
-    DebugDirectoryEntry             = &TeHdr.DataDirectory[1];\r
-    DebugDirectoryEntryRva          = DebugDirectoryEntry->VirtualAddress;\r
-    SectionHeaderOffset             = (UINTN) (sizeof (EFI_TE_IMAGE_HEADER));\r
+    DebugDirectoryEntryFileOffset = 0;\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
-      Status = ImageContext->ImageRead (\r
-                               ImageContext->Handle,\r
-                               SectionHeaderOffset,\r
-                               &Size,\r
-                               &SectionHeader\r
-                               );\r
-      if (RETURN_ERROR (Status)) {\r
+      Size     = sizeof (EFI_IMAGE_SECTION_HEADER);\r
+      ReadSize = Size;\r
+      Status   = ImageContext->ImageRead (\r
+                                 ImageContext->Handle,\r
+                                 SectionHeaderOffset,\r
+                                 &Size,\r
+                                 &SectionHeader\r
+                                 );\r
+      if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
         ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+        if (Size != ReadSize) {\r
+          Status = RETURN_UNSUPPORTED;\r
+        }\r
+\r
         return Status;\r
       }\r
 \r
-      if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
-          DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
+      if ((DebugDirectoryEntryRva >= SectionHeader.VirtualAddress) &&\r
+          (DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize))\r
+      {\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
+                                        TeStrippedOffset;\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
-      // a mulitple of Section Alignment). Per the PE/COFF specification, the\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 multiple 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
-        ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize +\r
-                                   ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1);\r
+      if ((++Index) == (UINTN)Hdr.Te->NumberOfSections) {\r
+        ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) - TeStrippedOffset;\r
       }\r
 \r
       SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\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
-        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
+        Size     = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
+        ReadSize = Size;\r
+        Status   = ImageContext->ImageRead (\r
+                                   ImageContext->Handle,\r
+                                   DebugDirectoryEntryFileOffset + Index,\r
+                                   &Size,\r
+                                   &DebugEntry\r
+                                   );\r
+        if (RETURN_ERROR (Status) || (Size != ReadSize)) {\r
           ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
+          if (Size != ReadSize) {\r
+            Status = RETURN_UNSUPPORTED;\r
+          }\r
+\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
           return RETURN_SUCCESS;\r
         }\r
       }\r
@@ -448,38 +856,59 @@ PeCoffLoaderGetImageInfo (
 /**\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
+  @param  TeStrippedOffset  Stripped offset for TE image.\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
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext,\r
+  IN     UINTN                         Address,\r
+  IN     UINTN                         TeStrippedOffset\r
   )\r
 {\r
-  if (Address >= ImageContext->ImageSize) {\r
+  //\r
+  // Make sure that Address and ImageSize is correct for the loaded image.\r
+  //\r
+  if (Address >= ImageContext->ImageSize + TeStrippedOffset) {\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 - TeStrippedOffset);\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
+\r
+  The ImageRead, Handle, PeCoffHeaderOffset,  IsTeImage, Machine, ImageType, ImageAddress,\r
+  ImageSize, DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders,\r
+  DebugDirectoryEntryRva, EntryPoint, FixupDataSize, CodeView, PdbPointer, and FixupData of\r
+  the ImageContext structure must be valid prior to invoking this service.\r
 \r
-  @param  This Calling context.\r
-  \r
-  @param  ImageContext Contains information on the loaded image to relocate.\r
+  If ImageContext is NULL, then ASSERT().\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
+  Note that if the platform does not maintain coherency between the instruction cache(s) and the data\r
+  cache(s) in hardware, then the caller is responsible for performing cache maintenance operations\r
+  prior to transferring control to a PE/COFF image that is loaded using this library.\r
+\r
+  @param  ImageContext        The 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
@@ -488,24 +917,27 @@ PeCoffLoaderRelocateImage (
   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            *RelocBaseOrg;\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                               *Fixup16;\r
+  UINT32                               *Fixup32;\r
+  UINT64                               *Fixup64;\r
+  CHAR8                                *FixupData;\r
+  PHYSICAL_ADDRESS                     BaseAddress;\r
+  UINT32                               NumberOfRvaAndSizes;\r
+  UINT32                               TeStrippedOffset;\r
+\r
+  ASSERT (ImageContext != NULL);\r
+\r
   //\r
   // Assume success\r
   //\r
@@ -515,6 +947,9 @@ PeCoffLoaderRelocateImage (
   // If there are no relocation entries, then we are done\r
   //\r
   if (ImageContext->RelocationsStripped) {\r
+    // Applies additional environment specific actions to relocate fixups\r
+    // to a PE/COFF image if needed\r
+    PeCoffLoaderRelocateImageExtraAction (ImageContext);\r
     return RETURN_SUCCESS;\r
   }\r
 \r
@@ -522,162 +957,246 @@ PeCoffLoaderRelocateImage (
   // 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
     BaseAddress = ImageContext->ImageAddress;\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
+    TeStrippedOffset = 0;\r
+\r
+    if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+      //\r
+      // Use PE32 offset\r
+      //\r
+      Adjust = (UINT64)BaseAddress - Hdr.Pe32->OptionalHeader.ImageBase;\r
+      if (Adjust != 0) {\r
+        Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress;\r
+      }\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
+      if (Adjust != 0) {\r
+        Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress;\r
+      }\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
-      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
+    if ((NumberOfRvaAndSizes < EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC)) {\r
+      RelocDir = NULL;\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
+    TeStrippedOffset = (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);\r
+    Adjust           = (UINT64)(BaseAddress - (Hdr.Te->ImageBase + TeStrippedOffset));\r
+    if (Adjust != 0) {\r
+      Hdr.Te->ImageBase = (UINT64)(BaseAddress - TeStrippedOffset);\r
+    }\r
 \r
     //\r
     // Find the relocation block\r
     //\r
-    RelocDir = &TeHdr->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
-    RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);\r
+    RelocDir = &Hdr.Te->DataDirectory[0];\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
-                             TeHdr->StrippedSize\r
-                             );\r
-    }\r
 \r
-    if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||\r
-        (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + \r
-          (UINTN)ImageContext->ImageSize)) {\r
+  if ((RelocDir != NULL) && (RelocDir->Size > 0)) {\r
+    RelocBase    = (EFI_IMAGE_BASE_RELOCATION *)PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress, TeStrippedOffset);\r
+    RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *)PeCoffLoaderImageAddress (\r
+                                                  ImageContext,\r
+                                                  RelocDir->VirtualAddress + RelocDir->Size - 1,\r
+                                                  TeStrippedOffset\r
+                                                  );\r
+    if ((RelocBase == NULL) || (RelocBaseEnd == NULL) || ((UINTN)RelocBaseEnd < (UINTN)RelocBase)) {\r
       ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
       return RETURN_LOAD_ERROR;\r
     }\r
+  } else {\r
+    //\r
+    // Set base and end to bypass processing below.\r
+    //\r
+    RelocBase = RelocBaseEnd = NULL;\r
+  }\r
+\r
+  RelocBaseOrg = RelocBase;\r
+\r
+  //\r
+  // If Adjust is not zero, then apply fix ups to the image\r
+  //\r
+  if (Adjust != 0) {\r
+    //\r
+    // Run the relocation information and apply the fixups\r
+    //\r
+    FixupData = ImageContext->FixupData;\r
+    while ((UINTN)RelocBase < (UINTN)RelocBaseEnd) {\r
+      Reloc = (UINT16 *)((CHAR8 *)RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
+      //\r
+      // Add check for RelocBase->SizeOfBlock field.\r
+      //\r
+      if (RelocBase->SizeOfBlock == 0) {\r
+        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
+        return RETURN_LOAD_ERROR;\r
+      }\r
+\r
+      if ((UINTN)RelocBase > MAX_ADDRESS - RelocBase->SizeOfBlock) {\r
+        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
+        return RETURN_LOAD_ERROR;\r
+      }\r
+\r
+      RelocEnd = (UINT16 *)((CHAR8 *)RelocBase + RelocBase->SizeOfBlock);\r
+      if ((UINTN)RelocEnd > (UINTN)RelocBaseOrg + RelocDir->Size) {\r
+        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
+        return RETURN_LOAD_ERROR;\r
+      }\r
+\r
+      FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress, TeStrippedOffset);\r
+      if (FixupBase == NULL) {\r
+        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
+        return RETURN_LOAD_ERROR;\r
+      }\r
+\r
+      //\r
+      // Run this relocation record\r
+      //\r
+      while ((UINTN)Reloc < (UINTN)RelocEnd) {\r
+        Fixup = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress + (*Reloc & 0xFFF), TeStrippedOffset);\r
+        if (Fixup == NULL) {\r
+          ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
+          return RETURN_LOAD_ERROR;\r
+        }\r
+\r
+        switch ((*Reloc) >> 12) {\r
+          case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
+            break;\r
+\r
+          case EFI_IMAGE_REL_BASED_HIGH:\r
+            Fixup16  = (UINT16 *)Fixup;\r
+            *Fixup16 = (UINT16)(*Fixup16 + ((UINT16)((UINT32)Adjust >> 16)));\r
+            if (FixupData != NULL) {\r
+              *(UINT16 *)FixupData = *Fixup16;\r
+              FixupData            = FixupData + sizeof (UINT16);\r
+            }\r
+\r
+            break;\r
+\r
+          case EFI_IMAGE_REL_BASED_LOW:\r
+            Fixup16  = (UINT16 *)Fixup;\r
+            *Fixup16 = (UINT16)(*Fixup16 + (UINT16)Adjust);\r
+            if (FixupData != NULL) {\r
+              *(UINT16 *)FixupData = *Fixup16;\r
+              FixupData            = FixupData + sizeof (UINT16);\r
+            }\r
+\r
+            break;\r
+\r
+          case EFI_IMAGE_REL_BASED_HIGHLOW:\r
+            Fixup32  = (UINT32 *)Fixup;\r
+            *Fixup32 = *Fixup32 + (UINT32)Adjust;\r
+            if (FixupData != NULL) {\r
+              FixupData            = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
+              *(UINT32 *)FixupData = *Fixup32;\r
+              FixupData            = FixupData + sizeof (UINT32);\r
+            }\r
 \r
-    //\r
-    // Run this relocation record\r
-    //\r
-    while (Reloc < RelocEnd) {\r
+            break;\r
 \r
-      Fixup = FixupBase + (*Reloc & 0xFFF);\r
-      switch ((*Reloc) >> 12) {\r
-      case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
-        break;\r
+          case EFI_IMAGE_REL_BASED_DIR64:\r
+            Fixup64  = (UINT64 *)Fixup;\r
+            *Fixup64 = *Fixup64 + (UINT64)Adjust;\r
+            if (FixupData != NULL) {\r
+              FixupData              = ALIGN_POINTER (FixupData, sizeof (UINT64));\r
+              *(UINT64 *)(FixupData) = *Fixup64;\r
+              FixupData              = FixupData + sizeof (UINT64);\r
+            }\r
 \r
-      case EFI_IMAGE_REL_BASED_HIGH:\r
-        F16   = (UINT16 *) Fixup;\r
-        *F16  = (UINT16) ((*F16 << 16) + (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_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
+            break;\r
+\r
+          default:\r
+            //\r
+            // The common code does not handle some of the stranger IPF relocations\r
+            // PeCoffLoaderRelocateImageEx () adds support for these complex fixups\r
+            // on IPF and is a No-Op on other architectures.\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
-        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
+        // Next relocation record\r
         //\r
-        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
-        return RETURN_UNSUPPORTED;\r
-\r
-      default:\r
-        Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);\r
-        if (RETURN_ERROR (Status)) {\r
-          ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
-          return Status;\r
-        }\r
+        Reloc += 1;\r
       }\r
 \r
       //\r
-      // Next relocation record\r
+      // Next reloc block\r
       //\r
-      Reloc += 1;\r
+      RelocBase = (EFI_IMAGE_BASE_RELOCATION *)RelocEnd;\r
     }\r
 \r
+    ASSERT ((UINTN)FixupData <= (UINTN)ImageContext->FixupData + ImageContext->FixupDataSize);\r
+\r
     //\r
-    // Next reloc block\r
+    // Adjust the EntryPoint to match the linked-to address\r
     //\r
-    RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r
+    if (ImageContext->DestinationAddress != 0) {\r
+      ImageContext->EntryPoint -= (UINT64)ImageContext->ImageAddress;\r
+      ImageContext->EntryPoint += (UINT64)ImageContext->DestinationAddress;\r
+    }\r
   }\r
 \r
+  // Applies additional environment specific actions to relocate fixups\r
+  // to a PE/COFF image if needed\r
+  PeCoffLoaderRelocateImageExtraAction (ImageContext);\r
+\r
   return RETURN_SUCCESS;\r
 }\r
 \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, PdbPointer and HiiResourceData fields of ImageContext are computed.\r
+  The ImageRead, Handle, PeCoffHeaderOffset,  IsTeImage,  Machine, ImageType, ImageAddress, ImageSize,\r
+  DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva\r
+  fields of the ImageContext structure must be valid prior to invoking this service.\r
+\r
+  If ImageContext is NULL, then ASSERT().\r
+\r
+  Note that if the platform does not maintain coherency between the instruction cache(s) and the data\r
+  cache(s) in hardware, then the caller is responsible for performing cache maintenance operations\r
+  prior to transferring control to a PE/COFF image that is loaded using this library.\r
+\r
+  @param  ImageContext              The 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
@@ -686,31 +1205,37 @@ PeCoffLoaderLoadImage (
   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
-  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
-\r
-  PeHdr = NULL;\r
-  TeHdr = NULL;\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
+  EFI_IMAGE_DATA_DIRECTORY             *DirectoryEntry;\r
+  EFI_IMAGE_DEBUG_DIRECTORY_ENTRY      *DebugEntry;\r
+  UINTN                                Size;\r
+  UINT32                               TempDebugEntryRva;\r
+  UINT32                               NumberOfRvaAndSizes;\r
+  EFI_IMAGE_RESOURCE_DIRECTORY         *ResourceDirectory;\r
+  EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY   *ResourceDirectoryEntry;\r
+  EFI_IMAGE_RESOURCE_DIRECTORY_STRING  *ResourceDirectoryString;\r
+  EFI_IMAGE_RESOURCE_DATA_ENTRY        *ResourceDataEntry;\r
+  CHAR16                               *String;\r
+  UINT32                               Offset;\r
+  UINT32                               TeStrippedOffset;\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
+  // Copy the provided context information 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
@@ -729,6 +1254,14 @@ PeCoffLoaderLoadImage (
     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
   //\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
@@ -742,6 +1275,7 @@ PeCoffLoaderLoadImage (
       ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;\r
       return RETURN_LOAD_ERROR;\r
     }\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
@@ -751,6 +1285,7 @@ PeCoffLoaderLoadImage (
       return RETURN_INVALID_PARAMETER;\r
     }\r
   }\r
+\r
   //\r
   // Make sure the allocated space has the proper section alignment\r
   //\r
@@ -760,44 +1295,44 @@ PeCoffLoaderLoadImage (
       return RETURN_INVALID_PARAMETER;\r
     }\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
-    PeHdr = (EFI_IMAGE_NT_HEADERS *)\r
-      ((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
-      );\r
-    NumberOfSections = (UINTN) (PeHdr->FileHeader.NumberOfSections);\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
+    TeStrippedOffset = 0;\r
   } else {\r
     Status = ImageContext->ImageRead (\r
-                            ImageContext->Handle,\r
-                            0,\r
-                            &ImageContext->SizeOfHeaders,\r
-                            (void *) (UINTN) ImageContext->ImageAddress\r
-                            );\r
-\r
-    TeHdr             = (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
-\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
+    FirstSection = (EFI_IMAGE_SECTION_HEADER *)(\r
+                                                (UINTN)ImageContext->ImageAddress +\r
+                                                sizeof (EFI_TE_IMAGE_HEADER)\r
+                                                );\r
+    NumberOfSections = (UINTN)(Hdr.Te->NumberOfSections);\r
+    TeStrippedOffset = (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);\r
   }\r
 \r
   if (RETURN_ERROR (Status)) {\r
@@ -809,57 +1344,36 @@ PeCoffLoaderLoadImage (
   // Load each section of the image\r
   //\r
   Section = FirstSection;\r
-  for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {\r
-\r
+  for (Index = 0; Index < NumberOfSections; Index++) {\r
     //\r
-    // Compute sections address\r
+    // Read the section\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) TeHdr->StrippedSize);\r
-      End   = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);\r
+    Size = (UINTN)Section->Misc.VirtualSize;\r
+    if ((Size == 0) || (Size > Section->SizeOfRawData)) {\r
+      Size = (UINTN)Section->SizeOfRawData;\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
+    // Compute sections address\r
     //\r
-    if ((Base == NULL) || (End == NULL)) {\r
-      ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;\r
-      return RETURN_LOAD_ERROR;\r
-    }\r
+    Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress, TeStrippedOffset);\r
+    End  = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress + Section->Misc.VirtualSize - 1, TeStrippedOffset);\r
 \r
     //\r
-    // Read the section\r
+    // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.\r
     //\r
-    Size = (UINTN) Section->Misc.VirtualSize;\r
-    if ((Size == 0) || (Size > Section->SizeOfRawData)) {\r
-      Size = (UINTN) Section->SizeOfRawData;\r
+    if ((Size > 0) && ((Base == NULL) || (End == NULL))) {\r
+      ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;\r
+      return RETURN_LOAD_ERROR;\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) TeHdr->StrippedSize,\r
-                                &Size,\r
-                                Base\r
-                                );\r
-      }\r
-\r
+    if (Section->SizeOfRawData > 0) {\r
+      Status = ImageContext->ImageRead (\r
+                               ImageContext->Handle,\r
+                               Section->PointerToRawData - TeStrippedOffset,\r
+                               &Size,\r
+                               Base\r
+                               );\r
       if (RETURN_ERROR (Status)) {\r
         ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
         return Status;\r
@@ -867,7 +1381,7 @@ PeCoffLoaderLoadImage (
     }\r
 \r
     //\r
-    // If raw size is less then virt size, zero fill the remaining\r
+    // If raw size is less then virtual size, zero fill the remaining\r
     //\r
 \r
     if (Size < Section->Misc.VirtualSize) {\r
@@ -884,17 +1398,34 @@ PeCoffLoaderLoadImage (
   // Get image's entry point\r
   //\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 (Hdr.Pe32->OptionalHeader.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
+                                                            0\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
+                                                            0\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
+    ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (\r
+                                                          ImageContext,\r
+                                                          (UINTN)Hdr.Te->AddressOfEntryPoint,\r
+                                                          TeStrippedOffset\r
+                                                          );\r
   }\r
 \r
   //\r
@@ -905,17 +1436,33 @@ PeCoffLoaderLoadImage (
   // 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
-      ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
+    if (Hdr.Pe32->OptionalHeader.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
+    //\r
+    // Must use UINT64 here, because there might a case that 32bit loader to load 64bit image.\r
+    //\r
+    if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
+      ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINT64);\r
     } else {\r
       ImageContext->FixupDataSize = 0;\r
     }\r
   } else {\r
-    DirectoryEntry              = &TeHdr->DataDirectory[0];\r
-    ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
+    DirectoryEntry              = &Hdr.Te->DataDirectory[0];\r
+    ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINT64);\r
   }\r
+\r
   //\r
   // Consumer must allocate a buffer for the relocation fixup log.\r
   // Only used for runtime drivers.\r
@@ -923,93 +1470,202 @@ PeCoffLoaderLoadImage (
   ImageContext->FixupData = NULL;\r
 \r
   //\r
-  // Load the Codeview info if present\r
+  // Load the Codeview information 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
-                                                        TeHdr->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
+    DebugEntry = PeCoffLoaderImageAddress (\r
+                   ImageContext,\r
+                   ImageContext->DebugDirectoryEntryRva,\r
+                   TeStrippedOffset\r
+                   );\r
+    if (DebugEntry == NULL) {\r
+      ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
+      return RETURN_LOAD_ERROR;\r
+    }\r
+\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) TeHdr->StrippedSize\r
-            );\r
-        }\r
+    if (TempDebugEntryRva != 0) {\r
+      ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva, TeStrippedOffset);\r
+      if (ImageContext->CodeView == NULL) {\r
+        ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
+        return RETURN_LOAD_ERROR;\r
+      }\r
+\r
+      if (DebugEntry->RVA == 0) {\r
+        Size   = DebugEntry->SizeOfData;\r
+        Status = ImageContext->ImageRead (\r
+                                 ImageContext->Handle,\r
+                                 DebugEntry->FileOffset - TeStrippedOffset,\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
-        if (ImageContext->CodeView == NULL) {\r
+        if (RETURN_ERROR (Status)) {\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) - TeHdr->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
+        DebugEntry->RVA = TempDebugEntryRva;\r
+      }\r
 \r
-          if (RETURN_ERROR (Status)) {\r
-            ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
-            return RETURN_LOAD_ERROR;\r
+      switch (*(UINT32 *)ImageContext->CodeView) {\r
+        case CODEVIEW_SIGNATURE_NB10:\r
+          if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)) {\r
+            ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+            return RETURN_UNSUPPORTED;\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
+          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
+          if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY)) {\r
+            ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+            return RETURN_UNSUPPORTED;\r
+          }\r
+\r
+          ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
+          break;\r
+\r
+        case CODEVIEW_SIGNATURE_MTOC:\r
+          if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY)) {\r
+            ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+            return RETURN_UNSUPPORTED;\r
+          }\r
+\r
+          ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);\r
           break;\r
 \r
         default:\r
           break;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Get Image's HII resource section\r
+  //\r
+  ImageContext->HiiResourceData = 0;\r
+  if (!(ImageContext->IsTeImage)) {\r
+    if (Hdr.Pe32->OptionalHeader.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_RESOURCE];\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_RESOURCE];\r
+    }\r
+\r
+    if ((NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE) && (DirectoryEntry->Size != 0)) {\r
+      Base = PeCoffLoaderImageAddress (ImageContext, DirectoryEntry->VirtualAddress, 0);\r
+      if (Base != NULL) {\r
+        ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *)Base;\r
+        Offset            = sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) *\r
+                            (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);\r
+        if (Offset > DirectoryEntry->Size) {\r
+          ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+          return RETURN_UNSUPPORTED;\r
+        }\r
+\r
+        ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(ResourceDirectory + 1);\r
+\r
+        for (Index = 0; Index < ResourceDirectory->NumberOfNamedEntries; Index++) {\r
+          if (ResourceDirectoryEntry->u1.s.NameIsString) {\r
+            //\r
+            // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.\r
+            //\r
+            if (ResourceDirectoryEntry->u1.s.NameOffset >= DirectoryEntry->Size) {\r
+              ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+              return RETURN_UNSUPPORTED;\r
+            }\r
+\r
+            ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *)(Base + ResourceDirectoryEntry->u1.s.NameOffset);\r
+            String                  = &ResourceDirectoryString->String[0];\r
+\r
+            if ((ResourceDirectoryString->Length == 3) &&\r
+                (String[0] == L'H') &&\r
+                (String[1] == L'I') &&\r
+                (String[2] == L'I'))\r
+            {\r
+              //\r
+              // Resource Type "HII" found\r
+              //\r
+              if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {\r
+                //\r
+                // Move to next level - resource Name\r
+                //\r
+                if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {\r
+                  ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+                  return RETURN_UNSUPPORTED;\r
+                }\r
+\r
+                ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *)(Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);\r
+                Offset            = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +\r
+                                    sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);\r
+                if (Offset > DirectoryEntry->Size) {\r
+                  ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+                  return RETURN_UNSUPPORTED;\r
+                }\r
+\r
+                ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(ResourceDirectory + 1);\r
+\r
+                if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {\r
+                  //\r
+                  // Move to next level - resource Language\r
+                  //\r
+                  if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {\r
+                    ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+                    return RETURN_UNSUPPORTED;\r
+                  }\r
+\r
+                  ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *)(Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);\r
+                  Offset            = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +\r
+                                      sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);\r
+                  if (Offset > DirectoryEntry->Size) {\r
+                    ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+                    return RETURN_UNSUPPORTED;\r
+                  }\r
+\r
+                  ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *)(ResourceDirectory + 1);\r
+                }\r
+              }\r
+\r
+              //\r
+              // Now it ought to be resource Data\r
+              //\r
+              if (!ResourceDirectoryEntry->u2.s.DataIsDirectory) {\r
+                if (ResourceDirectoryEntry->u2.OffsetToData >= DirectoryEntry->Size) {\r
+                  ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;\r
+                  return RETURN_UNSUPPORTED;\r
+                }\r
+\r
+                ResourceDataEntry             = (EFI_IMAGE_RESOURCE_DATA_ENTRY *)(Base + ResourceDirectoryEntry->u2.OffsetToData);\r
+                ImageContext->HiiResourceData = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (ImageContext, ResourceDataEntry->OffsetToData, 0);\r
+                break;\r
+              }\r
+            }\r
+          }\r
+\r
+          ResourceDirectoryEntry++;\r
         }\r
       }\r
     }\r
@@ -1017,3 +1673,323 @@ PeCoffLoaderLoadImage (
 \r
   return Status;\r
 }\r
+\r
+/**\r
+  Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI\r
+  runtime.\r
+\r
+  This function reapplies relocation fixups to the PE/COFF image specified by ImageBase\r
+  and ImageSize so the image will execute correctly when the PE/COFF image is mapped\r
+  to the address specified by VirtualImageBase.  RelocationData must be identical\r
+  to the FiuxupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure\r
+  after this PE/COFF image was relocated with PeCoffLoaderRelocateImage().\r
+\r
+  Note that if the platform does not maintain coherency between the instruction cache(s) and the data\r
+  cache(s) in hardware, then the caller is responsible for performing cache maintenance operations\r
+  prior to transferring control to a PE/COFF image that is loaded using this library.\r
+\r
+  @param  ImageBase          The base address of a PE/COFF image that has been loaded\r
+                             and relocated into system memory.\r
+  @param  VirtImageBase      The request virtual address that the PE/COFF image is to\r
+                             be fixed up for.\r
+  @param  ImageSize          The size, in bytes, of the PE/COFF image.\r
+  @param  RelocationData     A pointer to the relocation data that was collected when the PE/COFF\r
+                             image was relocated using PeCoffLoaderRelocateImage().\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
+  EFI_IMAGE_BASE_RELOCATION            *RelocBaseOrig;\r
+  UINT16                               *Reloc;\r
+  UINT16                               *RelocEnd;\r
+  CHAR8                                *Fixup;\r
+  CHAR8                                *FixupBase;\r
+  UINT16                               *Fixup16;\r
+  UINT32                               *Fixup32;\r
+  UINT64                               *Fixup64;\r
+  CHAR8                                *FixupData;\r
+  UINTN                                Adjust;\r
+  RETURN_STATUS                        Status;\r
+  PE_COFF_LOADER_IMAGE_CONTEXT         ImageContext;\r
+\r
+  if ((RelocationData == NULL) || (ImageBase == 0x0) || (VirtImageBase == 0x0)) {\r
+    return;\r
+  }\r
+\r
+  OldBase = (CHAR8 *)((UINTN)ImageBase);\r
+  NewBase = (CHAR8 *)((UINTN)VirtImageBase);\r
+  Adjust  = (UINTN)NewBase - (UINTN)OldBase;\r
+\r
+  ImageContext.ImageAddress = ImageBase;\r
+  ImageContext.ImageSize    = ImageSize;\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
+  if (Hdr.Pe32->OptionalHeader.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
+  RelocBase    = NULL;\r
+  RelocBaseEnd = NULL;\r
+  if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
+    RelocDir = DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;\r
+    if ((RelocDir != NULL) && (RelocDir->Size > 0)) {\r
+      RelocBase    = (EFI_IMAGE_BASE_RELOCATION *)PeCoffLoaderImageAddress (&ImageContext, RelocDir->VirtualAddress, 0);\r
+      RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *)PeCoffLoaderImageAddress (\r
+                                                    &ImageContext,\r
+                                                    RelocDir->VirtualAddress + RelocDir->Size - 1,\r
+                                                    0\r
+                                                    );\r
+    }\r
+\r
+    if ((RelocBase == NULL) || (RelocBaseEnd == NULL) || ((UINTN)RelocBaseEnd < (UINTN)RelocBase)) {\r
+      //\r
+      // relocation block is not valid, just return\r
+      //\r
+      return;\r
+    }\r
+  } else {\r
+    //\r
+    // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.\r
+    //\r
+    ASSERT (FALSE);\r
+    return;\r
+  }\r
+\r
+  //\r
+  // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.\r
+  //\r
+  ASSERT (RelocBase != NULL && RelocBaseEnd != NULL);\r
+\r
+  if (Adjust != 0) {\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
+    RelocBaseOrig = RelocBase;\r
+    while ((UINTN)RelocBase < (UINTN)RelocBaseEnd) {\r
+      //\r
+      // Add check for RelocBase->SizeOfBlock field.\r
+      //\r
+      if ((RelocBase->SizeOfBlock == 0) || (RelocBase->SizeOfBlock > RelocDir->Size)) {\r
+        //\r
+        // Data invalid, cannot continue to relocate the image, just return.\r
+        //\r
+        return;\r
+      }\r
+\r
+      Reloc    = (UINT16 *)((UINT8 *)RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
+      RelocEnd = (UINT16 *)((UINT8 *)RelocBase + RelocBase->SizeOfBlock);\r
+      if ((UINTN)RelocEnd > (UINTN)RelocBaseOrig + RelocDir->Size) {\r
+        return;\r
+      }\r
+\r
+      FixupBase = PeCoffLoaderImageAddress (&ImageContext, RelocBase->VirtualAddress, 0);\r
+      if (FixupBase == NULL) {\r
+        return;\r
+      }\r
+\r
+      //\r
+      // Run this relocation record\r
+      //\r
+      while ((UINTN)Reloc < (UINTN)RelocEnd) {\r
+        Fixup = PeCoffLoaderImageAddress (&ImageContext, RelocBase->VirtualAddress + (*Reloc & 0xFFF), 0);\r
+        if (Fixup == NULL) {\r
+          return;\r
+        }\r
+\r
+        switch ((*Reloc) >> 12) {\r
+          case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
+            break;\r
+\r
+          case EFI_IMAGE_REL_BASED_HIGH:\r
+            Fixup16 = (UINT16 *)Fixup;\r
+            if (*(UINT16 *)FixupData == *Fixup16) {\r
+              *Fixup16 = (UINT16)(*Fixup16 + ((UINT16)((UINT32)Adjust >> 16)));\r
+            }\r
+\r
+            FixupData = FixupData + sizeof (UINT16);\r
+            break;\r
+\r
+          case EFI_IMAGE_REL_BASED_LOW:\r
+            Fixup16 = (UINT16 *)Fixup;\r
+            if (*(UINT16 *)FixupData == *Fixup16) {\r
+              *Fixup16 = (UINT16)(*Fixup16 + ((UINT16)Adjust & 0xffff));\r
+            }\r
+\r
+            FixupData = FixupData + sizeof (UINT16);\r
+            break;\r
+\r
+          case EFI_IMAGE_REL_BASED_HIGHLOW:\r
+            Fixup32   = (UINT32 *)Fixup;\r
+            FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
+            if (*(UINT32 *)FixupData == *Fixup32) {\r
+              *Fixup32 = *Fixup32 + (UINT32)Adjust;\r
+            }\r
+\r
+            FixupData = FixupData + sizeof (UINT32);\r
+            break;\r
+\r
+          case EFI_IMAGE_REL_BASED_DIR64:\r
+            Fixup64   = (UINT64 *)Fixup;\r
+            FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));\r
+            if (*(UINT64 *)FixupData == *Fixup64) {\r
+              *Fixup64 = *Fixup64 + (UINT64)Adjust;\r
+            }\r
+\r
+            FixupData = FixupData + sizeof (UINT64);\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
+        //\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
+}\r
+\r
+/**\r
+  Reads contents of a PE/COFF image from a buffer in system memory.\r
+\r
+  This is the default implementation of a PE_COFF_LOADER_READ_FILE function\r
+  that assumes FileHandle pointer to the beginning of a PE/COFF image.\r
+  This function reads contents of the PE/COFF image that starts at the system memory\r
+  address specified by FileHandle.  The read operation copies ReadSize bytes from the\r
+  PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer.\r
+  The size of the buffer actually read is returned in ReadSize.\r
+\r
+  The caller must make sure the FileOffset and ReadSize within the file scope.\r
+\r
+  If FileHandle is NULL, then ASSERT().\r
+  If ReadSize is NULL, then ASSERT().\r
+  If Buffer is NULL, then ASSERT().\r
+\r
+  @param  FileHandle        The pointer to base of the input stream\r
+  @param  FileOffset        Offset into the PE/COFF image to begin the read operation.\r
+  @param  ReadSize          On input, the size in bytes of the requested read operation.\r
+                            On output, the number of bytes actually read.\r
+  @param  Buffer            Output buffer that contains the data read from the PE/COFF image.\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
+  ASSERT (ReadSize != NULL);\r
+  ASSERT (FileHandle != NULL);\r
+  ASSERT (Buffer != NULL);\r
+\r
+  CopyMem (Buffer, ((UINT8 *)FileHandle) + FileOffset, *ReadSize);\r
+  return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+  Unloads a loaded PE/COFF image from memory and releases its taken resource.\r
+  Releases any environment specific resources that were allocated when the image\r
+  specified by ImageContext was loaded using PeCoffLoaderLoadImage().\r
+\r
+  For NT32 emulator, the PE/COFF image loaded by system needs to release.\r
+  For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded,\r
+  this function can simply return RETURN_SUCCESS.\r
+\r
+  If ImageContext is NULL, then ASSERT().\r
+\r
+  @param  ImageContext              The pointer to the image context structure that describes the PE/COFF\r
+                                    image to be unloaded.\r
+\r
+  @retval RETURN_SUCCESS            The PE/COFF image was unloaded successfully.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+PeCoffLoaderUnloadImage (\r
+  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext\r
+  )\r
+{\r
+  //\r
+  // Applies additional environment specific actions to unload a\r
+  // PE/COFF image if needed\r
+  //\r
+  PeCoffLoaderUnloadImageExtraAction (ImageContext);\r
+  return RETURN_SUCCESS;\r
+}\r