summaryrefslogtreecommitdiff
path: root/devel/llvm60/files/lld/patch-head-r338251.diff
diff options
context:
space:
mode:
Diffstat (limited to 'devel/llvm60/files/lld/patch-head-r338251.diff')
-rw-r--r--devel/llvm60/files/lld/patch-head-r338251.diff123
1 files changed, 123 insertions, 0 deletions
diff --git a/devel/llvm60/files/lld/patch-head-r338251.diff b/devel/llvm60/files/lld/patch-head-r338251.diff
new file mode 100644
index 000000000000..1c3df02100cd
--- /dev/null
+++ b/devel/llvm60/files/lld/patch-head-r338251.diff
@@ -0,0 +1,123 @@
+r338251 | markj | 2018-08-23 16:58:19 +0200 (Thu, 23 Aug 2018) | 29 lines
+
+Add an lld option to emit PC-relative relocations for ifunc calls.
+
+The current kernel ifunc implementation creates a PLT entry for each
+ifunc definition. ifunc calls therefore consist of a call to the
+PLT entry followed by an indirect jump. The jump target is written
+during boot when the kernel linker resolves R_[*]_IRELATIVE relocations.
+This implementation is defined by requirements for userland code, where
+text relocations are avoided. This requirement is not present for the
+kernel, so the implementation has avoidable overhead (namely, an extra
+indirect jump per call).
+
+Address this for now by adding a special option to the static linker
+to inhibit PLT creation for ifuncs. Instead, relocations to ifunc call
+sites are passed through to the output file, so the kernel linker can
+enumerate such call sites and apply PC-relative relocations directly
+to the text section. Thus the overhead of an ifunc call becomes exactly
+the same as that of an ordinary function call. This option is only for
+use by the kernel and will not work for regular programs.
+
+The final form of this optimization is up for debate; for now, this
+change is simple and static enough to be acceptable as an interim
+solution.
+
+Reviewed by: emaste
+Discussed with: arichardson, dim
+MFC after: 1 month
+Sponsored by: The FreeBSD Foundation
+Differential Revision: https://reviews.freebsd.org/D16748
+
+Index: tools/lld/ELF/Config.h
+===================================================================
+--- tools/lld/ELF/Config.h (revision 338250)
++++ tools/lld/ELF/Config.h (revision 338251)
+@@ -155,6 +155,7 @@ struct Configuration {
+ bool ZCombreloc;
+ bool ZExecstack;
+ bool ZHazardplt;
++ bool ZIfuncnoplt;
+ bool ZNocopyreloc;
+ bool ZNodelete;
+ bool ZNodlopen;
+Index: tools/lld/ELF/Driver.cpp
+===================================================================
+--- tools/lld/ELF/Driver.cpp (revision 338250)
++++ tools/lld/ELF/Driver.cpp (revision 338251)
+@@ -669,6 +669,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &
+ Config->ZCombreloc = !hasZOption(Args, "nocombreloc");
+ Config->ZExecstack = hasZOption(Args, "execstack");
+ Config->ZHazardplt = hasZOption(Args, "hazardplt");
++ Config->ZIfuncnoplt = hasZOption(Args, "ifunc-noplt");
+ Config->ZNocopyreloc = hasZOption(Args, "nocopyreloc");
+ Config->ZNodelete = hasZOption(Args, "nodelete");
+ Config->ZNodlopen = hasZOption(Args, "nodlopen");
+Index: tools/lld/ELF/Relocations.cpp
+===================================================================
+--- tools/lld/ELF/Relocations.cpp (revision 338250)
++++ tools/lld/ELF/Relocations.cpp (revision 338251)
+@@ -374,6 +374,9 @@ static bool isStaticLinkTimeConstant(RelExpr E, Re
+ R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E))
+ return true;
+
++ if (Sym.isGnuIFunc() && Config->ZIfuncnoplt)
++ return false;
++
+ // These never do, except if the entire file is position dependent or if
+ // only the low bits are used.
+ if (E == R_GOT || E == R_PLT || E == R_TLSDESC)
+@@ -921,7 +924,9 @@ static void scanRelocs(InputSectionBase &Sec, Arra
+ // Strenghten or relax a PLT access.
+ //
+ // GNU ifunc symbols must be accessed via PLT because their addresses
+- // are determined by runtime.
++ // are determined by runtime. If the -z ifunc-noplt option is specified,
++ // we permit the optimization of ifunc calls by omitting the PLT entry
++ // and preserving relocations at ifunc call sites.
+ //
+ // On the other hand, if we know that a PLT entry will be resolved within
+ // the same ELF module, we can skip PLT access and directly jump to the
+@@ -929,7 +934,7 @@ static void scanRelocs(InputSectionBase &Sec, Arra
+ // all dynamic symbols that can be resolved within the executable will
+ // actually be resolved that way at runtime, because the main exectuable
+ // is always at the beginning of a search list. We can leverage that fact.
+- if (Sym.isGnuIFunc())
++ if (Sym.isGnuIFunc() && !Config->ZIfuncnoplt)
+ Expr = toPlt(Expr);
+ else if (!Preemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym))
+ Expr =
+@@ -1034,6 +1039,16 @@ static void scanRelocs(InputSectionBase &Sec, Arra
+ continue;
+ }
+
++ // Preserve relocations against ifuncs if we were asked to do so.
++ if (Sym.isGnuIFunc() && Config->ZIfuncnoplt) {
++ if (Config->IsRela)
++ InX::RelaDyn->addReloc({Type, &Sec, Offset, false, &Sym, Addend});
++ else
++ // Preserve the existing addend.
++ InX::RelaDyn->addReloc({Type, &Sec, Offset, false, &Sym, 0});
++ continue;
++ }
++
+ // If the output being produced is position independent, the final value
+ // is still not known. In that case we still need some help from the
+ // dynamic linker. We can however do better than just copying the incoming
+Index: tools/lld/ELF/Writer.cpp
+===================================================================
+--- tools/lld/ELF/Writer.cpp (revision 338250)
++++ tools/lld/ELF/Writer.cpp (revision 338251)
+@@ -1400,8 +1400,11 @@ template <class ELFT> void Writer<ELFT>::finalizeS
+ applySynthetic({InX::EhFrame},
+ [](SyntheticSection *SS) { SS->finalizeContents(); });
+
+- for (Symbol *S : Symtab->getSymbols())
++ for (Symbol *S : Symtab->getSymbols()) {
+ S->IsPreemptible |= computeIsPreemptible(*S);
++ if (S->isGnuIFunc() && Config->ZIfuncnoplt)
++ S->ExportDynamic = true;
++ }
+
+ // Scan relocations. This must be done after every symbol is declared so that
+ // we can correctly decide if a dynamic relocation is needed.