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;
}
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.
}
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>();
}
}
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;
}
// 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
}
}
+// 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,
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))});
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)});
}
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") {}
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>;
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>;
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:
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;
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;
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;
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>>();
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>>();
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
// 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() {
--- /dev/null
+.syntax unified
+.global bar2
+.type bar2, %function
+bar2:
+
+.global zed2
+.type zed2, %function
+zed2:
--- /dev/null
+.global bar2
+.type bar2, @function
+bar2:
+ ret
+
+.global zed2
+.type zed2, @function
+zed2:
+ ret
--- /dev/null
+// 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
// 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
--- /dev/null
+// 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
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
// 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
// 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
--- /dev/null
+// 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
--- /dev/null
+// 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
// 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