From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=134.134.136.24; helo=mga09.intel.com; envelope-from=liming.gao@intel.com; receiver=edk2-devel@lists.01.org Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 897E4203B99BF for ; Tue, 10 Jul 2018 00:07:33 -0700 (PDT) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 10 Jul 2018 00:07:33 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.51,333,1526367600"; d="scan'208";a="71026822" Received: from fmsmsx108.amr.corp.intel.com ([10.18.124.206]) by fmsmga001.fm.intel.com with ESMTP; 10 Jul 2018 00:07:32 -0700 Received: from fmsmsx102.amr.corp.intel.com (10.18.124.200) by FMSMSX108.amr.corp.intel.com (10.18.124.206) with Microsoft SMTP Server (TLS) id 14.3.319.2; Tue, 10 Jul 2018 00:07:32 -0700 Received: from shsmsx103.ccr.corp.intel.com (10.239.4.69) by FMSMSX102.amr.corp.intel.com (10.18.124.200) with Microsoft SMTP Server (TLS) id 14.3.319.2; Tue, 10 Jul 2018 00:07:32 -0700 Received: from shsmsx104.ccr.corp.intel.com ([169.254.5.81]) by SHSMSX103.ccr.corp.intel.com ([169.254.4.100]) with mapi id 14.03.0319.002; Tue, 10 Jul 2018 15:07:32 +0800 From: "Gao, Liming" To: Zenith432 , "edk2-devel@lists.01.org" Thread-Topic: [edk2] [PATCH v4] BaseTools/GenFw: Add X64 GOTPCREL Support to GenFw Thread-Index: AQHUF4SH8du8TdNbH0Cbr1/owEzAeKSICklw Date: Tue, 10 Jul 2018 07:07:31 +0000 Message-ID: <4A89E2EF3DFEDB4C8BFDE51014F606A14E2B93B2@SHSMSX104.ccr.corp.intel.com> References: <1442830504.1295133.1531141095532.ref@mail.yahoo.com> <1442830504.1295133.1531141095532@mail.yahoo.com> In-Reply-To: <1442830504.1295133.1531141095532@mail.yahoo.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Subject: Re: [PATCH v4] BaseTools/GenFw: Add X64 GOTPCREL Support to GenFw X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.27 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 10 Jul 2018 07:07:33 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Reviewed-by: Liming Gao >-----Original Message----- >From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of >Zenith432 >Sent: Monday, July 09, 2018 8:58 PM >To: edk2-devel@lists.01.org >Cc: Gao, Liming >Subject: [edk2] [PATCH v4] 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 > >Background: >The GCC49 and GCC5 toolchains use the small pie model for X64. In the >small pie model, gcc emits a GOTPCREL relocation whenever C code takes >the address of a global function. The emission of GOTPCREL is mitigated >by several factors >1. In GCC49, all global symbols are declared hidden thereby eliminating >the emission of GOTPCREL. >2. In GCC5, LTO is used. In LTO, the complier first creates intermediate >representation (IR) files. During the static link stage, the LTO compiler >combines all IR files as a single compilation unit, using linker symbol >assistance to generate code. Any global symbols defined in the IR that >are not referenced from outside the IR are converted to local symbols - >thereby eliminating the emission of GOTPCREL for them. >3. The linker (binutils ld) further transforms any GOTPCREL used with >the movq opcode to a direct rip-relative relocation used with the leaq >opcode. This linker optimization can be disabled with the option >-Wl,--no-relax. Furthermore, gcc is able to emit GOTPCREL with other >opcodes > - pushq opcode for passing arguments to functions. > - addq/subq opcodes for pointer arithmetic. >These other opcode uses are not transformed by the linker. >Ultimately, in GCC5 there are some emissions of GOTPCREL that survive >all these mitigations - if C code takes the address of a global function >defined in assembly code - and performs pointer arithmetic on the >address - then the GOTPCREL remains in the final linker product. >A GOTPCREL relocation today causes the build to stop since GenFw does >not handle them. It is possible to eliminate any remaining GOTPCREL >emissions by manually declaring the global symbols causing them to have >hidden visibility. This patch is offered instead to allow GenFw to >handle any residual GOTPCREL. > >Cc: Shi Steven >Cc: Yonghong Zhu >Cc: Liming Gao >Contributed-under: TianoCore Contribution Agreement 1.1 >Signed-off-by: Zenith432 >--- > BaseTools/Source/C/GenFw/Elf64Convert.c | 203 >+++++++++++++++++++++++- > BaseTools/Source/C/GenFw/elf_common.h | 17 ++ > 2 files changed, 219 insertions(+), 1 deletion(-) > >diff --git a/BaseTools/Source/C/GenFw/Elf64Convert.c >b/BaseTools/Source/C/GenFw/Elf64Convert.c >index 4636cfee..90351125 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 =3D NULL; >+STATIC UINT32 mGOTShindex =3D 0; >+STATIC UINT32 *mGOTCoffEntries =3D NULL; >+STATIC UINT32 mGOTMaxCoffEntries =3D 0; >+STATIC UINT32 mGOTNumCoffEntries =3D 0; >+ > // > // Coff information > // >@@ -322,6 +331,134 @@ 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 !=3D NULL) { >+ if (GOTEntryElfRva >=3D 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 =3D 0; i < mEhdr->e_shnum; i++) { >+ Elf_Shdr *shdr =3D GetShdrByIndex(i); >+ if (GOTEntryElfRva >=3D shdr->sh_addr && >+ GOTEntryElfRva < shdr->sh_addr + shdr->sh_size) { >+ mGOTShdr =3D shdr; >+ mGOTShindex =3D 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 !=3D NULL) { >+ for (i =3D 0; i < mGOTNumCoffEntries; i++) { >+ if (mGOTCoffEntries[i] =3D=3D GOTCoffEntry) { >+ return FALSE; >+ } >+ } >+ } >+ if (mGOTCoffEntries =3D=3D NULL) { >+ mGOTCoffEntries =3D (UINT32*)malloc(5 * sizeof *mGOTCoffEntries); >+ if (mGOTCoffEntries =3D=3D NULL) { >+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); >+ } >+ assert (mGOTCoffEntries !=3D NULL); >+ mGOTMaxCoffEntries =3D 5; >+ mGOTNumCoffEntries =3D 0; >+ } else if (mGOTNumCoffEntries =3D=3D mGOTMaxCoffEntries) { >+ mGOTCoffEntries =3D (UINT32*)realloc(mGOTCoffEntries, 2 * >mGOTMaxCoffEntries * sizeof *mGOTCoffEntries); >+ if (mGOTCoffEntries =3D=3D NULL) { >+ Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); >+ } >+ assert (mGOTCoffEntries !=3D NULL); >+ mGOTMaxCoffEntries +=3D mGOTMaxCoffEntries; >+ } >+ mGOTCoffEntries[mGOTNumCoffEntries++] =3D GOTCoffEntry; >+ return TRUE; >+} >+ >+// >+// 32-bit Unsigned integer comparator for qsort. >+// >+STATIC >+int >+UINT32Comparator ( >+ const void* lhs, >+ const void* rhs >+ ) >+{ >+ if (*(const UINT32*)lhs < *(const UINT32*)rhs) { >+ return -1; >+ } >+ return *(const UINT32*)lhs > *(const UINT32*)rhs; >+} >+ >+// >+// Emit accumulated Coff GOT entry relocations into >+// Coff image. This function performs its job >+// once and then releases the entry list, so >+// it can safely be called multiple times. >+// >+STATIC >+VOID >+EmitGOTRelocations ( >+ VOID >+ ) >+{ >+ UINT32 i; >+ if (mGOTCoffEntries =3D=3D NULL) { >+ return; >+ } >+ // >+ // Emit Coff relocations with Rvas ordered. >+ // >+ qsort( >+ mGOTCoffEntries, >+ mGOTNumCoffEntries, >+ sizeof *mGOTCoffEntries, >+ UINT32Comparator); >+ for (i =3D 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 =3D NULL; >+ mGOTMaxCoffEntries =3D 0; >+ mGOTNumCoffEntries =3D 0; >+} >+ > // > // Elf functions interface implementation > // >@@ -643,6 +780,7 @@ WriteSections64 ( > Elf_Shdr *SecShdr; > UINT32 SecOffset; > BOOLEAN (*Filter)(Elf_Shdr *); >+ Elf64_Addr GOTEntryRva; > > // > // Initialize filter pointer >@@ -710,7 +848,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 cl= eared). > // >- // 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 relocation= s, >one > // for every R_xxx_xx64 relocation appearing in the per-section RELA >sections. > // (i.e., .rela.text and .rela.data) >@@ -846,6 +984,44 @@ 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 =3D Rel->r_offset - Rel->r_addend + *(INT32 *)Tar= g; >+ FindElfGOTSectionFromGOTEntryElfRva(GOTEntryRva); >+ *(UINT32 *)Targ =3D (UINT32) (*(UINT32 *)Targ >+ + (mCoffSectionsOffset[mGOTShindex] - mGOTShdr->sh_addr) >+ - (SecOffset - SecShdr->sh_addr)); >+ VerboseMsg ("Relocation: 0x%08X", *(UINT32 *)Targ); >+ GOTEntryRva +=3D (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 =3D mCoffFile + GOTEntryRva; >+ // >+ // Limitation: The following three statements assume memory >+ // at *Targ is valid because the section containing the G= OT >+ // has already been copied from the ELF image to the Coff= image. >+ // This pre-condition presently holds because the GOT is = placed >+ // in section .text, and the ELF text sections are all co= pied >+ // prior to reaching this point. >+ // If the pre-condition is violated in the future, this f= ixup >+ // either needs to be deferred after the GOT section is c= opied >+ // to the Coff image, or the fixup should be performed on= the >+ // source Elf image instead of the destination Coff image= . >+ // >+ VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX", >+ (UINT32)GOTEntryRva, >+ *(UINT64 *)Targ); >+ *(UINT64 *)Targ =3D *(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_6= 4 >relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info)); > } >@@ -984,6 +1160,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", >@@ -1052,10 +1231,32 @@ WriteRelocations64 ( > Error (NULL, 0, 3000, "Not Supported", "This tool does not su= pport >relocations for ELF with e_machine %u (processor type).", (unsigned) mEhdr= - >>e_machine); > } > } >+ if (mEhdr->e_machine =3D=3D EM_X86_64 && RelShdr->sh_info =3D=3D >mGOTShindex) { >+ // >+ // Tack relocations for GOT entries after other relocations for >+ // the section the GOT is in, as it's usually found at the en= d >+ // of the section. This is done in order to maintain Rva ord= er >+ // of Coff relocations. >+ // >+ EmitGOTRelocations(); >+ } > } > } > } > >+ if (mEhdr->e_machine =3D=3D EM_X86_64) { >+ // >+ // This is a safety net just in case the GOT is in a section >+ // with no other relocations and the first invocation of >+ // EmitGOTRelocations() above was skipped. This invocation >+ // does not maintain Rva order of Coff relocations. >+ // At present, with a single text section, all references to >+ // the GOT and the GOT itself reside in section .text, so >+ // if there's a GOT at all, the first invocation above >+ // is executed. >+ // >+ 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 242ad00a..03dec50c 100644 >--- a/BaseTools/Source/C/GenFw/elf_common.h >+++ b/BaseTools/Source/C/GenFw/elf_common.h >@@ -1052,6 +1052,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_GOTPC3 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 ent= ry >*/ >+#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 entr= y >*/ >+#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