Add support to convert missing Elf relocation types
(R_X86_64_PLT32, R_X86_64_GOTPCREL, R_X86_64_REX_GOTPCRELX)
to PeCoff, which are required by LTO image.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Steven Shi <steven....@intel.com>
---
 BaseTools/Source/C/GenFw/Elf64Convert.c | 98 ++++++++++++++++++++++++++++-----
 BaseTools/Source/C/GenFw/elf_common.h   |  2 +-
 2 files changed, 86 insertions(+), 14 deletions(-)
 mode change 100644 => 100755 BaseTools/Source/C/GenFw/Elf64Convert.c
 mode change 100644 => 100755 BaseTools/Source/C/GenFw/elf_common.h

diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c 
b/BaseTools/Source/C/GenFw/Elf64Convert.c
old mode 100644
new mode 100755
index 024a2a0..205360c
--- a/BaseTools/Source/C/GenFw/Elf64Convert.c
+++ b/BaseTools/Source/C/GenFw/Elf64Convert.c
@@ -75,7 +75,7 @@ CleanUp64 (
   );
 
 //
-// Rename ELF32 strucutres to common names to help when porting to ELF64.
+// Rename ELF32 structures to common names to help when porting to ELF64.
 //
 typedef Elf64_Shdr Elf_Shdr;
 typedef Elf64_Ehdr Elf_Ehdr;
@@ -233,7 +233,7 @@ IsTextShdr (
   Elf_Shdr *Shdr
   )
 {
-  return (BOOLEAN) ((Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC);
+  return (BOOLEAN) ((Shdr->sh_flags & (SHF_EXECINSTR | SHF_WRITE | SHF_ALLOC)) 
== (SHF_EXECINSTR | SHF_ALLOC));
 }
 
 STATIC
@@ -256,7 +256,7 @@ IsDataShdr (
   if (IsHiiRsrcShdr(Shdr)) {
     return FALSE;
   }
-  return (BOOLEAN) (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | 
SHF_WRITE);
+  return (BOOLEAN) (Shdr->sh_flags & (SHF_EXECINSTR | SHF_WRITE | SHF_ALLOC)) 
== (SHF_ALLOC | SHF_WRITE);
 }
 
 STATIC
@@ -661,9 +661,9 @@ WriteSections64 (
 
       default:
         //
-        //  Ignore for unkown section type.
+        //  Ignore for unknown section type.
         //
-        VerboseMsg ("%s unknown section type %x. We directly copy this section 
into Coff file", mInImageName, (unsigned)Shdr->sh_type);
+        VerboseMsg ("%s unknown section type %x. We directly ignore this 
section and NOT copy into Coff file", mInImageName, (unsigned)Shdr->sh_type);
         break;
       }
     }
@@ -763,24 +763,24 @@ WriteSections64 (
             // Absolute relocation.
             //
             VerboseMsg ("R_X86_64_64");
-            VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX", 
-              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), 
+            VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX",
+              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),
               *(UINT64 *)Targ);
             *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + 
mCoffSectionsOffset[Sym->st_shndx];
             VerboseMsg ("Relocation:  0x%016LX", *(UINT64*)Targ);
             break;
           case R_X86_64_32:
             VerboseMsg ("R_X86_64_32");
-            VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", 
-              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), 
+            VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",
+              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),
               *(UINT32 *)Targ);
             *(UINT32 *)Targ = (UINT32)((UINT64)(*(UINT32 *)Targ) - 
SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);
             VerboseMsg ("Relocation:  0x%08X", *(UINT32*)Targ);
             break;
           case R_X86_64_32S:
             VerboseMsg ("R_X86_64_32S");
-            VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", 
-              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), 
+            VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",
+              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),
               *(UINT32 *)Targ);
             *(INT32 *)Targ = (INT32)((INT64)(*(INT32 *)Targ) - 
SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);
             VerboseMsg ("Relocation:  0x%08X", *(UINT32*)Targ);
@@ -790,14 +790,34 @@ WriteSections64 (
             // Relative relocation: Symbol - Ip + Addend
             //
             VerboseMsg ("R_X86_64_PC32");
-            VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", 
-              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), 
+            VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",
+              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),
               *(UINT32 *)Targ);
             *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ
               + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)
               - (SecOffset - SecShdr->sh_addr));
             VerboseMsg ("Relocation:  0x%08X", *(UINT32 *)Targ);
             break;
+          case R_X86_64_PLT32:
+            //
+            // Relative relocation: L + A - P
+            //
+            VerboseMsg ("R_X86_64_PLT32");
+            VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X",
+              (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)),
+              *(UINT32 *)Targ);
+            *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ
+              + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)
+              - (SecOffset - SecShdr->sh_addr));
+            VerboseMsg ("Relocation:  0x%08X", *(UINT32 *)Targ);
+            break;
+          case R_X86_64_GOTPCREL:
+          case R_X86_64_REX_GOTPCRELX:
+            //
+            // Relative relocation: G + GOT + A - P
+            //
+            VerboseMsg ("R_X86_64_GOTPCREL");
+            break;
           default:
             Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 
relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
           }
@@ -887,6 +907,12 @@ WriteRelocations64 (
   UINT32                           Index;
   EFI_IMAGE_OPTIONAL_HEADER_UNION  *NtHdr;
   EFI_IMAGE_DATA_DIRECTORY         *Dir;
+  UINT64                           GoTPcRelPtrOffset = 0;
+  UINT64                           *RipDisplacementPtr;
+  UINT64                           *ElfFileGoTPcRelPtr;
+  UINT64                           *CoffFileGoTPcRelPtr;
+  Elf_Shdr                         *shdr;
+  UINT32                           i;
 
   for (Index = 0; Index < mEhdr->e_shnum; Index++) {
     Elf_Shdr *RelShdr = GetShdrByIndex(Index);
@@ -902,6 +928,52 @@ WriteRelocations64 (
             switch (ELF_R_TYPE(Rel->r_info)) {
             case R_X86_64_NONE:
             case R_X86_64_PC32:
+            case R_X86_64_PLT32:
+              break;
+            case R_X86_64_GOTPCREL:
+            case R_X86_64_REX_GOTPCRELX:
+              //
+              // link script force .got and .got.* in .text section, so 
GoTPcRel pointer must be in .text section
+              // but its value might point to .text or .data section
+              //
+              RipDisplacementPtr  = (UINT64 *)((UINT8*)mEhdr + 
SecShdr->sh_offset + Rel->r_offset - SecShdr->sh_addr);
+              GoTPcRelPtrOffset   = Rel->r_offset + 4 + 
(INT32)(*RipDisplacementPtr) - SecShdr->sh_addr;
+              ElfFileGoTPcRelPtr  = (UINT64 *)((UINT8*)mEhdr + 
SecShdr->sh_offset + GoTPcRelPtrOffset);
+              CoffFileGoTPcRelPtr = (UINT64 *)(mCoffFile + 
mCoffSectionsOffset[RelShdr->sh_info] + GoTPcRelPtrOffset);
+              //
+              // Check which section the GoTPcRel pointer point to, and 
calculate Elf to Coff sections displacement accordingly
+              //
+              shdr = NULL;
+              for (i = 0; i < mEhdr->e_shnum; i++) {
+                shdr = GetShdrByIndex(i);
+                if ((*ElfFileGoTPcRelPtr >= shdr->sh_addr) &&
+                    (*ElfFileGoTPcRelPtr < shdr->sh_addr + shdr->sh_size)) {
+                  break;
+                }
+              }
+              //
+              // Fix the Elf to Coff sections displacement
+              //
+              if(IsDataShdr(shdr)) {
+                *CoffFileGoTPcRelPtr = *CoffFileGoTPcRelPtr + mDataOffset - 
shdr->sh_addr;
+              }else if (IsTextShdr(SecShdr)){
+                *CoffFileGoTPcRelPtr = *CoffFileGoTPcRelPtr + mTextOffset - 
shdr->sh_addr;
+              }else {
+                //
+                // link script force to merge .rodata .rodata.*, .got and 
.got.* in .text section,
+                // not support GoTPcRel point to section other than .data or 
.text
+                //
+                Error (NULL, 0, 3000, "Invalid", "Not support relocate 
R_X86_64_GOTPCREL address in section other than .data or .text");
+                assert (FALSE);
+              }
+
+              VerboseMsg ("R_X86_64_GOTPCREL to EFI_IMAGE_REL_BASED_DIR64 
Offset: 0x%08X",
+                mCoffSectionsOffset[RelShdr->sh_info] + GoTPcRelPtrOffset);
+              CoffAddFixup(
+                (UINT32)(UINTN)((UINT64) mCoffSectionsOffset[RelShdr->sh_info] 
+ GoTPcRelPtrOffset),
+                EFI_IMAGE_REL_BASED_DIR64);
+              VerboseMsg ("Relocation: 0x%08X", *(UINT64*)CoffFileGoTPcRelPtr);
+
               break;
             case R_X86_64_64:
               VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", 
diff --git a/BaseTools/Source/C/GenFw/elf_common.h 
b/BaseTools/Source/C/GenFw/elf_common.h
old mode 100644
new mode 100755
index 766d0e4..caaae23
--- a/BaseTools/Source/C/GenFw/elf_common.h
+++ b/BaseTools/Source/C/GenFw/elf_common.h
@@ -1052,6 +1052,6 @@ typedef struct {
 #define        R_X86_64_DTPOFF32       21      /* Offset in TLS block */
 #define        R_X86_64_GOTTPOFF       22      /* PC relative offset to IE GOT 
entry */
 #define        R_X86_64_TPOFF32        23      /* Offset in static TLS block */
-
+#define R_X86_64_REX_GOTPCRELX  0x2a
 
 #endif /* !_SYS_ELF_COMMON_H_ */
-- 
2.7.4

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to