From: Zenith432 <zenith432@users.sourceforge.net>
To: "edk2-devel@lists.01.org" <edk2-devel@lists.01.org>
Cc: LimingGao <liming.gao@intel.com>
Subject: [PATCH v2] BaseTools/GenFw: Add X64 GOTPCREL Support to GenFw
Date: Thu, 7 Jun 2018 12:49:41 +0000 (UTC) [thread overview]
Message-ID: <1917777633.1686290.1528375781778@mail.yahoo.com> (raw)
In-Reply-To: 1917777633.1686290.1528375781778.ref@mail.yahoo.com
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.shi@intel.com>
CC: Yonghong Zhu <yonghong.zhu@intel.com>
CC: Liming Gao <liming.gao@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Zenith432 <zenith432@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..1518c395 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 + *(INT32 *)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
next parent reply other threads:[~2018-06-07 12:49 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <1917777633.1686290.1528375781778.ref@mail.yahoo.com>
2018-06-07 12:49 ` Zenith432 [this message]
2018-06-08 4:02 ` [PATCH v2] BaseTools/GenFw: Add X64 GOTPCREL Support to GenFw Andrew Fish
2018-07-02 9:22 ` Shi, Steven
[not found] <1761571963.2244772.1528455976855.ref@mail.yahoo.com>
2018-06-08 11:06 ` Zenith432
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1917777633.1686290.1528375781778@mail.yahoo.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox