Home | History | Annotate | Download | only in BasePeCoffLib
      1 /** @file
      2   Base PE/COFF loader supports loading any PE32/PE32+ or TE image, but
      3   only supports relocating IA32, x64, IPF, and EBC images.
      4 
      5   Caution: This file requires additional review when modified.
      6   This library will have external input - PE/COFF image.
      7   This external input must be validated carefully to avoid security issue like
      8   buffer overflow, integer overflow.
      9 
     10   The basic guideline is that caller need provide ImageContext->ImageRead () with the
     11   necessary data range check, to make sure when this library reads PE/COFF image, the
     12   PE image buffer is always in valid range.
     13   This library will also do some additional check for PE header fields.
     14 
     15   PeCoffLoaderGetPeHeader() routine will do basic check for PE/COFF header.
     16   PeCoffLoaderGetImageInfo() routine will do basic check for whole PE/COFF image.
     17 
     18   Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
     19   Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
     20   This program and the accompanying materials
     21   are licensed and made available under the terms and conditions of the BSD License
     22   which accompanies this distribution.  The full text of the license may be found at
     23   http://opensource.org/licenses/bsd-license.php.
     24 
     25   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     26   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     27 
     28 **/
     29 
     30 #include "BasePeCoffLibInternals.h"
     31 
     32 /**
     33   Adjust some fields in section header for TE image.
     34 
     35   @param  SectionHeader             Pointer to the section header.
     36   @param  TeStrippedOffset          Size adjust for the TE image.
     37 
     38 **/
     39 VOID
     40 PeCoffLoaderAdjustOffsetForTeImage (
     41   EFI_IMAGE_SECTION_HEADER              *SectionHeader,
     42   UINT32                                TeStrippedOffset
     43   )
     44 {
     45   SectionHeader->VirtualAddress   -= TeStrippedOffset;
     46   SectionHeader->PointerToRawData -= TeStrippedOffset;
     47 }
     48 
     49 /**
     50   Retrieves the magic value from the PE/COFF header.
     51 
     52   @param  Hdr             The buffer in which to return the PE32, PE32+, or TE header.
     53 
     54   @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32
     55   @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+
     56 
     57 **/
     58 UINT16
     59 PeCoffLoaderGetPeHeaderMagicValue (
     60   IN  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr
     61   )
     62 {
     63   //
     64   // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
     65   //       in the PE/COFF Header.  If the MachineType is Itanium(IA64) and the
     66   //       Magic value in the OptionalHeader is  EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
     67   //       then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
     68   //
     69   if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
     70     return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
     71   }
     72   //
     73   // Return the magic value from the PC/COFF Optional Header
     74   //
     75   return Hdr.Pe32->OptionalHeader.Magic;
     76 }
     77 
     78 
     79 /**
     80   Retrieves the PE or TE Header from a PE/COFF or TE image.
     81 
     82   Caution: This function may receive untrusted input.
     83   PE/COFF image is external input, so this routine will
     84   also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
     85   SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
     86 
     87   @param  ImageContext    The context of the image being loaded.
     88   @param  Hdr             The buffer in which to return the PE32, PE32+, or TE header.
     89 
     90   @retval RETURN_SUCCESS  The PE or TE Header is read.
     91   @retval Other           The error status from reading the PE/COFF or TE image using the ImageRead function.
     92 
     93 **/
     94 RETURN_STATUS
     95 PeCoffLoaderGetPeHeader (
     96   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext,
     97   OUT    EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr
     98   )
     99 {
    100   RETURN_STATUS         Status;
    101   EFI_IMAGE_DOS_HEADER  DosHdr;
    102   UINTN                 Size;
    103   UINTN                 ReadSize;
    104   UINT16                Magic;
    105   UINT32                SectionHeaderOffset;
    106   UINT32                Index;
    107   UINT32                HeaderWithoutDataDir;
    108   CHAR8                 BufferData;
    109   UINTN                 NumberOfSections;
    110   EFI_IMAGE_SECTION_HEADER  SectionHeader;
    111 
    112   //
    113   // Read the DOS image header to check for its existence
    114   //
    115   Size = sizeof (EFI_IMAGE_DOS_HEADER);
    116   ReadSize = Size;
    117   Status = ImageContext->ImageRead (
    118                            ImageContext->Handle,
    119                            0,
    120                            &Size,
    121                            &DosHdr
    122                            );
    123   if (RETURN_ERROR (Status) || (Size != ReadSize)) {
    124     ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    125     if (Size != ReadSize) {
    126       Status = RETURN_UNSUPPORTED;
    127     }
    128     return Status;
    129   }
    130 
    131   ImageContext->PeCoffHeaderOffset = 0;
    132   if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {
    133     //
    134     // DOS image header is present, so read the PE header after the DOS image
    135     // header
    136     //
    137     ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;
    138   }
    139 
    140   //
    141   // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much
    142   // data, but that should not hurt anything. Hdr.Pe32->OptionalHeader.Magic
    143   // determines if this is a PE32 or PE32+ image. The magic is in the same
    144   // location in both images.
    145   //
    146   Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
    147   ReadSize = Size;
    148   Status = ImageContext->ImageRead (
    149                            ImageContext->Handle,
    150                            ImageContext->PeCoffHeaderOffset,
    151                            &Size,
    152                            Hdr.Pe32
    153                            );
    154   if (RETURN_ERROR (Status) || (Size != ReadSize)) {
    155     ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    156     if (Size != ReadSize) {
    157       Status = RETURN_UNSUPPORTED;
    158     }
    159     return Status;
    160   }
    161 
    162   //
    163   // Use Signature to figure out if we understand the image format
    164   //
    165   if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
    166     ImageContext->IsTeImage         = TRUE;
    167     ImageContext->Machine           = Hdr.Te->Machine;
    168     ImageContext->ImageType         = (UINT16)(Hdr.Te->Subsystem);
    169     //
    170     // For TeImage, SectionAlignment is undefined to be set to Zero
    171     // ImageSize can be calculated.
    172     //
    173     ImageContext->ImageSize         = 0;
    174     ImageContext->SectionAlignment  = 0;
    175     ImageContext->SizeOfHeaders     = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;
    176 
    177     //
    178     // Check the StrippedSize.
    179     //
    180     if (sizeof (EFI_TE_IMAGE_HEADER) >= (UINT32)Hdr.Te->StrippedSize) {
    181       ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    182       return RETURN_UNSUPPORTED;
    183     }
    184 
    185     //
    186     // Check the SizeOfHeaders field.
    187     //
    188     if (Hdr.Te->BaseOfCode <= Hdr.Te->StrippedSize) {
    189       ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    190       return RETURN_UNSUPPORTED;
    191     }
    192 
    193     //
    194     // Read last byte of Hdr.Te->SizeOfHeaders from the file.
    195     //
    196     Size = 1;
    197     ReadSize = Size;
    198     Status = ImageContext->ImageRead (
    199                              ImageContext->Handle,
    200                              ImageContext->SizeOfHeaders - 1,
    201                              &Size,
    202                              &BufferData
    203                              );
    204     if (RETURN_ERROR (Status) || (Size != ReadSize)) {
    205       ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    206       if (Size != ReadSize) {
    207         Status = RETURN_UNSUPPORTED;
    208       }
    209       return Status;
    210     }
    211 
    212     //
    213     // TE Image Data Directory Entry size is non-zero, but the Data Directory Virtual Address is zero.
    214     // This case is not a valid TE image.
    215     //
    216     if ((Hdr.Te->DataDirectory[0].Size != 0 && Hdr.Te->DataDirectory[0].VirtualAddress == 0) ||
    217         (Hdr.Te->DataDirectory[1].Size != 0 && Hdr.Te->DataDirectory[1].VirtualAddress == 0)) {
    218       ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    219       return RETURN_UNSUPPORTED;
    220     }
    221   } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE)  {
    222     ImageContext->IsTeImage = FALSE;
    223     ImageContext->Machine = Hdr.Pe32->FileHeader.Machine;
    224 
    225     Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
    226 
    227     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    228       //
    229       // 1. Check OptionalHeader.NumberOfRvaAndSizes filed.
    230       //
    231       if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {
    232         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    233         return RETURN_UNSUPPORTED;
    234       }
    235 
    236       //
    237       // 2. Check the FileHeader.SizeOfOptionalHeader field.
    238       // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
    239       // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
    240       //
    241       HeaderWithoutDataDir = sizeof (EFI_IMAGE_OPTIONAL_HEADER32) - sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
    242       if (((UINT32)Hdr.Pe32->FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) !=
    243           Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY)) {
    244         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    245         return RETURN_UNSUPPORTED;
    246       }
    247 
    248       SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
    249       //
    250       // 3. Check the FileHeader.NumberOfSections field.
    251       //
    252       if (Hdr.Pe32->OptionalHeader.SizeOfImage <= SectionHeaderOffset) {
    253         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    254         return RETURN_UNSUPPORTED;
    255       }
    256       if ((Hdr.Pe32->OptionalHeader.SizeOfImage - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER <= Hdr.Pe32->FileHeader.NumberOfSections) {
    257         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    258         return RETURN_UNSUPPORTED;
    259       }
    260 
    261       //
    262       // 4. Check the OptionalHeader.SizeOfHeaders field.
    263       //
    264       if (Hdr.Pe32->OptionalHeader.SizeOfHeaders <= SectionHeaderOffset) {
    265         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    266         return RETURN_UNSUPPORTED;
    267       }
    268       if (Hdr.Pe32->OptionalHeader.SizeOfHeaders >= Hdr.Pe32->OptionalHeader.SizeOfImage) {
    269         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    270         return RETURN_UNSUPPORTED;
    271       }
    272       if ((Hdr.Pe32->OptionalHeader.SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER < (UINT32)Hdr.Pe32->FileHeader.NumberOfSections) {
    273         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    274         return RETURN_UNSUPPORTED;
    275       }
    276 
    277       //
    278       // 4.2 Read last byte of Hdr.Pe32.OptionalHeader.SizeOfHeaders from the file.
    279       //
    280       Size = 1;
    281       ReadSize = Size;
    282       Status = ImageContext->ImageRead (
    283                                ImageContext->Handle,
    284                                Hdr.Pe32->OptionalHeader.SizeOfHeaders - 1,
    285                                &Size,
    286                                &BufferData
    287                                );
    288       if (RETURN_ERROR (Status) || (Size != ReadSize)) {
    289         ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    290         if (Size != ReadSize) {
    291           Status = RETURN_UNSUPPORTED;
    292         }
    293         return Status;
    294       }
    295 
    296       //
    297       // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
    298       // Read the last byte to make sure the data is in the image region.
    299       // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
    300       //
    301       if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes) {
    302         if (Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size != 0) {
    303           //
    304           // Check the member data to avoid overflow.
    305           //
    306           if ((UINT32) (~0) - Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress <
    307               Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {
    308             ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    309             return RETURN_UNSUPPORTED;
    310           }
    311 
    312           //
    313           // Read last byte of section header from file
    314           //
    315           Size = 1;
    316           ReadSize = Size;
    317           Status = ImageContext->ImageRead (
    318                                    ImageContext->Handle,
    319                                    Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +
    320                                     Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - 1,
    321                                    &Size,
    322                                    &BufferData
    323                                    );
    324           if (RETURN_ERROR (Status) || (Size != ReadSize)) {
    325             ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    326             if (Size != ReadSize) {
    327               Status = RETURN_UNSUPPORTED;
    328             }
    329             return Status;
    330           }
    331         }
    332       }
    333 
    334       //
    335       // Use PE32 offset
    336       //
    337       ImageContext->ImageType         = Hdr.Pe32->OptionalHeader.Subsystem;
    338       ImageContext->ImageSize         = (UINT64)Hdr.Pe32->OptionalHeader.SizeOfImage;
    339       ImageContext->SectionAlignment  = Hdr.Pe32->OptionalHeader.SectionAlignment;
    340       ImageContext->SizeOfHeaders     = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
    341 
    342     } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
    343       //
    344       // 1. Check FileHeader.NumberOfRvaAndSizes filed.
    345       //
    346       if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {
    347         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    348         return RETURN_UNSUPPORTED;
    349       }
    350       //
    351       // 2. Check the FileHeader.SizeOfOptionalHeader field.
    352       // OptionalHeader.NumberOfRvaAndSizes is not bigger than 16, so
    353       // OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY) will not overflow.
    354       //
    355       HeaderWithoutDataDir = sizeof (EFI_IMAGE_OPTIONAL_HEADER64) - sizeof (EFI_IMAGE_DATA_DIRECTORY) * EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
    356       if (((UINT32)Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader - HeaderWithoutDataDir) !=
    357           Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes * sizeof (EFI_IMAGE_DATA_DIRECTORY)) {
    358         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    359         return RETURN_UNSUPPORTED;
    360       }
    361 
    362       SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32Plus->FileHeader.SizeOfOptionalHeader;
    363       //
    364       // 3. Check the FileHeader.NumberOfSections field.
    365       //
    366       if (Hdr.Pe32Plus->OptionalHeader.SizeOfImage <= SectionHeaderOffset) {
    367         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    368         return RETURN_UNSUPPORTED;
    369       }
    370       if ((Hdr.Pe32Plus->OptionalHeader.SizeOfImage - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER <= Hdr.Pe32Plus->FileHeader.NumberOfSections) {
    371         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    372         return RETURN_UNSUPPORTED;
    373       }
    374 
    375       //
    376       // 4. Check the OptionalHeader.SizeOfHeaders field.
    377       //
    378       if (Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders <= SectionHeaderOffset) {
    379         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    380         return RETURN_UNSUPPORTED;
    381       }
    382       if (Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders >= Hdr.Pe32Plus->OptionalHeader.SizeOfImage) {
    383         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    384         return RETURN_UNSUPPORTED;
    385       }
    386       if ((Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - SectionHeaderOffset) / EFI_IMAGE_SIZEOF_SECTION_HEADER < (UINT32)Hdr.Pe32Plus->FileHeader.NumberOfSections) {
    387         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    388         return RETURN_UNSUPPORTED;
    389       }
    390 
    391       //
    392       // 4.2 Read last byte of Hdr.Pe32Plus.OptionalHeader.SizeOfHeaders from the file.
    393       //
    394       Size = 1;
    395       ReadSize = Size;
    396       Status = ImageContext->ImageRead (
    397                                ImageContext->Handle,
    398                                Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - 1,
    399                                &Size,
    400                                &BufferData
    401                                );
    402       if (RETURN_ERROR (Status) || (Size != ReadSize)) {
    403         ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    404         if (Size != ReadSize) {
    405           Status = RETURN_UNSUPPORTED;
    406         }
    407         return Status;
    408       }
    409 
    410       //
    411       // Check the EFI_IMAGE_DIRECTORY_ENTRY_SECURITY data.
    412       // Read the last byte to make sure the data is in the image region.
    413       // The DataDirectory array begin with 1, not 0, so here use < to compare not <=.
    414       //
    415       if (EFI_IMAGE_DIRECTORY_ENTRY_SECURITY < Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes) {
    416         if (Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size != 0) {
    417           //
    418           // Check the member data to avoid overflow.
    419           //
    420           if ((UINT32) (~0) - Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress <
    421               Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size) {
    422             ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    423             return RETURN_UNSUPPORTED;
    424           }
    425 
    426           //
    427           // Read last byte of section header from file
    428           //
    429           Size = 1;
    430           ReadSize = Size;
    431           Status = ImageContext->ImageRead (
    432                                    ImageContext->Handle,
    433                                    Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress +
    434                                     Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size - 1,
    435                                    &Size,
    436                                    &BufferData
    437                                    );
    438           if (RETURN_ERROR (Status) || (Size != ReadSize)) {
    439             ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    440             if (Size != ReadSize) {
    441               Status = RETURN_UNSUPPORTED;
    442             }
    443             return Status;
    444           }
    445         }
    446       }
    447 
    448       //
    449       // Use PE32+ offset
    450       //
    451       ImageContext->ImageType         = Hdr.Pe32Plus->OptionalHeader.Subsystem;
    452       ImageContext->ImageSize         = (UINT64) Hdr.Pe32Plus->OptionalHeader.SizeOfImage;
    453       ImageContext->SectionAlignment  = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;
    454       ImageContext->SizeOfHeaders     = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
    455     } else {
    456       ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;
    457       return RETURN_UNSUPPORTED;
    458     }
    459   } else {
    460     ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;
    461     return RETURN_UNSUPPORTED;
    462   }
    463 
    464   if (!PeCoffLoaderImageFormatSupported (ImageContext->Machine)) {
    465     //
    466     // If the PE/COFF loader does not support the image type return
    467     // unsupported. This library can support lots of types of images
    468     // this does not mean the user of this library can call the entry
    469     // point of the image.
    470     //
    471     return RETURN_UNSUPPORTED;
    472   }
    473 
    474   //
    475   // Check each section field.
    476   //
    477   if (ImageContext->IsTeImage) {
    478     SectionHeaderOffset = sizeof(EFI_TE_IMAGE_HEADER);
    479     NumberOfSections    = (UINTN) (Hdr.Te->NumberOfSections);
    480   } else {
    481     SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + Hdr.Pe32->FileHeader.SizeOfOptionalHeader;
    482     NumberOfSections    = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);
    483   }
    484 
    485   for (Index = 0; Index < NumberOfSections; Index++) {
    486     //
    487     // Read section header from file
    488     //
    489     Size = sizeof (EFI_IMAGE_SECTION_HEADER);
    490     ReadSize = Size;
    491     Status = ImageContext->ImageRead (
    492                              ImageContext->Handle,
    493                              SectionHeaderOffset,
    494                              &Size,
    495                              &SectionHeader
    496                              );
    497     if (RETURN_ERROR (Status) || (Size != ReadSize)) {
    498       ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    499       if (Size != ReadSize) {
    500         Status = RETURN_UNSUPPORTED;
    501       }
    502       return Status;
    503     }
    504 
    505     //
    506     // Adjust some field in Section Header for TE image.
    507     //
    508     if (ImageContext->IsTeImage) {
    509       PeCoffLoaderAdjustOffsetForTeImage (&SectionHeader, (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
    510     }
    511 
    512     if (SectionHeader.SizeOfRawData > 0) {
    513       //
    514       // Section data should bigger than the Pe header.
    515       //
    516       if (SectionHeader.VirtualAddress < ImageContext->SizeOfHeaders ||
    517           SectionHeader.PointerToRawData < ImageContext->SizeOfHeaders) {
    518         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    519         return RETURN_UNSUPPORTED;
    520       }
    521 
    522       //
    523       // Check the member data to avoid overflow.
    524       //
    525       if ((UINT32) (~0) - SectionHeader.PointerToRawData < SectionHeader.SizeOfRawData) {
    526         ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
    527         return RETURN_UNSUPPORTED;
    528       }
    529 
    530       //
    531       // Base on the ImageRead function to check the section data field.
    532       // Read the last byte to make sure the data is in the image region.
    533       //
    534       Size = 1;
    535       ReadSize = Size;
    536       Status = ImageContext->ImageRead (
    537                                ImageContext->Handle,
    538                                SectionHeader.PointerToRawData + SectionHeader.SizeOfRawData - 1,
    539                                &Size,
    540                                &BufferData
    541                                );
    542       if (RETURN_ERROR (Status) || (Size != ReadSize)) {
    543         ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    544         if (Size != ReadSize) {
    545           Status = RETURN_UNSUPPORTED;
    546         }
    547         return Status;
    548       }
    549     }
    550 
    551     //
    552     // Check next section.
    553     //
    554     SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
    555   }
    556 
    557   return RETURN_SUCCESS;
    558 }
    559 
    560 
    561 /**
    562   Retrieves information about a PE/COFF image.
    563 
    564   Computes the PeCoffHeaderOffset, IsTeImage, ImageType, ImageAddress, ImageSize,
    565   DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and
    566   DebugDirectoryEntryRva fields of the ImageContext structure.
    567   If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.
    568   If the PE/COFF image accessed through the ImageRead service in the ImageContext
    569   structure is not a supported PE/COFF image type, then return RETURN_UNSUPPORTED.
    570   If any errors occur while computing the fields of ImageContext,
    571   then the error status is returned in the ImageError field of ImageContext.
    572   If the image is a TE image, then SectionAlignment is set to 0.
    573   The ImageRead and Handle fields of ImageContext structure must be valid prior
    574   to invoking this service.
    575 
    576   Caution: This function may receive untrusted input.
    577   PE/COFF image is external input, so this routine will
    578   also done many checks in PE image to make sure PE image DosHeader, PeOptionHeader,
    579   SizeOfHeader, Section Data Region and Security Data Region be in PE image range.
    580 
    581   @param  ImageContext              The pointer to the image context structure that describes the PE/COFF
    582                                     image that needs to be examined by this function.
    583 
    584   @retval RETURN_SUCCESS            The information on the PE/COFF image was collected.
    585   @retval RETURN_INVALID_PARAMETER  ImageContext is NULL.
    586   @retval RETURN_UNSUPPORTED        The PE/COFF image is not supported.
    587 
    588 **/
    589 RETURN_STATUS
    590 EFIAPI
    591 PeCoffLoaderGetImageInfo (
    592   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
    593   )
    594 {
    595   RETURN_STATUS                         Status;
    596   EFI_IMAGE_OPTIONAL_HEADER_UNION       HdrData;
    597   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
    598   EFI_IMAGE_DATA_DIRECTORY              *DebugDirectoryEntry;
    599   UINTN                                 Size;
    600   UINTN                                 ReadSize;
    601   UINTN                                 Index;
    602   UINTN                                 DebugDirectoryEntryRva;
    603   UINTN                                 DebugDirectoryEntryFileOffset;
    604   UINTN                                 SectionHeaderOffset;
    605   EFI_IMAGE_SECTION_HEADER              SectionHeader;
    606   EFI_IMAGE_DEBUG_DIRECTORY_ENTRY       DebugEntry;
    607   UINT32                                NumberOfRvaAndSizes;
    608   UINT16                                Magic;
    609   UINT32                                TeStrippedOffset;
    610 
    611   if (ImageContext == NULL) {
    612     return RETURN_INVALID_PARAMETER;
    613   }
    614   //
    615   // Assume success
    616   //
    617   ImageContext->ImageError  = IMAGE_ERROR_SUCCESS;
    618 
    619   Hdr.Union = &HdrData;
    620   Status = PeCoffLoaderGetPeHeader (ImageContext, Hdr);
    621   if (RETURN_ERROR (Status)) {
    622     return Status;
    623   }
    624 
    625   Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
    626 
    627   //
    628   // Retrieve the base address of the image
    629   //
    630   if (!(ImageContext->IsTeImage)) {
    631     TeStrippedOffset = 0;
    632     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    633       //
    634       // Use PE32 offset
    635       //
    636       ImageContext->ImageAddress = Hdr.Pe32->OptionalHeader.ImageBase;
    637     } else {
    638       //
    639       // Use PE32+ offset
    640       //
    641       ImageContext->ImageAddress = Hdr.Pe32Plus->OptionalHeader.ImageBase;
    642     }
    643   } else {
    644     TeStrippedOffset = (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
    645     ImageContext->ImageAddress = (PHYSICAL_ADDRESS)(Hdr.Te->ImageBase + TeStrippedOffset);
    646   }
    647 
    648   //
    649   // Initialize the alternate destination address to 0 indicating that it
    650   // should not be used.
    651   //
    652   ImageContext->DestinationAddress = 0;
    653 
    654   //
    655   // Initialize the debug codeview pointer.
    656   //
    657   ImageContext->DebugDirectoryEntryRva = 0;
    658   ImageContext->CodeView               = NULL;
    659   ImageContext->PdbPointer             = NULL;
    660 
    661   //
    662   // Three cases with regards to relocations:
    663   // - Image has base relocs, RELOCS_STRIPPED==0    => image is relocatable
    664   // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
    665   // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
    666   //   has no base relocs to apply
    667   // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
    668   //
    669   // Look at the file header to determine if relocations have been stripped, and
    670   // save this information in the image context for later use.
    671   //
    672   if ((!(ImageContext->IsTeImage)) && ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {
    673     ImageContext->RelocationsStripped = TRUE;
    674   } else if ((ImageContext->IsTeImage) && (Hdr.Te->DataDirectory[0].Size == 0) && (Hdr.Te->DataDirectory[0].VirtualAddress == 0)) {
    675     ImageContext->RelocationsStripped = TRUE;
    676   } else {
    677     ImageContext->RelocationsStripped = FALSE;
    678   }
    679 
    680   if (!(ImageContext->IsTeImage)) {
    681     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    682       //
    683       // Use PE32 offset
    684       //
    685       NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
    686       DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
    687     } else {
    688       //
    689       // Use PE32+ offset
    690       //
    691       NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
    692       DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
    693     }
    694 
    695     if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
    696 
    697       DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
    698 
    699       //
    700       // Determine the file offset of the debug directory...  This means we walk
    701       // the sections to find which section contains the RVA of the debug
    702       // directory
    703       //
    704       DebugDirectoryEntryFileOffset = 0;
    705 
    706       SectionHeaderOffset = (UINTN)(
    707                                ImageContext->PeCoffHeaderOffset +
    708                                sizeof (UINT32) +
    709                                sizeof (EFI_IMAGE_FILE_HEADER) +
    710                                Hdr.Pe32->FileHeader.SizeOfOptionalHeader
    711                                );
    712 
    713       for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
    714         //
    715         // Read section header from file
    716         //
    717         Size = sizeof (EFI_IMAGE_SECTION_HEADER);
    718         ReadSize = Size;
    719         Status = ImageContext->ImageRead (
    720                                  ImageContext->Handle,
    721                                  SectionHeaderOffset,
    722                                  &Size,
    723                                  &SectionHeader
    724                                  );
    725         if (RETURN_ERROR (Status) || (Size != ReadSize)) {
    726           ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    727           if (Size != ReadSize) {
    728             Status = RETURN_UNSUPPORTED;
    729           }
    730           return Status;
    731         }
    732 
    733         if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
    734             DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
    735 
    736           DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
    737           break;
    738         }
    739 
    740         SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
    741       }
    742 
    743       if (DebugDirectoryEntryFileOffset != 0) {
    744         for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
    745           //
    746           // Read next debug directory entry
    747           //
    748           Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
    749           ReadSize = Size;
    750           Status = ImageContext->ImageRead (
    751                                    ImageContext->Handle,
    752                                    DebugDirectoryEntryFileOffset + Index,
    753                                    &Size,
    754                                    &DebugEntry
    755                                    );
    756           if (RETURN_ERROR (Status) || (Size != ReadSize)) {
    757             ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    758             if (Size != ReadSize) {
    759               Status = RETURN_UNSUPPORTED;
    760             }
    761             return Status;
    762           }
    763 
    764           //
    765           // From PeCoff spec, when DebugEntry.RVA == 0 means this debug info will not load into memory.
    766           // Here we will always load EFI_IMAGE_DEBUG_TYPE_CODEVIEW type debug info. so need adjust the
    767           // ImageContext->ImageSize when DebugEntry.RVA == 0.
    768           //
    769           if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
    770             ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
    771             if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {
    772               ImageContext->ImageSize += DebugEntry.SizeOfData;
    773             }
    774 
    775             return RETURN_SUCCESS;
    776           }
    777         }
    778       }
    779     }
    780   } else {
    781 
    782     DebugDirectoryEntry             = &Hdr.Te->DataDirectory[1];
    783     DebugDirectoryEntryRva          = DebugDirectoryEntry->VirtualAddress;
    784     SectionHeaderOffset             = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));
    785 
    786     DebugDirectoryEntryFileOffset   = 0;
    787 
    788     for (Index = 0; Index < Hdr.Te->NumberOfSections;) {
    789       //
    790       // Read section header from file
    791       //
    792       Size   = sizeof (EFI_IMAGE_SECTION_HEADER);
    793       ReadSize = Size;
    794       Status = ImageContext->ImageRead (
    795                                ImageContext->Handle,
    796                                SectionHeaderOffset,
    797                                &Size,
    798                                &SectionHeader
    799                                );
    800       if (RETURN_ERROR (Status) || (Size != ReadSize)) {
    801         ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    802         if (Size != ReadSize) {
    803           Status = RETURN_UNSUPPORTED;
    804         }
    805         return Status;
    806       }
    807 
    808       if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
    809           DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
    810         DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -
    811                                         SectionHeader.VirtualAddress +
    812                                         SectionHeader.PointerToRawData -
    813                                         TeStrippedOffset;
    814 
    815         //
    816         // File offset of the debug directory was found, if this is not the last
    817         // section, then skip to the last section for calculating the image size.
    818         //
    819         if (Index < (UINTN) Hdr.Te->NumberOfSections - 1) {
    820           SectionHeaderOffset += (Hdr.Te->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);
    821           Index = Hdr.Te->NumberOfSections - 1;
    822           continue;
    823         }
    824       }
    825 
    826       //
    827       // In Te image header there is not a field to describe the ImageSize.
    828       // Actually, the ImageSize equals the RVA plus the VirtualSize of
    829       // the last section mapped into memory (Must be rounded up to
    830       // a multiple of Section Alignment). Per the PE/COFF specification, the
    831       // section headers in the Section Table must appear in order of the RVA
    832       // values for the corresponding sections. So the ImageSize can be determined
    833       // by the RVA and the VirtualSize of the last section header in the
    834       // Section Table.
    835       //
    836       if ((++Index) == (UINTN)Hdr.Te->NumberOfSections) {
    837         ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) - TeStrippedOffset;
    838       }
    839 
    840       SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
    841     }
    842 
    843     if (DebugDirectoryEntryFileOffset != 0) {
    844       for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
    845         //
    846         // Read next debug directory entry
    847         //
    848         Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
    849         ReadSize = Size;
    850         Status = ImageContext->ImageRead (
    851                                  ImageContext->Handle,
    852                                  DebugDirectoryEntryFileOffset + Index,
    853                                  &Size,
    854                                  &DebugEntry
    855                                  );
    856         if (RETURN_ERROR (Status) || (Size != ReadSize)) {
    857           ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
    858           if (Size != ReadSize) {
    859             Status = RETURN_UNSUPPORTED;
    860           }
    861           return Status;
    862         }
    863 
    864         if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
    865           ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
    866           return RETURN_SUCCESS;
    867         }
    868       }
    869     }
    870   }
    871 
    872   return RETURN_SUCCESS;
    873 }
    874 
    875 
    876 /**
    877   Converts an image address to the loaded address.
    878 
    879   @param  ImageContext      The context of the image being loaded.
    880   @param  Address           The address to be converted to the loaded address.
    881   @param  TeStrippedOffset  Stripped offset for TE image.
    882 
    883   @return The converted address or NULL if the address can not be converted.
    884 
    885 **/
    886 VOID *
    887 PeCoffLoaderImageAddress (
    888   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT          *ImageContext,
    889   IN     UINTN                                 Address,
    890   IN     UINTN                                 TeStrippedOffset
    891   )
    892 {
    893   //
    894   // Make sure that Address and ImageSize is correct for the loaded image.
    895   //
    896   if (Address >= ImageContext->ImageSize + TeStrippedOffset) {
    897     ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
    898     return NULL;
    899   }
    900 
    901   return (CHAR8 *)((UINTN) ImageContext->ImageAddress + Address - TeStrippedOffset);
    902 }
    903 
    904 /**
    905   Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().
    906 
    907   If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of
    908   ImageContext as the relocation base address.  Otherwise, use the DestinationAddress field
    909   of ImageContext as the relocation base address.  The caller must allocate the relocation
    910   fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.
    911 
    912   The ImageRead, Handle, PeCoffHeaderOffset,  IsTeImage, Machine, ImageType, ImageAddress,
    913   ImageSize, DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders,
    914   DebugDirectoryEntryRva, EntryPoint, FixupDataSize, CodeView, PdbPointer, and FixupData of
    915   the ImageContext structure must be valid prior to invoking this service.
    916 
    917   If ImageContext is NULL, then ASSERT().
    918 
    919   Note that if the platform does not maintain coherency between the instruction cache(s) and the data
    920   cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
    921   prior to transferring control to a PE/COFF image that is loaded using this library.
    922 
    923   @param  ImageContext        The pointer to the image context structure that describes the PE/COFF
    924                               image that is being relocated.
    925 
    926   @retval RETURN_SUCCESS      The PE/COFF image was relocated.
    927                               Extended status information is in the ImageError field of ImageContext.
    928   @retval RETURN_LOAD_ERROR   The image in not a valid PE/COFF image.
    929                               Extended status information is in the ImageError field of ImageContext.
    930   @retval RETURN_UNSUPPORTED  A relocation record type is not supported.
    931                               Extended status information is in the ImageError field of ImageContext.
    932 
    933 **/
    934 RETURN_STATUS
    935 EFIAPI
    936 PeCoffLoaderRelocateImage (
    937   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
    938   )
    939 {
    940   RETURN_STATUS                         Status;
    941   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
    942   EFI_IMAGE_DATA_DIRECTORY              *RelocDir;
    943   UINT64                                Adjust;
    944   EFI_IMAGE_BASE_RELOCATION             *RelocBaseOrg;
    945   EFI_IMAGE_BASE_RELOCATION             *RelocBase;
    946   EFI_IMAGE_BASE_RELOCATION             *RelocBaseEnd;
    947   UINT16                                *Reloc;
    948   UINT16                                *RelocEnd;
    949   CHAR8                                 *Fixup;
    950   CHAR8                                 *FixupBase;
    951   UINT16                                *Fixup16;
    952   UINT32                                *Fixup32;
    953   UINT64                                *Fixup64;
    954   CHAR8                                 *FixupData;
    955   PHYSICAL_ADDRESS                      BaseAddress;
    956   UINT32                                NumberOfRvaAndSizes;
    957   UINT16                                Magic;
    958   UINT32                                TeStrippedOffset;
    959 
    960   ASSERT (ImageContext != NULL);
    961 
    962   //
    963   // Assume success
    964   //
    965   ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
    966 
    967   //
    968   // If there are no relocation entries, then we are done
    969   //
    970   if (ImageContext->RelocationsStripped) {
    971     // Applies additional environment specific actions to relocate fixups
    972     // to a PE/COFF image if needed
    973     PeCoffLoaderRelocateImageExtraAction (ImageContext);
    974     return RETURN_SUCCESS;
    975   }
    976 
    977   //
    978   // If the destination address is not 0, use that rather than the
    979   // image address as the relocation target.
    980   //
    981   if (ImageContext->DestinationAddress != 0) {
    982     BaseAddress = ImageContext->DestinationAddress;
    983   } else {
    984     BaseAddress = ImageContext->ImageAddress;
    985   }
    986 
    987   if (!(ImageContext->IsTeImage)) {
    988     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
    989     TeStrippedOffset = 0;
    990     Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
    991 
    992     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    993       //
    994       // Use PE32 offset
    995       //
    996       Adjust = (UINT64)BaseAddress - Hdr.Pe32->OptionalHeader.ImageBase;
    997       if (Adjust != 0) {
    998         Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress;
    999       }
   1000 
   1001       NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
   1002       RelocDir  = &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
   1003     } else {
   1004       //
   1005       // Use PE32+ offset
   1006       //
   1007       Adjust = (UINT64) BaseAddress - Hdr.Pe32Plus->OptionalHeader.ImageBase;
   1008       if (Adjust != 0) {
   1009         Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress;
   1010       }
   1011 
   1012       NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
   1013       RelocDir  = &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
   1014     }
   1015 
   1016     //
   1017     // Find the relocation block
   1018     // Per the PE/COFF spec, you can't assume that a given data directory
   1019     // is present in the image. You have to check the NumberOfRvaAndSizes in
   1020     // the optional header to verify a desired directory entry is there.
   1021     //
   1022     if ((NumberOfRvaAndSizes < EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC)) {
   1023       RelocDir = NULL;
   1024     }
   1025   } else {
   1026     Hdr.Te             = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
   1027     TeStrippedOffset   = (UINT32)Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
   1028     Adjust             = (UINT64) (BaseAddress - (Hdr.Te->ImageBase + TeStrippedOffset));
   1029     if (Adjust != 0) {
   1030       Hdr.Te->ImageBase  = (UINT64) (BaseAddress - TeStrippedOffset);
   1031     }
   1032 
   1033     //
   1034     // Find the relocation block
   1035     //
   1036     RelocDir = &Hdr.Te->DataDirectory[0];
   1037   }
   1038 
   1039   if ((RelocDir != NULL) && (RelocDir->Size > 0)) {
   1040     RelocBase = (EFI_IMAGE_BASE_RELOCATION *) PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress, TeStrippedOffset);
   1041     RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) PeCoffLoaderImageAddress (ImageContext,
   1042                                                                             RelocDir->VirtualAddress + RelocDir->Size - 1,
   1043                                                                             TeStrippedOffset
   1044                                                                             );
   1045     if (RelocBase == NULL || RelocBaseEnd == NULL || RelocBaseEnd < RelocBase) {
   1046       ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
   1047       return RETURN_LOAD_ERROR;
   1048     }
   1049   } else {
   1050     //
   1051     // Set base and end to bypass processing below.
   1052     //
   1053     RelocBase = RelocBaseEnd = NULL;
   1054   }
   1055   RelocBaseOrg = RelocBase;
   1056 
   1057   //
   1058   // If Adjust is not zero, then apply fix ups to the image
   1059   //
   1060   if (Adjust != 0) {
   1061     //
   1062     // Run the relocation information and apply the fixups
   1063     //
   1064     FixupData = ImageContext->FixupData;
   1065     while (RelocBase < RelocBaseEnd) {
   1066 
   1067       Reloc     = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
   1068       //
   1069       // Add check for RelocBase->SizeOfBlock field.
   1070       //
   1071       if (RelocBase->SizeOfBlock == 0) {
   1072         ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
   1073         return RETURN_LOAD_ERROR;
   1074       }
   1075       if ((UINTN)RelocBase > MAX_ADDRESS - RelocBase->SizeOfBlock) {
   1076         ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
   1077         return RETURN_LOAD_ERROR;
   1078       }
   1079 
   1080       RelocEnd  = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);
   1081       if ((UINTN)RelocEnd > (UINTN)RelocBaseOrg + RelocDir->Size) {
   1082         ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
   1083         return RETURN_LOAD_ERROR;
   1084       }
   1085       FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress, TeStrippedOffset);
   1086       if (FixupBase == NULL) {
   1087         ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
   1088         return RETURN_LOAD_ERROR;
   1089       }
   1090 
   1091       //
   1092       // Run this relocation record
   1093       //
   1094       while (Reloc < RelocEnd) {
   1095         Fixup = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress + (*Reloc & 0xFFF), TeStrippedOffset);
   1096         if (Fixup == NULL) {
   1097           ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
   1098           return RETURN_LOAD_ERROR;
   1099         }
   1100         switch ((*Reloc) >> 12) {
   1101         case EFI_IMAGE_REL_BASED_ABSOLUTE:
   1102           break;
   1103 
   1104         case EFI_IMAGE_REL_BASED_HIGH:
   1105           Fixup16   = (UINT16 *) Fixup;
   1106           *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
   1107           if (FixupData != NULL) {
   1108             *(UINT16 *) FixupData = *Fixup16;
   1109             FixupData             = FixupData + sizeof (UINT16);
   1110           }
   1111           break;
   1112 
   1113         case EFI_IMAGE_REL_BASED_LOW:
   1114           Fixup16   = (UINT16 *) Fixup;
   1115           *Fixup16  = (UINT16) (*Fixup16 + (UINT16) Adjust);
   1116           if (FixupData != NULL) {
   1117             *(UINT16 *) FixupData = *Fixup16;
   1118             FixupData             = FixupData + sizeof (UINT16);
   1119           }
   1120           break;
   1121 
   1122         case EFI_IMAGE_REL_BASED_HIGHLOW:
   1123           Fixup32   = (UINT32 *) Fixup;
   1124           *Fixup32  = *Fixup32 + (UINT32) Adjust;
   1125           if (FixupData != NULL) {
   1126             FixupData             = ALIGN_POINTER (FixupData, sizeof (UINT32));
   1127             *(UINT32 *)FixupData  = *Fixup32;
   1128             FixupData             = FixupData + sizeof (UINT32);
   1129           }
   1130           break;
   1131 
   1132         case EFI_IMAGE_REL_BASED_DIR64:
   1133           Fixup64 = (UINT64 *) Fixup;
   1134           *Fixup64 = *Fixup64 + (UINT64) Adjust;
   1135           if (FixupData != NULL) {
   1136             FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));
   1137             *(UINT64 *)(FixupData) = *Fixup64;
   1138             FixupData = FixupData + sizeof(UINT64);
   1139           }
   1140           break;
   1141 
   1142         default:
   1143           //
   1144           // The common code does not handle some of the stranger IPF relocations
   1145           // PeCoffLoaderRelocateImageEx () adds support for these complex fixups
   1146           // on IPF and is a No-Op on other architectures.
   1147           //
   1148           Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
   1149           if (RETURN_ERROR (Status)) {
   1150             ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
   1151             return Status;
   1152           }
   1153         }
   1154 
   1155         //
   1156         // Next relocation record
   1157         //
   1158         Reloc += 1;
   1159       }
   1160 
   1161       //
   1162       // Next reloc block
   1163       //
   1164       RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
   1165     }
   1166     ASSERT ((UINTN)FixupData <= (UINTN)ImageContext->FixupData + ImageContext->FixupDataSize);
   1167 
   1168     //
   1169     // Adjust the EntryPoint to match the linked-to address
   1170     //
   1171     if (ImageContext->DestinationAddress != 0) {
   1172        ImageContext->EntryPoint -= (UINT64) ImageContext->ImageAddress;
   1173        ImageContext->EntryPoint += (UINT64) ImageContext->DestinationAddress;
   1174     }
   1175   }
   1176 
   1177   // Applies additional environment specific actions to relocate fixups
   1178   // to a PE/COFF image if needed
   1179   PeCoffLoaderRelocateImageExtraAction (ImageContext);
   1180 
   1181   return RETURN_SUCCESS;
   1182 }
   1183 
   1184 /**
   1185   Loads a PE/COFF image into memory.
   1186 
   1187   Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer
   1188   specified by the ImageAddress and ImageSize fields of ImageContext.  The caller must allocate
   1189   the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.
   1190   The EntryPoint, FixupDataSize, CodeView, PdbPointer and HiiResourceData fields of ImageContext are computed.
   1191   The ImageRead, Handle, PeCoffHeaderOffset,  IsTeImage,  Machine, ImageType, ImageAddress, ImageSize,
   1192   DestinationAddress, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva
   1193   fields of the ImageContext structure must be valid prior to invoking this service.
   1194 
   1195   If ImageContext is NULL, then ASSERT().
   1196 
   1197   Note that if the platform does not maintain coherency between the instruction cache(s) and the data
   1198   cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
   1199   prior to transferring control to a PE/COFF image that is loaded using this library.
   1200 
   1201   @param  ImageContext              The pointer to the image context structure that describes the PE/COFF
   1202                                     image that is being loaded.
   1203 
   1204   @retval RETURN_SUCCESS            The PE/COFF image was loaded into the buffer specified by
   1205                                     the ImageAddress and ImageSize fields of ImageContext.
   1206                                     Extended status information is in the ImageError field of ImageContext.
   1207   @retval RETURN_BUFFER_TOO_SMALL   The caller did not provide a large enough buffer.
   1208                                     Extended status information is in the ImageError field of ImageContext.
   1209   @retval RETURN_LOAD_ERROR         The PE/COFF image is an EFI Runtime image with no relocations.
   1210                                     Extended status information is in the ImageError field of ImageContext.
   1211   @retval RETURN_INVALID_PARAMETER  The image address is invalid.
   1212                                     Extended status information is in the ImageError field of ImageContext.
   1213 
   1214 **/
   1215 RETURN_STATUS
   1216 EFIAPI
   1217 PeCoffLoaderLoadImage (
   1218   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
   1219   )
   1220 {
   1221   RETURN_STATUS                         Status;
   1222   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
   1223   PE_COFF_LOADER_IMAGE_CONTEXT          CheckContext;
   1224   EFI_IMAGE_SECTION_HEADER              *FirstSection;
   1225   EFI_IMAGE_SECTION_HEADER              *Section;
   1226   UINTN                                 NumberOfSections;
   1227   UINTN                                 Index;
   1228   CHAR8                                 *Base;
   1229   CHAR8                                 *End;
   1230   EFI_IMAGE_DATA_DIRECTORY              *DirectoryEntry;
   1231   EFI_IMAGE_DEBUG_DIRECTORY_ENTRY       *DebugEntry;
   1232   UINTN                                 Size;
   1233   UINT32                                TempDebugEntryRva;
   1234   UINT32                                NumberOfRvaAndSizes;
   1235   UINT16                                Magic;
   1236   EFI_IMAGE_RESOURCE_DIRECTORY          *ResourceDirectory;
   1237   EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY    *ResourceDirectoryEntry;
   1238   EFI_IMAGE_RESOURCE_DIRECTORY_STRING   *ResourceDirectoryString;
   1239   EFI_IMAGE_RESOURCE_DATA_ENTRY         *ResourceDataEntry;
   1240   CHAR16                                *String;
   1241   UINT32                                Offset;
   1242   UINT32                                TeStrippedOffset;
   1243 
   1244   ASSERT (ImageContext != NULL);
   1245 
   1246   //
   1247   // Assume success
   1248   //
   1249   ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
   1250 
   1251   //
   1252   // Copy the provided context information into our local version, get what we
   1253   // can from the original image, and then use that to make sure everything
   1254   // is legit.
   1255   //
   1256   CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
   1257 
   1258   Status = PeCoffLoaderGetImageInfo (&CheckContext);
   1259   if (RETURN_ERROR (Status)) {
   1260     return Status;
   1261   }
   1262 
   1263   //
   1264   // Make sure there is enough allocated space for the image being loaded
   1265   //
   1266   if (ImageContext->ImageSize < CheckContext.ImageSize) {
   1267     ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
   1268     return RETURN_BUFFER_TOO_SMALL;
   1269   }
   1270   if (ImageContext->ImageAddress == 0) {
   1271     //
   1272     // Image cannot be loaded into 0 address.
   1273     //
   1274     ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
   1275     return RETURN_INVALID_PARAMETER;
   1276   }
   1277   //
   1278   // If there's no relocations, then make sure it's not a runtime driver,
   1279   // and that it's being loaded at the linked address.
   1280   //
   1281   if (CheckContext.RelocationsStripped) {
   1282     //
   1283     // If the image does not contain relocations and it is a runtime driver
   1284     // then return an error.
   1285     //
   1286     if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
   1287       ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
   1288       return RETURN_LOAD_ERROR;
   1289     }
   1290     //
   1291     // If the image does not contain relocations, and the requested load address
   1292     // is not the linked address, then return an error.
   1293     //
   1294     if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
   1295       ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
   1296       return RETURN_INVALID_PARAMETER;
   1297     }
   1298   }
   1299   //
   1300   // Make sure the allocated space has the proper section alignment
   1301   //
   1302   if (!(ImageContext->IsTeImage)) {
   1303     if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
   1304       ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
   1305       return RETURN_INVALID_PARAMETER;
   1306     }
   1307   }
   1308   //
   1309   // Read the entire PE/COFF or TE header into memory
   1310   //
   1311   if (!(ImageContext->IsTeImage)) {
   1312     Status = ImageContext->ImageRead (
   1313                             ImageContext->Handle,
   1314                             0,
   1315                             &ImageContext->SizeOfHeaders,
   1316                             (VOID *) (UINTN) ImageContext->ImageAddress
   1317                             );
   1318 
   1319     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
   1320 
   1321     FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
   1322                       (UINTN)ImageContext->ImageAddress +
   1323                       ImageContext->PeCoffHeaderOffset +
   1324                       sizeof(UINT32) +
   1325                       sizeof(EFI_IMAGE_FILE_HEADER) +
   1326                       Hdr.Pe32->FileHeader.SizeOfOptionalHeader
   1327       );
   1328     NumberOfSections = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);
   1329     TeStrippedOffset = 0;
   1330   } else {
   1331     Status = ImageContext->ImageRead (
   1332                             ImageContext->Handle,
   1333                             0,
   1334                             &ImageContext->SizeOfHeaders,
   1335                             (void *)(UINTN)ImageContext->ImageAddress
   1336                             );
   1337 
   1338     Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);
   1339     FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
   1340                       (UINTN)ImageContext->ImageAddress +
   1341                       sizeof(EFI_TE_IMAGE_HEADER)
   1342                       );
   1343     NumberOfSections  = (UINTN) (Hdr.Te->NumberOfSections);
   1344     TeStrippedOffset  = (UINT32) Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
   1345   }
   1346 
   1347   if (RETURN_ERROR (Status)) {
   1348     ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
   1349     return RETURN_LOAD_ERROR;
   1350   }
   1351 
   1352   //
   1353   // Load each section of the image
   1354   //
   1355   Section = FirstSection;
   1356   for (Index = 0; Index < NumberOfSections; Index++) {
   1357     //
   1358     // Read the section
   1359     //
   1360     Size = (UINTN) Section->Misc.VirtualSize;
   1361     if ((Size == 0) || (Size > Section->SizeOfRawData)) {
   1362       Size = (UINTN) Section->SizeOfRawData;
   1363     }
   1364 
   1365     //
   1366     // Compute sections address
   1367     //
   1368     Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress, TeStrippedOffset);
   1369     End  = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress + Section->Misc.VirtualSize - 1, TeStrippedOffset);
   1370 
   1371     //
   1372     // If the size of the section is non-zero and the base address or end address resolved to 0, then fail.
   1373     //
   1374     if ((Size > 0) && ((Base == NULL) || (End == NULL))) {
   1375       ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
   1376       return RETURN_LOAD_ERROR;
   1377     }
   1378 
   1379     if (Section->SizeOfRawData > 0) {
   1380       Status = ImageContext->ImageRead (
   1381                               ImageContext->Handle,
   1382                               Section->PointerToRawData - TeStrippedOffset,
   1383                               &Size,
   1384                               Base
   1385                               );
   1386       if (RETURN_ERROR (Status)) {
   1387         ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
   1388         return Status;
   1389       }
   1390     }
   1391 
   1392     //
   1393     // If raw size is less then virtual size, zero fill the remaining
   1394     //
   1395 
   1396     if (Size < Section->Misc.VirtualSize) {
   1397       ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);
   1398     }
   1399 
   1400     //
   1401     // Next Section
   1402     //
   1403     Section += 1;
   1404   }
   1405 
   1406   //
   1407   // Get image's entry point
   1408   //
   1409   Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
   1410   if (!(ImageContext->IsTeImage)) {
   1411     //
   1412     // Sizes of AddressOfEntryPoint are different so we need to do this safely
   1413     //
   1414     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
   1415       //
   1416       // Use PE32 offset
   1417       //
   1418       ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
   1419                                                             ImageContext,
   1420                                                             (UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint,
   1421                                                             0
   1422                                                             );
   1423     } else {
   1424       //
   1425       // Use PE32+ offset
   1426       //
   1427       ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
   1428                                                             ImageContext,
   1429                                                             (UINTN)Hdr.Pe32Plus->OptionalHeader.AddressOfEntryPoint,
   1430                                                             0
   1431                                                             );
   1432     }
   1433   } else {
   1434     ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (
   1435                                                           ImageContext,
   1436                                                           (UINTN)Hdr.Te->AddressOfEntryPoint,
   1437                                                           TeStrippedOffset
   1438                                                           );
   1439   }
   1440 
   1441   //
   1442   // Determine the size of the fixup data
   1443   //
   1444   // Per the PE/COFF spec, you can't assume that a given data directory
   1445   // is present in the image. You have to check the NumberOfRvaAndSizes in
   1446   // the optional header to verify a desired directory entry is there.
   1447   //
   1448   if (!(ImageContext->IsTeImage)) {
   1449     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
   1450       //
   1451       // Use PE32 offset
   1452       //
   1453       NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
   1454       DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
   1455     } else {
   1456       //
   1457       // Use PE32+ offset
   1458       //
   1459       NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
   1460       DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
   1461     }
   1462 
   1463     //
   1464     // Must use UINT64 here, because there might a case that 32bit loader to load 64bit image.
   1465     //
   1466     if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
   1467       ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINT64);
   1468     } else {
   1469       ImageContext->FixupDataSize = 0;
   1470     }
   1471   } else {
   1472     DirectoryEntry              = &Hdr.Te->DataDirectory[0];
   1473     ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINT64);
   1474   }
   1475   //
   1476   // Consumer must allocate a buffer for the relocation fixup log.
   1477   // Only used for runtime drivers.
   1478   //
   1479   ImageContext->FixupData = NULL;
   1480 
   1481   //
   1482   // Load the Codeview information if present
   1483   //
   1484   if (ImageContext->DebugDirectoryEntryRva != 0) {
   1485     DebugEntry = PeCoffLoaderImageAddress (
   1486                 ImageContext,
   1487                 ImageContext->DebugDirectoryEntryRva,
   1488                 TeStrippedOffset
   1489                 );
   1490     if (DebugEntry == NULL) {
   1491       ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
   1492       return RETURN_LOAD_ERROR;
   1493     }
   1494 
   1495     TempDebugEntryRva = DebugEntry->RVA;
   1496     if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {
   1497       Section--;
   1498       if ((UINTN)Section->SizeOfRawData < Section->Misc.VirtualSize) {
   1499         TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
   1500       } else {
   1501         TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
   1502       }
   1503     }
   1504 
   1505     if (TempDebugEntryRva != 0) {
   1506       ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva, TeStrippedOffset);
   1507       if (ImageContext->CodeView == NULL) {
   1508         ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
   1509         return RETURN_LOAD_ERROR;
   1510       }
   1511 
   1512       if (DebugEntry->RVA == 0) {
   1513         Size = DebugEntry->SizeOfData;
   1514         Status = ImageContext->ImageRead (
   1515                                 ImageContext->Handle,
   1516                                 DebugEntry->FileOffset - TeStrippedOffset,
   1517                                 &Size,
   1518                                 ImageContext->CodeView
   1519                                 );
   1520         //
   1521         // Should we apply fix up to this field according to the size difference between PE and TE?
   1522         // Because now we maintain TE header fields unfixed, this field will also remain as they are
   1523         // in original PE image.
   1524         //
   1525 
   1526         if (RETURN_ERROR (Status)) {
   1527           ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
   1528           return RETURN_LOAD_ERROR;
   1529         }
   1530 
   1531         DebugEntry->RVA = TempDebugEntryRva;
   1532       }
   1533 
   1534       switch (*(UINT32 *) ImageContext->CodeView) {
   1535       case CODEVIEW_SIGNATURE_NB10:
   1536         if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)) {
   1537           ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
   1538           return RETURN_UNSUPPORTED;
   1539         }
   1540         ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
   1541         break;
   1542 
   1543       case CODEVIEW_SIGNATURE_RSDS:
   1544         if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY)) {
   1545           ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
   1546           return RETURN_UNSUPPORTED;
   1547         }
   1548         ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
   1549         break;
   1550 
   1551       case CODEVIEW_SIGNATURE_MTOC:
   1552         if (DebugEntry->SizeOfData < sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY)) {
   1553           ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
   1554           return RETURN_UNSUPPORTED;
   1555         }
   1556         ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);
   1557         break;
   1558 
   1559       default:
   1560         break;
   1561       }
   1562     }
   1563   }
   1564 
   1565   //
   1566   // Get Image's HII resource section
   1567   //
   1568   ImageContext->HiiResourceData = 0;
   1569   if (!(ImageContext->IsTeImage)) {
   1570     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
   1571       //
   1572       // Use PE32 offset
   1573       //
   1574       NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
   1575       DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
   1576     } else {
   1577       //
   1578       // Use PE32+ offset
   1579       //
   1580       NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
   1581       DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE];
   1582     }
   1583 
   1584     if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE && DirectoryEntry->Size != 0) {
   1585       Base = PeCoffLoaderImageAddress (ImageContext, DirectoryEntry->VirtualAddress, 0);
   1586       if (Base != NULL) {
   1587         ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) Base;
   1588         Offset = sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) *
   1589                (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
   1590         if (Offset > DirectoryEntry->Size) {
   1591           ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
   1592           return RETURN_UNSUPPORTED;
   1593         }
   1594         ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);
   1595 
   1596         for (Index = 0; Index < ResourceDirectory->NumberOfNamedEntries; Index++) {
   1597           if (ResourceDirectoryEntry->u1.s.NameIsString) {
   1598             //
   1599             // Check the ResourceDirectoryEntry->u1.s.NameOffset before use it.
   1600             //
   1601             if (ResourceDirectoryEntry->u1.s.NameOffset >= DirectoryEntry->Size) {
   1602               ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
   1603               return RETURN_UNSUPPORTED;
   1604             }
   1605             ResourceDirectoryString = (EFI_IMAGE_RESOURCE_DIRECTORY_STRING *) (Base + ResourceDirectoryEntry->u1.s.NameOffset);
   1606             String = &ResourceDirectoryString->String[0];
   1607 
   1608             if (ResourceDirectoryString->Length == 3 &&
   1609                 String[0] == L'H' &&
   1610                 String[1] == L'I' &&
   1611                 String[2] == L'I') {
   1612               //
   1613               // Resource Type "HII" found
   1614               //
   1615               if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
   1616                 //
   1617                 // Move to next level - resource Name
   1618                 //
   1619                 if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {
   1620                   ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
   1621                   return RETURN_UNSUPPORTED;
   1622                 }
   1623                 ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
   1624                 Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +
   1625                          sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
   1626                 if (Offset > DirectoryEntry->Size) {
   1627                   ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
   1628                   return RETURN_UNSUPPORTED;
   1629                 }
   1630                 ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);
   1631 
   1632                 if (ResourceDirectoryEntry->u2.s.DataIsDirectory) {
   1633                   //
   1634                   // Move to next level - resource Language
   1635                   //
   1636                   if (ResourceDirectoryEntry->u2.s.OffsetToDirectory >= DirectoryEntry->Size) {
   1637                     ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
   1638                     return RETURN_UNSUPPORTED;
   1639                   }
   1640                   ResourceDirectory = (EFI_IMAGE_RESOURCE_DIRECTORY *) (Base + ResourceDirectoryEntry->u2.s.OffsetToDirectory);
   1641                   Offset = ResourceDirectoryEntry->u2.s.OffsetToDirectory + sizeof (EFI_IMAGE_RESOURCE_DIRECTORY) +
   1642                            sizeof (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY) * (ResourceDirectory->NumberOfNamedEntries + ResourceDirectory->NumberOfIdEntries);
   1643                   if (Offset > DirectoryEntry->Size) {
   1644                     ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
   1645                     return RETURN_UNSUPPORTED;
   1646                   }
   1647                   ResourceDirectoryEntry = (EFI_IMAGE_RESOURCE_DIRECTORY_ENTRY *) (ResourceDirectory + 1);
   1648                 }
   1649               }
   1650 
   1651               //
   1652               // Now it ought to be resource Data
   1653               //
   1654               if (!ResourceDirectoryEntry->u2.s.DataIsDirectory) {
   1655                 if (ResourceDirectoryEntry->u2.OffsetToData >= DirectoryEntry->Size) {
   1656                   ImageContext->ImageError = IMAGE_ERROR_UNSUPPORTED;
   1657                   return RETURN_UNSUPPORTED;
   1658                 }
   1659                 ResourceDataEntry = (EFI_IMAGE_RESOURCE_DATA_ENTRY *) (Base + ResourceDirectoryEntry->u2.OffsetToData);
   1660                 ImageContext->HiiResourceData = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (ImageContext, ResourceDataEntry->OffsetToData, 0);
   1661                 break;
   1662               }
   1663             }
   1664           }
   1665           ResourceDirectoryEntry++;
   1666         }
   1667       }
   1668     }
   1669   }
   1670 
   1671   return Status;
   1672 }
   1673 
   1674 
   1675 /**
   1676   Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI
   1677   runtime.
   1678 
   1679   This function reapplies relocation fixups to the PE/COFF image specified by ImageBase
   1680   and ImageSize so the image will execute correctly when the PE/COFF image is mapped
   1681   to the address specified by VirtualImageBase.  RelocationData must be identical
   1682   to the FiuxupData buffer from the PE_COFF_LOADER_IMAGE_CONTEXT structure
   1683   after this PE/COFF image was relocated with PeCoffLoaderRelocateImage().
   1684 
   1685   Note that if the platform does not maintain coherency between the instruction cache(s) and the data
   1686   cache(s) in hardware, then the caller is responsible for performing cache maintenance operations
   1687   prior to transferring control to a PE/COFF image that is loaded using this library.
   1688 
   1689   @param  ImageBase          The base address of a PE/COFF image that has been loaded
   1690                              and relocated into system memory.
   1691   @param  VirtImageBase      The request virtual address that the PE/COFF image is to
   1692                              be fixed up for.
   1693   @param  ImageSize          The size, in bytes, of the PE/COFF image.
   1694   @param  RelocationData     A pointer to the relocation data that was collected when the PE/COFF
   1695                              image was relocated using PeCoffLoaderRelocateImage().
   1696 
   1697 **/
   1698 VOID
   1699 EFIAPI
   1700 PeCoffLoaderRelocateImageForRuntime (
   1701   IN  PHYSICAL_ADDRESS        ImageBase,
   1702   IN  PHYSICAL_ADDRESS        VirtImageBase,
   1703   IN  UINTN                   ImageSize,
   1704   IN  VOID                    *RelocationData
   1705   )
   1706 {
   1707   CHAR8                               *OldBase;
   1708   CHAR8                               *NewBase;
   1709   EFI_IMAGE_DOS_HEADER                *DosHdr;
   1710   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
   1711   UINT32                              NumberOfRvaAndSizes;
   1712   EFI_IMAGE_DATA_DIRECTORY            *DataDirectory;
   1713   EFI_IMAGE_DATA_DIRECTORY            *RelocDir;
   1714   EFI_IMAGE_BASE_RELOCATION           *RelocBase;
   1715   EFI_IMAGE_BASE_RELOCATION           *RelocBaseEnd;
   1716   UINT16                              *Reloc;
   1717   UINT16                              *RelocEnd;
   1718   CHAR8                               *Fixup;
   1719   CHAR8                               *FixupBase;
   1720   UINT16                              *Fixup16;
   1721   UINT32                              *Fixup32;
   1722   UINT64                              *Fixup64;
   1723   CHAR8                               *FixupData;
   1724   UINTN                               Adjust;
   1725   RETURN_STATUS                       Status;
   1726   UINT16                              Magic;
   1727 
   1728   OldBase = (CHAR8 *)((UINTN)ImageBase);
   1729   NewBase = (CHAR8 *)((UINTN)VirtImageBase);
   1730   Adjust = (UINTN) NewBase - (UINTN) OldBase;
   1731 
   1732   //
   1733   // Find the image's relocate dir info
   1734   //
   1735   DosHdr = (EFI_IMAGE_DOS_HEADER *)OldBase;
   1736   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
   1737     //
   1738     // Valid DOS header so get address of PE header
   1739     //
   1740     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(((CHAR8 *)DosHdr) + DosHdr->e_lfanew);
   1741   } else {
   1742     //
   1743     // No Dos header so assume image starts with PE header.
   1744     //
   1745     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)OldBase;
   1746   }
   1747 
   1748   if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
   1749     //
   1750     // Not a valid PE image so Exit
   1751     //
   1752     return ;
   1753   }
   1754 
   1755   Magic = PeCoffLoaderGetPeHeaderMagicValue (Hdr);
   1756 
   1757   if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
   1758     //
   1759     // Use PE32 offset
   1760     //
   1761     NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
   1762     DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[0]);
   1763   } else {
   1764     //
   1765     // Use PE32+ offset
   1766     //
   1767     NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
   1768     DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[0]);
   1769   }
   1770 
   1771   //
   1772   // Find the relocation block
   1773   //
   1774   // Per the PE/COFF spec, you can't assume that a given data directory
   1775   // is present in the image. You have to check the NumberOfRvaAndSizes in
   1776   // the optional header to verify a desired directory entry is there.
   1777   //
   1778   if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
   1779     RelocDir      = DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;
   1780     RelocBase     = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress);
   1781     RelocBaseEnd  = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress + RelocDir->Size);
   1782   } else {
   1783     //
   1784     // Cannot find relocations, cannot continue to relocate the image, ASSERT for this invalid image.
   1785     //
   1786     ASSERT (FALSE);
   1787     return ;
   1788   }
   1789 
   1790   //
   1791   // ASSERT for the invalid image when RelocBase and RelocBaseEnd are both NULL.
   1792   //
   1793   ASSERT (RelocBase != NULL && RelocBaseEnd != NULL);
   1794 
   1795   //
   1796   // Run the whole relocation block. And re-fixup data that has not been
   1797   // modified. The FixupData is used to see if the image has been modified
   1798   // since it was relocated. This is so data sections that have been updated
   1799   // by code will not be fixed up, since that would set them back to
   1800   // defaults.
   1801   //
   1802   FixupData = RelocationData;
   1803   while (RelocBase < RelocBaseEnd) {
   1804     //
   1805     // Add check for RelocBase->SizeOfBlock field.
   1806     //
   1807     if ((RelocBase->SizeOfBlock == 0) || (RelocBase->SizeOfBlock > RelocDir->Size)) {
   1808       //
   1809       // Data invalid, cannot continue to relocate the image, just return.
   1810       //
   1811       return;
   1812     }
   1813 
   1814     Reloc     = (UINT16 *) ((UINT8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
   1815     RelocEnd  = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock);
   1816     FixupBase = (CHAR8 *) ((UINTN)ImageBase) + RelocBase->VirtualAddress;
   1817 
   1818     //
   1819     // Run this relocation record
   1820     //
   1821     while (Reloc < RelocEnd) {
   1822 
   1823       Fixup = FixupBase + (*Reloc & 0xFFF);
   1824       switch ((*Reloc) >> 12) {
   1825 
   1826       case EFI_IMAGE_REL_BASED_ABSOLUTE:
   1827         break;
   1828 
   1829       case EFI_IMAGE_REL_BASED_HIGH:
   1830         Fixup16 = (UINT16 *) Fixup;
   1831         if (*(UINT16 *) FixupData == *Fixup16) {
   1832           *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) ((UINT32) Adjust >> 16)));
   1833         }
   1834 
   1835         FixupData = FixupData + sizeof (UINT16);
   1836         break;
   1837 
   1838       case EFI_IMAGE_REL_BASED_LOW:
   1839         Fixup16 = (UINT16 *) Fixup;
   1840         if (*(UINT16 *) FixupData == *Fixup16) {
   1841           *Fixup16 = (UINT16) (*Fixup16 + ((UINT16) Adjust & 0xffff));
   1842         }
   1843 
   1844         FixupData = FixupData + sizeof (UINT16);
   1845         break;
   1846 
   1847       case EFI_IMAGE_REL_BASED_HIGHLOW:
   1848         Fixup32       = (UINT32 *) Fixup;
   1849         FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
   1850         if (*(UINT32 *) FixupData == *Fixup32) {
   1851           *Fixup32 = *Fixup32 + (UINT32) Adjust;
   1852         }
   1853 
   1854         FixupData = FixupData + sizeof (UINT32);
   1855         break;
   1856 
   1857       case EFI_IMAGE_REL_BASED_DIR64:
   1858         Fixup64       = (UINT64 *)Fixup;
   1859         FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));
   1860         if (*(UINT64 *) FixupData == *Fixup64) {
   1861           *Fixup64 = *Fixup64 + (UINT64)Adjust;
   1862         }
   1863 
   1864         FixupData = FixupData + sizeof (UINT64);
   1865         break;
   1866 
   1867       default:
   1868         //
   1869         // Only Itanium requires ConvertPeImage_Ex
   1870         //
   1871         Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);
   1872         if (RETURN_ERROR (Status)) {
   1873           return ;
   1874         }
   1875       }
   1876       //
   1877       // Next relocation record
   1878       //
   1879       Reloc += 1;
   1880     }
   1881     //
   1882     // next reloc block
   1883     //
   1884     RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
   1885   }
   1886 }
   1887 
   1888 
   1889 /**
   1890   Reads contents of a PE/COFF image from a buffer in system memory.
   1891 
   1892   This is the default implementation of a PE_COFF_LOADER_READ_FILE function
   1893   that assumes FileHandle pointer to the beginning of a PE/COFF image.
   1894   This function reads contents of the PE/COFF image that starts at the system memory
   1895   address specified by FileHandle.  The read operation copies ReadSize bytes from the
   1896   PE/COFF image starting at byte offset FileOffset into the buffer specified by Buffer.
   1897   The size of the buffer actually read is returned in ReadSize.
   1898 
   1899   The caller must make sure the FileOffset and ReadSize within the file scope.
   1900 
   1901   If FileHandle is NULL, then ASSERT().
   1902   If ReadSize is NULL, then ASSERT().
   1903   If Buffer is NULL, then ASSERT().
   1904 
   1905   @param  FileHandle        The pointer to base of the input stream
   1906   @param  FileOffset        Offset into the PE/COFF image to begin the read operation.
   1907   @param  ReadSize          On input, the size in bytes of the requested read operation.
   1908                             On output, the number of bytes actually read.
   1909   @param  Buffer            Output buffer that contains the data read from the PE/COFF image.
   1910 
   1911   @retval RETURN_SUCCESS    Data is read from FileOffset from the Handle into
   1912                             the buffer.
   1913 **/
   1914 RETURN_STATUS
   1915 EFIAPI
   1916 PeCoffLoaderImageReadFromMemory (
   1917   IN     VOID    *FileHandle,
   1918   IN     UINTN   FileOffset,
   1919   IN OUT UINTN   *ReadSize,
   1920   OUT    VOID    *Buffer
   1921   )
   1922 {
   1923   ASSERT (ReadSize != NULL);
   1924   ASSERT (FileHandle != NULL);
   1925   ASSERT (Buffer != NULL);
   1926 
   1927   CopyMem (Buffer, ((UINT8 *)FileHandle) + FileOffset, *ReadSize);
   1928   return RETURN_SUCCESS;
   1929 }
   1930 
   1931 /**
   1932   Unloads a loaded PE/COFF image from memory and releases its taken resource.
   1933   Releases any environment specific resources that were allocated when the image
   1934   specified by ImageContext was loaded using PeCoffLoaderLoadImage().
   1935 
   1936   For NT32 emulator, the PE/COFF image loaded by system needs to release.
   1937   For real platform, the PE/COFF image loaded by Core doesn't needs to be unloaded,
   1938   this function can simply return RETURN_SUCCESS.
   1939 
   1940   If ImageContext is NULL, then ASSERT().
   1941 
   1942   @param  ImageContext              The pointer to the image context structure that describes the PE/COFF
   1943                                     image to be unloaded.
   1944 
   1945   @retval RETURN_SUCCESS            The PE/COFF image was unloaded successfully.
   1946 **/
   1947 RETURN_STATUS
   1948 EFIAPI
   1949 PeCoffLoaderUnloadImage (
   1950   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
   1951   )
   1952 {
   1953   //
   1954   // Applies additional environment specific actions to unload a
   1955   // PE/COFF image if needed
   1956   //
   1957   PeCoffLoaderUnloadImageExtraAction (ImageContext);
   1958   return RETURN_SUCCESS;
   1959 }
   1960