Home | History | Annotate | Download | only in FwImage
      1 /*++
      2 
      3 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 Module Name:
     13 
     14   fwimage.c
     15 
     16 Abstract:
     17 
     18   Converts a pe32/pe32+ image to an FW image type
     19 
     20 --*/
     21 
     22 #include <windows.h>
     23 #include <stdio.h>
     24 #include <stdlib.h>
     25 #include <string.h>
     26 #include <time.h>
     27 
     28 #include "TianoCommon.h"
     29 #include "EfiImage.h"
     30 #include "EfiUtilityMsgs.c"
     31 
     32 #define UTILITY_NAME    "FwImage"
     33 #define UTILITY_VERSION "v1.0"
     34 
     35 typedef union {
     36   IMAGE_NT_HEADERS32 PeHeader32;
     37   IMAGE_NT_HEADERS64 PeHeader64;
     38 } PE_HEADER;
     39 
     40 VOID
     41 Usage (
     42   VOID
     43   )
     44 {
     45   int         Index;
     46   const char  *Str[] = {
     47     UTILITY_NAME" "UTILITY_VERSION" - Intel Firmware Image Utility",
     48     "  Copyright (C), 2004 - 2008 Intel Corporation",
     49 
     50 #if ( defined(UTILITY_BUILD) && defined(UTILITY_VENDOR) )
     51     "  Built from "UTILITY_BUILD", project of "UTILITY_VENDOR,
     52 #endif
     53 
     54     "",
     55     "Usage:",
     56     "  "UTILITY_NAME" [OPTION]... FWTYPE SOURCE [DEST]",
     57     "Description:",
     58     "  Converts a pe32/pe32+ SOURCE to DEST with FWTYPE image type.",
     59     "Options:",
     60     "  FWTYPE        Can be one of APPLICATION, BS_DRIVER, RT_DRIVER, SAL_RT_DRIVER,",
     61     "                COMBINED_PEIM_DRIVER, SECURITY_CORE, PEI_CORE, PE32_PEIM and",
     62     "                RELOCATABLE_PEIM",
     63     "  -t time-date  Add Time Stamp for output image",
     64     "  -e            Not clear ExceptionTable for output image",
     65     "  -r            Not strip zero pending of .reloc for output image",
     66     NULL
     67   };
     68 
     69   for (Index = 0; Str[Index] != NULL; Index++) {
     70     fprintf (stdout, "%s\n", Str[Index]);
     71   }
     72 }
     73 
     74 static
     75 STATUS
     76 FReadFile (
     77   FILE    *in,
     78   VOID    **Buffer,
     79   UINTN   *Length
     80   )
     81 {
     82   fseek (in, 0, SEEK_END);
     83   *Length = ftell (in);
     84   *Buffer = malloc (*Length);
     85   fseek (in, 0, SEEK_SET);
     86   fread (*Buffer, *Length, 1, in);
     87   return STATUS_SUCCESS;
     88 }
     89 
     90 static
     91 STATUS
     92 FWriteFile (
     93   FILE    *out,
     94   VOID    *Buffer,
     95   UINTN   Length
     96   )
     97 {
     98   fseek (out, 0, SEEK_SET);
     99   fwrite (Buffer, Length, 1, out);
    100   if ((ULONG) ftell (out) != Length) {
    101     Error (NULL, 0, 0, "write error", NULL);
    102     return STATUS_ERROR;
    103   }
    104   free (Buffer);
    105   return STATUS_SUCCESS;
    106 }
    107 
    108 VOID
    109 ZeroExceptionTable (
    110   IN UINT8                 *FileBuffer,
    111   IN EFI_IMAGE_DOS_HEADER  *DosHdr,
    112   IN PE_HEADER             *PeHdr
    113   )
    114 {
    115   UINT32                   PdataSize;
    116   UINT32                   PdataOffset;
    117   UINT32                   PdataRVASize;
    118   UINT32                   PdataRVA;
    119   UINT32                   SectionOffset;
    120   UINT16                   SectionNumber;
    121   UINT32                   SectionNameSize;
    122   EFI_IMAGE_SECTION_HEADER *Section;
    123 
    124   PdataSize     = 0;
    125   PdataOffset   = 0;
    126   PdataRVASize  = 0;
    127   PdataRVA      = 0;
    128   SectionOffset = 0;
    129 
    130   //
    131   // Search .pdata section
    132   //
    133   if (PeHdr->PeHeader32.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    134     if ((PeHdr->PeHeader32.OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_EXCEPTION) &&
    135         (PeHdr->PeHeader32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress != 0) &&
    136         (PeHdr->PeHeader32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size != 0)) {
    137 
    138       PdataRVA     = PeHdr->PeHeader32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
    139       PdataRVASize = PeHdr->PeHeader32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
    140 
    141       PeHdr->PeHeader32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = 0;
    142       PeHdr->PeHeader32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = 0;
    143 
    144       SectionOffset = sizeof(PeHdr->PeHeader32);
    145     }
    146   } else {
    147     if ((PeHdr->PeHeader64.OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_EXCEPTION) &&
    148         (PeHdr->PeHeader64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress != 0) &&
    149         (PeHdr->PeHeader64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size != 0)) {
    150 
    151       PdataRVA     = PeHdr->PeHeader64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress;
    152       PdataRVASize = PeHdr->PeHeader64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size;
    153 
    154       PeHdr->PeHeader64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = 0;
    155       PeHdr->PeHeader64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = 0;
    156 
    157       SectionOffset = sizeof(PeHdr->PeHeader64);
    158     }
    159   }
    160 
    161   if ((PdataRVASize != 0) && (PdataRVA != 0)) {
    162 
    163     SectionNumber = PeHdr->PeHeader32.FileHeader.NumberOfSections;
    164     SectionNameSize = sizeof(Section->Name);
    165     while (SectionNumber > 0) {
    166       Section = (EFI_IMAGE_SECTION_HEADER *) &FileBuffer[DosHdr->e_lfanew + SectionOffset];
    167       if (strcmp (Section->Name, ".pdata") == 0) {
    168         //
    169         // Zero .pdata Section Header Name
    170         //
    171         memset (
    172           FileBuffer + DosHdr->e_lfanew + SectionOffset,
    173           0,
    174           SectionNameSize);
    175 
    176         //
    177         // Zero .pdata Secton raw data
    178         //
    179         PdataOffset = Section->PointerToRawData;
    180         PdataSize   = Section->SizeOfRawData;
    181         memset (FileBuffer + PdataOffset, 0, PdataSize);
    182         break;
    183       }
    184       SectionNumber--;
    185       SectionOffset += sizeof(EFI_IMAGE_SECTION_HEADER);
    186     }
    187   }
    188 
    189   return ;
    190 }
    191 
    192 VOID
    193 StripZeroPendingReloc (
    194   IN UINT8                 *FileBuffer,
    195   IN OUT UINTN             *FileLength,
    196   IN EFI_IMAGE_DOS_HEADER  *DosHdr,
    197   IN PE_HEADER             *PeHdr
    198   )
    199 {
    200   EFI_IMAGE_OPTIONAL_HEADER32  *Optional32;
    201   EFI_IMAGE_OPTIONAL_HEADER64  *Optional64;
    202   EFI_IMAGE_SECTION_HEADER     *SectionHeader;
    203   UINTN                        AllignedRelocSize;
    204   UINTN                        Index;
    205 
    206   if (PeHdr->PeHeader32.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    207     Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->PeHeader32.OptionalHeader;
    208     if ((Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) &&
    209         (Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size != 0)) {
    210       SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->PeHeader32.FileHeader.SizeOfOptionalHeader);
    211       for (Index = 0; Index < PeHdr->PeHeader32.FileHeader.NumberOfSections; Index++, SectionHeader++) {
    212         //
    213         // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
    214         //
    215         if (strcmp (SectionHeader->Name, ".reloc") == 0) {
    216           SectionHeader->Misc.VirtualSize = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
    217 
    218           AllignedRelocSize = (Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size +
    219                                Optional32->FileAlignment - 1) & (~(Optional32->FileAlignment - 1));
    220           //
    221           // Check to see if there is zero padding at the end of the base relocations
    222           //
    223           if (AllignedRelocSize < SectionHeader->SizeOfRawData) {
    224             //
    225             // Check to see if the base relocations are at the end of the file
    226             //
    227             if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional32->SizeOfImage) {
    228               //
    229               // All the required conditions are met to strip the zero padding of the end of the base relocations section
    230               //
    231               Optional32->SizeOfImage           -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
    232               Optional32->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
    233               SectionHeader->SizeOfRawData       = AllignedRelocSize;
    234               *FileLength                        = Optional32->SizeOfImage;
    235             }
    236           }
    237         }
    238       }
    239     }
    240   } else {
    241     Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->PeHeader64.OptionalHeader;
    242     if ((Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) &&
    243         (Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size != 0)) {
    244       SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->PeHeader64.FileHeader.SizeOfOptionalHeader);
    245       for (Index = 0; Index < PeHdr->PeHeader64.FileHeader.NumberOfSections; Index++, SectionHeader++) {
    246         //
    247         // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory
    248         //
    249         if (strcmp (SectionHeader->Name, ".reloc") == 0) {
    250           SectionHeader->Misc.VirtualSize = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
    251 
    252           AllignedRelocSize = (Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size +
    253                                Optional64->FileAlignment - 1) & (~(Optional64->FileAlignment - 1));
    254           //
    255           // Check to see if there is zero padding at the end of the base relocations
    256           //
    257           if (AllignedRelocSize < SectionHeader->SizeOfRawData) {
    258             //
    259             // Check to see if the base relocations are at the end of the file
    260             //
    261             if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional64->SizeOfImage) {
    262               //
    263               // All the required conditions are met to strip the zero padding of the end of the base relocations section
    264               //
    265               Optional64->SizeOfImage           -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
    266               Optional64->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);
    267               SectionHeader->SizeOfRawData       = AllignedRelocSize;
    268               *FileLength                        = Optional64->SizeOfImage;
    269             }
    270           }
    271         }
    272       }
    273     }
    274   }
    275 }
    276 
    277 int
    278 main (
    279   int  argc,
    280   char *argv[]
    281   )
    282 /*++
    283 
    284 Routine Description:
    285 
    286   Main function.
    287 
    288 Arguments:
    289 
    290   argc - Number of command line parameters.
    291   argv - Array of pointers to command line parameter strings.
    292 
    293 Returns:
    294 
    295   STATUS_SUCCESS - Utility exits successfully.
    296   STATUS_ERROR   - Some error occurred during execution.
    297 
    298 --*/
    299 {
    300   ULONG                        Type;
    301   PUCHAR                       Ext;
    302   PUCHAR                       p;
    303   PUCHAR                       pe;
    304   PUCHAR                       OutImageName;
    305   UCHAR                        outname[500];
    306   FILE                         *fpIn;
    307   FILE                         *fpOut;
    308   EFI_IMAGE_DOS_HEADER         *DosHdr;
    309   PE_HEADER                    *PeHdr;
    310   time_t                       TimeStamp;
    311   struct tm                    TimeStruct;
    312   EFI_IMAGE_DOS_HEADER         BackupDosHdr;
    313   ULONG                        Index;
    314   BOOLEAN                      TimeStampPresent;
    315   BOOLEAN                      NeedClearExceptionTable;
    316   BOOLEAN                      NeedStripZeroPendingReloc;
    317   UINT8                        *FileBuffer;
    318   UINTN                        FileLength;
    319   EFI_IMAGE_OPTIONAL_HEADER32  *Optional32;
    320   EFI_IMAGE_OPTIONAL_HEADER64  *Optional64;
    321 
    322   SetUtilityName (UTILITY_NAME);
    323   //
    324   // Assign to fix compile warning
    325   //
    326   OutImageName      = NULL;
    327   Type              = 0;
    328   Ext               = 0;
    329   TimeStamp         = 0;
    330   TimeStampPresent  = FALSE;
    331 
    332   NeedClearExceptionTable   = TRUE;
    333   NeedStripZeroPendingReloc = TRUE;
    334 
    335   //
    336   // Look for -t time-date option first. If the time is "0", then
    337   // skip it.
    338   //
    339   if ((argc > 2) && !strcmp (argv[1], "-t")) {
    340     TimeStampPresent = TRUE;
    341     if (strcmp (argv[2], "0") != 0) {
    342       //
    343       // Convert the string to a value
    344       //
    345       memset ((char *) &TimeStruct, 0, sizeof (TimeStruct));
    346       if (sscanf(
    347           argv[2], "%d/%d/%d,%d:%d:%d",
    348           &TimeStruct.tm_mon,   /* months since January - [0,11] */
    349           &TimeStruct.tm_mday,  /* day of the month - [1,31] */
    350           &TimeStruct.tm_year,  /* years since 1900 */
    351           &TimeStruct.tm_hour,  /* hours since midnight - [0,23] */
    352           &TimeStruct.tm_min,   /* minutes after the hour - [0,59] */
    353           &TimeStruct.tm_sec    /* seconds after the minute - [0,59] */
    354             ) != 6) {
    355         Error (NULL, 0, 0, argv[2], "failed to convert to mm/dd/yyyy,hh:mm:ss format");
    356         return STATUS_ERROR;
    357       }
    358       //
    359       // Now fixup some of the fields
    360       //
    361       TimeStruct.tm_mon--;
    362       TimeStruct.tm_year -= 1900;
    363       //
    364       // Sanity-check values?
    365       // Convert
    366       //
    367       TimeStamp = mktime (&TimeStruct);
    368       if (TimeStamp == (time_t) - 1) {
    369         Error (NULL, 0, 0, argv[2], "failed to convert time");
    370         return STATUS_ERROR;
    371       }
    372     }
    373     //
    374     // Skip over the args
    375     //
    376     argc -= 2;
    377     argv += 2;
    378   }
    379 
    380   //
    381   // Look for -e option.
    382   //
    383   if ((argc > 1) && !strcmp (argv[1], "-e")) {
    384     NeedClearExceptionTable = FALSE;
    385     //
    386     // Skip over the args
    387     //
    388     argc -= 1;
    389     argv += 1;
    390   }
    391 
    392   //
    393   // Look for -r option
    394   //
    395   if ((argc > 1) && !strcmp (argv[1], "-r")) {
    396     NeedStripZeroPendingReloc = FALSE;
    397     //
    398     // Skip over the args
    399     //
    400     argc -= 1;
    401     argv += 1;
    402   }
    403 
    404   //
    405   // Check for enough args
    406   //
    407   if (argc < 3) {
    408     Usage ();
    409     return STATUS_ERROR;
    410   }
    411 
    412   if (argc == 4) {
    413     OutImageName = argv[3];
    414   }
    415   //
    416   // Get new image type
    417   //
    418   p = argv[1];
    419   if (*p == '/' || *p == '\\') {
    420     p += 1;
    421   }
    422 
    423   if (_stricmp (p, "app") == 0 || _stricmp (p, "APPLICATION") == 0) {
    424     Type  = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;
    425     Ext   = ".efi";
    426 
    427   } else if (_stricmp (p, "bsdrv") == 0 || _stricmp (p, "BS_DRIVER") == 0) {
    428     Type  = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
    429     Ext   = ".efi";
    430 
    431   } else if (_stricmp (p, "rtdrv") == 0 || _stricmp (p, "RT_DRIVER") == 0) {
    432     Type  = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;
    433     Ext   = ".efi";
    434 
    435   } else if (_stricmp (p, "rtdrv") == 0 || _stricmp (p, "SAL_RT_DRIVER") == 0) {
    436     Type  = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;
    437     Ext   = ".efi";
    438   } else if (_stricmp (p, "SECURITY_CORE") == 0) {
    439     Type  = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
    440     Ext   = ".sec";
    441   } else if (_stricmp (p, "peim") == 0 ||
    442            _stricmp (p, "PEI_CORE") == 0 ||
    443            _stricmp (p, "PE32_PEIM") == 0 ||
    444            _stricmp (p, "RELOCATABLE_PEIM") == 0 ||
    445            _stricmp (p, "combined_peim_driver") == 0
    446           ) {
    447     Type  = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;
    448     Ext   = ".pei";
    449   } else {
    450     Usage ();
    451     return STATUS_ERROR;
    452   }
    453   //
    454   // open source file
    455   //
    456   fpIn = fopen (argv[2], "rb");
    457   if (!fpIn) {
    458     Error (NULL, 0, 0, argv[2], "failed to open input file for reading");
    459     return STATUS_ERROR;
    460   }
    461   FReadFile (fpIn, (VOID **)&FileBuffer, &FileLength);
    462   //
    463   // Read the dos & pe hdrs of the image
    464   //
    465   DosHdr = (EFI_IMAGE_DOS_HEADER *) FileBuffer;
    466   if (DosHdr->e_magic != IMAGE_DOS_SIGNATURE) {
    467     Error (NULL, 0, 0, argv[2], "DOS header signature not found in source image");
    468     fclose (fpIn);
    469     return STATUS_ERROR;
    470   }
    471 
    472   PeHdr = (PE_HEADER *)(FileBuffer + DosHdr->e_lfanew);
    473   if (PeHdr->PeHeader32.Signature != IMAGE_NT_SIGNATURE) {
    474     Error (NULL, 0, 0, argv[2], "PE header signature not found in source image");
    475     fclose (fpIn);
    476     return STATUS_ERROR;
    477   }
    478   //
    479   // open output file
    480   //
    481   strcpy (outname, argv[2]);
    482   pe = NULL;
    483   for (p = outname; *p; p++) {
    484     if (*p == '.') {
    485       pe = p;
    486     }
    487   }
    488 
    489   if (!pe) {
    490     pe = p;
    491   }
    492 
    493   strcpy (pe, Ext);
    494 
    495   if (!OutImageName) {
    496     OutImageName = outname;
    497   }
    498 
    499   fpOut = fopen (OutImageName, "w+b");
    500   if (!fpOut) {
    501     Error (NULL, 0, 0, OutImageName, "could not open output file for writing");
    502     fclose (fpIn);
    503     return STATUS_ERROR;
    504   }
    505   //
    506   // Zero all unused fields of the DOS header
    507   //
    508   memcpy (&BackupDosHdr, DosHdr, sizeof (EFI_IMAGE_DOS_HEADER));
    509   memset (DosHdr, 0, sizeof (EFI_IMAGE_DOS_HEADER));
    510   DosHdr->e_magic  = BackupDosHdr.e_magic;
    511   DosHdr->e_lfanew = BackupDosHdr.e_lfanew;
    512 
    513   for (Index = sizeof (EFI_IMAGE_DOS_HEADER); Index < (ULONG) DosHdr->e_lfanew; Index++) {
    514     FileBuffer[Index] = (UINT8) DosHdr->e_cp;
    515   }
    516 
    517   //
    518   // Modify some fields in the PE header
    519   //
    520 
    521   //
    522   // TimeDateStamp's offset is fixed for PE32/32+
    523   //
    524   if (TimeStampPresent) {
    525     PeHdr->PeHeader32.FileHeader.TimeDateStamp = (UINT32) TimeStamp;
    526   }
    527 
    528   //
    529   // PE32/32+ has different optional header layout
    530   // Determine format is PE32 or PE32+ before modification
    531   //
    532   if (PeHdr->PeHeader32.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
    533     //
    534     // PE32 image
    535     //
    536     Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->PeHeader32.OptionalHeader;
    537 
    538     Optional32->MajorLinkerVersion          = 0;
    539     Optional32->MinorLinkerVersion          = 0;
    540     Optional32->MajorOperatingSystemVersion = 0;
    541     Optional32->MinorOperatingSystemVersion = 0;
    542     Optional32->MajorImageVersion           = 0;
    543     Optional32->MinorImageVersion           = 0;
    544     Optional32->MajorSubsystemVersion       = 0;
    545     Optional32->MinorSubsystemVersion       = 0;
    546     Optional32->Win32VersionValue           = 0;
    547     Optional32->CheckSum                    = 0;
    548     Optional32->SizeOfStackReserve          = 0;
    549     Optional32->SizeOfStackCommit           = 0;
    550     Optional32->SizeOfHeapReserve           = 0;
    551     Optional32->SizeOfHeapCommit            = 0;
    552     Optional32->Subsystem                   = (USHORT) Type;
    553 
    554     //
    555     // Strip zero padding at the end of the .reloc section
    556     //
    557     if (NeedStripZeroPendingReloc) {
    558       StripZeroPendingReloc (FileBuffer, &FileLength, DosHdr, PeHdr);
    559     }
    560   } else if (PeHdr->PeHeader32.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
    561     //
    562     // PE32+ image
    563     //
    564     Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->PeHeader64.OptionalHeader;
    565 
    566     Optional64->MajorLinkerVersion          = 0;
    567     Optional64->MinorLinkerVersion          = 0;
    568     Optional64->MajorOperatingSystemVersion = 0;
    569     Optional64->MinorOperatingSystemVersion = 0;
    570     Optional64->MajorImageVersion           = 0;
    571     Optional64->MinorImageVersion           = 0;
    572     Optional64->MajorSubsystemVersion       = 0;
    573     Optional64->MinorSubsystemVersion       = 0;
    574     Optional64->Win32VersionValue           = 0;
    575     Optional64->CheckSum                    = 0;
    576     Optional64->SizeOfStackReserve          = 0;
    577     Optional64->SizeOfStackCommit           = 0;
    578     Optional64->SizeOfHeapReserve           = 0;
    579     Optional64->SizeOfHeapCommit            = 0;
    580     Optional64->Subsystem                   = (USHORT) Type;
    581 
    582     //
    583     // Strip zero padding at the end of the .reloc section
    584     //
    585     if (NeedStripZeroPendingReloc) {
    586       StripZeroPendingReloc (FileBuffer, &FileLength, DosHdr, PeHdr);
    587     }
    588   } else {
    589     Error (NULL, 0, 0, argv[2], "Unsupported PE image");
    590     fclose (fpIn);
    591     fclose (fpOut);
    592     return STATUS_ERROR;
    593   }
    594 
    595   //
    596   // Zero PDATA section for smaller binary size after compression
    597   //
    598   if (NeedClearExceptionTable) {
    599     ZeroExceptionTable (FileBuffer, DosHdr, PeHdr);
    600   }
    601 
    602   FWriteFile (fpOut, FileBuffer, FileLength);
    603 
    604   //
    605   // Done
    606   //
    607   fclose (fpIn);
    608   fclose (fpOut);
    609 
    610   return STATUS_SUCCESS;
    611 }
    612