[lld] r353981 - ELF: Allow GOT relocs pointing to non-preemptable ifunc to resolve to an IRELATIVE where possible.

Peter Collingbourne via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 13 13:49:55 PST 2019


Author: pcc
Date: Wed Feb 13 13:49:55 2019
New Revision: 353981

URL: http://llvm.org/viewvc/llvm-project?rev=353981&view=rev
Log:
ELF: Allow GOT relocs pointing to non-preemptable ifunc to resolve to an IRELATIVE where possible.

Non-GOT non-PLT relocations to non-preemptible ifuncs result in the
creation of a canonical PLT, which now takes the identity of the IFUNC
in the symbol table. This (a) ensures address consistency inside and
outside the module, and (b) fixes a bug where some of these relocations
end up pointing to the resolver.

Fixes (at least) PR40474 and PR40501.

Differential Revision: https://reviews.llvm.org/D57371

Added:
    lld/trunk/test/ELF/Inputs/gnu-ifunc-canon-ro-abs.s
    lld/trunk/test/ELF/Inputs/gnu-ifunc-canon-ro-pcrel.s
    lld/trunk/test/ELF/Inputs/gnu-ifunc-canon-rw-addend.s
    lld/trunk/test/ELF/gnu-ifunc-canon.s
Modified:
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/Relocations.cpp
    lld/trunk/ELF/Relocations.h
    lld/trunk/ELF/Symbols.cpp
    lld/trunk/ELF/Symbols.h
    lld/trunk/ELF/SyntheticSections.cpp
    lld/trunk/ELF/Writer.cpp
    lld/trunk/test/ELF/aarch64-gnu-ifunc-address-pie.s
    lld/trunk/test/ELF/aarch64-gnu-ifunc-address.s
    lld/trunk/test/ELF/aarch64-gnu-ifunc2.s
    lld/trunk/test/ELF/aarch64-gnu-ifunc3.s
    lld/trunk/test/ELF/gnu-ifunc-i386.s

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=353981&r1=353980&r2=353981&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Wed Feb 13 13:49:55 2019
@@ -611,7 +611,6 @@ static uint64_t getRelocTargetVA(const I
   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:
@@ -630,7 +629,6 @@ static uint64_t getRelocTargetVA(const I
   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:
@@ -680,10 +678,6 @@ static uint64_t getRelocTargetVA(const I
     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: {
     if (const Relocation *HiRel = getRISCVPCRelHi20(&Sym, A))
       return getRelocTargetVA(File, HiRel->Type, HiRel->Addend, Sym.getVA(),

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=353981&r1=353980&r2=353981&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Wed Feb 13 13:49:55 2019
@@ -336,8 +336,7 @@ static bool isAbsoluteValue(const Symbol
 
 // 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
@@ -346,8 +345,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
@@ -355,7 +353,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.
@@ -373,8 +371,8 @@ static bool isStaticLinkTimeConstant(Rel
   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))
@@ -382,7 +380,7 @@ static bool isStaticLinkTimeConstant(Rel
 
   // 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)
@@ -428,14 +426,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;
   }
@@ -767,14 +759,7 @@ static void addPltEntry(PltSection *Plt,
 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,
@@ -969,6 +954,15 @@ static void processRelocAux(InputSection
               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) {
@@ -1011,32 +1005,29 @@ static void scanReloc(InputSectionBase &
   if (Config->EMachine == EM_PPC64 && isPPC64SmallCodeModelTocReloc(Type))
     Sec.File->PPC64SmallCodeModelTocRelocs = true;
 
-  // Strengthen or relax relocations.
-  //
-  // GNU ifunc symbols must be accessed via PLT because their addresses
-  // are determined by runtime.
+  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.
   //
-  // 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()) {
-    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()) {
+    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
@@ -1056,28 +1047,136 @@ static void scanReloc(InputSectionBase &
     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
+  // 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);
+    // 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);
+      }
     }
   }
 
@@ -1107,6 +1206,21 @@ template <class ELFT> void elf::scanRelo
     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) {
   // std::merge requires a strict weak ordering.
   if (A->OutSecOff < B->OutSecOff)

Modified: lld/trunk/ELF/Relocations.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.h?rev=353981&r1=353980&r2=353981&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.h (original)
+++ lld/trunk/ELF/Relocations.h Wed Feb 13 13:49:55 2019
@@ -33,19 +33,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;
 struct InputSectionDescription;

Modified: lld/trunk/ELF/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.cpp?rev=353981&r1=353980&r2=353981&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.cpp (original)
+++ lld/trunk/ELF/Symbols.cpp Wed Feb 13 13:49:55 2019
@@ -120,20 +120,24 @@ uint64_t Symbol::getVA(int64_t Addend) c
   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: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=353981&r1=353980&r2=353981&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Wed Feb 13 13:49:55 2019
@@ -181,7 +181,7 @@ 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) {}
 
@@ -190,11 +190,13 @@ public:
   // 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: lld/trunk/ELF/SyntheticSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.cpp?rev=353981&r1=353980&r2=353981&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.cpp (original)
+++ lld/trunk/ELF/SyntheticSections.cpp Wed Feb 13 13:49:55 2019
@@ -1142,7 +1142,6 @@ IgotPltSection::IgotPltSection()
                        Target->GotPltEntrySize, getIgotPltName()) {}
 
 void IgotPltSection::addEntry(Symbol &Sym) {
-  Sym.IsInIgot = true;
   assert(Sym.PltIndex == Entries.size());
   Entries.push_back(&Sym);
 }
@@ -2344,10 +2343,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: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=353981&r1=353980&r2=353981&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Wed Feb 13 13:49:55 2019
@@ -1677,6 +1677,8 @@ template <class ELFT> void Writer<ELFT>:
   if (!Config->Relocatable)
     forEachRelSec(scanRelocations<ELFT>);
 
+  addIRelativeRelocs();
+
   if (In.Plt && !In.Plt->empty())
     In.Plt->addSymbols();
   if (In.Iplt && !In.Iplt->empty())

Added: lld/trunk/test/ELF/Inputs/gnu-ifunc-canon-ro-abs.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/gnu-ifunc-canon-ro-abs.s?rev=353981&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/gnu-ifunc-canon-ro-abs.s (added)
+++ lld/trunk/test/ELF/Inputs/gnu-ifunc-canon-ro-abs.s Wed Feb 13 13:49:55 2019
@@ -0,0 +1,2 @@
+.rodata
+.8byte ifunc

Added: lld/trunk/test/ELF/Inputs/gnu-ifunc-canon-ro-pcrel.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/gnu-ifunc-canon-ro-pcrel.s?rev=353981&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/gnu-ifunc-canon-ro-pcrel.s (added)
+++ lld/trunk/test/ELF/Inputs/gnu-ifunc-canon-ro-pcrel.s Wed Feb 13 13:49:55 2019
@@ -0,0 +1,2 @@
+.rodata
+.4byte ifunc - .

Added: lld/trunk/test/ELF/Inputs/gnu-ifunc-canon-rw-addend.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/gnu-ifunc-canon-rw-addend.s?rev=353981&view=auto
==============================================================================
--- lld/trunk/test/ELF/Inputs/gnu-ifunc-canon-rw-addend.s (added)
+++ lld/trunk/test/ELF/Inputs/gnu-ifunc-canon-rw-addend.s Wed Feb 13 13:49:55 2019
@@ -0,0 +1,2 @@
+.data
+.8byte ifunc + 1

Modified: lld/trunk/test/ELF/aarch64-gnu-ifunc-address-pie.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/aarch64-gnu-ifunc-address-pie.s?rev=353981&r1=353980&r2=353981&view=diff
==============================================================================
--- lld/trunk/test/ELF/aarch64-gnu-ifunc-address-pie.s (original)
+++ lld/trunk/test/ELF/aarch64-gnu-ifunc-address-pie.s Wed Feb 13 13:49:55 2019
@@ -12,6 +12,9 @@
 .globl myfunc
 .type myfunc, at gnu_indirect_function
 myfunc:
+.globl myfunc_resolver
+.type myfunc_resolver, at function
+myfunc_resolver:
  ret
 
 .text
@@ -22,7 +25,7 @@ main:
  add  x8, x8, :lo12: myfunc
  ret
 
-# CHECK: 0000000000010000 myfunc:
+# CHECK: 0000000000010000 myfunc_resolver:
 # CHECK-NEXT:    10000:	c0 03 5f d6 	ret
 # CHECK: 0000000000010004 main:
 # CHECK-NEXT:    10004:	08 00 00 90 	adrp	x8, #0
@@ -31,7 +34,7 @@ main:
 # x8 = 0x10010 = .plt for myfunc
 # CHECK-NEXT:    1000c:	c0 03 5f d6 	ret
 # CHECK-NEXT: Disassembly of section .plt:
-# CHECK-NEXT: 0000000000010010 .plt:
+# CHECK-NEXT: 0000000000010010 myfunc:
 # CHECK-NEXT:    10010:	90 00 00 90 	adrp	x16, #65536
 # CHECK-NEXT:    10014:	11 02 40 f9 	ldr	x17, [x16]
 # CHECK-NEXT:    10018:	10 02 00 91 	add	x16, x16, #0

Modified: lld/trunk/test/ELF/aarch64-gnu-ifunc-address.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/aarch64-gnu-ifunc-address.s?rev=353981&r1=353980&r2=353981&view=diff
==============================================================================
--- lld/trunk/test/ELF/aarch64-gnu-ifunc-address.s (original)
+++ lld/trunk/test/ELF/aarch64-gnu-ifunc-address.s Wed Feb 13 13:49:55 2019
@@ -21,20 +21,17 @@ main:
  ldr  x8, [x8, :got_lo12:myfunc]
  ret
 # CHECK:   0000000000010004 main:
-# x8 = 0x30000
-# CHECK-NEXT:    10004: 08 01 00 90     adrp    x8, #131072
-# x8 = 0x300e0 = .got entry for myfunc with R_AARCH64_GLOB_DAT
-# CHECK-NEXT:    10008: 08 71 40 f9     ldr     x8, [x8, #224]
+# x8 = 0x20000
+# CHECK-NEXT:    10004: 88 00 00 90     adrp    x8, #65536
+# x8 = 0x200a0 = .got entry for myfunc with R_AARCH64_GLOB_DAT
+# CHECK-NEXT:    10008: 08 51 40 f9     ldr     x8, [x8, #160]
 # CHECK-NEXT:    1000c: c0 03 5f d6     ret
 
 # CHECK: Disassembly of section .got:
-# CHECK-NEXT: 00000000000300e0 .got:
+# CHECK-NEXT: 00000000000200a0 .got:
 
 # CHECK-RELOCS: Relocations [
 # CHECK-RELOCS-NEXT:   Section {{.*}} .rela.dyn {
-# CHECK-RELOCS-NEXT:     0x300E0 R_AARCH64_GLOB_DAT myfunc 0x0
-# CHECK-RELOCS-NEXT:   }
-# CHECK-RELOCS-NEXT:   Section {{.*}} .rela.plt {
-# CHECK-RELOCS-NEXT:     0x20018 R_AARCH64_JUMP_SLOT myfunc 0x0
+# CHECK-RELOCS-NEXT:     0x200A0 R_AARCH64_GLOB_DAT myfunc 0x0
 # CHECK-RELOCS-NEXT:   }
 # CHECK-RELOCS-NEXT: ]

Modified: lld/trunk/test/ELF/aarch64-gnu-ifunc2.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/aarch64-gnu-ifunc2.s?rev=353981&r1=353980&r2=353981&view=diff
==============================================================================
--- lld/trunk/test/ELF/aarch64-gnu-ifunc2.s (original)
+++ lld/trunk/test/ELF/aarch64-gnu-ifunc2.s Wed Feb 13 13:49:55 2019
@@ -9,8 +9,8 @@
 # CHECK-NEXT:   210000:
 
 # CHECK:      main:
-# adrp x8, 0x230000, 0x230000 == address in .got
-# CHECK-NEXT:   210004: {{.*}} adrp    x8, #131072
+# adrp x8, 0x220000, 0x220000 == address in .got.plt
+# CHECK-NEXT:   210004: {{.*}} adrp    x8, #65536
 # CHECK-NEXT:   210008: {{.*}} ldr     x8, [x8]
 # CHECK-NEXT:   21000c: {{.*}} ret
 
@@ -26,11 +26,6 @@
 # CHECK-NEXT: .got.plt:
 # CHECK-NEXT:   220000:
 
-# CHECK:      Disassembly of section .got:
-# CHECK-NEXT: .got:
-# 0x210010 == address in .plt
-# CHECK-NEXT:   230000: 10 00 21 00
-
 # RELOC:      Relocations [
 # RELOC-NEXT:   Section {{.*}} .rela.plt {
 # RELOC-NEXT:     0x220000 R_AARCH64_IRELATIVE - 0x210000

Modified: lld/trunk/test/ELF/aarch64-gnu-ifunc3.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/aarch64-gnu-ifunc3.s?rev=353981&r1=353980&r2=353981&view=diff
==============================================================================
--- lld/trunk/test/ELF/aarch64-gnu-ifunc3.s (original)
+++ lld/trunk/test/ELF/aarch64-gnu-ifunc3.s Wed Feb 13 13:49:55 2019
@@ -11,6 +11,9 @@
 .globl myfunc
 .type myfunc, at gnu_indirect_function
 myfunc:
+.globl myfunc_resolver
+.type myfunc_resolver, at function
+myfunc_resolver:
  ret
 
 .text
@@ -22,7 +25,7 @@ _start:
  ret
 
 # CHECK: Disassembly of section .text:
-# CHECK-NEXT: myfunc:
+# CHECK-NEXT: myfunc_resolver:
 # CHECK-NEXT:   210000:	c0 03 5f d6 	ret
 # CHECK: _start:
 # adrp x8, 0x210000 + 0x10 from add == .plt entry
@@ -30,7 +33,7 @@ _start:
 # CHECK-NEXT:   210008:	08 41 00 91 	add	x8, x8, #16
 # CHECK-NEXT:   21000c:	c0 03 5f d6 	ret
 # CHECK-NEXT: Disassembly of section .plt:
-# CHECK-NEXT: .plt:
+# CHECK-NEXT: myfunc:
 # adrp x16, 0x220000, 0x220000 == address in .got.plt
 # CHECK-NEXT:   210010:	90 00 00 90 	adrp	x16, #65536
 # CHECK-NEXT:   210014:	11 02 40 f9 	ldr	x17, [x16]

Added: lld/trunk/test/ELF/gnu-ifunc-canon.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/gnu-ifunc-canon.s?rev=353981&view=auto
==============================================================================
--- lld/trunk/test/ELF/gnu-ifunc-canon.s (added)
+++ lld/trunk/test/ELF/gnu-ifunc-canon.s Wed Feb 13 13:49:55 2019
@@ -0,0 +1,92 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gnu-ifunc-canon-ro-pcrel.s -o %t-ro-pcrel.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gnu-ifunc-canon-ro-abs.s -o %t-ro-abs.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gnu-ifunc-canon-rw-addend.s -o %t-rw-addend.o
+// RUN: ld.lld %t.o -o %t1
+// RUN: llvm-readobj -relocs %t1 | FileCheck --check-prefix=IREL2 %s
+// RUN: ld.lld %t.o %t-ro-pcrel.o -o %t2
+// RUN: llvm-readobj -relocs %t2 | FileCheck --check-prefix=IREL1 %s
+// RUN: ld.lld %t.o %t-ro-abs.o -o %t3
+// RUN: llvm-readobj -relocs %t3 | FileCheck --check-prefix=IREL1 %s
+// RUN: ld.lld %t.o %t-rw-addend.o -o %t4
+// RUN: llvm-readobj -relocs %t4 | FileCheck --check-prefix=IREL1 %s
+// RUN: llvm-objdump -s %t4 | FileCheck --check-prefix=DUMP %s
+// RUN: ld.lld %t.o %t-rw-addend.o -o %t4a -z retpolineplt
+// RUN: llvm-readobj -relocs %t4a | FileCheck --check-prefix=IREL1 %s
+// RUN: llvm-objdump -s %t4a | FileCheck --check-prefix=DUMP2 %s
+// RUN: ld.lld %t-ro-pcrel.o %t.o -o %t5
+// RUN: llvm-readobj -relocs %t5 | FileCheck --check-prefix=IREL1 %s
+// RUN: ld.lld %t-ro-abs.o %t.o -o %t6
+// RUN: llvm-readobj -relocs %t6 | FileCheck --check-prefix=IREL1 %s
+// RUN: ld.lld %t-rw-addend.o %t.o -o %t7
+// RUN: llvm-readobj -relocs %t7 | FileCheck --check-prefix=IREL1 %s
+// RUN: ld.lld %t.o -o %t8 -pie
+// RUN: llvm-readobj -relocs %t8 | FileCheck --check-prefix=IREL2 %s
+// RUN: ld.lld %t.o %t-ro-pcrel.o -o %t9 -pie
+// RUN: llvm-readobj -relocs %t9 | FileCheck --check-prefix=IREL1-REL2 %s
+// RUN: ld.lld %t.o %t-rw-addend.o -o %t10 -pie
+// RUN: llvm-readobj -relocs %t10 | FileCheck --check-prefix=IREL1-REL3 %s
+// RUN: ld.lld %t-ro-pcrel.o %t.o -o %t11 -pie
+// RUN: llvm-readobj -relocs %t11 | FileCheck --check-prefix=IREL1-REL2 %s
+// RUN: ld.lld %t-rw-addend.o %t.o -o %t12 -pie
+// RUN: llvm-readobj -relocs %t12 | FileCheck --check-prefix=IREL1-REL3 %s
+
+// Two relocs, one for the GOT and the other for .data.
+// IREL2-NOT: R_X86_64_
+// IREL2: .rela.plt
+// IREL2-NEXT: R_X86_64_IRELATIVE
+// IREL2-NEXT: R_X86_64_IRELATIVE
+// IREL2-NOT: R_X86_64_
+
+// One reloc for the canonical PLT.
+// IREL1-NOT: R_X86_64_
+// IREL1: .rela.plt
+// IREL1-NEXT: R_X86_64_IRELATIVE
+// IREL1-NOT: R_X86_64_
+
+// One reloc for the canonical PLT and two RELATIVE relocations pointing to it,
+// one in the GOT and one in .data.
+// IREL1-REL2-NOT: R_X86_64_
+// IREL1-REL2: .rela.dyn
+// IREL1-REL2-NEXT: R_X86_64_RELATIVE
+// IREL1-REL2-NEXT: R_X86_64_RELATIVE
+// IREL1-REL2: .rela.plt
+// IREL1-REL2-NEXT: R_X86_64_IRELATIVE
+// IREL1-REL2-NOT: R_X86_64_
+
+// One reloc for the canonical PLT and three RELATIVE relocations pointing to it,
+// one in the GOT and two in .data.
+// IREL1-REL3-NOT: R_X86_64_
+// IREL1-REL3: .rela.dyn
+// IREL1-REL3-NEXT: R_X86_64_RELATIVE
+// IREL1-REL3-NEXT: R_X86_64_RELATIVE
+// IREL1-REL3-NEXT: R_X86_64_RELATIVE
+// IREL1-REL3: .rela.plt
+// IREL1-REL3-NEXT: R_X86_64_IRELATIVE
+// IREL1-REL3-NOT: R_X86_64_
+
+// Make sure the static relocations look right, both with and without headers.
+// DUMP: Contents of section .plt:
+// DUMP-NEXT: 201010
+// DUMP: Contents of section .data:
+// DUMP-NEXT: 202000 10102000 00000000 11102000 00000000
+// DUMP: Contents of section .got:
+// DUMP-NEXT: 203000 10102000 00000000
+
+// DUMP2: Contents of section .plt:
+// DUMP2-NEXT: 201010
+// DUMP2: Contents of section .data:
+// DUMP2-NEXT: 202000 40102000 00000000 41102000 00000000
+// DUMP2: Contents of section .got:
+// DUMP2-NEXT: 203000 40102000 00000000
+
+lea ifunc at gotpcrel(%rip), %rbx
+
+.type ifunc STT_GNU_IFUNC
+.globl ifunc
+ifunc:
+ret
+
+.data
+.8byte ifunc

Modified: lld/trunk/test/ELF/gnu-ifunc-i386.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/gnu-ifunc-i386.s?rev=353981&r1=353980&r2=353981&view=diff
==============================================================================
--- lld/trunk/test/ELF/gnu-ifunc-i386.s (original)
+++ lld/trunk/test/ELF/gnu-ifunc-i386.s Wed Feb 13 13:49:55 2019
@@ -70,28 +70,46 @@
 // CHECK-NEXT: }
 // CHECK-NEXT: Symbol {
 // CHECK-NEXT:   Name: bar
+// CHECK-NEXT:   Value: 0x401030
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Global
+// CHECK-NEXT:   Type: Function
+// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Section: .plt
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: bar_resolver
 // CHECK-NEXT:   Value: 0x401001
 // CHECK-NEXT:   Size: 0
 // CHECK-NEXT:   Binding: Global
-// CHECK-NEXT:   Type: GNU_IFunc
+// CHECK-NEXT:   Type: Function
 // CHECK-NEXT:   Other: 0
 // CHECK-NEXT:   Section: .text
 // CHECK-NEXT: }
 // CHECK-NEXT: Symbol {
 // CHECK-NEXT:   Name: foo
+// CHECK-NEXT:   Value: 0x401020
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Global
+// CHECK-NEXT:   Type: Function
+// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Section: .plt
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT:   Name: foo_resolver
 // CHECK-NEXT:   Value: 0x401000
 // CHECK-NEXT:   Size: 0
 // CHECK-NEXT:   Binding: Global
-// CHECK-NEXT:   Type: GNU_IFunc
+// CHECK-NEXT:   Type: Function
 // CHECK-NEXT:   Other: 0
 // CHECK-NEXT:   Section: .text
 // CHECK-NEXT: }
 // CHECK-NEXT:]
 
 // DISASM: Disassembly of section .text:
-// DISASM-NEXT: foo:
+// DISASM-NEXT: foo_resolver:
 // DISASM-NEXT:    401000: c3 retl
-// DISASM: bar:
+// DISASM: bar_resolver:
 // DISASM-NEXT:    401001: c3 retl
 // DISASM:      _start:
 // DISASM-NEXT:    401002: e8 19 00 00 00 calll 25
@@ -99,10 +117,11 @@
 // DISASM-NEXT:    40100c: ba d4 00 40 00 movl $4194516, %edx
 // DISASM-NEXT:    401011: ba e4 00 40 00 movl $4194532, %edx
 // DISASM-NEXT: Disassembly of section .plt:
-// DISASM-NEXT: .plt:
+// DISASM-NEXT: foo:
 // DISASM-NEXT:    401020: ff 25 00 20 40 00 jmpl *4202496
 // DISASM-NEXT:    401026: 68 10 00 00 00 pushl $16
 // DISASM-NEXT:    40102b: e9 e0 ff ff ff jmp -32 <_start+0xe>
+// DISASM:      bar:
 // DISASM-NEXT:    401030: ff 25 04 20 40 00 jmpl *4202500
 // DISASM-NEXT:    401036: 68 18 00 00 00 pushl $24
 // DISASM-NEXT:    40103b: e9 d0 ff ff ff jmp -48 <_start+0xe>
@@ -111,11 +130,17 @@
 .type foo STT_GNU_IFUNC
 .globl foo
 foo:
+.type foo_resolver STT_FUNC
+.globl foo_resolver
+foo_resolver:
  ret
 
 .type bar STT_GNU_IFUNC
 .globl bar
 bar:
+.type bar_resolver STT_FUNC
+.globl bar_resolver
+bar_resolver:
  ret
 
 .globl _start




More information about the llvm-commits mailing list