[ELF] ifunc implementation using synthetic sections
authorPeter Smith <peter.smith@linaro.org>
Thu, 8 Dec 2016 12:58:55 +0000 (12:58 +0000)
committerPeter Smith <peter.smith@linaro.org>
Thu, 8 Dec 2016 12:58:55 +0000 (12:58 +0000)
This change introduces new synthetic sections IpltSection, IgotPltSection
that represent the ifunc entries that would previously have been put in
the PltSection and the GotPltSection. The separation makes sure that
the R_*_IRELATIVE relocations are placed after the non R_*_IRELATIVE
relocations, which permits ifunc resolvers to know that the .got.plt
slots will be initialized prior to the resolver being called.

A secondary benefit is that for ARM we can move the IgotPltSection and its
dynamic relocations to the .got and .rel.dyn as the ARM glibc expects all
the R_*_IRELATIVE relocations to be in the .rel.dyn

Differential revision: https://reviews.llvm.org/D27406

llvm-svn: 289045

16 files changed:
lld/ELF/Relocations.cpp
lld/ELF/Symbols.cpp
lld/ELF/Symbols.h
lld/ELF/SyntheticSections.cpp
lld/ELF/SyntheticSections.h
lld/ELF/Writer.cpp
lld/test/ELF/Inputs/arm-shared.s [new file with mode: 0644]
lld/test/ELF/Inputs/shared2-x86-64.s [new file with mode: 0644]
lld/test/ELF/aarch64-gnu-ifunc-plt.s [new file with mode: 0644]
lld/test/ELF/aarch64-gnu-ifunc.s
lld/test/ELF/arm-gnu-ifunc-plt.s [new file with mode: 0644]
lld/test/ELF/arm-gnu-ifunc.s
lld/test/ELF/gnu-ifunc-i386.s
lld/test/ELF/gnu-ifunc-plt.s [new file with mode: 0644]
lld/test/ELF/gnu-ifunc-shared.s [new file with mode: 0644]
lld/test/ELF/gnu-ifunc.s

index a394569..11c1552 100644 (file)
@@ -719,18 +719,20 @@ static void scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
     if (needsPlt(Expr)) {
       if (Body.isInPlt())
         continue;
-      In<ELFT>::Plt->addEntry(Body);
 
-      uint32_t Rel;
-      if (Body.isGnuIFunc() && !Preemptible)
-        Rel = Target->IRelativeRel;
-      else
-        Rel = Target->PltRel;
-
-      In<ELFT>::GotPlt->addEntry(Body);
-      In<ELFT>::RelaPlt->addReloc({Rel, In<ELFT>::GotPlt,
-                                   Body.getGotPltOffset<ELFT>(), !Preemptible,
-                                   &Body, 0});
+      if (Body.isGnuIFunc() && !Preemptible) {
+        In<ELFT>::Iplt->addEntry(Body);
+        In<ELFT>::IgotPlt->addEntry(Body);
+        In<ELFT>::RelaIplt->addReloc({Target->IRelativeRel, In<ELFT>::IgotPlt,
+                                      Body.getGotPltOffset<ELFT>(),
+                                      !Preemptible, &Body, 0});
+      } else {
+        In<ELFT>::Plt->addEntry(Body);
+        In<ELFT>::GotPlt->addEntry(Body);
+        In<ELFT>::RelaPlt->addReloc({Target->PltRel, In<ELFT>::GotPlt,
+                                     Body.getGotPltOffset<ELFT>(), !Preemptible,
+                                     &Body, 0});
+      }
       continue;
     }
 
index 9fa1ed4..ba1f218 100644 (file)
@@ -95,8 +95,8 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
 SymbolBody::SymbolBody(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther,
                        uint8_t Type)
     : SymbolKind(K), NeedsCopyOrPltAddr(false), IsLocal(IsLocal),
-      IsInGlobalMipsGot(false), Is32BitMipsGot(false), Type(Type),
-      StOther(StOther), Name(Name) {}
+      IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false),
+      IsInIgot(false), Type(Type), StOther(StOther), Name(Name) {}
 
 // Returns true if a symbol can be replaced at load-time by a symbol
 // with the same name defined in other ELF executable or DSO.
@@ -151,6 +151,8 @@ template <class ELFT> typename ELFT::uint SymbolBody::getGotOffset() const {
 }
 
 template <class ELFT> typename ELFT::uint SymbolBody::getGotPltVA() const {
+  if (this->IsInIgot)
+    return In<ELFT>::IgotPlt->getVA() + getGotPltOffset<ELFT>();
   return In<ELFT>::GotPlt->getVA() + getGotPltOffset<ELFT>();
 }
 
@@ -159,6 +161,8 @@ template <class ELFT> typename ELFT::uint SymbolBody::getGotPltOffset() const {
 }
 
 template <class ELFT> typename ELFT::uint SymbolBody::getPltVA() const {
+  if (this->IsInIplt)
+    return In<ELFT>::Iplt->getVA() + PltIndex * Target->PltEntrySize;
   return In<ELFT>::Plt->getVA() + Target->PltHeaderSize +
          PltIndex * Target->PltEntrySize;
 }
index 42194eb..4a646bc 100644 (file)
@@ -117,6 +117,12 @@ public:
   // True if this symbol is referenced by 32-bit GOT relocations.
   unsigned Is32BitMipsGot : 1;
 
+  // True if this symbol is in the Iplt sub-section of the Plt.
+  unsigned IsInIplt : 1;
+
+  // True if this symbol is in the Igot sub-section of the .got.plt or .got.
+  unsigned IsInIgot : 1;
+
   // The following fields have the same meaning as the ELF symbol attributes.
   uint8_t Type;    // symbol type
   uint8_t StOther; // st_other field value
index 3653354..d69100a 100644 (file)
@@ -707,6 +707,36 @@ template <class ELFT> void GotPltSection<ELFT>::writeTo(uint8_t *Buf) {
   }
 }
 
+// On ARM the IgotPltSection is part of the GotSection, on other Targets it is
+// part of the .got.plt
+template <class ELFT>
+IgotPltSection<ELFT>::IgotPltSection()
+    : SyntheticSection<ELFT>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
+                             Target->GotPltEntrySize,
+                             Config->EMachine == EM_ARM ? ".got" : ".got.plt") {
+}
+
+template <class ELFT> void IgotPltSection<ELFT>::addEntry(SymbolBody &Sym) {
+  Sym.IsInIgot = true;
+  Sym.GotPltIndex = Entries.size();
+  Entries.push_back(&Sym);
+}
+
+template <class ELFT> size_t IgotPltSection<ELFT>::getSize() const {
+  return Entries.size() * Target->GotPltEntrySize;
+}
+
+template <class ELFT> void IgotPltSection<ELFT>::writeTo(uint8_t *Buf) {
+  for (const SymbolBody *B : Entries) {
+    if (Config->EMachine == EM_ARM)
+      // On ARM we are actually part of the Got and not GotPlt.
+      write32le(Buf, B->getVA<ELFT>());
+    else
+      Target->writeGotPlt(Buf, *B);
+    Buf += sizeof(uintX_t);
+  }
+}
+
 template <class ELFT>
 StringTableSection<ELFT>::StringTableSection(StringRef Name, bool Dynamic)
     : SyntheticSection<ELFT>(Dynamic ? (uintX_t)SHF_ALLOC : 0, SHT_STRTAB, 1,
@@ -805,11 +835,10 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
     return; // Already finalized.
 
   this->Link = In<ELFT>::DynStrTab->OutSec->SectionIndex;
-
-  if (!In<ELFT>::RelaDyn->empty()) {
+  if (In<ELFT>::RelaDyn->OutSec->Size > 0) {
     bool IsRela = Config->Rela;
     add({IsRela ? DT_RELA : DT_REL, In<ELFT>::RelaDyn});
-    add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->getSize()});
+    add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->OutSec->Size});
     add({IsRela ? DT_RELAENT : DT_RELENT,
          uintX_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))});
 
@@ -822,9 +851,9 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
         add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels});
     }
   }
-  if (!In<ELFT>::RelaPlt->empty()) {
+  if (In<ELFT>::RelaPlt->OutSec->Size > 0) {
     add({DT_JMPREL, In<ELFT>::RelaPlt});
-    add({DT_PLTRELSZ, In<ELFT>::RelaPlt->getSize()});
+    add({DT_PLTRELSZ, In<ELFT>::RelaPlt->OutSec->Size});
     add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT,
          In<ELFT>::GotPlt});
     add({DT_PLTREL, uint64_t(Config->Rela ? DT_RELA : DT_REL)});
@@ -1401,6 +1430,36 @@ template <class ELFT> size_t PltSection<ELFT>::getSize() const {
 }
 
 template <class ELFT>
+IpltSection<ELFT>::IpltSection()
+    : SyntheticSection<ELFT>(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16,
+                             ".plt") {}
+
+template <class ELFT> void IpltSection<ELFT>::writeTo(uint8_t *Buf) {
+  // The IRelative relocations do not support lazy binding so no header is
+  // needed
+  size_t Off = 0;
+  for (auto &I : Entries) {
+    const SymbolBody *B = I.first;
+    unsigned RelOff = I.second + In<ELFT>::Plt->getSize();
+    uint64_t Got = B->getGotPltVA<ELFT>();
+    uint64_t Plt = this->getVA() + Off;
+    Target->writePlt(Buf + Off, Got, Plt, B->PltIndex, RelOff);
+    Off += Target->PltEntrySize;
+  }
+}
+
+template <class ELFT> void IpltSection<ELFT>::addEntry(SymbolBody &Sym) {
+  Sym.PltIndex = Entries.size();
+  Sym.IsInIplt = true;
+  unsigned RelOff = In<ELFT>::RelaIplt->getRelocOffset();
+  Entries.push_back(std::make_pair(&Sym, RelOff));
+}
+
+template <class ELFT> size_t IpltSection<ELFT>::getSize() const {
+  return Entries.size() * Target->PltEntrySize;
+}
+
+template <class ELFT>
 GdbIndexSection<ELFT>::GdbIndexSection()
     : SyntheticSection<ELFT>(0, SHT_PROGBITS, 1, ".gdb_index") {}
 
@@ -1750,6 +1809,11 @@ template class elf::GotPltSection<ELF32BE>;
 template class elf::GotPltSection<ELF64LE>;
 template class elf::GotPltSection<ELF64BE>;
 
+template class elf::IgotPltSection<ELF32LE>;
+template class elf::IgotPltSection<ELF32BE>;
+template class elf::IgotPltSection<ELF64LE>;
+template class elf::IgotPltSection<ELF64BE>;
+
 template class elf::StringTableSection<ELF32LE>;
 template class elf::StringTableSection<ELF32BE>;
 template class elf::StringTableSection<ELF64LE>;
@@ -1785,6 +1849,11 @@ template class elf::PltSection<ELF32BE>;
 template class elf::PltSection<ELF64LE>;
 template class elf::PltSection<ELF64BE>;
 
+template class elf::IpltSection<ELF32LE>;
+template class elf::IpltSection<ELF32BE>;
+template class elf::IpltSection<ELF64LE>;
+template class elf::IpltSection<ELF64BE>;
+
 template class elf::GdbIndexSection<ELF32LE>;
 template class elf::GdbIndexSection<ELF32BE>;
 template class elf::GdbIndexSection<ELF64LE>;
index bafd4e9..f0932df 100644 (file)
@@ -206,6 +206,25 @@ private:
   std::vector<const SymbolBody *> Entries;
 };
 
+// The IgotPltSection is a Got associated with the IpltSection for GNU Ifunc
+// Symbols that will be relocated by Target->IRelativeRel.
+// On most Targets the IgotPltSection will immediately follow the GotPltSection
+// on ARM the IgotPltSection will immediately follow the GotSection.
+template <class ELFT>
+class IgotPltSection final : public SyntheticSection<ELFT> {
+  typedef typename ELFT::uint uintX_t;
+
+public:
+  IgotPltSection();
+  void addEntry(SymbolBody &Sym);
+  size_t getSize() const override;
+  void writeTo(uint8_t *Buf) override;
+  bool empty() const override { return Entries.empty(); }
+
+private:
+  std::vector<const SymbolBody *> Entries;
+};
+
 template <class ELFT>
 class StringTableSection final : public SyntheticSection<ELFT> {
 public:
@@ -431,6 +450,21 @@ private:
   std::vector<std::pair<const SymbolBody *, unsigned>> Entries;
 };
 
+// The IpltSection is a variant of Plt for recording entries for GNU Ifunc
+// symbols that will be subject to a Target->IRelativeRel
+// The IpltSection immediately follows the Plt section in the Output Section
+template <class ELFT> class IpltSection final : public SyntheticSection<ELFT> {
+public:
+  IpltSection();
+  void writeTo(uint8_t *Buf) override;
+  size_t getSize() const override;
+  void addEntry(SymbolBody &Sym);
+  bool empty() const override { return Entries.empty(); }
+
+private:
+  std::vector<std::pair<const SymbolBody *, unsigned>> Entries;
+};
+
 template <class ELFT>
 class GdbIndexSection final : public SyntheticSection<ELFT> {
   typedef typename ELFT::uint uintX_t;
@@ -644,12 +678,15 @@ template <class ELFT> struct In {
   static GotSection<ELFT> *Got;
   static MipsGotSection<ELFT> *MipsGot;
   static GotPltSection<ELFT> *GotPlt;
+  static IgotPltSection<ELFT> *IgotPlt;
   static HashTableSection<ELFT> *HashTab;
   static InputSection<ELFT> *Interp;
   static MipsRldMapSection<ELFT> *MipsRldMap;
   static PltSection<ELFT> *Plt;
+  static IpltSection<ELFT> *Iplt;
   static RelocationSection<ELFT> *RelaDyn;
   static RelocationSection<ELFT> *RelaPlt;
+  static RelocationSection<ELFT> *RelaIplt;
   static StringTableSection<ELFT> *ShStrTab;
   static StringTableSection<ELFT> *StrTab;
   static SymbolTableSection<ELFT> *SymTab;
@@ -669,12 +706,15 @@ template <class ELFT> GnuHashTableSection<ELFT> *In<ELFT>::GnuHashTab;
 template <class ELFT> GotSection<ELFT> *In<ELFT>::Got;
 template <class ELFT> MipsGotSection<ELFT> *In<ELFT>::MipsGot;
 template <class ELFT> GotPltSection<ELFT> *In<ELFT>::GotPlt;
+template <class ELFT> IgotPltSection<ELFT> *In<ELFT>::IgotPlt;
 template <class ELFT> HashTableSection<ELFT> *In<ELFT>::HashTab;
 template <class ELFT> InputSection<ELFT> *In<ELFT>::Interp;
 template <class ELFT> MipsRldMapSection<ELFT> *In<ELFT>::MipsRldMap;
 template <class ELFT> PltSection<ELFT> *In<ELFT>::Plt;
+template <class ELFT> IpltSection<ELFT> *In<ELFT>::Iplt;
 template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaDyn;
 template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaPlt;
+template <class ELFT> RelocationSection<ELFT> *In<ELFT>::RelaIplt;
 template <class ELFT> StringTableSection<ELFT> *In<ELFT>::ShStrTab;
 template <class ELFT> StringTableSection<ELFT> *In<ELFT>::StrTab;
 template <class ELFT> SymbolTableSection<ELFT> *In<ELFT>::SymTab;
index dbaa593..be9be49 100644 (file)
@@ -356,6 +356,8 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
 
   In<ELFT>::GotPlt = make<GotPltSection<ELFT>>();
   Symtab<ELFT>::X->Sections.push_back(In<ELFT>::GotPlt);
+  In<ELFT>::IgotPlt = make<IgotPltSection<ELFT>>();
+  Symtab<ELFT>::X->Sections.push_back(In<ELFT>::IgotPlt);
 
   if (Config->GdbIndex) {
     In<ELFT>::GdbIndex = make<GdbIndexSection<ELFT>>();
@@ -368,8 +370,17 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() {
       Config->Rela ? ".rela.plt" : ".rel.plt", false /*Sort*/);
   Symtab<ELFT>::X->Sections.push_back(In<ELFT>::RelaPlt);
 
+  // The RelaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure
+  // that the IRelative relocations are processed last by the dynamic loader
+  In<ELFT>::RelaIplt = make<RelocationSection<ELFT>>(
+      (Config->EMachine == EM_ARM) ? ".rel.dyn" : In<ELFT>::RelaPlt->Name,
+      false /*Sort*/);
+  Symtab<ELFT>::X->Sections.push_back(In<ELFT>::RelaIplt);
+
   In<ELFT>::Plt = make<PltSection<ELFT>>();
   Symtab<ELFT>::X->Sections.push_back(In<ELFT>::Plt);
+  In<ELFT>::Iplt = make<IpltSection<ELFT>>();
+  Symtab<ELFT>::X->Sections.push_back(In<ELFT>::Iplt);
 
   if (Config->EhFrameHdr) {
     In<ELFT>::EhFrameHdr = make<EhFrameHeader<ELFT>>();
@@ -651,10 +662,10 @@ template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
   if (In<ELFT>::DynSymTab)
     return;
   StringRef S = Config->Rela ? "__rela_iplt_start" : "__rel_iplt_start";
-  addOptionalRegular<ELFT>(S, In<ELFT>::RelaPlt, 0);
+  addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, 0);
 
   S = Config->Rela ? "__rela_iplt_end" : "__rel_iplt_end";
-  addOptionalRegular<ELFT>(S, In<ELFT>::RelaPlt, -1);
+  addOptionalRegular<ELFT>(S, In<ELFT>::RelaIplt, -1);
 }
 
 // The linker is expected to define some symbols depending on
@@ -1036,11 +1047,13 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
   // symbol table section (DynSymTab) must be the first one.
   finalizeSynthetic<ELFT>(
       {In<ELFT>::DynSymTab, In<ELFT>::GnuHashTab, In<ELFT>::HashTab,
-       In<ELFT>::SymTab, In<ELFT>::ShStrTab, In<ELFT>::StrTab, In<ELFT>::VerDef,
-       In<ELFT>::DynStrTab, In<ELFT>::GdbIndex, In<ELFT>::Got,
-       In<ELFT>::MipsGot, In<ELFT>::GotPlt, In<ELFT>::RelaDyn,
-       In<ELFT>::RelaPlt, In<ELFT>::Plt, In<ELFT>::EhFrameHdr, In<ELFT>::VerSym,
-       In<ELFT>::VerNeed, In<ELFT>::Dynamic});
+       In<ELFT>::SymTab,    In<ELFT>::ShStrTab,   In<ELFT>::StrTab,
+       In<ELFT>::VerDef,    In<ELFT>::DynStrTab,  In<ELFT>::GdbIndex,
+       In<ELFT>::Got,       In<ELFT>::MipsGot,    In<ELFT>::IgotPlt,
+       In<ELFT>::GotPlt,    In<ELFT>::RelaDyn,    In<ELFT>::RelaIplt,
+       In<ELFT>::RelaPlt,   In<ELFT>::Plt,        In<ELFT>::Iplt,
+       In<ELFT>::Plt,       In<ELFT>::EhFrameHdr, In<ELFT>::VerSym,
+       In<ELFT>::VerNeed,   In<ELFT>::Dynamic});
 }
 
 template <class ELFT> void Writer<ELFT>::addPredefinedSections() {
diff --git a/lld/test/ELF/Inputs/arm-shared.s b/lld/test/ELF/Inputs/arm-shared.s
new file mode 100644 (file)
index 0000000..4330a1d
--- /dev/null
@@ -0,0 +1,8 @@
+.syntax unified
+.global bar2
+.type bar2, %function
+bar2:
+
+.global zed2
+.type zed2, %function
+zed2:
diff --git a/lld/test/ELF/Inputs/shared2-x86-64.s b/lld/test/ELF/Inputs/shared2-x86-64.s
new file mode 100644 (file)
index 0000000..925e6a4
--- /dev/null
@@ -0,0 +1,9 @@
+.global bar2
+.type bar2, @function
+bar2:
+ ret
+
+.global zed2
+.type  zed2, @function
+zed2:
+ ret
diff --git a/lld/test/ELF/aarch64-gnu-ifunc-plt.s b/lld/test/ELF/aarch64-gnu-ifunc-plt.s
new file mode 100644 (file)
index 0000000..50e63f5
--- /dev/null
@@ -0,0 +1,85 @@
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %S/Inputs/shared2.s -o %t1.o
+// RUN: ld.lld %t1.o --shared -o %t.so
+// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o
+// RUN: ld.lld %t.so %t.o -o %tout
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT
+// RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s
+// REQUIRES: aarch64
+
+// Check that the IRELATIVE relocations are after the JUMP_SLOT in the plt
+// CHECK: Relocations [
+// CHECK-NEXT:   Section (4) .rela.plt {
+// CHECK:     0x40018 R_AARCH64_JUMP_SLOT bar2 0x0
+// CHECK-NEXT:     0x40020 R_AARCH64_JUMP_SLOT zed2 0x0
+// CHECK-NEXT:     0x40028 R_AARCH64_IRELATIVE - 0x20000
+// CHECK-NEXT:     0x40030 R_AARCH64_IRELATIVE - 0x20004
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// Check that .got.plt entries point back to PLT header
+// GOTPLT: Contents of section .got.plt:
+// GOTPLT-NEXT:  40000 00000000 00000000 00000000 00000000
+// GOTPLT-NEXT:  40010 00000000 00000000 20000200 00000000
+// GOTPLT-NEXT:  40020 20000200 00000000 20000200 00000000
+// GOTPLT-NEXT:  40030 20000200 00000000
+
+// Check that the PLTRELSZ tag includes the IRELATIVE relocations
+// CHECK: DynamicSection [
+// CHECK:   0x0000000000000002 PLTRELSZ             96 (bytes)
+
+// Check that a PLT header is written and the ifunc entries appear last
+// DISASM: Disassembly of section .text:
+// DISASM-NEXT: foo:
+// DISASM-NEXT:    20000:       c0 03 5f d6     ret
+// DISASM:      bar:
+// DISASM-NEXT:    20004:       c0 03 5f d6     ret
+// DISASM:      _start:
+// DISASM-NEXT:    20008:       16 00 00 94     bl      #88
+// DISASM-NEXT:    2000c:       19 00 00 94     bl      #100
+// DISASM-NEXT:    20010:       0c 00 00 94     bl      #48
+// DISASM-NEXT:    20014:       0f 00 00 94     bl      #60
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:    20020:       f0 7b bf a9     stp     x16, x30, [sp, #-16]!
+// DISASM-NEXT:    20024:       10 01 00 90     adrp    x16, #131072
+// DISASM-NEXT:    20028:       11 0a 40 f9     ldr     x17, [x16, #16]
+// DISASM-NEXT:    2002c:       10 42 00 91     add     x16, x16, #16
+// DISASM-NEXT:    20030:       20 02 1f d6     br      x17
+// DISASM-NEXT:    20034:       1f 20 03 d5     nop
+// DISASM-NEXT:    20038:       1f 20 03 d5     nop
+// DISASM-NEXT:    2003c:       1f 20 03 d5     nop
+// DISASM-NEXT:    20040:       10 01 00 90     adrp    x16, #131072
+// DISASM-NEXT:    20044:       11 0e 40 f9     ldr     x17, [x16, #24]
+// DISASM-NEXT:    20048:       10 62 00 91     add     x16, x16, #24
+// DISASM-NEXT:    2004c:       20 02 1f d6     br      x17
+// DISASM-NEXT:    20050:       10 01 00 90     adrp    x16, #131072
+// DISASM-NEXT:    20054:       11 12 40 f9     ldr     x17, [x16, #32]
+// DISASM-NEXT:    20058:       10 82 00 91     add     x16, x16, #32
+// DISASM-NEXT:    2005c:       20 02 1f d6     br      x17
+// DISASM-NEXT:    20060:       10 01 00 90     adrp    x16, #131072
+// DISASM-NEXT:    20064:       11 16 40 f9     ldr     x17, [x16, #40]
+// DISASM-NEXT:    20068:       10 a2 00 91     add     x16, x16, #40
+// DISASM-NEXT:    2006c:       20 02 1f d6     br      x17
+// DISASM-NEXT:    20070:       10 01 00 90     adrp    x16, #131072
+// DISASM-NEXT:    20074:       11 1a 40 f9     ldr     x17, [x16, #48]
+// DISASM-NEXT:    20078:       10 c2 00 91     add     x16, x16, #48
+// DISASM-NEXT:    2007c:       20 02 1f d6     br      x17
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ bl foo
+ bl bar
+ bl bar2
+ bl zed2
index 0ec0b93..46f4a29 100644 (file)
@@ -22,8 +22,8 @@
 // CHECK-NEXT: }
 // CHECK:      Relocations [
 // CHECK-NEXT:   Section ({{.*}}) .rela.plt {
-// CHECK-NEXT:     0x30018 R_AARCH64_IRELATIVE
-// CHECK-NEXT:     0x30020 R_AARCH64_IRELATIVE
+// CHECK-NEXT:     0x30000 R_AARCH64_IRELATIVE
+// CHECK-NEXT:     0x30008 R_AARCH64_IRELATIVE
 // CHECK-NEXT:   }
 // CHECK-NEXT: ]
 // CHECK:      Symbols [
 
 // 344 = 0x158
 // 392 = 0x188
-// DISASM:      Disassembly of section .text:
+
+// DISASM: Disassembly of section .text:
 // DISASM-NEXT: foo:
 // DISASM-NEXT:  20000: c0 03 5f d6 ret
-// DISASM:      bar:
+// DISASM: bar:
 // DISASM-NEXT:  20004: c0 03 5f d6 ret
 // DISASM:      _start:
-// DISASM-NEXT:  20008: 0e 00 00 94 bl #56
-// DISASM-NEXT:  2000c: 11 00 00 94 bl #68
-// DISASM-NEXT:  20010: 42 60 05 91 add x2, x2, #344
-// DISASM-NEXT:  20014: 42 20 06 91 add x2, x2, #392
+// DISASM-NEXT:  20008: 06 00 00 94 bl #24
+// DISASM-NEXT:  2000c: 09 00 00 94     bl      #36
+// DISASM-NEXT:  20010: 42 60 05 91     add     x2, x2, #344
+// DISASM-NEXT:  20014: 42 20 06 91     add     x2, x2, #392
 // DISASM-NEXT: Disassembly of section .plt:
 // DISASM-NEXT: .plt:
-// DISASM-NEXT:  20020: f0 7b bf a9 stp x16, x30, [sp, #-16]!
-// DISASM-NEXT:  20024: 90 00 00 90 adrp x16, #65536
-// DISASM-NEXT:  20028: 11 0a 40 f9 ldr x17, [x16, #16]
-// DISASM-NEXT:  2002c: 10 42 00 91 add x16, x16, #16
-// DISASM-NEXT:  20030: 20 02 1f d6 br x17
-// DISASM-NEXT:  20034: 1f 20 03 d5 nop
-// DISASM-NEXT:  20038: 1f 20 03 d5 nop
-// DISASM-NEXT:  2003c: 1f 20 03 d5 nop
-// DISASM-NEXT:  20040: 90 00 00 90 adrp x16, #65536
-// DISASM-NEXT:  20044: 11 0e 40 f9 ldr x17, [x16, #24]
-// DISASM-NEXT:  20048: 10 62 00 91 add x16, x16, #24
-// DISASM-NEXT:  2004c: 20 02 1f d6 br x17
-// DISASM-NEXT:  20050: 90 00 00 90 adrp x16, #65536
-// DISASM-NEXT:  20054: 11 12 40 f9 ldr x17, [x16, #32]
-// DISASM-NEXT:  20058: 10 82 00 91 add x16, x16, #32
-// DISASM-NEXT:  2005c: 20 02 1f d6 br x17
+// DISASM-NEXT:  20020: 90 00 00 90 adrp x16, #65536
+// DISASM-NEXT:  20024: 11 02 40 f9 ldr x17, [x16]
+// DISASM-NEXT:  20028: 10 02 00 91 add x16, x16, #0
+// DISASM-NEXT:  2002c: 20 02 1f d6 br x17
+// DISASM-NEXT:  20030: 90 00 00 90 adrp x16, #65536
+// DISASM-NEXT:  20034: 11 06 40 f9 ldr x17, [x16, #8]
+// DISASM-NEXT:  20038: 10 22 00 91 add x16, x16, #8
+// DISASM-NEXT:  2003c: 20 02 1f d6 br x17
 
 .text
 .type foo STT_GNU_IFUNC
diff --git a/lld/test/ELF/arm-gnu-ifunc-plt.s b/lld/test/ELF/arm-gnu-ifunc-plt.s
new file mode 100644 (file)
index 0000000..30ef66a
--- /dev/null
@@ -0,0 +1,93 @@
+// RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabihf %S/Inputs/arm-shared.s -o %t1.o
+// RUN: ld.lld %t1.o --shared -o %t.so
+// RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabihf %s -o %t.o
+// RUN: ld.lld %t.so %t.o -o %tout
+// RUN: llvm-objdump -triple=armv7a-linux-gnueabihf -d %tout | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT
+// RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s
+// REQUIRES: arm
+
+// Check that the IRELATIVE relocations are last in the .got
+// CHECK: Relocations [
+// CHECK-NEXT:   Section (4) .rel.dyn {
+// CHECK-NEXT:     0x12078 R_ARM_GLOB_DAT bar2 0x0
+// CHECK-NEXT:     0x1207C R_ARM_GLOB_DAT zed2 0x0
+// CHECK-NEXT:     0x12080 R_ARM_IRELATIVE - 0x0
+// CHECK-NEXT:     0x12084 R_ARM_IRELATIVE - 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section (5) .rel.plt {
+// CHECK-NEXT:     0x1300C R_ARM_JUMP_SLOT bar2 0x0
+// CHECK-NEXT:     0x13010 R_ARM_JUMP_SLOT zed2 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// Check that the GOT entries refer back to the ifunc resolver
+// GOTPLT: Contents of section .got:
+// GOTPLT-NEXT:  12078 00000000 00000000 00100100 04100100
+// GOTPLT-NEXT: Contents of section .got.plt:
+// GOTPLT-NEXT:  13000 00000000 00000000 00000000 20100100
+// GOTPLT-NEXT:  13010 20100100
+
+// DISASM: Disassembly of section .text:
+// DISASM-NEXT: foo:
+// DISASM-NEXT:    11000:       1e ff 2f e1     bx      lr
+// DISASM: bar:
+// DISASM-NEXT:    11004:       1e ff 2f e1     bx      lr
+// DISASM:      _start:
+// DISASM-NEXT:    11008:       14 00 00 eb     bl      #80
+// DISASM-NEXT:    1100c:       17 00 00 eb     bl      #92
+// DISASM:         11010:       00 00 00 00     .word   0x00000000
+// DISASM-NEXT:    11014:       04 00 00 00     .word   0x00000004
+// DISASM:         11018:       05 00 00 eb     bl      #20
+// DISASM-NEXT:    1101c:       08 00 00 eb     bl      #32
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:    11020:       04 e0 2d e5     str     lr, [sp, #-4]!
+// DISASM-NEXT:    11024:       04 e0 9f e5     ldr     lr, [pc, #4]
+// DISASM-NEXT:    11028:       0e e0 8f e0     add     lr, pc, lr
+// DISASM-NEXT:    1102c:       08 f0 be e5     ldr     pc, [lr, #8]!
+// DISASM-NEXT:    11030:       d0 1f 00 00
+// DISASM-NEXT:    11034:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DISASM-NEXT:    11038:       0f c0 8c e0     add     r12, r12, pc
+// DISASM-NEXT:    1103c:       00 f0 9c e5     ldr     pc, [r12]
+// DISASM-NEXT:    11040:       cc 1f 00 00
+// DISASM-NEXT:    11044:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DISASM-NEXT:    11048:       0f c0 8c e0     add     r12, r12, pc
+// DISASM-NEXT:    1104c:       00 f0 9c e5     ldr     pc, [r12]
+// DISASM-NEXT:    11050:       c0 1f 00 00
+// Alignment to 16 byte boundary not strictly necessary on ARM, but harmless
+// DISASM-NEXT:    11054:       00 00 00 00     andeq   r0, r0, r0
+// DISASM-NEXT:    11058:       00 00 00 00     andeq   r0, r0, r0
+// DISASM-NEXT:    1105c:       00 00 00 00     andeq   r0, r0, r0
+// DISASM-NEXT:    11060:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DISASM-NEXT:    11064:       0f c0 8c e0     add     r12, r12, pc
+// DISASM-NEXT:    11068:       00 f0 9c e5     ldr     pc, [r12]
+// DISASM-NEXT:    1106c:       14 10 00 00
+// DISASM-NEXT:    11070:       04 c0 9f e5     ldr     r12, [pc, #4]
+// DISASM-NEXT:    11074:       0f c0 8c e0     add     r12, r12, pc
+// DISASM-NEXT:    11078:       00 f0 9c e5     ldr     pc, [r12]
+// DISASM-NEXT:    1107c:       08 10 00 00
+
+
+.syntax unified
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ bx lr
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ bx lr
+
+.globl _start
+_start:
+ bl foo
+ bl bar
+ // Create entries in the .got and .rel.dyn so that we don't just have
+ // IRELATIVE
+ .word bar2(got)
+ .word zed2(got)
+ bl bar2
+ bl zed2
index d3864c2..214a882 100644 (file)
@@ -24,51 +24,63 @@ _start:
  movw r0,:lower16:__rel_iplt_end
  movt r0,:upper16:__rel_iplt_end
 
-// CHECK:      Sections [
-// CHECK:       Section {
-// CHECK:       Index: 1
-// CHECK-NEXT:  Name: .rel.plt
-// CHECK-NEXT:  Type: SHT_REL
-// CHECK-NEXT:  Flags [
-// CHECK-NEXT:    SHF_ALLOC
-// CHECK-NEXT:  ]
-// CHECK-NEXT:  Address: [[REL:.*]]
-// CHECK-NEXT:  Offset:
-// CHECK-NEXT:   Size: 16
-// CHECK-NEXT:   Link:
-// CHECK-NEXT:   Info:
-// CHECK-NEXT:   AddressAlignment: 4
-// CHECK-NEXT:   EntrySize: 8
-// CHECK-NEXT:  }
-// CHECK: Relocations [
-// CHECK-NEXT:  Section (1) .rel.plt {
-// CHECK-NEXT:    0x1200C R_ARM_IRELATIVE
-// CHECK-NEXT:    0x12010 R_ARM_IRELATIVE
-// CHECK-NEXT:  }
-// CHECK-NEXT:]
-// CHECK:  Symbols [
-// CHECK:   Symbol {
-// CHECK:         Name: __rel_iplt_end
-// CHECK-NEXT:    Value: 0x100E4
-// CHECK-NEXT:    Size: 0
-// CHECK-NEXT:    Binding: Local
-// CHECK-NEXT:    Type: None
-// CHECK-NEXT:    Other [
-// CHECK-NEXT:      STV_HIDDEN
-// CHECK-NEXT:    ]
-// CHECK-NEXT:    Section: .rel.plt
-// CHECK-NEXT:  }
-// CHECK-NEXT:  Symbol {
-// CHECK-NEXT:    Name: __rel_iplt_start
-// CHECK-NEXT:    Value: 0x100D4
-// CHECK-NEXT:    Size: 0
-// CHECK-NEXT:    Binding: Local
-// CHECK-NEXT:    Type: None
-// CHECK-NEXT:    Other [
-// CHECK-NEXT:      STV_HIDDEN
-// CHECK-NEXT:    ]
-// CHECK-NEXT:    Section: .rel.plt
-// CHECK-NEXT:  }
+// CHECK: Sections [
+// CHECK:   Section {
+// CHECK:        Section {
+// CHECK:          Name: .rel.dyn
+// CHECK-NEXT:     Type: SHT_REL
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x100F4
+// CHECK-NEXT:     Offset: 0xF4
+// CHECK-NEXT:     Size: 16
+// CHECK:          Name: .plt
+// CHECK-NEXT:     Type: SHT_PROGBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_EXECINSTR
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x11020
+// CHECK-NEXT:     Offset: 0x1020
+// CHECK-NEXT:     Size: 32
+// CHECK:          Name: .got
+// CHECK-NEXT:     Type: SHT_PROGBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:       SHF_WRITE
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x12000
+// CHECK-NEXT:     Offset: 0x2000
+// CHECK-NEXT:     Size: 8
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section (1) .rel.dyn {
+// CHECK-NEXT:     0x12000 R_ARM_IRELATIVE
+// CHECK-NEXT:     0x12004 R_ARM_IRELATIVE
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+// CHECK:        Symbol {
+// CHECK:          Name: __rel_iplt_end (6)
+// CHECK-NEXT:     Value: 0x10104
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .rel.dyn
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Symbol {
+// CHECK-NEXT:     Name: __rel_iplt_start
+// CHECK-NEXT:     Value: 0x100F4
+// CHECK-NEXT:     Size: 0
+// CHECK-NEXT:     Binding: Local
+// CHECK-NEXT:     Type: None
+// CHECK-NEXT:     Other [
+// CHECK-NEXT:       STV_HIDDEN
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Section: .rel.dyn
+// CHECK-NEXT:   }
 // CHECK-NEXT:  Symbol {
 // CHECK-NEXT:    Name: _start
 // CHECK-NEXT:    Value: 0x11008
@@ -97,35 +109,29 @@ _start:
 // CHECK-NEXT:    Section: .text
 // CHECK-NEXT:  }
 
-// DISASM:      Disassembly of section .text:
+// DISASM: Disassembly of section .text:
 // DISASM-NEXT: foo:
-// DISASM-NEXT:   11000:       1e ff 2f e1     bx      lr
-// DISASM: bar:
-// DISASM-NEXT:   11004:       1e ff 2f e1     bx      lr
-// DISASM: _start:
-// DISASM-NEXT:   11008:       09 00 00 eb     bl      #36
-// DISASM-NEXT:   1100c:       0c 00 00 eb     bl      #48
-// DISASM-NEXT:   11010:       d4 00 00 e3     movw    r0, #212
-// DISASM-NEXT:   11014:       01 00 40 e3     movt    r0, #1
-// r0 = 212 + 1 * 65536 = 100D4 = __rel_iplt_start
-// DISASM-NEXT:   11018:       e4 00 00 e3     movw    r0, #228
-// DISASM-NEXT:   1101c:       01 00 40 e3     movt    r0, #1
-// r1 = 228 + 1 * 65536 = 100E4 = __rel_iplt_end
+// DISASM-NEXT:    11000:      1e ff 2f e1     bx      lr
+// DISASM:      bar:
+// DISASM-NEXT:    11004:      1e ff 2f e1     bx      lr
+// DISASM:       _start:
+// DISASM-NEXT:    11008:      04 00 00 eb     bl      #16
+// DISASM-NEXT:    1100c:      07 00 00 eb     bl      #28
+// 1 * 65536 + 244 = 0x100f4 __rel_iplt_start
+// DISASM-NEXT:    11010:      f4 00 00 e3     movw    r0, #244
+// DISASM-NEXT:    11014:      01 00 40 e3     movt    r0, #1
+// 1 * 65536 + 260 = 0x10104 __rel_iplt_end
+// DISASM-NEXT:    11018:      04 01 00 e3     movw    r0, #260
+// DISASM-NEXT:    1101c:      01 00 40 e3     movt    r0, #1
 // DISASM-NEXT: Disassembly of section .plt:
 // DISASM-NEXT: .plt:
-// DISASM-NEXT:   11020:       04 e0 2d e5     str     lr, [sp, #-4]!
-// DISASM-NEXT:   11024:       04 e0 9f e5     ldr     lr, [pc, #4]
-// DISASM-NEXT:   11028:       0e e0 8f e0     add     lr, pc, lr
-// DISASM-NEXT:   1102c:       08 f0 be e5     ldr     pc, [lr, #8]!
-// 0x0fd0 + 0x11028 + 0x8 = 0x12000
-// DISASM-NEXT:   11030:       d0 0f 00 00
-// DISASM-NEXT:   11034:       04 c0 9f e5     ldr     r12, [pc, #4]
-// DISASM-NEXT:   11038:       0f c0 8c e0     add     r12, r12, pc
-// DISASM-NEXT:   1103c:       00 f0 9c e5     ldr     pc, [r12]
-// 0x0fcc + 0x11038 + 0x8 = 0x1200C
-// DISASM-NEXT:   11040:       cc 0f 00 00
-// DISASM-NEXT:   11044:       04 c0 9f e5     ldr     r12, [pc, #4]
-// DISASM-NEXT:   11048:       0f c0 8c e0     add     r12, r12, pc
-// DISASM-NEXT:   1104c:       00 f0 9c e5     ldr     pc, [r12]
-// 0x0fc0 + 0x11048 + 0x8 = 0x12010
-// DISASM-NEXT:   11050:       c0 0f 00 00
+// DISASM-NEXT:    11020:      04 c0 9f e5     ldr     r12, [pc, #4]
+// DISASM-NEXT:    11024:      0f c0 8c e0     add     r12, r12, pc
+// 11024 + 8 + fd4 = 0x12000
+// DISASM-NEXT:    11028:      00 f0 9c e5     ldr     pc, [r12]
+// DISASM-NEXT:    1102c:      d4 0f 00 00
+// DISASM-NEXT:    11030:      04 c0 9f e5     ldr     r12, [pc, #4]
+// DISASM-NEXT:    11034:      0f c0 8c e0     add     r12, r12, pc
+// 11034 + 8 + fc8 = 0x12004
+// DISASM-NEXT:    11038:      00 f0 9c e5     ldr     pc, [r12]
+// DISASM-NEXT:    1103c:      c8 0f 00 00
index 8285d39..21f1313 100644 (file)
@@ -22,8 +22,8 @@
 // CHECK-NEXT: }
 // CHECK:     Relocations [
 // CHECK-NEXT:   Section ({{.*}}) .rel.plt {
-// CHECK-NEXT:     0x1200C R_386_IRELATIVE
-// CHECK-NEXT:     0x12010 R_386_IRELATIVE
+// CHECK-NEXT:     0x12000 R_386_IRELATIVE
+// CHECK-NEXT:     0x12004 R_386_IRELATIVE
 // CHECK-NEXT:   }
 // CHECK-NEXT: ]
 
 // CHECK-NEXT: }
 // CHECK-NEXT:]
 
-// DISASM:      Disassembly of section .text:
+// DISASM: Disassembly of section .text:
 // DISASM-NEXT: foo:
-// DISASM-NEXT: 11000: c3 retl
-// DISASM:      bar:
-// DISASM-NEXT: 11001: c3 retl
+// DISASM-NEXT:    11000: c3 retl
+// DISASM: bar:
+// DISASM-NEXT:    11001: c3 retl
 // DISASM:      _start:
-// DISASM-NEXT:    11002: e8 29 00 00 00 calll 41
-// DISASM-NEXT:    11007: e8 34 00 00 00 calll 52
+// DISASM-NEXT:    11002: e8 19 00 00 00 calll 25
+// DISASM-NEXT:    11007: e8 24 00 00 00 calll 36
 // DISASM-NEXT:    1100c: ba d4 00 01 00 movl $65748, %edx
 // DISASM-NEXT:    11011: ba e4 00 01 00 movl $65764, %edx
 // DISASM-NEXT: Disassembly of section .plt:
 // DISASM-NEXT: .plt:
-// DISASM-NEXT:    11020: ff 35 04 20 01 00 pushl 73732
-// DISASM-NEXT:    11026: ff 25 08 20 01 00 jmpl *73736
-// DISASM-NEXT:    1102c: 90 nop
-// DISASM-NEXT:    1102d: 90 nop
-// DISASM-NEXT:    1102e: 90 nop
-// DISASM-NEXT:    1102f: 90 nop
-// DISASM-NEXT:    11030: ff 25 0c 20 01 00 jmpl *73740
-// DISASM-NEXT:    11036: 68 00 00 00 00    pushl $0
-// DISASM-NEXT:    1103b: e9 e0 ff ff ff    jmp -32 <.plt>
-// DISASM-NEXT:    11040: ff 25 10 20 01 00 jmpl *73744
-// DISASM-NEXT:    11046: 68 08 00 00 00    pushl $8
-// DISASM-NEXT:    1104b: e9 d0 ff ff ff    jmp -48 <.plt>
+// DISASM-NEXT:    11020: ff 25 00 20 01 00 jmpl *73728
+// DISASM-NEXT:    11026: 68 10 00 00 00 pushl $16
+// DISASM-NEXT:    1102b: e9 e0 ff ff ff jmp -32 <_start+0xE>
+// DISASM-NEXT:    11030: ff 25 04 20 01 00 jmpl *73732
+// DISASM-NEXT:    11036: 68 18 00 00 00 pushl $24
+// DISASM-NEXT:    1103b: e9 d0 ff ff ff jmp -48 <_start+0xE>
 
 .text
 .type foo STT_GNU_IFUNC
diff --git a/lld/test/ELF/gnu-ifunc-plt.s b/lld/test/ELF/gnu-ifunc-plt.s
new file mode 100644 (file)
index 0000000..c7bd6b6
--- /dev/null
@@ -0,0 +1,74 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/shared2-x86-64.s -o %t1.o
+// RUN: ld.lld %t1.o --shared -o %t.so
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld %t.so %t.o -o %tout
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT
+// RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s
+// REQUIRES: x86
+
+// Check that the IRELATIVE relocations are after the JUMP_SLOT in the plt
+// CHECK: Relocations [
+// CHECK-NEXT:   Section (4) .rela.plt {
+// CHECK-NEXT:     0x203018 R_X86_64_JUMP_SLOT bar2 0x0
+// CHECK-NEXT:     0x203020 R_X86_64_JUMP_SLOT zed2 0x0
+// CHECK-NEXT:     0x203028 R_X86_64_IRELATIVE - 0x201000
+// CHECK-NEXT:     0x203030 R_X86_64_IRELATIVE - 0x201001
+
+// Check that .got.plt entries point back to PLT header
+// GOTPLT: Contents of section .got.plt:
+// GOTPLT-NEXT:  203000 00202000 00000000 00000000 00000000  .  .............
+// GOTPLT-NEXT:  203010 00000000 00000000 36102000 00000000  ........6. .....
+// GOTPLT-NEXT:  203020 46102000 00000000 56102000 00000000  F. .....V. .....
+// GOTPLT-NEXT:  203030 66102000 00000000
+
+// Check that the PLTRELSZ tag includes the IRELATIVE relocations
+// CHECK: DynamicSection [
+// CHECK:   0x0000000000000002 PLTRELSZ             96 (bytes)
+
+// Check that a PLT header is written and the ifunc entries appear last
+// DISASM: Disassembly of section .text:
+// DISASM-NEXT: foo:
+// DISASM-NEXT:   201000:       c3      retq
+// DISASM:      bar:
+// DISASM-NEXT:   201001:       c3      retq
+// DISASM:      _start:
+// DISASM-NEXT:   201002:       e8 49 00 00 00          callq   73
+// DISASM-NEXT:   201007:       e8 54 00 00 00          callq   84
+// DISASM-NEXT:   20100c:       e8 1f 00 00 00          callq   31
+// DISASM-NEXT:   201011:       e8 2a 00 00 00          callq   42
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:   201020:       ff 35 e2 1f 00 00       pushq   8162(%rip)
+// DISASM-NEXT:   201026:       ff 25 e4 1f 00 00       jmpq    *8164(%rip)
+// DISASM-NEXT:   20102c:       0f 1f 40 00     nopl    (%rax)
+// DISASM-NEXT:   201030:       ff 25 e2 1f 00 00       jmpq    *8162(%rip)
+// DISASM-NEXT:   201036:       68 00 00 00 00          pushq   $0
+// DISASM-NEXT:   20103b:       e9 e0 ff ff ff          jmp     -32 <.plt>
+// DISASM-NEXT:   201040:       ff 25 da 1f 00 00       jmpq    *8154(%rip)
+// DISASM-NEXT:   201046:       68 01 00 00 00          pushq   $1
+// DISASM-NEXT:   20104b:       e9 d0 ff ff ff          jmp     -48 <.plt>
+// DISASM-NEXT:   201050:       ff 25 d2 1f 00 00       jmpq    *8146(%rip)
+// DISASM-NEXT:   201056:       68 00 00 00 00          pushq   $0
+// DISASM-NEXT:   20105b:       e9 e0 ff ff ff          jmp     -32 <.plt+0x20>
+// DISASM-NEXT:   201060:       ff 25 ca 1f 00 00       jmpq    *8138(%rip)
+// DISASM-NEXT:   201066:       68 01 00 00 00          pushq   $1
+// DISASM-NEXT:   20106b:       e9 d0 ff ff ff          jmp     -48 <.plt+0x20>
+
+.text
+.type foo STT_GNU_IFUNC
+.globl foo
+foo:
+ ret
+
+.type bar STT_GNU_IFUNC
+.globl bar
+bar:
+ ret
+
+.globl _start
+_start:
+ call foo
+ call bar
+ call bar2
+ call zed2
diff --git a/lld/test/ELF/gnu-ifunc-shared.s b/lld/test/ELF/gnu-ifunc-shared.s
new file mode 100644 (file)
index 0000000..30142b6
--- /dev/null
@@ -0,0 +1,66 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: ld.lld --shared -o %t.so %t.o
+// RUN: llvm-objdump -d %t.so | FileCheck %s --check-prefix=DISASM
+// RUN: llvm-readobj -r %t.so | FileCheck %s
+
+// Check that an IRELATIVE relocation is used for a non-preemptible ifunc
+// handler and a JUMP_SLOT is used for a preemptible ifunc
+// DISASM: Disassembly of section .text:
+// DISASM-NEXT: fct:
+// DISASM-NEXT:     1000:       c3      retq
+// DISASM:     fct2:
+// DISASM-NEXT:     1001:       c3      retq
+// DISASM:     f1:
+// DISASM-NEXT:     1002:       e8 49 00 00 00          callq   73
+// DISASM-NEXT:     1007:       e8 24 00 00 00          callq   36
+// DISASM-NEXT:     100c:       e8 2f 00 00 00          callq   47
+// DISASM-NEXT:     1011:       c3      retq
+// DISASM:     f2:
+// DISASM-NEXT:     1012:       c3      retq
+// DISASM-NEXT: Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:     1020:       ff 35 e2 1f 00 00       pushq   8162(%rip)
+// DISASM-NEXT:     1026:       ff 25 e4 1f 00 00       jmpq    *8164(%rip)
+// DISASM-NEXT:     102c:       0f 1f 40 00     nopl    (%rax)
+// DISASM-NEXT:     1030:       ff 25 e2 1f 00 00       jmpq    *8162(%rip)
+// DISASM-NEXT:     1036:       68 00 00 00 00          pushq   $0
+// DISASM-NEXT:     103b:       e9 e0 ff ff ff          jmp     -32 <.plt>
+// DISASM-NEXT:     1040:       ff 25 da 1f 00 00       jmpq    *8154(%rip)
+// DISASM-NEXT:     1046:       68 01 00 00 00          pushq   $1
+// DISASM-NEXT:     104b:       e9 d0 ff ff ff          jmp     -48 <.plt>
+// DISASM-NEXT:     1050:       ff 25 d2 1f 00 00       jmpq    *8146(%rip)
+// DISASM-NEXT:     1056:       68 00 00 00 00          pushq   $0
+// DISASM-NEXT:     105b:       e9 e0 ff ff ff          jmp     -32 <.plt+0x20>
+
+// CHECK: Relocations [
+// CHECK-NEXT:   Section (4) .rela.plt {
+// CHECK-NEXT:     0x3018 R_X86_64_JUMP_SLOT fct2 0x0
+// CHECK-NEXT:     0x3020 R_X86_64_JUMP_SLOT f2 0x0
+// CHECK-NEXT:     0x3028 R_X86_64_IRELATIVE - 0x1000
+
+ // Hidden expect IRELATIVE
+ .globl fct
+ .hidden fct
+ .type  fct, STT_GNU_IFUNC
+fct:
+ ret
+
+ // Not hidden expect JUMP_SLOT
+ .globl fct2
+ .type  fct2, STT_GNU_IFUNC
+fct2:
+ ret
+
+ .globl f1
+ .type f1, @function
+f1:
+ call fct
+ call fct2
+ call f2@PLT
+ ret
+
+ .globl f2
+ .type f2, @function
+f2:
+ ret
index 45b58f2..f86f030 100644 (file)
@@ -22,8 +22,8 @@
 // CHECK-NEXT: }
 // CHECK:      Relocations [
 // CHECK-NEXT:   Section ({{.*}}) .rela.plt {
-// CHECK-NEXT:     0x202018 R_X86_64_IRELATIVE
-// CHECK-NEXT:     0x202020 R_X86_64_IRELATIVE
+// CHECK-NEXT:     0x202000 R_X86_64_IRELATIVE
+// CHECK-NEXT:     0x202008 R_X86_64_IRELATIVE
 // CHECK-NEXT:   }
 // CHECK-NEXT: ]
 // CHECK:      Symbols [
 // CHECK-NEXT:  }
 // CHECK-NEXT: ]
 
-// DISASM:      Disassembly of section .text:
+// DISASM: Disassembly of section .text:
 // DISASM-NEXT: foo:
-// DISASM-NEXT:   201000: {{.*}} retq
+// DISASM-NEXT:  201000: {{.*}} retq
 // DISASM:      bar:
-// DISASM-NEXT:   201001: {{.*}} retq
+// DISASM-NEXT:  201001: {{.*}} retq
 // DISASM:      _start:
-// DISASM-NEXT:   201002: {{.*}} callq 41
-// DISASM-NEXT:   201007: {{.*}} callq 52
-// DISASM-NEXT:   20100c: {{.*}} movl $2097496, %edx
-// DISASM-NEXT:   201011: {{.*}} movl $2097544, %edx
-// DISASM-NEXT:   201016: {{.*}} movl $2097545, %edx
+// DISASM-NEXT:  201002: {{.*}} callq 25
+// DISASM-NEXT:  201007: {{.*}} callq 36
+// DISASM-NEXT:  20100c: {{.*}} movl $2097496, %edx
+// DISASM-NEXT:  201011: {{.*}} movl $2097544, %edx
+// DISASM-NEXT:  201016: {{.*}} movl $2097545, %edx
 // DISASM-NEXT: Disassembly of section .plt:
 // DISASM-NEXT: .plt:
-// DISASM-NEXT:   201020: {{.*}} pushq 4066(%rip)
-// DISASM-NEXT:   201026: {{.*}} jmpq *4068(%rip)
-// DISASM-NEXT:   20102c: {{.*}} nopl (%rax)
-// DISASM-NEXT:   201030: {{.*}} jmpq *4066(%rip)
-// DISASM-NEXT:   201036: {{.*}} pushq $0
-// DISASM-NEXT:   20103b: {{.*}} jmp -32
-// DISASM-NEXT:   201040: {{.*}} jmpq *4058(%rip)
-// DISASM-NEXT:   201046: {{.*}} pushq $1
-// DISASM-NEXT:   20104b: {{.*}} jmp -48
+// DISASM-NEXT:  201020: {{.*}} jmpq *4058(%rip)
+// DISASM-NEXT:  201026: {{.*}} pushq $0
+// DISASM-NEXT:  20102b: {{.*}} jmp -32 <_start+0xE>
+// DISASM-NEXT:  201030: {{.*}} jmpq *4050(%rip)
+// DISASM-NEXT:  201036: {{.*}} pushq $1
+// DISASM-NEXT:  20103b: {{.*}} jmp -48 <_start+0xE>
 
 .text
 .type foo STT_GNU_IFUNC