Skip to content

Commit dc06b0b

Browse files
committedAug 13, 2019
[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
1 parent 5390d25 commit dc06b0b

6 files changed

+63
-63
lines changed
 

‎lld/ELF/Arch/PPC64.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -172,13 +172,13 @@ bool elf::tryRelaxPPC64TocIndirection(RelType type, const Relocation &rel,
172172
: getRelaTocSymAndAddend<ELF64BE>(tocISB, rel.addend);
173173

174174
// Only non-preemptable defined symbols can be relaxed.
175-
//
176-
// The toc entry of a non-preemptable ifunc is relocated by R_PPC64_IRELATIVE,
177-
// which will run at load time to determine the relocated value. It is not
178-
// known until load time, so the access cannot be relaxed.
179-
if (!d || d->isPreemptible || d->isGnuIFunc())
175+
if (!d || d->isPreemptible)
180176
return false;
181177

178+
// R_PPC64_ADDR64 should have created a canonical PLT for the non-preemptable
179+
// ifunc and changed its type to STT_FUNC.
180+
assert(!d->isGnuIFunc());
181+
182182
// Two instructions can materialize a 32-bit signed offset from the toc base.
183183
uint64_t tocRelative = d->getVA(addend) - getPPC64TocBase();
184184
if (!isInt<32>(tocRelative))

‎lld/ELF/Relocations.cpp

-41
Original file line numberDiff line numberDiff line change
@@ -1089,15 +1089,6 @@ static void processRelocAux(InputSectionBase &sec, RelExpr expr, RelType type,
10891089
getLocation(sec, sym, offset));
10901090
}
10911091

1092-
struct IRelativeReloc {
1093-
RelType type;
1094-
InputSectionBase *sec;
1095-
uint64_t offset;
1096-
Symbol *sym;
1097-
};
1098-
1099-
static std::vector<IRelativeReloc> iRelativeRelocs;
1100-
11011092
template <class ELFT, class RelTy>
11021093
static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
11031094
RelTy *end) {
@@ -1265,12 +1256,6 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
12651256
// correctly, the IRELATIVE relocations are stored in an array which a
12661257
// statically linked executable's startup code must enumerate using the
12671258
// linker-defined symbols __rela?_iplt_{start,end}.
1268-
//
1269-
// - An absolute relocation to a non-preemptible ifunc (such as a global
1270-
// variable containing a pointer to the ifunc) needs to be relocated in
1271-
// the exact same way as a GOT entry, so we can avoid needing to make the
1272-
// PLT entry canonical by translating such relocations into IRELATIVE
1273-
// relocations in the relaIplt.
12741259
if (!sym.isInPlt()) {
12751260
// Create PLT and GOTPLT slots for the symbol.
12761261
sym.isInIplt = true;
@@ -1287,17 +1272,6 @@ static void scanReloc(InputSectionBase &sec, OffsetGetter &getOffset, RelTy *&i,
12871272
*directSym);
12881273
sym.pltIndex = directSym->pltIndex;
12891274
}
1290-
if (expr == R_ABS && addend == 0 && (sec.flags & SHF_WRITE)) {
1291-
// We might be able to represent this as an IRELATIVE. But we don't know
1292-
// yet whether some later relocation will make the symbol point to a
1293-
// canonical PLT, which would make this either a dynamic RELATIVE (PIC) or
1294-
// static (non-PIC) relocation. So we keep a record of the information
1295-
// required to process the relocation, and after scanRelocs() has been
1296-
// called on all relocations, the relocation is resolved by
1297-
// addIRelativeRelocs().
1298-
iRelativeRelocs.push_back({type, &sec, offset, &sym});
1299-
return;
1300-
}
13011275
if (needsGot(expr)) {
13021276
// Redirect GOT accesses to point to the Igot.
13031277
//
@@ -1365,21 +1339,6 @@ template <class ELFT> void elf::scanRelocations(InputSectionBase &s) {
13651339
scanRelocs<ELFT>(s, s.rels<ELFT>());
13661340
}
13671341

1368-
// Figure out which representation to use for any absolute relocs to
1369-
// non-preemptible ifuncs that we visited during scanRelocs().
1370-
void elf::addIRelativeRelocs() {
1371-
for (IRelativeReloc &r : iRelativeRelocs) {
1372-
if (r.sym->type == STT_GNU_IFUNC)
1373-
in.relaIplt->addReloc(
1374-
{target->iRelativeRel, r.sec, r.offset, true, r.sym, 0});
1375-
else if (config->isPic)
1376-
addRelativeReloc(r.sec, r.offset, r.sym, 0, R_ABS, r.type);
1377-
else
1378-
r.sec->relocations.push_back({R_ABS, r.type, r.offset, 0, r.sym});
1379-
}
1380-
iRelativeRelocs.clear();
1381-
}
1382-
13831342
static bool mergeCmp(const InputSection *a, const InputSection *b) {
13841343
// std::merge requires a strict weak ordering.
13851344
if (a->outSecOff < b->outSecOff)

‎lld/ELF/Writer.cpp

-2
Original file line numberDiff line numberDiff line change
@@ -1738,8 +1738,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
17381738
reportUndefinedSymbols<ELFT>();
17391739
}
17401740

1741-
addIRelativeRelocs();
1742-
17431741
if (in.plt && in.plt->isNeeded())
17441742
in.plt->addSymbols();
17451743
if (in.iplt && in.iplt->isNeeded())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# REQUIRES: aarch64
2+
# RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o
3+
# RUN: ld.lld %t.o -o %t
4+
# RUN: llvm-readelf -S -s %t | FileCheck %s --check-prefix=SEC
5+
# RUN: llvm-readelf -x .rodata -x .data %t | FileCheck --check-prefix=HEX %s
6+
# RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=RELOC
7+
8+
## ifunc is a non-preemptable STT_GNU_IFUNC. Check we create a canonical PLT
9+
## and redirect .rodata and .data references to it.
10+
11+
# SEC: .text PROGBITS 0000000000210000
12+
# SEC: .got.plt PROGBITS 0000000000220008
13+
# SEC: 0000000000210010 0 FUNC GLOBAL DEFAULT 4 ifunc
14+
15+
## .rodata[0] and .data[0] store the address of the canonical PLT.
16+
# HEX: section '.rodata':
17+
# HEX-NEXT: 0x00200170 10002100 00000000
18+
# HEX: section '.data':
19+
# HEX-NEXT: 0x00220000 10002100 00000000
20+
21+
# RELOC: .rela.dyn {
22+
# RELOC-NEXT: 0x220008 R_AARCH64_IRELATIVE - 0x210000
23+
# RELOC-NEXT: }
24+
25+
.globl ifunc
26+
.type ifunc,@gnu_indirect_function
27+
ifunc:
28+
ret
29+
30+
.rodata
31+
.p2align 3
32+
.xword ifunc
33+
34+
.data
35+
.p2align 3
36+
.xword ifunc

‎lld/test/ELF/gnu-ifunc-canon.s

+2-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gnu-ifunc-canon-ro-abs.s -o %t-ro-abs.o
55
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gnu-ifunc-canon-rw-addend.s -o %t-rw-addend.o
66
// RUN: ld.lld %t.o -o %t1
7-
// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=IREL2 %s
7+
// RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=IREL1 %s
88
// RUN: ld.lld %t.o %t-ro-pcrel.o -o %t2
99
// RUN: llvm-readobj -r %t2 | FileCheck --check-prefix=IREL1 %s
1010
// RUN: ld.lld %t.o %t-ro-abs.o -o %t3
@@ -22,7 +22,7 @@
2222
// RUN: ld.lld %t-rw-addend.o %t.o -o %t7
2323
// RUN: llvm-readobj -r %t7 | FileCheck --check-prefix=IREL1 %s
2424
// RUN: ld.lld %t.o -o %t8 -pie
25-
// RUN: llvm-readobj -r %t8 | FileCheck --check-prefix=IREL2 %s
25+
// RUN: llvm-readobj -r %t8 | FileCheck --check-prefix=IREL1-REL2 %s
2626
// RUN: ld.lld %t.o %t-ro-pcrel.o -o %t9 -pie
2727
// RUN: llvm-readobj -r %t9 | FileCheck --check-prefix=IREL1-REL2 %s
2828
// RUN: ld.lld %t.o %t-rw-addend.o -o %t10 -pie
@@ -32,13 +32,6 @@
3232
// RUN: ld.lld %t-rw-addend.o %t.o -o %t12 -pie
3333
// RUN: llvm-readobj -r %t12 | FileCheck --check-prefix=IREL1-REL3 %s
3434

35-
// Two relocs, one for the GOT and the other for .data.
36-
// IREL2-NOT: R_X86_64_
37-
// IREL2: .rela.dyn
38-
// IREL2-NEXT: R_X86_64_IRELATIVE
39-
// IREL2-NEXT: R_X86_64_IRELATIVE
40-
// IREL2-NOT: R_X86_64_
41-
4235
// One reloc for the canonical PLT.
4336
// IREL1-NOT: R_X86_64_
4437
// IREL1: .rela.dyn

‎lld/test/ELF/ppc64-toc-relax-ifunc.s

+20-6
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,28 @@
44
# RUN: echo '.globl ifunc; .type ifunc, %gnu_indirect_function; ifunc:' | \
55
# RUN: llvm-mc -filetype=obj -triple=powerpc64le - -o %t1.o
66
# RUN: ld.lld %t.o %t1.o -o %t
7-
# RUN: llvm-objdump -d %t | FileCheck %s
7+
# RUN: llvm-readelf -S -s %t | FileCheck --check-prefix=SEC %s
8+
# RUN: llvm-readelf -x .toc %t | FileCheck --check-prefix=HEX %s
9+
# RUN: llvm-objdump -d %t | FileCheck --check-prefix=DIS %s
810

9-
## ifunc is a non-preemptable STT_GNU_IFUNC. Its toc entry will be
10-
## relocated by R_PPC64_IRELATIVE, not representable by a toc-relative value.
11-
## Check the toc-indirect access is not relaxed.
11+
## ifunc is a non-preemptable STT_GNU_IFUNC. The R_PPC64_ADDR64 in .toc
12+
## creates a canonical PLT for it and changes its type to STT_FUNC. We can thus
13+
## still perform toc-indirect to toc-relative relaxation because the distance
14+
## to the address of the canonical PLT is fixed.
1215

13-
# CHECK: nop
14-
# CHECK-NEXT: ld 3, -32768(2)
16+
# SEC: .text PROGBITS 0000000010010000
17+
# SEC: .plt NOBITS 0000000010030000
18+
# SEC: 0000000010010010 0 FUNC GLOBAL DEFAULT 3 ifunc
19+
20+
## .toc[0] stores the address of the canonical PLT.
21+
# HEX: section '.toc':
22+
# HEX-NEXT: 0x10020000 10000110 00000000
23+
24+
# REL: .rela.dyn {
25+
# REL-NEXT: 0x10030000 R_PPC64_IRELATIVE - 0x10010008
26+
# REL-NEXT: }
27+
28+
# DIS: addi 3, 3,
1529

1630
addis 3, 2, .toc@toc@ha
1731
ld 3, .toc@toc@l(3)

0 commit comments

Comments
 (0)
Please sign in to comment.