[ELF] Don't special case symbolic relocations with 0 addend to ifunc in writable locations

Currently the following 3 relocation types do not trigger the creation
of a canonical PLT (which changes STT_GNU_IFUNC to STT_FUNC and
redirects all references):

1) GOT-generating (`needsGot`)
2) PLT-generating (`needsPlt`)
3) R_ABS with 0 addend in a writable location. This is used for
  for ifunc function pointers in writable sections such as .data and .toc.

This patch deletes case 3) to simplify the R_*_IRELATIVE generating
logic added in D57371. Other advantages:

* It is guaranteed no more than 1 R_*_IRELATIVE is created for an ifunc.
* PPC64: no need to special case ifunc in toc-indirect to toc-relative relaxation. See D65755

The deleted elf::addIRelativeRelocs demonstrates that one-pass scan
through relocations makes several optimizations difficult. This is
something we can think about in the future.

Reviewed By: peter.smith

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

llvm-svn: 368661
This commit is contained in:
Fangrui Song 2019-08-13 09:43:40 +00:00
parent 5390d25f2b
commit dc06b0bc9a
6 changed files with 63 additions and 63 deletions

View File

@ -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))

View File

@ -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)

View File

@ -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())

View File

@ -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

View File

@ -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

View File

@ -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)