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