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