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

Reply via email to