forked from OSchip/llvm-project
[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:
parent
5390d25f2b
commit
dc06b0bc9a
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue