]> git.proxmox.com Git - mirror_edk2.git/blobdiff - Tools/Source/TianoTools/FwImage/fwimage.c
1) Simplify implementation by reading the entire input file into memory, modifying...
[mirror_edk2.git] / Tools / Source / TianoTools / FwImage / fwimage.c
index e06e7dc16cb8f9241ac17e84cf89e8497627c81f..ce3a8127b7ca84e8807c2cf5bb967f5cca9dad65 100644 (file)
@@ -90,6 +90,40 @@ FCopyFile (
   return STATUS_SUCCESS;\r
 }\r
 \r
+static\r
+STATUS\r
+FReadFile (\r
+  FILE    *in,\r
+  VOID    **Buffer,\r
+  UINTN   *Length\r
+  )\r
+{\r
+  fseek (in, 0, SEEK_END);\r
+  *Length = ftell (in);\r
+  *Buffer = malloc (*Length);\r
+  fseek (in, 0, SEEK_SET);\r
+  fread (*Buffer, *Length, 1, in);\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
+static\r
+STATUS\r
+FWriteFile (\r
+  FILE    *out,\r
+  VOID    *Buffer,\r
+  UINTN   Length\r
+  )\r
+{\r
+  fseek (out, 0, SEEK_SET);\r
+  fwrite (Buffer, Length, 1, out);\r
+  if ((ULONG) ftell (out) != Length) {\r
+    Error (NULL, 0, 0, "write error", NULL);\r
+    return STATUS_ERROR;\r
+  }\r
+  free (Buffer);\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
 int\r
 main (\r
   int  argc,\r
@@ -120,13 +154,22 @@ Returns:
   UCHAR             outname[500];\r
   FILE              *fpIn;\r
   FILE              *fpOut;\r
-  EFI_IMAGE_DOS_HEADER  DosHdr;\r
-  EFI_IMAGE_NT_HEADERS  PeHdr;\r
+  VOID              *ZeroBuffer;\r
+  EFI_IMAGE_DOS_HEADER  *DosHdr;\r
+  EFI_IMAGE_NT_HEADERS  *PeHdr;\r
+  EFI_IMAGE_OPTIONAL_HEADER32  *Optional32;\r
+  EFI_IMAGE_OPTIONAL_HEADER64  *Optional64;\r
   time_t            TimeStamp;\r
   struct tm         TimeStruct;\r
   EFI_IMAGE_DOS_HEADER  BackupDosHdr;\r
   ULONG             Index;\r
+  ULONG             Index1;\r
   BOOLEAN           TimeStampPresent;\r
+  UINTN                                 RelocSize;\r
+  UINTN                                 Delta;\r
+  EFI_IMAGE_SECTION_HEADER              *SectionHeader;\r
+  UINT8      *FileBuffer;\r
+  UINTN      FileLength;\r
 \r
   SetUtilityName (UTILITY_NAME);\r
   //\r
@@ -245,24 +288,26 @@ Returns:
     Error (NULL, 0, 0, argv[2], "failed to open input file for reading");\r
     return STATUS_ERROR;\r
   }\r
+\r
+  FReadFile (fpIn, (VOID **)&FileBuffer, &FileLength);\r
+\r
   //\r
   // Read the dos & pe hdrs of the image\r
   //\r
-  fseek (fpIn, 0, SEEK_SET);\r
-  fread (&DosHdr, sizeof (DosHdr), 1, fpIn);\r
-  if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
+  DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer;\r
+  if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
     Error (NULL, 0, 0, argv[2], "DOS header signature not found in source image");\r
     fclose (fpIn);\r
     return STATUS_ERROR;\r
   }\r
 \r
-  fseek (fpIn, DosHdr.e_lfanew, SEEK_SET);\r
-  fread (&PeHdr, sizeof (PeHdr), 1, fpIn);\r
-  if (PeHdr.Signature != EFI_IMAGE_NT_SIGNATURE) {\r
+  PeHdr = (EFI_IMAGE_NT_HEADERS *)(FileBuffer + DosHdr->e_lfanew);\r
+  if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
     Error (NULL, 0, 0, argv[2], "PE header signature not found in source image");\r
     fclose (fpIn);\r
     return STATUS_ERROR;\r
   }\r
+\r
   //\r
   // open output file\r
   //\r
@@ -290,42 +335,146 @@ Returns:
     fclose (fpIn);\r
     return STATUS_ERROR;\r
   }\r
-  //\r
-  // Copy the file\r
-  //\r
-  if (FCopyFile (fpIn, fpOut) != STATUS_SUCCESS) {\r
-    fclose (fpIn);\r
-    fclose (fpOut);\r
-    return STATUS_ERROR;\r
-  }\r
+\r
   //\r
   // Zero all unused fields of the DOS header\r
   //\r
-  memcpy (&BackupDosHdr, &DosHdr, sizeof (DosHdr));\r
-  memset (&DosHdr, 0, sizeof (DosHdr));\r
-  DosHdr.e_magic  = BackupDosHdr.e_magic;\r
-  DosHdr.e_lfanew = BackupDosHdr.e_lfanew;\r
-  fseek (fpOut, 0, SEEK_SET);\r
-  fwrite (&DosHdr, sizeof (DosHdr), 1, fpOut);\r
-\r
-  fseek (fpOut, sizeof (DosHdr), SEEK_SET);\r
-  for (Index = sizeof (DosHdr); Index < (ULONG) DosHdr.e_lfanew; Index++) {\r
-    fwrite (&DosHdr.e_cp, 1, 1, fpOut);\r
+  memcpy (&BackupDosHdr, DosHdr, sizeof (EFI_IMAGE_DOS_HEADER));\r
+  memset (DosHdr, 0, sizeof (EFI_IMAGE_DOS_HEADER));\r
+  DosHdr->e_magic  = BackupDosHdr.e_magic;\r
+  DosHdr->e_lfanew = BackupDosHdr.e_lfanew;\r
+\r
+  for (Index = sizeof (EFI_IMAGE_DOS_HEADER); Index < (ULONG) DosHdr->e_lfanew; Index++) {\r
+    FileBuffer[Index] = DosHdr->e_cp;\r
   }\r
+\r
   //\r
   // Path the PE header\r
   //\r
-  PeHdr.OptionalHeader.Subsystem = (USHORT) Type;\r
+  PeHdr->OptionalHeader.Subsystem = (USHORT) Type;\r
   if (TimeStampPresent) {\r
-    PeHdr.FileHeader.TimeDateStamp = (UINT32) TimeStamp;\r
+    PeHdr->FileHeader.TimeDateStamp = (UINT32) TimeStamp;\r
+  }\r
+\r
+  RelocSize = 0;\r
+  if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+    Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->OptionalHeader;\r
+    Optional32->MajorLinkerVersion          = 0;\r
+    Optional32->MinorLinkerVersion          = 0;\r
+    Optional32->MajorOperatingSystemVersion = 0;\r
+    Optional32->MinorOperatingSystemVersion = 0;\r
+    Optional32->MajorImageVersion           = 0;\r
+    Optional32->MinorImageVersion           = 0;\r
+    Optional32->MajorSubsystemVersion       = 0;\r
+    Optional32->MinorSubsystemVersion       = 0;\r
+    Optional32->Win32VersionValue           = 0;\r
+    Optional32->CheckSum                    = 0;\r
+    Optional32->SizeOfStackReserve = 0;\r
+    Optional32->SizeOfStackCommit  = 0;\r
+    Optional32->SizeOfHeapReserve  = 0;\r
+    Optional32->SizeOfHeapCommit   = 0;\r
+\r
+    //\r
+    // Zero the .pdata section if the machine type is X64 and the Debug Directoty entry is empty\r
+    //\r
+    if (PeHdr->FileHeader.Machine == 0x8664) { // X64\r
+      if (Optional32->NumberOfRvaAndSizes >= 4) {\r
+        if (Optional32->NumberOfRvaAndSizes < 7 || (Optional32->NumberOfRvaAndSizes >= 7 && Optional32->DataDirectory[6].Size == 0)) {\r
+          SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
+          for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
+            if (SectionHeader->VirtualAddress == Optional32->DataDirectory[3].VirtualAddress) {\r
+              for (Index1 = 0; Index1 < Optional32->DataDirectory[3].Size; Index1++) {\r
+                FileBuffer[SectionHeader->PointerToRawData + Index1] = 0;\r
+              }\r
+            }\r
+          }\r
+          Optional32->DataDirectory[3].Size = 0;\r
+          Optional32->DataDirectory[3].VirtualAddress = 0;\r
+        }\r
+      }\r
+    }\r
+\r
+    //\r
+    // Strip zero padding at the end of the .reloc section \r
+    //\r
+    if (Optional32->NumberOfRvaAndSizes >= 6) {\r
+      if (Optional32->DataDirectory[5].Size != 0) {\r
+        SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
+        for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
+          if (SectionHeader->VirtualAddress == Optional32->DataDirectory[5].VirtualAddress) {\r
+            FileLength = SectionHeader->PointerToRawData + Optional32->DataDirectory[5].Size;\r
+            FileLength = (FileLength + 7) & 0xfffffff8;\r
+            RelocSize = FileLength - SectionHeader->PointerToRawData;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  } \r
+  if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
+    Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->OptionalHeader;\r
+    Optional64->MajorLinkerVersion          = 0;\r
+    Optional64->MinorLinkerVersion          = 0;\r
+    Optional64->MajorOperatingSystemVersion = 0;\r
+    Optional64->MinorOperatingSystemVersion = 0;\r
+    Optional64->MajorImageVersion           = 0;\r
+    Optional64->MinorImageVersion           = 0;\r
+    Optional64->MajorSubsystemVersion       = 0;\r
+    Optional64->MinorSubsystemVersion       = 0;\r
+    Optional64->Win32VersionValue           = 0;\r
+    Optional64->CheckSum                    = 0;\r
+    Optional64->SizeOfStackReserve = 0;\r
+    Optional64->SizeOfStackCommit  = 0;\r
+    Optional64->SizeOfHeapReserve  = 0;\r
+    Optional64->SizeOfHeapCommit   = 0;\r
+\r
+    //\r
+    // Zero the .pdata section if the machine type is X64 and the Debug Directory is empty\r
+    //\r
+    if (PeHdr->FileHeader.Machine == 0x8664) { // X64\r
+      if (Optional64->NumberOfRvaAndSizes >= 4) {\r
+        if (Optional64->NumberOfRvaAndSizes < 7 || (Optional64->NumberOfRvaAndSizes >= 7 && Optional64->DataDirectory[6].Size == 0)) {\r
+          SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
+          for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
+            if (SectionHeader->VirtualAddress == Optional64->DataDirectory[3].VirtualAddress) {\r
+              for (Index1 = 0; Index1 < Optional64->DataDirectory[3].Size; Index1++) {\r
+                FileBuffer[SectionHeader->PointerToRawData + Index1] = 0;\r
+              }\r
+            }\r
+          }\r
+          Optional64->DataDirectory[3].Size = 0;\r
+          Optional64->DataDirectory[3].VirtualAddress = 0;\r
+        }\r
+      }\r
+    }\r
+\r
+    //\r
+    // Strip zero padding at the end of the .reloc section \r
+    //\r
+    if (Optional64->NumberOfRvaAndSizes >= 6) {\r
+      if (Optional64->DataDirectory[5].Size != 0) {\r
+        SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
+        for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
+          if (SectionHeader->VirtualAddress == Optional64->DataDirectory[5].VirtualAddress) {\r
+            FileLength = SectionHeader->PointerToRawData + Optional64->DataDirectory[5].Size;\r
+            FileLength = (FileLength + 7) & 0xfffffff8;\r
+            RelocSize = FileLength - SectionHeader->PointerToRawData;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  if (RelocSize != 0) {\r
+    SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
+    for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
+      if (strcmp(SectionHeader->Name, ".reloc") == 0) {\r
+        SectionHeader->Misc.VirtualSize = (RelocSize + 0x1f) & 0xffffffe0;\r
+        SectionHeader->SizeOfRawData = RelocSize;\r
+      }\r
+    }\r
   }\r
 \r
-  PeHdr.OptionalHeader.SizeOfStackReserve = 0;\r
-  PeHdr.OptionalHeader.SizeOfStackCommit  = 0;\r
-  PeHdr.OptionalHeader.SizeOfHeapReserve  = 0;\r
-  PeHdr.OptionalHeader.SizeOfHeapCommit   = 0;\r
-  fseek (fpOut, DosHdr.e_lfanew, SEEK_SET);\r
-  fwrite (&PeHdr, sizeof (PeHdr), 1, fpOut);\r
+  FWriteFile (fpOut, FileBuffer, FileLength);\r
 \r
   //\r
   // Done\r