]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/GenFw/Elf32Convert.c
BaseTools/GenFw: disregard payload in PE debug directory entry size
[mirror_edk2.git] / BaseTools / Source / C / GenFw / Elf32Convert.c
index 10d9892ba1e06839e1adcaf8e6284695573d589c..14fe4a285857d694a2e1ab038f05c14a02d73be7 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 Elf32 Convert solution\r
 \r
-Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>\r
 Portions copyright (c) 2013, ARM Ltd. All rights reserved.<BR>\r
 \r
 This program and the accompanying materials are licensed and made available\r
@@ -101,7 +101,7 @@ STATIC UINT32 mCoffAlignment = 0x20;
 //\r
 // PE section alignment.\r
 //\r
-STATIC const UINT16 mCoffNbrSections = 5;\r
+STATIC const UINT16 mCoffNbrSections = 4;\r
 \r
 //\r
 // ELF sections to offset in Coff file.\r
@@ -116,6 +116,7 @@ STATIC UINT32 mTextOffset;
 STATIC UINT32 mDataOffset;\r
 STATIC UINT32 mHiiRsrcOffset;\r
 STATIC UINT32 mRelocOffset;\r
+STATIC UINT32 mDebugOffset;\r
 \r
 //\r
 // Initialization Function\r
@@ -165,6 +166,10 @@ InitializeElf32 (
   // Create COFF Section offset buffer and zero.\r
   //\r
   mCoffSectionsOffset = (UINT32 *)malloc(mEhdr->e_shnum * sizeof (UINT32));\r
+  if (mCoffSectionsOffset == NULL) {\r
+    Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
+    return FALSE;\r
+  }\r
   memset(mCoffSectionsOffset, 0, mEhdr->e_shnum * sizeof(UINT32));\r
 \r
   //\r
@@ -190,8 +195,11 @@ GetShdrByIndex (
   UINT32 Num\r
   )\r
 {\r
-  if (Num >= mEhdr->e_shnum)\r
-    return NULL;\r
+  if (Num >= mEhdr->e_shnum) {\r
+    Error (NULL, 0, 3000, "Invalid", "GetShdrByIndex: Index %u is too high.", Num);\r
+    exit(EXIT_FAILURE);\r
+  }\r
+\r
   return (Elf_Shdr*)((UINT8*)mShdrBase + Num * mEhdr->e_shentsize);\r
 }\r
 \r
@@ -202,7 +210,8 @@ GetPhdrByIndex (
   )\r
 {\r
   if (num >= mEhdr->e_phnum) {\r
-    return NULL;\r
+    Error (NULL, 0, 3000, "Invalid", "GetPhdrByIndex: Index %u is too high.", num);\r
+    exit(EXIT_FAILURE);\r
   }\r
 \r
   return (Elf_Phdr *)((UINT8*)mPhdrBase + num * mEhdr->e_phentsize);\r
@@ -217,6 +226,15 @@ CoffAlign (
   return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1);\r
 }\r
 \r
+STATIC\r
+UINT32\r
+DebugRvaAlign (\r
+  UINT32 Offset\r
+  )\r
+{\r
+  return (Offset + 3) & ~3;\r
+}\r
+\r
 //\r
 // filter functions\r
 //\r
@@ -252,6 +270,66 @@ IsDataShdr (
   return (BOOLEAN) (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);\r
 }\r
 \r
+STATIC\r
+BOOLEAN\r
+IsStrtabShdr (\r
+  Elf_Shdr *Shdr\r
+  )\r
+{\r
+  Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx);\r
+\r
+  return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_STRTAB_SECTION_NAME) == 0);\r
+}\r
+\r
+STATIC\r
+Elf_Shdr *\r
+FindStrtabShdr (\r
+  VOID\r
+  )\r
+{\r
+  UINT32 i;\r
+  for (i = 0; i < mEhdr->e_shnum; i++) {\r
+    Elf_Shdr *shdr = GetShdrByIndex(i);\r
+    if (IsStrtabShdr(shdr)) {\r
+      return shdr;\r
+    }\r
+  }\r
+  return NULL;\r
+}\r
+\r
+STATIC\r
+const UINT8 *\r
+GetSymName (\r
+  Elf_Sym *Sym\r
+  )\r
+{\r
+  Elf_Shdr *StrtabShdr;\r
+  UINT8    *StrtabContents;\r
+  BOOLEAN  foundEnd;\r
+  UINT32   i;\r
+\r
+  if (Sym->st_name == 0) {\r
+    return NULL;\r
+  }\r
+\r
+  StrtabShdr = FindStrtabShdr();\r
+  if (StrtabShdr == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  assert(Sym->st_name < StrtabShdr->sh_size);\r
+\r
+  StrtabContents = (UINT8*)mEhdr + StrtabShdr->sh_offset;\r
+\r
+  foundEnd = FALSE;\r
+  for (i = Sym->st_name; (i < StrtabShdr->sh_size) && !foundEnd; i++) {\r
+    foundEnd = (BOOLEAN)(StrtabContents[i] == 0);\r
+  }\r
+  assert(foundEnd);\r
+\r
+  return StrtabContents + Sym->st_name;\r
+}\r
+\r
 //\r
 // Elf functions interface implementation\r
 //\r
@@ -305,6 +383,16 @@ ScanSections32 (
     }\r
   }\r
 \r
+  //\r
+  // Move the PE/COFF header right before the first section. This will help us\r
+  // save space when converting to TE.\r
+  //\r
+  if (mCoffAlignment > mCoffOffset) {\r
+    mNtHdrOffset += mCoffAlignment - mCoffOffset;\r
+    mTableOffset += mCoffAlignment - mCoffOffset;\r
+    mCoffOffset = mCoffAlignment;\r
+  }\r
+\r
   //\r
   // First text sections.\r
   //\r
@@ -320,12 +408,8 @@ ScanSections32 (
         if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
           // if the section address is aligned we must align PE/COFF\r
           mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);\r
-        } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {\r
-          // ARM RVCT tools have behavior outside of the ELF specification to try\r
-          // and make images smaller.  If sh_addr is not aligned to sh_addralign\r
-          // then the section needs to preserve sh_addr MOD sh_addralign.\r
-          // Normally doing nothing here works great.\r
-          Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");\r
+        } else {\r
+          Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
         }\r
       }\r
 \r
@@ -354,9 +438,8 @@ ScanSections32 (
     assert (FALSE);\r
   }\r
 \r
-  if (mEhdr->e_machine != EM_ARM) {\r
-    mCoffOffset = CoffAlign(mCoffOffset);\r
-  }\r
+  mDebugOffset = DebugRvaAlign(mCoffOffset);\r
+  mCoffOffset = CoffAlign(mCoffOffset);\r
 \r
   if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
     Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName);\r
@@ -376,12 +459,8 @@ ScanSections32 (
         if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
           // if the section address is aligned we must align PE/COFF\r
           mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);\r
-        } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {\r
-          // ARM RVCT tools have behavior outside of the ELF specification to try\r
-          // and make images smaller.  If sh_addr is not aligned to sh_addralign\r
-          // then the section needs to preserve sh_addr MOD sh_addralign.\r
-          // Normally doing nothing here works great.\r
-          Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");\r
+        } else {\r
+          Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
         }\r
       }\r
 \r
@@ -398,12 +477,29 @@ ScanSections32 (
       SectionCount ++;\r
     }\r
   }\r
-  mCoffOffset = CoffAlign(mCoffOffset);\r
 \r
   if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
     Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName);\r
   }\r
 \r
+  //\r
+  // Make room for .debug data in .data (or .text if .data is empty) instead of\r
+  // putting it in a section of its own. This is explicitly allowed by the\r
+  // PE/COFF spec, and prevents bloat in the binary when using large values for\r
+  // section alignment.\r
+  //\r
+  if (SectionCount > 0) {\r
+    mDebugOffset = DebugRvaAlign(mCoffOffset);\r
+  }\r
+  mCoffOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) +\r
+                sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) +\r
+                strlen(mInImageName) + 1;\r
+\r
+  mCoffOffset = CoffAlign(mCoffOffset);\r
+  if (SectionCount == 0) {\r
+    mDataOffset = mCoffOffset;\r
+  }\r
+\r
   //\r
   //  The HII resource sections.\r
   //\r
@@ -416,12 +512,8 @@ ScanSections32 (
         if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
           // if the section address is aligned we must align PE/COFF\r
           mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);\r
-        } else if ((shdr->sh_addr % shdr->sh_addralign) != (mCoffOffset % shdr->sh_addralign)) {\r
-          // ARM RVCT tools have behavior outside of the ELF specification to try\r
-          // and make images smaller.  If sh_addr is not aligned to sh_addralign\r
-          // then the section needs to preserve sh_addr MOD sh_addralign.\r
-          // Normally doing nothing here works great.\r
-          Error (NULL, 0, 3000, "Invalid", "Unsupported section alignment.");\r
+        } else {\r
+          Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
         }\r
       }\r
       if (shdr->sh_size != 0) {\r
@@ -441,6 +533,10 @@ ScanSections32 (
   // Allocate base Coff file.  Will be expanded later for relocations.\r
   //\r
   mCoffFile = (UINT8 *)malloc(mCoffOffset);\r
+  if (mCoffFile == NULL) {\r
+    Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
+  }\r
+  assert (mCoffFile != NULL);\r
   memset(mCoffFile, 0, mCoffOffset);\r
 \r
   //\r
@@ -464,7 +560,7 @@ ScanSections32 (
     NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
     break;\r
   default:\r
-    VerboseMsg ("%s unknown e_machine type. Assume IA-32", (UINTN)mEhdr->e_machine);\r
+    VerboseMsg ("%s unknown e_machine type %hu. Assume IA-32", mInImageName, mEhdr->e_machine);\r
     NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_IA32;\r
     NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
   }\r
@@ -643,9 +739,18 @@ WriteSections32 (
         // header location.\r
         //\r
         if (Sym->st_shndx == SHN_UNDEF\r
-            || Sym->st_shndx == SHN_ABS\r
-            || Sym->st_shndx > mEhdr->e_shnum) {\r
-          Error (NULL, 0, 3000, "Invalid", "%s bad symbol definition.", mInImageName);\r
+            || Sym->st_shndx >= mEhdr->e_shnum) {\r
+          const UINT8 *SymName = GetSymName(Sym);\r
+          if (SymName == NULL) {\r
+            SymName = (const UINT8 *)"<unknown>";\r
+          }\r
+\r
+          Error (NULL, 0, 3000, "Invalid",\r
+                 "%s: Bad definition for symbol '%s'@%#x or unsupported symbol type.  "\r
+                 "For example, absolute and undefined symbols are not supported.",\r
+                 mInImageName, SymName, Sym->st_value);\r
+\r
+          exit(EXIT_FAILURE);\r
         }\r
         SymShdr = GetShdrByIndex(Sym->st_shndx);\r
 \r
@@ -692,6 +797,7 @@ WriteSections32 (
             // break skipped\r
 \r
           case R_ARM_PC24:\r
+          case R_ARM_REL32:\r
           case R_ARM_XPC25:\r
           case R_ARM_THM_PC22:\r
           case R_ARM_THM_JUMP19:\r
@@ -779,9 +885,7 @@ WriteRelocations32 (
   UINTN                            RelSize;\r
   UINTN                            RelOffset;\r
   UINTN                            K;\r
-  UINT8                            *Targ;\r
   Elf32_Phdr                       *DynamicSegment;\r
-  Elf32_Phdr                       *TargetSegment;\r
 \r
   for (Index = 0, FoundRelocations = FALSE; Index < mEhdr->e_shnum; Index++) {\r
     Elf_Shdr *RelShdr = GetShdrByIndex(Index);\r
@@ -792,7 +896,7 @@ WriteRelocations32 (
 \r
         FoundRelocations = TRUE;\r
         for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {\r
-          Elf_Rel  *Rel = (Elf_Rel *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
+          Rel = (Elf_Rel *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
 \r
           if (mEhdr->e_machine == EM_386) { \r
             switch (ELF_R_TYPE(Rel->r_info)) {\r
@@ -820,6 +924,7 @@ WriteRelocations32 (
               // break skipped\r
 \r
             case R_ARM_PC24:\r
+            case R_ARM_REL32:\r
             case R_ARM_XPC25:\r
             case R_ARM_THM_PC22:\r
             case R_ARM_THM_JUMP19:\r
@@ -931,6 +1036,31 @@ WriteRelocations32 (
           Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations.", mInImageName);\r
         }\r
 \r
+        for (Index = 0; Index < mEhdr->e_shnum; Index++) {\r
+          Elf_Shdr *shdr = GetShdrByIndex(Index);\r
+\r
+          //\r
+          // The PT_DYNAMIC section contains DT_REL relocations whose r_offset\r
+          // field is relative to the base of a segment (or the entire image),\r
+          // and not to the base of an ELF input section as is the case for\r
+          // SHT_REL sections. This means that we cannot fix up such relocations\r
+          // unless we cross-reference ELF sections and segments, considering\r
+          // that the output placement recorded in mCoffSectionsOffset[] is\r
+          // section based, not segment based.\r
+          //\r
+          // Fortunately, there is a simple way around this: we require that the\r
+          // in-memory layout of the ELF and PE/COFF versions of the binary is\r
+          // identical. That way, r_offset will retain its validity as a PE/COFF\r
+          // image offset, and we can record it in the COFF fixup table\r
+          // unmodified.\r
+          //\r
+          if (shdr->sh_addr != mCoffSectionsOffset[Index]) {\r
+            Error (NULL, 0, 3000,\r
+              "Invalid", "%s: PT_DYNAMIC relocations require identical ELF and PE/COFF section offsets.",\r
+              mInImageName);\r
+          }\r
+        }\r
+\r
         for (K = 0; K < RelSize; K += RelElementSize) {\r
 \r
           if (DynamicSegment->p_paddr == 0) {\r
@@ -947,14 +1077,7 @@ WriteRelocations32 (
             break;\r
 \r
           case  R_ARM_RABS32:\r
-            TargetSegment = GetPhdrByIndex (ELF32_R_SYM (Rel->r_info) - 1);\r
-\r
-            // Note: r_offset in a memory address.  Convert it to a pointer in the coff file.\r
-            Targ = mCoffFile + mCoffSectionsOffset[ ELF32_R_SYM( Rel->r_info ) ] + Rel->r_offset - TargetSegment->p_vaddr;\r
-\r
-            *(UINT32 *)Targ = *(UINT32 *)Targ + mCoffSectionsOffset [ELF32_R_SYM( Rel->r_info )];\r
-\r
-            CoffAddFixup (mCoffSectionsOffset[ELF32_R_SYM (Rel->r_info)] + (Rel->r_offset - TargetSegment->p_vaddr), EFI_IMAGE_REL_BASED_HIGHLOW);\r
+            CoffAddFixup (Rel->r_offset, EFI_IMAGE_REL_BASED_HIGHLOW);\r
             break;\r
           \r
           default:\r
@@ -998,28 +1121,18 @@ WriteDebug32 (
   )\r
 {\r
   UINT32                              Len;\r
-  UINT32                              DebugOffset;\r
   EFI_IMAGE_OPTIONAL_HEADER_UNION     *NtHdr;\r
   EFI_IMAGE_DATA_DIRECTORY            *DataDir;\r
   EFI_IMAGE_DEBUG_DIRECTORY_ENTRY     *Dir;\r
   EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;\r
 \r
   Len = strlen(mInImageName) + 1;\r
-  DebugOffset = mCoffOffset;\r
 \r
-  mCoffOffset += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)\r
-    + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)\r
-    + Len;\r
-  mCoffOffset = CoffAlign(mCoffOffset);\r
-\r
-  mCoffFile = realloc(mCoffFile, mCoffOffset);\r
-  memset(mCoffFile + DebugOffset, 0, mCoffOffset - DebugOffset);\r
-\r
-  Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + DebugOffset);\r
+  Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + mDebugOffset);\r
   Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;\r
   Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;\r
-  Dir->RVA = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
-  Dir->FileOffset = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
+  Dir->RVA = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
+  Dir->FileOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
 \r
   Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);\r
   Nb10->Signature = CODEVIEW_SIGNATURE_NB10;\r
@@ -1028,20 +1141,8 @@ WriteDebug32 (
 \r
   NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
   DataDir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
-  DataDir->VirtualAddress = DebugOffset;\r
-  DataDir->Size = mCoffOffset - DebugOffset;\r
-  if (DataDir->Size == 0) {\r
-    // If no debug, null out the directory entry and don't add the .debug section\r
-    DataDir->VirtualAddress = 0;\r
-    NtHdr->Pe32.FileHeader.NumberOfSections--;\r
-  } else {\r
-    DataDir->VirtualAddress = DebugOffset;\r
-    CreateSectionHeader (".debug", DebugOffset, mCoffOffset - DebugOffset,\r
-            EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
-            | EFI_IMAGE_SCN_MEM_DISCARDABLE\r
-            | EFI_IMAGE_SCN_MEM_READ);\r
-\r
-  }\r
+  DataDir->VirtualAddress = mDebugOffset;\r
+  DataDir->Size = sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
 }\r
 \r
 STATIC\r