Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 31 Jul 2019 16:22:06 +0000 (UTC)
From:      Leandro Lupori <luporl@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r350467 - head/contrib/llvm/tools/lld/ELF
Message-ID:  <201907311622.x6VGM69X045118@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: luporl
Date: Wed Jul 31 16:22:05 2019
New Revision: 350467
URL: https://svnweb.freebsd.org/changeset/base/350467

Log:
  [PPC64] Backport fix for missing IRELATIVE relocations
  
  This is a backport of LLVM commit 8331f61a51a7a0a1efbf5ed398e181593023d151,
  llvm-svn: 353981:
  
  ELF: Allow GOT relocs pointing to non-preemptable ifunc to resolve to an
  IRELATIVE where possible.
  
  This is needed in order to make ifuncs work correctly on PPC64.
  
  It fixes an issue with lld, in which it would skip emitting necessary IRELATIVE
  relocations.  Without this change, indirect calls to ifuncs would result in a
  segmentation fault, in static binaries or when defined in the main binary
  (outside shared libraries).
  
  This change also reverts the local
  "Preserve relocations against ifuncs when -zifunc-noplt" commit and
  replaces it by its upstream version, as part of the merge.
  
  Reviewed by:	markj
  Differential Revision:	https://reviews.freebsd.org/D21102

Modified:
  head/contrib/llvm/tools/lld/ELF/Config.h
  head/contrib/llvm/tools/lld/ELF/Driver.cpp
  head/contrib/llvm/tools/lld/ELF/InputSection.cpp
  head/contrib/llvm/tools/lld/ELF/Relocations.cpp
  head/contrib/llvm/tools/lld/ELF/Relocations.h
  head/contrib/llvm/tools/lld/ELF/Symbols.cpp
  head/contrib/llvm/tools/lld/ELF/Symbols.h
  head/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp
  head/contrib/llvm/tools/lld/ELF/Writer.cpp

Modified: head/contrib/llvm/tools/lld/ELF/Config.h
==============================================================================
--- head/contrib/llvm/tools/lld/ELF/Config.h	Wed Jul 31 16:07:16 2019	(r350466)
+++ head/contrib/llvm/tools/lld/ELF/Config.h	Wed Jul 31 16:22:05 2019	(r350467)
@@ -191,7 +191,7 @@ struct Configuration {
   bool ZExecstack;
   bool ZGlobal;
   bool ZHazardplt;
-  bool ZIfuncnoplt;
+  bool ZIfuncNoplt;
   bool ZInitfirst;
   bool ZInterpose;
   bool ZKeepTextSectionPrefix;

Modified: head/contrib/llvm/tools/lld/ELF/Driver.cpp
==============================================================================
--- head/contrib/llvm/tools/lld/ELF/Driver.cpp	Wed Jul 31 16:07:16 2019	(r350466)
+++ head/contrib/llvm/tools/lld/ELF/Driver.cpp	Wed Jul 31 16:22:05 2019	(r350467)
@@ -299,6 +299,9 @@ static void checkOptions() {
   if (!Config->Relocatable && !Config->DefineCommon)
     error("-no-define-common not supported in non relocatable output");
 
+  if (Config->ZText && Config->ZIfuncNoplt)
+    error("-z text and -z ifunc-noplt may not be used together");
+
   if (Config->Relocatable) {
     if (Config->Shared)
       error("-r and -shared may not be used together");
@@ -348,8 +351,7 @@ static bool getZFlag(opt::InputArgList &Args, StringRe
 static bool isKnownZFlag(StringRef S) {
   return S == "combreloc" || S == "copyreloc" || S == "defs" ||
          S == "execstack" || S == "global" || S == "hazardplt" ||
-         S == "ifunc-noplt" ||
-         S == "initfirst" || S == "interpose" ||
+         S == "ifunc-noplt" || S == "initfirst" || S == "interpose" ||
          S == "keep-text-section-prefix" || S == "lazy" || S == "muldefs" ||
          S == "nocombreloc" || S == "nocopyreloc" || S == "nodefaultlib" ||
          S == "nodelete" || S == "nodlopen" || S == "noexecstack" ||
@@ -875,7 +877,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args
   Config->ZExecstack = getZFlag(Args, "execstack", "noexecstack", false);
   Config->ZGlobal = hasZOption(Args, "global");
   Config->ZHazardplt = hasZOption(Args, "hazardplt");
-  Config->ZIfuncnoplt = hasZOption(Args, "ifunc-noplt");
+  Config->ZIfuncNoplt = hasZOption(Args, "ifunc-noplt");
   Config->ZInitfirst = hasZOption(Args, "initfirst");
   Config->ZInterpose = hasZOption(Args, "interpose");
   Config->ZKeepTextSectionPrefix = getZFlag(

Modified: head/contrib/llvm/tools/lld/ELF/InputSection.cpp
==============================================================================
--- head/contrib/llvm/tools/lld/ELF/InputSection.cpp	Wed Jul 31 16:07:16 2019	(r350466)
+++ head/contrib/llvm/tools/lld/ELF/InputSection.cpp	Wed Jul 31 16:22:05 2019	(r350467)
@@ -610,7 +610,6 @@ static uint64_t getRelocTargetVA(const InputFile *File
   case R_ARM_SBREL:
     return Sym.getVA(A) - getARMStaticBase(Sym);
   case R_GOT:
-  case R_GOT_PLT:
   case R_RELAX_TLS_GD_TO_IE_ABS:
     return Sym.getGotVA() + A;
   case R_GOTONLY_PC:
@@ -629,7 +628,6 @@ static uint64_t getRelocTargetVA(const InputFile *File
   case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
     return Sym.getGotOffset() + A;
   case R_AARCH64_GOT_PAGE_PC:
-  case R_AARCH64_GOT_PAGE_PC_PLT:
   case R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
     return getAArch64Page(Sym.getGotVA() + A) - getAArch64Page(P);
   case R_GOT_PC:
@@ -677,10 +675,6 @@ static uint64_t getRelocTargetVA(const InputFile *File
            In.MipsGot->getGp(File);
   case R_AARCH64_PAGE_PC: {
     uint64_t Val = Sym.isUndefWeak() ? P + A : Sym.getVA(A);
-    return getAArch64Page(Val) - getAArch64Page(P);
-  }
-  case R_AARCH64_PLT_PAGE_PC: {
-    uint64_t Val = Sym.isUndefWeak() ? P + A : Sym.getPltVA() + A;
     return getAArch64Page(Val) - getAArch64Page(P);
   }
   case R_RISCV_PC_INDIRECT: {

Modified: head/contrib/llvm/tools/lld/ELF/Relocations.cpp
==============================================================================
--- head/contrib/llvm/tools/lld/ELF/Relocations.cpp	Wed Jul 31 16:07:16 2019	(r350466)
+++ head/contrib/llvm/tools/lld/ELF/Relocations.cpp	Wed Jul 31 16:22:05 2019	(r350467)
@@ -337,8 +337,7 @@ static bool isAbsoluteValue(const Symbol &Sym) {
 
 // Returns true if Expr refers a PLT entry.
 static bool needsPlt(RelExpr Expr) {
-  return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_AARCH64_PLT_PAGE_PC,
-                        R_GOT_PLT, R_AARCH64_GOT_PAGE_PC_PLT>(Expr);
+  return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT>(Expr);
 }
 
 // Returns true if Expr refers a GOT entry. Note that this function
@@ -347,8 +346,7 @@ static bool needsPlt(RelExpr Expr) {
 static bool needsGot(RelExpr Expr) {
   return isRelExprOneOf<R_GOT, R_GOT_OFF, R_HEXAGON_GOT, R_MIPS_GOT_LOCAL_PAGE,
                         R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC,
-                        R_AARCH64_GOT_PAGE_PC_PLT, R_GOT_PC, R_GOT_FROM_END,
-                        R_GOT_PLT>(Expr);
+                        R_GOT_PC, R_GOT_FROM_END>(Expr);
 }
 
 // True if this expression is of the form Sym - X, where X is a position in the
@@ -356,7 +354,7 @@ static bool needsGot(RelExpr Expr) {
 static bool isRelExpr(RelExpr Expr) {
   return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL,
                         R_PPC_CALL, R_PPC_CALL_PLT, R_AARCH64_PAGE_PC,
-                        R_AARCH64_PLT_PAGE_PC, R_RELAX_GOT_PC>(Expr);
+                        R_RELAX_GOT_PC>(Expr);
 }
 
 // Returns true if a given relocation can be computed at link-time.
@@ -374,20 +372,16 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelTyp
   if (isRelExprOneOf<R_GOT_FROM_END, R_GOT_OFF, R_HEXAGON_GOT, R_TLSLD_GOT_OFF,
                      R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOTREL, R_MIPS_GOT_OFF,
                      R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, R_MIPS_TLSGD,
-                     R_AARCH64_GOT_PAGE_PC, R_AARCH64_GOT_PAGE_PC_PLT, R_GOT_PC,
-                     R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT,
+                     R_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
+                     R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT,
                      R_TLSGD_GOT_FROM_END, R_TLSGD_PC, R_PPC_CALL_PLT,
                      R_TLSDESC_CALL, R_AARCH64_TLSDESC_PAGE, R_HINT,
                      R_TLSLD_HINT, R_TLSIE_HINT>(E))
     return true;
 
-  // The computation involves output from the ifunc resolver.
-  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_GOT_PLT || E == R_PLT || E == R_TLSDESC)
+  if (E == R_GOT || E == R_PLT || E == R_TLSDESC)
     return Target->usesOnlyLowPageBits(Type) || !Config->Pic;
 
   if (Sym.IsPreemptible)
@@ -433,14 +427,8 @@ static RelExpr toPlt(RelExpr Expr) {
     return R_PPC_CALL_PLT;
   case R_PC:
     return R_PLT_PC;
-  case R_AARCH64_PAGE_PC:
-    return R_AARCH64_PLT_PAGE_PC;
-  case R_AARCH64_GOT_PAGE_PC:
-    return R_AARCH64_GOT_PAGE_PC_PLT;
   case R_ABS:
     return R_PLT;
-  case R_GOT:
-    return R_GOT_PLT;
   default:
     return Expr;
   }
@@ -772,14 +760,7 @@ static void addPltEntry(PltSection *Plt, GotPltSection
 template <class ELFT> static void addGotEntry(Symbol &Sym) {
   In.Got->addEntry(Sym);
 
-  RelExpr Expr;
-  if (Sym.isTls())
-    Expr = R_TLS;
-  else if (Sym.isGnuIFunc())
-    Expr = R_PLT;
-  else
-    Expr = R_ABS;
-
+  RelExpr Expr = Sym.isTls() ? R_TLS : R_ABS;
   uint64_t Off = Sym.getGotOffset();
 
   // If a GOT slot value can be calculated at link-time, which is now,
@@ -848,10 +829,6 @@ static void processRelocAux(InputSectionBase &Sec, Rel
     Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
     return;
   }
-  if (Sym.isGnuIFunc() && Config->ZIfuncnoplt) {
-    In.RelaDyn->addReloc(Type, &Sec, Offset, &Sym, Addend, R_ADDEND, Type);
-    return;
-  }
   bool CanWrite = (Sec.Flags & SHF_WRITE) || !Config->ZText;
   if (CanWrite) {
     // R_GOT refers to a position in the got, even if the symbol is preemptible.
@@ -978,6 +955,15 @@ static void processRelocAux(InputSectionBase &Sec, Rel
               getLocation(Sec, Sym, Offset));
 }
 
+struct IRelativeReloc {
+  RelType Type;
+  InputSectionBase *Sec;
+  uint64_t Offset;
+  Symbol *Sym;
+};
+
+static std::vector<IRelativeReloc> IRelativeRelocs;
+
 template <class ELFT, class RelTy>
 static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I,
                       RelTy *End) {
@@ -1009,32 +995,29 @@ static void scanReloc(InputSectionBase &Sec, OffsetGet
   if (isRelExprOneOf<R_HINT, R_NONE>(Expr))
     return;
 
-  // Strenghten or relax relocations.
+  if (Sym.isGnuIFunc() && !Config->ZText && Config->WarnIfuncTextrel) {
+    warn("using ifunc symbols when text relocations are allowed may produce "
+         "a binary that will segfault, if the object file is linked with "
+         "old version of glibc (glibc 2.28 and earlier). If this applies to "
+         "you, consider recompiling the object files without -fPIC and "
+         "without -Wl,-z,notext option. Use -no-warn-ifunc-textrel to "
+         "turn off this warning." +
+         getLocation(Sec, Sym, Offset));
+  }
+
+  // Relax relocations.
   //
-  // GNU ifunc symbols must be accessed via PLT because their addresses
-  // are determined by runtime.
-  //
-  // 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
-  // destination function. For example, if we are linking a main exectuable,
-  // 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() && !Config->ZIfuncnoplt) {
-    if (!Config->ZText && Config->WarnIfuncTextrel) {
-      warn("using ifunc symbols when text relocations are allowed may produce "
-           "a binary that will segfault, if the object file is linked with "
-           "old version of glibc (glibc 2.28 and earlier). If this applies to "
-           "you, consider recompiling the object files without -fPIC and "
-           "without -Wl,-z,notext option. Use -no-warn-ifunc-textrel to "
-           "turn off this warning." +
-           getLocation(Sec, Sym, Offset));
-    }
-    Expr = toPlt(Expr);
-  } else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym)) {
-    Expr = Target->adjustRelaxExpr(Type, RelocatedAddr, Expr);
-  } else if (!Sym.IsPreemptible) {
-    Expr = fromPlt(Expr);
+  // 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 destination function. For
+  // example, if we are linking a main exectuable, 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.IsPreemptible && (!Sym.isGnuIFunc() || Config->ZIfuncNoplt)) {
+    if (Expr == R_GOT_PC && !isAbsoluteValue(Sym))
+      Expr = Target->adjustRelaxExpr(Type, RelocatedAddr, Expr);
+    else
+      Expr = fromPlt(Expr);
   }
 
   // This relocation does not require got entry, but it is relative to got and
@@ -1054,29 +1037,145 @@ static void scanReloc(InputSectionBase &Sec, OffsetGet
     return;
   }
 
-  // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
-  if (needsPlt(Expr) && !Sym.isInPlt()) {
-    if (Sym.isGnuIFunc() && !Sym.IsPreemptible)
-      addPltEntry<ELFT>(In.Iplt, In.IgotPlt, In.RelaIplt, Target->IRelativeRel,
-                        Sym);
-    else
-      addPltEntry<ELFT>(In.Plt, In.GotPlt, In.RelaPlt, Target->PltRel, Sym);
+  // We were asked not to generate PLT entries for ifuncs. Instead, pass the
+  // direct relocation on through.
+  if (Sym.isGnuIFunc() && Config->ZIfuncNoplt) {
+    Sym.ExportDynamic = true;
+    In.RelaDyn->addReloc(Type, &Sec, Offset, &Sym, Addend, R_ADDEND, Type);
+    return;
   }
 
-  // Create a GOT slot if a relocation needs GOT.
-  if (needsGot(Expr)) {
-    if (Config->EMachine == EM_MIPS) {
-      // MIPS ABI has special rules to process GOT entries and doesn't
-      // require relocation entries for them. A special case is TLS
-      // relocations. In that case dynamic loader applies dynamic
-      // relocations to initialize TLS GOT entries.
-      // See "Global Offset Table" in Chapter 5 in the following document
-      // for detailed description:
-      // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
-      In.MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
-    } else if (!Sym.isInGot()) {
-      addGotEntry<ELFT>(Sym);
+  // Non-preemptible ifuncs require special handling. First, handle the usual
+  // case where the symbol isn't one of these.
+  if (!Sym.isGnuIFunc() || Sym.IsPreemptible) {
+    // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol.
+    if (needsPlt(Expr) && !Sym.isInPlt())
+      addPltEntry<ELFT>(In.Plt, In.GotPlt, In.RelaPlt, Target->PltRel, Sym);
+
+    // Create a GOT slot if a relocation needs GOT.
+    if (needsGot(Expr)) {
+      if (Config->EMachine == EM_MIPS) {
+        // MIPS ABI has special rules to process GOT entries and doesn't
+        // require relocation entries for them. A special case is TLS
+        // relocations. In that case dynamic loader applies dynamic
+        // relocations to initialize TLS GOT entries.
+        // See "Global Offset Table" in Chapter 5 in the following document
+        // for detailed description:
+        // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
+        In.MipsGot->addEntry(*Sec.File, Sym, Addend, Expr);
+      } else if (!Sym.isInGot()) {
+        addGotEntry<ELFT>(Sym);
+      }
     }
+  } else {
+    // Handle a reference to a non-preemptible ifunc. These are special in a
+    // few ways:
+    //
+    // - Unlike most non-preemptible symbols, non-preemptible ifuncs do not have
+    //   a fixed value. But assuming that all references to the ifunc are
+    //   GOT-generating or PLT-generating, the handling of an ifunc is
+    //   relatively straightforward. We create a PLT entry in Iplt, which is
+    //   usually at the end of .plt, which makes an indirect call using a
+    //   matching GOT entry in IgotPlt, which is usually at the end of .got.plt.
+    //   The GOT entry is relocated using an IRELATIVE relocation in RelaIplt,
+    //   which is usually at the end of .rela.plt. Unlike most relocations in
+    //   .rela.plt, which may be evaluated lazily without -z now, dynamic
+    //   loaders evaluate IRELATIVE relocs eagerly, which means that for
+    //   IRELATIVE relocs only, GOT-generating relocations can point directly to
+    //   .got.plt without requiring a separate GOT entry.
+    //
+    // - Despite the fact that an ifunc does not have a fixed value, compilers
+    //   that are not passed -fPIC will assume that they do, and will emit
+    //   direct (non-GOT-generating, non-PLT-generating) relocations to the
+    //   symbol. This means that if a direct relocation to the symbol is
+    //   seen, the linker must set a value for the symbol, and this value must
+    //   be consistent no matter what type of reference is made to the symbol.
+    //   This can be done by creating a PLT entry for the symbol in the way
+    //   described above and making it canonical, that is, making all references
+    //   point to the PLT entry instead of the resolver. In lld we also store
+    //   the address of the PLT entry in the dynamic symbol table, which means
+    //   that the symbol will also have the same value in other modules.
+    //   Because the value loaded from the GOT needs to be consistent with
+    //   the value computed using a direct relocation, a non-preemptible ifunc
+    //   may end up with two GOT entries, one in .got.plt that points to the
+    //   address returned by the resolver and is used only by the PLT entry,
+    //   and another in .got that points to the PLT entry and is used by
+    //   GOT-generating relocations.
+    //
+    // - The fact that these symbols do not have a fixed value makes them an
+    //   exception to the general rule that a statically linked executable does
+    //   not require any form of dynamic relocation. To handle these relocations
+    //   correctly, the IRELATIVE relocations are stored in an array which a
+    //   statically linked executable's startup code must enumerate using the
+    //   linker-defined symbols __rela?_iplt_{start,end}.
+    //
+    // - An absolute relocation to a non-preemptible ifunc (such as a global
+    //   variable containing a pointer to the ifunc) needs to be relocated in
+    //   the exact same way as a GOT entry, so we can avoid needing to make the
+    //   PLT entry canonical by translating such relocations into IRELATIVE
+    //   relocations in the RelaIplt.
+    if (!Sym.isInPlt()) {
+      // Create PLT and GOTPLT slots for the symbol.
+      Sym.IsInIplt = true;
+
+      // Create a copy of the symbol to use as the target of the IRELATIVE
+      // relocation in the IgotPlt. This is in case we make the PLT canonical
+      // later, which would overwrite the original symbol.
+      //
+      // FIXME: Creating a copy of the symbol here is a bit of a hack. All
+      // that's really needed to create the IRELATIVE is the section and value,
+      // so ideally we should just need to copy those.
+      auto *DirectSym = make<Defined>(cast<Defined>(Sym));
+      addPltEntry<ELFT>(In.Iplt, In.IgotPlt, In.RelaIplt, Target->IRelativeRel,
+                        *DirectSym);
+      Sym.PltIndex = DirectSym->PltIndex;
+    }
+    if (Expr == R_ABS && Addend == 0 && (Sec.Flags & SHF_WRITE)) {
+      // We might be able to represent this as an IRELATIVE. But we don't know
+      // yet whether some later relocation will make the symbol point to a
+      // canonical PLT, which would make this either a dynamic RELATIVE (PIC) or
+      // static (non-PIC) relocation. So we keep a record of the information
+      // required to process the relocation, and after scanRelocs() has been
+      // called on all relocations, the relocation is resolved by
+      // addIRelativeRelocs().
+      IRelativeRelocs.push_back({Type, &Sec, Offset, &Sym});
+      return;
+    }
+    if (needsGot(Expr)) {
+      // Redirect GOT accesses to point to the Igot.
+      //
+      // This field is also used to keep track of whether we ever needed a GOT
+      // entry. If we did and we make the PLT canonical later, we'll need to
+      // create a GOT entry pointing to the PLT entry for Sym.
+      Sym.GotInIgot = true;
+    } else if (!needsPlt(Expr)) {
+      // Make the ifunc's PLT entry canonical by changing the value of its
+      // symbol to redirect all references to point to it.
+      unsigned EntryOffset = Sym.PltIndex * Target->PltEntrySize;
+      if (Config->ZRetpolineplt)
+        EntryOffset += Target->PltHeaderSize;
+
+      auto &D = cast<Defined>(Sym);
+      D.Section = In.Iplt;
+      D.Value = EntryOffset;
+      D.Size = 0;
+      // It's important to set the symbol type here so that dynamic loaders
+      // don't try to call the PLT as if it were an ifunc resolver.
+      D.Type = STT_FUNC;
+
+      if (Sym.GotInIgot) {
+        // We previously encountered a GOT generating reference that we
+        // redirected to the Igot. Now that the PLT entry is canonical we must
+        // clear the redirection to the Igot and add a GOT entry. As we've
+        // changed the symbol type to STT_FUNC future GOT generating references
+        // will naturally use this GOT entry.
+        //
+        // We don't need to worry about creating a MIPS GOT here because ifuncs
+        // aren't a thing on MIPS.
+        Sym.GotInIgot = false;
+        addGotEntry<ELFT>(Sym);
+      }
+    }
   }
 
   processRelocAux<ELFT>(Sec, Expr, Type, Offset, Sym, Rel, Addend);
@@ -1103,6 +1202,21 @@ template <class ELFT> void elf::scanRelocations(InputS
     scanRelocs<ELFT>(S, S.relas<ELFT>());
   else
     scanRelocs<ELFT>(S, S.rels<ELFT>());
+}
+
+// Figure out which representation to use for any absolute relocs to
+// non-preemptible ifuncs that we visited during scanRelocs().
+void elf::addIRelativeRelocs() {
+  for (IRelativeReloc &R : IRelativeRelocs) {
+    if (R.Sym->Type == STT_GNU_IFUNC)
+      In.RelaIplt->addReloc(
+          {Target->IRelativeRel, R.Sec, R.Offset, true, R.Sym, 0});
+    else if (Config->Pic)
+      addRelativeReloc(R.Sec, R.Offset, R.Sym, 0, R_ABS, R.Type);
+    else
+      R.Sec->Relocations.push_back({R_ABS, R.Type, R.Offset, 0, R.Sym});
+  }
+  IRelativeRelocs.clear();
 }
 
 static bool mergeCmp(const InputSection *A, const InputSection *B) {

Modified: head/contrib/llvm/tools/lld/ELF/Relocations.h
==============================================================================
--- head/contrib/llvm/tools/lld/ELF/Relocations.h	Wed Jul 31 16:07:16 2019	(r350466)
+++ head/contrib/llvm/tools/lld/ELF/Relocations.h	Wed Jul 31 16:22:05 2019	(r350467)
@@ -34,19 +34,11 @@ enum RelExpr {
   R_ABS,
   R_ADDEND,
   R_AARCH64_GOT_PAGE_PC,
-  // The expression is used for IFUNC support. Describes PC-relative
-  // address of the memory page of GOT entry. This entry is used for
-  // a redirection to IPLT.
-  R_AARCH64_GOT_PAGE_PC_PLT,
   R_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
   R_AARCH64_PAGE_PC,
-  R_AARCH64_PLT_PAGE_PC,
   R_AARCH64_TLSDESC_PAGE,
   R_ARM_SBREL,
   R_GOT,
-  // The expression is used for IFUNC support. Evaluates to GOT entry,
-  // containing redirection to the IPLT.
-  R_GOT_PLT,
   R_GOTONLY_PC,
   R_GOTONLY_PC_FROM_END,
   R_GOTREL,
@@ -154,6 +146,8 @@ struct RelocationOffsetComparator {
 };
 
 template <class ELFT> void scanRelocations(InputSectionBase &);
+
+void addIRelativeRelocs();
 
 class ThunkSection;
 class Thunk;

Modified: head/contrib/llvm/tools/lld/ELF/Symbols.cpp
==============================================================================
--- head/contrib/llvm/tools/lld/ELF/Symbols.cpp	Wed Jul 31 16:07:16 2019	(r350466)
+++ head/contrib/llvm/tools/lld/ELF/Symbols.cpp	Wed Jul 31 16:22:05 2019	(r350467)
@@ -121,20 +121,24 @@ uint64_t Symbol::getVA(int64_t Addend) const {
   return OutVA + Addend;
 }
 
-uint64_t Symbol::getGotVA() const { return In.Got->getVA() + getGotOffset(); }
+uint64_t Symbol::getGotVA() const {
+  if (GotInIgot)
+    return In.IgotPlt->getVA() + getGotPltOffset();
+  return In.Got->getVA() + getGotOffset();
+}
 
 uint64_t Symbol::getGotOffset() const {
   return GotIndex * Target->GotEntrySize;
 }
 
 uint64_t Symbol::getGotPltVA() const {
-  if (this->IsInIgot)
+  if (IsInIplt)
     return In.IgotPlt->getVA() + getGotPltOffset();
   return In.GotPlt->getVA() + getGotPltOffset();
 }
 
 uint64_t Symbol::getGotPltOffset() const {
-  if (IsInIgot)
+  if (IsInIplt)
     return PltIndex * Target->GotPltEntrySize;
   return (PltIndex + Target->GotPltHeaderEntriesNum) * Target->GotPltEntrySize;
 }

Modified: head/contrib/llvm/tools/lld/ELF/Symbols.h
==============================================================================
--- head/contrib/llvm/tools/lld/ELF/Symbols.h	Wed Jul 31 16:07:16 2019	(r350466)
+++ head/contrib/llvm/tools/lld/ELF/Symbols.h	Wed Jul 31 16:22:05 2019	(r350467)
@@ -182,7 +182,7 @@ class Symbol { (protected)
          uint8_t StOther, uint8_t Type)
       : File(File), NameData(Name.Data), NameSize(Name.Size), Binding(Binding),
         Type(Type), StOther(StOther), SymbolKind(K), NeedsPltAddr(false),
-        IsInIplt(false), IsInIgot(false), IsPreemptible(false),
+        IsInIplt(false), GotInIgot(false), IsPreemptible(false),
         Used(!Config->GcSections), NeedsTocRestore(false),
         ScriptDefined(false) {}
 
@@ -191,11 +191,13 @@ class Symbol { (protected)
   // For SharedSymbol only.
   unsigned NeedsPltAddr : 1;
 
-  // True if this symbol is in the Iplt sub-section of the Plt.
+  // True if this symbol is in the Iplt sub-section of the Plt and the Igot
+  // sub-section of the .got.plt or .got.
   unsigned IsInIplt : 1;
 
-  // True if this symbol is in the Igot sub-section of the .got.plt or .got.
-  unsigned IsInIgot : 1;
+  // True if this symbol needs a GOT entry and its GOT entry is actually in
+  // Igot. This will be true only for certain non-preemptible ifuncs.
+  unsigned GotInIgot : 1;
 
   // True if this symbol is preemptible at load time.
   unsigned IsPreemptible : 1;

Modified: head/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp
==============================================================================
--- head/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp	Wed Jul 31 16:07:16 2019	(r350466)
+++ head/contrib/llvm/tools/lld/ELF/SyntheticSections.cpp	Wed Jul 31 16:22:05 2019	(r350467)
@@ -1133,7 +1133,6 @@ IgotPltSection::IgotPltSection()
                        Target->GotPltEntrySize, getIgotPltName()) {}
 
 void IgotPltSection::addEntry(Symbol &Sym) {
-  Sym.IsInIgot = true;
   assert(Sym.PltIndex == Entries.size());
   Entries.push_back(&Sym);
 }
@@ -2340,10 +2339,8 @@ void PltSection::writeTo(uint8_t *Buf) {
 template <class ELFT> void PltSection::addEntry(Symbol &Sym) {
   Sym.PltIndex = Entries.size();
   RelocationBaseSection *PltRelocSection = In.RelaPlt;
-  if (IsIplt) {
+  if (IsIplt)
     PltRelocSection = In.RelaIplt;
-    Sym.IsInIplt = true;
-  }
   unsigned RelOff =
       static_cast<RelocationSection<ELFT> *>(PltRelocSection)->getRelocOffset();
   Entries.push_back(std::make_pair(&Sym, RelOff));

Modified: head/contrib/llvm/tools/lld/ELF/Writer.cpp
==============================================================================
--- head/contrib/llvm/tools/lld/ELF/Writer.cpp	Wed Jul 31 16:07:16 2019	(r350466)
+++ head/contrib/llvm/tools/lld/ELF/Writer.cpp	Wed Jul 31 16:22:05 2019	(r350467)
@@ -1656,17 +1656,15 @@ template <class ELFT> void Writer<ELFT>::finalizeSecti
   // earlier.
   finalizeSynthetic(In.EhFrame);
 
-  for (Symbol *S : Symtab->getSymbols()) {
-    if (!S->IsPreemptible)
-      S->IsPreemptible = computeIsPreemptible(*S);
-    if (S->isGnuIFunc() && Config->ZIfuncnoplt)
-      S->ExportDynamic = true;
-  }
+  for (Symbol *S : Symtab->getSymbols())
+    S->IsPreemptible |= computeIsPreemptible(*S);
 
   // Scan relocations. This must be done after every symbol is declared so that
   // we can correctly decide if a dynamic relocation is needed.
   if (!Config->Relocatable)
     forEachRelSec(scanRelocations<ELFT>);
+
+  addIRelativeRelocs();
 
   if (In.Plt && !In.Plt->empty())
     In.Plt->addSymbols();



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201907311622.x6VGM69X045118>