: 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))
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) {
// 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;
*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.
//
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)
reportUndefinedSymbols<ELFT>();
}
- addIRelativeRelocs();
-
if (in.plt && in.plt->isNeeded())
in.plt->addSymbols();
if (in.iplt && in.iplt->isNeeded())
--- /dev/null
+# 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
// 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
// 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
// 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
# 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)