What's purpose to support GOTPCREL in GenFw? Could you introduce your usage model?
> -----Original Message----- > From: Zenith432 [mailto:zenith...@users.sourceforge.net] > Sent: Thursday, June 7, 2018 2:01 AM > To: edk2-devel@lists.01.org > Cc: Shi, Steven <steven....@intel.com>; Zhu, Yonghong > <yonghong....@intel.com>; Gao, Liming <liming....@intel.com> > Subject: [PATCH] BaseTools/GenFw: Add X64 GOTPCREL Support to GenFw > > Adds support for the following X64 ELF relocations to GenFw > R_X86_64_GOTPCREL > R_X86_64_GOTPCRELX > R_X86_64_REX_GOTPCRELX > > CC: Shi Steven <steven....@intel.com> > CC: Yonghong Zhu <yonghong....@intel.com> > CC: Liming Gao <liming....@intel.com> > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Zenith432 <zenith...@users.sourceforge.net> > --- > BaseTools/Source/C/GenFw/Elf64Convert.c | 166 +++++++++++++++++++++++- > BaseTools/Source/C/GenFw/elf_common.h | 23 ++++ > 2 files changed, 188 insertions(+), 1 deletion(-) > > diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c > b/BaseTools/Source/C/GenFw/Elf64Convert.c > index c39bdff0..d2f9bb46 100644 > --- a/BaseTools/Source/C/GenFw/Elf64Convert.c > +++ b/BaseTools/Source/C/GenFw/Elf64Convert.c > @@ -94,6 +94,15 @@ STATIC Elf_Ehdr *mEhdr; > STATIC Elf_Shdr *mShdrBase; > STATIC Elf_Phdr *mPhdrBase; > > +// > +// GOT information > +// > +STATIC Elf_Shdr *mGOTShdr = NULL; > +STATIC UINT32 mGOTShindex = 0; > +STATIC UINT32 *mGOTCoffEntries = NULL; > +STATIC UINT32 mGOTMaxCoffEntries = 0; > +STATIC UINT32 mGOTNumCoffEntries = 0; > + > // > // Coff information > // > @@ -322,6 +331,117 @@ GetSymName ( > return StrtabContents + Sym->st_name; > } > > +// > +// Find the ELF section hosting the GOT from an ELF Rva > +// of a single GOT entry. Normally, GOT is placed in > +// ELF .text section, so assume once we find in which > +// section the GOT is, all GOT entries are there, and > +// just verify this. > +// > +STATIC > +VOID > +FindElfGOTSectionFromGOTEntryElfRva ( > + Elf64_Addr GOTEntryElfRva > + ) > +{ > + UINT32 i; > + if (mGOTShdr != NULL) { > + if (GOTEntryElfRva >= mGOTShdr->sh_addr && > + GOTEntryElfRva < mGOTShdr->sh_addr + mGOTShdr->sh_size) > + return; > + Error (NULL, 0, 3000, "Unsupported", > "FindElfGOTSectionFromGOTEntryElfRva: GOT entries found in multiple > sections."); > + exit(EXIT_FAILURE); > + } > + for (i = 0; i < mEhdr->e_shnum; i++) { > + Elf_Shdr *shdr = GetShdrByIndex(i); > + if (GOTEntryElfRva >= shdr->sh_addr && > + GOTEntryElfRva < shdr->sh_addr + shdr->sh_size) { > + mGOTShdr = shdr; > + mGOTShindex = i; > + return; > + } > + } > + Error (NULL, 0, 3000, "Invalid", "FindElfGOTSectionFromGOTEntryElfRva: > ElfRva 0x%016LX for GOT entry not found in any section.", > GOTEntryElfRva); > + exit(EXIT_FAILURE); > +} > + > +// > +// Stores locations of GOT entries in COFF image. > +// Returns TRUE if GOT entry is new. > +// Simple implementation as number of GOT > +// entries is expected to be low. > +// > + > +STATIC > +BOOLEAN > +AccumulateCoffGOTEntries ( > + UINT32 GOTCoffEntry > + ) > +{ > + UINT32 i; > + if (mGOTCoffEntries != NULL) { > + for (i = 0; i < mGOTNumCoffEntries; i++) > + if (mGOTCoffEntries[i] == GOTCoffEntry) > + return FALSE; > + } > + if (mGOTCoffEntries == NULL) { > + mGOTCoffEntries = (UINT32*)malloc(5 * sizeof *mGOTCoffEntries); > + if (mGOTCoffEntries == NULL) { > + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); > + } > + assert (mGOTCoffEntries != NULL); > + mGOTMaxCoffEntries = 5; > + mGOTNumCoffEntries = 0; > + } else if (mGOTNumCoffEntries == mGOTMaxCoffEntries) { > + mGOTCoffEntries = (UINT32*)realloc(mGOTCoffEntries, 2 * > mGOTMaxCoffEntries * sizeof *mGOTCoffEntries); > + if (mGOTCoffEntries == NULL) { > + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); > + } > + assert (mGOTCoffEntries != NULL); > + mGOTMaxCoffEntries += mGOTMaxCoffEntries; > + } > + mGOTCoffEntries[mGOTNumCoffEntries++] = GOTCoffEntry; > + return TRUE; > +} > + > +STATIC > +int > +__comparator ( > + const void* lhs, > + const void* rhs > + ) > +{ > + if (*(const UINT32*)lhs < *(const UINT32*)rhs) > + return -1; > + return *(const UINT32*)lhs > *(const UINT32*)rhs; > +} > + > +STATIC > +VOID > +EmitGOTRelocations ( > + VOID > + ) > +{ > + UINT32 i; > + if (mGOTCoffEntries == NULL) > + return; > + qsort( > + mGOTCoffEntries, > + mGOTNumCoffEntries, > + sizeof *mGOTCoffEntries, > + __comparator); > + for (i = 0; i < mGOTNumCoffEntries; i++) { > + VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", > mGOTCoffEntries[i]); > + CoffAddFixup( > + mGOTCoffEntries[i], > + EFI_IMAGE_REL_BASED_DIR64); > + } > + free(mGOTCoffEntries); > + mGOTCoffEntries = NULL; > + mGOTMaxCoffEntries = 0; > + mGOTNumCoffEntries = 0; > +} > + > // > // Elf functions interface implementation > // > @@ -698,7 +818,7 @@ WriteSections64 ( > // section that applies to the entire binary, and which will have its > section > // index set to #0 (which is a NULL section with the SHF_ALLOC bit > cleared). > // > - // In the absence of GOT based relocations (which we currently don't > support), > + // In the absence of GOT based relocations, > // this RELA section will contain redundant R_xxx_RELATIVE relocations, > one > // for every R_xxx_xx64 relocation appearing in the per-section RELA > sections. > // (i.e., .rela.text and .rela.data) > @@ -780,6 +900,7 @@ WriteSections64 ( > // Determine how to handle each relocation type based on the machine > type. > // > if (mEhdr->e_machine == EM_X86_64) { > + Elf64_Addr GOTEntryRva; > switch (ELF_R_TYPE(Rel->r_info)) { > case R_X86_64_NONE: > break; > @@ -834,6 +955,32 @@ WriteSections64 ( > - (SecOffset - SecShdr->sh_addr)); > VerboseMsg ("Relocation: 0x%08X", *(UINT32 *)Targ); > break; > + case R_X86_64_GOTPCREL: > + case R_X86_64_GOTPCRELX: > + case R_X86_64_REX_GOTPCRELX: > + VerboseMsg ("R_X86_64_GOTPCREL family"); > + VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", > + (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), > + *(UINT32 *)Targ); > + GOTEntryRva = Rel->r_offset - Rel->r_addend + *(UINT32 *)Targ; > + FindElfGOTSectionFromGOTEntryElfRva(GOTEntryRva); > + *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ > + + (mCoffSectionsOffset[mGOTShindex] - mGOTShdr->sh_addr) > + - (SecOffset - SecShdr->sh_addr)); > + VerboseMsg ("Relocation: 0x%08X", *(UINT32 *)Targ); > + GOTEntryRva += (mCoffSectionsOffset[mGOTShindex] - > mGOTShdr->sh_addr); // ELF Rva -> COFF Rva > + if (AccumulateCoffGOTEntries((UINT32)GOTEntryRva)) { > + // > + // Relocate GOT entry if it's the first time we run into it > + // > + Targ = mCoffFile + GOTEntryRva; > + VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX", > + (UINT32)GOTEntryRva, > + *(UINT64 *)Targ); > + *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + > mCoffSectionsOffset[Sym->st_shndx]; > + VerboseMsg ("Relocation: 0x%016LX", *(UINT64*)Targ); > + } > + break; > default: > Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 > relocation 0x%x.", mInImageName, (unsigned) > ELF_R_TYPE(Rel->r_info)); > } > @@ -972,6 +1119,9 @@ WriteRelocations64 ( > case R_X86_64_NONE: > case R_X86_64_PC32: > case R_X86_64_PLT32: > + case R_X86_64_GOTPCREL: > + case R_X86_64_GOTPCRELX: > + case R_X86_64_REX_GOTPCRELX: > break; > case R_X86_64_64: > VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", > @@ -1040,10 +1190,24 @@ WriteRelocations64 ( > Error (NULL, 0, 3000, "Not Supported", "This tool does not > support relocations for ELF with e_machine %u (processor > type).", (unsigned) mEhdr->e_machine); > } > } > + if (mEhdr->e_machine == EM_X86_64 && RelShdr->sh_info == > mGOTShindex) { > + // > + // Tack relocations for GOT entries after other relocations for > + // the section the GOT is in, as it's usually found at the end > + // of the section. > + // > + EmitGOTRelocations(); > + } > } > } > } > > + if (mEhdr->e_machine == EM_X86_64) { > + // > + // Just in case GOT is in a section with no other relocations > + // > + EmitGOTRelocations(); > + } > // > // Pad by adding empty entries. > // > diff --git a/BaseTools/Source/C/GenFw/elf_common.h > b/BaseTools/Source/C/GenFw/elf_common.h > index 766d0e42..50b4e1f2 100644 > --- a/BaseTools/Source/C/GenFw/elf_common.h > +++ b/BaseTools/Source/C/GenFw/elf_common.h > @@ -544,6 +544,12 @@ typedef struct { > #define R_386_TLS_DTPMOD32 35 /* GOT entry containing TLS > index */ > #define R_386_TLS_DTPOFF32 36 /* GOT entry containing TLS > offset */ > #define R_386_TLS_TPOFF32 37 /* GOT entry of -ve static TLS > offset */ > +#define R_386_SIZE32 38 /* 32-bit symbol size */ > +#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS > descriptor. */ > +#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS > descriptor for relaxation. */ > +#define R_386_TLS_DESC 41 /* TLS descriptor containing > pointer to code and to argument, returning the TLS offset for the > symbol. */ > +#define R_386_IRELATIVE 42 /* Adjust indirectly by program > base */ > +#define R_386_GOT32X 43 /* Load from 32 bit GOT entry, > relaxable. */ > > /* Null relocation */ > #define R_AARCH64_NONE 256 /* No > relocation */ > @@ -1052,6 +1058,23 @@ 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_PC64 24 /* PC relative 64 bit */ > +#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ > +#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative > offset to GOT */ > +#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ > +#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset to > GOT entry */ > +#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to > GOT */ > +#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry > needed */ > +#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset > to PLT entry */ > +#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit > addend */ > +#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit > addend */ > +#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS > descriptor. */ > +#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS > descriptor. */ > +#define R_X86_64_TLSDESC 36 /* TLS descriptor. */ > +#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program > base */ > +#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program > base */ > +#define R_X86_64_GOTPCRELX 41 /* Load from 32 bit signed pc > relative offset to GOT entry without REX prefix, relaxable. */ > +#define R_X86_64_REX_GOTPCRELX 42 /* Load from 32 bit signed pc > relative offset to GOT entry with REX prefix, relaxable. */ > > > #endif /* !_SYS_ELF_COMMON_H_ */ > -- > 2.17.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel