summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/Arch/PPC64.cpp10
-rw-r--r--lld/ELF/Relocations.cpp41
-rw-r--r--lld/ELF/Writer.cpp2
-rw-r--r--lld/test/ELF/aarch64-gnu-ifunc-nonpreemptable2.s36
-rw-r--r--lld/test/ELF/gnu-ifunc-canon.s11
-rw-r--r--lld/test/ELF/ppc64-toc-relax-ifunc.s26
6 files changed, 63 insertions, 63 deletions
diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp
index c448d8488b8..b330dff0735 100644
--- a/lld/ELF/Arch/PPC64.cpp
+++ b/lld/ELF/Arch/PPC64.cpp
@@ -172,13 +172,13 @@ bool elf::tryRelaxPPC64TocIndirection(RelType type, const Relocation &rel,
: getRelaTocSymAndAddend<ELF64BE>(tocISB, rel.addend);
// Only non-preemptable defined symbols can be relaxed.
- //
- // The toc entry of a non-preemptable ifunc is relocated by R_PPC64_IRELATIVE,
- // which will run at load time to determine the relocated value. It is not
- // known until load time, so the access cannot be relaxed.
- if (!d || d->isPreemptible || d->isGnuIFunc())
+ if (!d || d->isPreemptible)
return false;
+ // R_PPC64_ADDR64 should have created a canonical PLT for the non-preemptable
+ // ifunc and changed its type to STT_FUNC.
+ assert(!d->isGnuIFunc());
+
// Two instructions can materialize a 32-bit signed offset from the toc base.
uint64_t tocRelative = d->getVA(addend) - getPPC64TocBase();
if (!isInt<32>(tocRelative))
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 22ae1725af4..d611acb000c 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1089,15 +1089,6 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
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) {
@@ -1265,12 +1256,6 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
// 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;
@@ -1287,17 +1272,6 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
*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.
//
@@ -1365,21 +1339,6 @@ template <class ELFT> void elf::scanRelocations(InputSectionBase &s) {
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->isPic)
- 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)
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 9c7044ac8df..111056a0b80 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1738,8 +1738,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
reportUndefinedSymbols<ELFT>();
}
- addIRelativeRelocs();
-
if (in.plt && in.plt->isNeeded())
in.plt->addSymbols();
if (in.iplt && in.iplt->isNeeded())
diff --git a/lld/test/ELF/aarch64-gnu-ifunc-nonpreemptable2.s b/lld/test/ELF/aarch64-gnu-ifunc-nonpreemptable2.s
new file mode 100644
index 00000000000..725b275c38b
--- /dev/null
+++ b/lld/test/ELF/aarch64-gnu-ifunc-nonpreemptable2.s
@@ -0,0 +1,36 @@
+# REQUIRES: aarch64
+# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o
+# RUN: ld.lld %t.o -o %t
+# RUN: llvm-readelf -S -s %t | FileCheck %s --check-prefix=SEC
+# RUN: llvm-readelf -x .rodata -x .data %t | FileCheck --check-prefix=HEX %s
+# RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=RELOC
+
+## ifunc is a non-preemptable STT_GNU_IFUNC. Check we create a canonical PLT
+## and redirect .rodata and .data references to it.
+
+# SEC: .text PROGBITS 0000000000210000
+# SEC: .got.plt PROGBITS 0000000000220008
+# SEC: 0000000000210010 0 FUNC GLOBAL DEFAULT 4 ifunc
+
+## .rodata[0] and .data[0] store the address of the canonical PLT.
+# HEX: section '.rodata':
+# HEX-NEXT: 0x00200170 10002100 00000000
+# HEX: section '.data':
+# HEX-NEXT: 0x00220000 10002100 00000000
+
+# RELOC: .rela.dyn {
+# RELOC-NEXT: 0x220008 R_AARCH64_IRELATIVE - 0x210000
+# RELOC-NEXT: }
+
+.globl ifunc
+.type ifunc,@gnu_indirect_function
+ifunc:
+ ret
+
+.rodata
+.p2align 3
+.xword ifunc
+
+.data
+.p2align 3
+.xword ifunc
diff --git a/lld/test/ELF/gnu-ifunc-canon.s b/lld/test/ELF/gnu-ifunc-canon.s
index 18ee10278da..a7ba3aff7ed 100644
--- a/lld/test/ELF/gnu-ifunc-canon.s
+++ b/lld/test/ELF/gnu-ifunc-canon.s
@@ -4,7 +4,7 @@
// 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 -r %t1 | FileCheck --check-prefix=IREL2 %s
+// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=IREL1 %s
// RUN: ld.lld %t.o %t-ro-pcrel.o -o %t2
// RUN: llvm-readobj -r %t2 | FileCheck --check-prefix=IREL1 %s
// RUN: ld.lld %t.o %t-ro-abs.o -o %t3
@@ -22,7 +22,7 @@
// RUN: ld.lld %t-rw-addend.o %t.o -o %t7
// RUN: llvm-readobj -r %t7 | FileCheck --check-prefix=IREL1 %s
// RUN: ld.lld %t.o -o %t8 -pie
-// RUN: llvm-readobj -r %t8 | FileCheck --check-prefix=IREL2 %s
+// RUN: llvm-readobj -r %t8 | FileCheck --check-prefix=IREL1-REL2 %s
// RUN: ld.lld %t.o %t-ro-pcrel.o -o %t9 -pie
// RUN: llvm-readobj -r %t9 | FileCheck --check-prefix=IREL1-REL2 %s
// RUN: ld.lld %t.o %t-rw-addend.o -o %t10 -pie
@@ -32,13 +32,6 @@
// RUN: ld.lld %t-rw-addend.o %t.o -o %t12 -pie
// RUN: llvm-readobj -r %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.dyn
-// 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.dyn
diff --git a/lld/test/ELF/ppc64-toc-relax-ifunc.s b/lld/test/ELF/ppc64-toc-relax-ifunc.s
index 54467e416b6..7018258b2ee 100644
--- a/lld/test/ELF/ppc64-toc-relax-ifunc.s
+++ b/lld/test/ELF/ppc64-toc-relax-ifunc.s
@@ -4,14 +4,28 @@
# RUN: echo '.globl ifunc; .type ifunc, %gnu_indirect_function; ifunc:' | \
# RUN: llvm-mc -filetype=obj -triple=powerpc64le - -o %t1.o
# RUN: ld.lld %t.o %t1.o -o %t
-# RUN: llvm-objdump -d %t | FileCheck %s
+# RUN: llvm-readelf -S -s %t | FileCheck --check-prefix=SEC %s
+# RUN: llvm-readelf -x .toc %t | FileCheck --check-prefix=HEX %s
+# RUN: llvm-objdump -d %t | FileCheck --check-prefix=DIS %s
-## ifunc is a non-preemptable STT_GNU_IFUNC. Its toc entry will be
-## relocated by R_PPC64_IRELATIVE, not representable by a toc-relative value.
-## Check the toc-indirect access is not relaxed.
+## ifunc is a non-preemptable STT_GNU_IFUNC. The R_PPC64_ADDR64 in .toc
+## creates a canonical PLT for it and changes its type to STT_FUNC. We can thus
+## still perform toc-indirect to toc-relative relaxation because the distance
+## to the address of the canonical PLT is fixed.
-# CHECK: nop
-# CHECK-NEXT: ld 3, -32768(2)
+# SEC: .text PROGBITS 0000000010010000
+# SEC: .plt NOBITS 0000000010030000
+# SEC: 0000000010010010 0 FUNC GLOBAL DEFAULT 3 ifunc
+
+## .toc[0] stores the address of the canonical PLT.
+# HEX: section '.toc':
+# HEX-NEXT: 0x10020000 10000110 00000000
+
+# REL: .rela.dyn {
+# REL-NEXT: 0x10030000 R_PPC64_IRELATIVE - 0x10010008
+# REL-NEXT: }
+
+# DIS: addi 3, 3,
addis 3, 2, .toc@toc@ha
ld 3, .toc@toc@l(3)
OpenPOWER on IntegriCloud