Skip to content

Commit 18a49f0

Browse files
committed
[ELF] Merge relaIplt into relaDyn
`relaIplt` was added so that IRELATIVE relocations are placed at the end of .rela.dyn (since https://reviews.llvm.org/D65651) or .rela.plt (--pack-dyn-relocs=android[+relr]). Unfortunately, handling `relaIplt` requires special cases all over the code base. We can extend partitionRels/computeRels to partition both RELATIVE and IRELATIVE relocations, rendering `relaIplt` unneeded. The change allows IRELATIVE relocations in the DT_ANDROID_REL[A] table (untested?!), which may be processed before other types of relocations. This seems acceptable for Bionic's DEFINE_IFUNC_FOR use cases. In addition, this change simplies changing .rel[a].dyn to a compact relocation format (CREL). SHF_INFO_LINK is removed from .rel[a].dyn with IRELATIVE relocations. (See https://reviews.llvm.org/D89828).
1 parent f0a8738 commit 18a49f0

File tree

8 files changed

+28
-63
lines changed

8 files changed

+28
-63
lines changed

lld/ELF/Relocations.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,12 +1620,8 @@ static bool handleNonPreemptibleIfunc(Symbol &sym, uint16_t flags) {
16201620
// relatively straightforward. We create a PLT entry in Iplt, which is
16211621
// usually at the end of .plt, which makes an indirect call using a
16221622
// matching GOT entry in igotPlt, which is usually at the end of .got.plt.
1623-
// The GOT entry is relocated using an IRELATIVE relocation in relaIplt,
1624-
// which is usually at the end of .rela.plt. Unlike most relocations in
1625-
// .rela.plt, which may be evaluated lazily without -z now, dynamic
1626-
// loaders evaluate IRELATIVE relocs eagerly, which means that for
1627-
// IRELATIVE relocs only, GOT-generating relocations can point directly to
1628-
// .got.plt without requiring a separate GOT entry.
1623+
// The GOT entry is relocated using an IRELATIVE relocation in relaDyn,
1624+
// which is usually at the end of .rela.dyn.
16291625
//
16301626
// - Despite the fact that an ifunc does not have a fixed value, compilers
16311627
// that are not passed -fPIC will assume that they do, and will emit
@@ -1665,7 +1661,7 @@ static bool handleNonPreemptibleIfunc(Symbol &sym, uint16_t flags) {
16651661
// section/value fixed.
16661662
auto *directSym = makeDefined(cast<Defined>(sym));
16671663
directSym->allocateAux();
1668-
addPltEntry(*in.iplt, *in.igotPlt, *in.relaIplt, target->iRelativeRel,
1664+
addPltEntry(*in.iplt, *in.igotPlt, *mainPart->relaDyn, target->iRelativeRel,
16691665
*directSym);
16701666
sym.allocateAux();
16711667
symAux.back().pltIdx = symAux[directSym->auxIdx].pltIdx;

lld/ELF/SyntheticSections.cpp

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,15 +1267,12 @@ DynamicSection<ELFT>::DynamicSection()
12671267
// The output section .rela.dyn may include these synthetic sections:
12681268
//
12691269
// - part.relaDyn
1270-
// - in.relaIplt: this is included if in.relaIplt is named .rela.dyn
12711270
// - in.relaPlt: this is included if a linker script places .rela.plt inside
12721271
// .rela.dyn
12731272
//
12741273
// DT_RELASZ is the total size of the included sections.
12751274
static uint64_t addRelaSz(const RelocationBaseSection &relaDyn) {
12761275
size_t size = relaDyn.getSize();
1277-
if (in.relaIplt->getParent() == relaDyn.getParent())
1278-
size += in.relaIplt->getSize();
12791276
if (in.relaPlt->getParent() == relaDyn.getParent())
12801277
size += in.relaPlt->getSize();
12811278
return size;
@@ -1372,9 +1369,7 @@ DynamicSection<ELFT>::computeContents() {
13721369
if (!config->shared && !config->relocatable && !config->zRodynamic)
13731370
addInt(DT_DEBUG, 0);
13741371

1375-
if (part.relaDyn->isNeeded() ||
1376-
(in.relaIplt->isNeeded() &&
1377-
part.relaDyn->getParent() == in.relaIplt->getParent())) {
1372+
if (part.relaDyn->isNeeded()) {
13781373
addInSec(part.relaDyn->dynamicTag, *part.relaDyn);
13791374
entries.emplace_back(part.relaDyn->sizeDynamicTag,
13801375
addRelaSz(*part.relaDyn));
@@ -1657,10 +1652,6 @@ void RelocationBaseSection::finalizeContents() {
16571652
getParent()->flags |= ELF::SHF_INFO_LINK;
16581653
getParent()->info = in.gotPlt->getParent()->sectionIndex;
16591654
}
1660-
if (in.relaIplt.get() == this && in.igotPlt->getParent()) {
1661-
getParent()->flags |= ELF::SHF_INFO_LINK;
1662-
getParent()->info = in.igotPlt->getParent()->sectionIndex;
1663-
}
16641655
}
16651656

16661657
void DynamicReloc::computeRaw(SymbolTableBaseSection *symtab) {
@@ -1674,6 +1665,11 @@ void RelocationBaseSection::computeRels() {
16741665
SymbolTableBaseSection *symTab = getPartition().dynSymTab.get();
16751666
parallelForEach(relocs,
16761667
[symTab](DynamicReloc &rel) { rel.computeRaw(symTab); });
1668+
1669+
auto irelative = std::partition(
1670+
relocs.begin() + numRelativeRelocs, relocs.end(),
1671+
[t = target->iRelativeRel](auto &r) { return r.type != t; });
1672+
16771673
// Sort by (!IsRelative,SymIndex,r_offset). DT_REL[A]COUNT requires us to
16781674
// place R_*_RELATIVE first. SymIndex is to improve locality, while r_offset
16791675
// is to make results easier to read.
@@ -1682,7 +1678,7 @@ void RelocationBaseSection::computeRels() {
16821678
parallelSort(relocs.begin(), nonRelative,
16831679
[&](auto &a, auto &b) { return a.r_offset < b.r_offset; });
16841680
// Non-relative relocations are few, so don't bother with parallelSort.
1685-
llvm::sort(nonRelative, relocs.end(), [&](auto &a, auto &b) {
1681+
llvm::sort(nonRelative, irelative, [&](auto &a, auto &b) {
16861682
return std::tie(a.r_sym, a.r_offset) < std::tie(b.r_sym, b.r_offset);
16871683
});
16881684
}
@@ -3843,7 +3839,6 @@ void InStruct::reset() {
38433839
ppc32Got2.reset();
38443840
ibtPlt.reset();
38453841
relaPlt.reset();
3846-
relaIplt.reset();
38473842
shStrTab.reset();
38483843
strTab.reset();
38493844
symTab.reset();

lld/ELF/SyntheticSections.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1358,7 +1358,6 @@ struct InStruct {
13581358
std::unique_ptr<PPC32Got2Section> ppc32Got2;
13591359
std::unique_ptr<IBTPltSection> ibtPlt;
13601360
std::unique_ptr<RelocationBaseSection> relaPlt;
1361-
std::unique_ptr<RelocationBaseSection> relaIplt;
13621361
std::unique_ptr<StringTableSection> shStrTab;
13631362
std::unique_ptr<StringTableSection> strTab;
13641363
std::unique_ptr<SymbolTableBaseSection> symTab;

lld/ELF/Writer.cpp

Lines changed: 14 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -449,8 +449,8 @@ template <class ELFT> void elf::createSyntheticSections() {
449449

450450
add(*part.dynamic);
451451
add(*part.dynStrTab);
452-
add(*part.relaDyn);
453452
}
453+
add(*part.relaDyn);
454454

455455
if (config->relrPackDynRelocs) {
456456
part.relrDyn = std::make_unique<RelrSection<ELFT>>(threadCount);
@@ -550,17 +550,6 @@ template <class ELFT> void elf::createSyntheticSections() {
550550
/*threadCount=*/1);
551551
add(*in.relaPlt);
552552

553-
// The relaIplt immediately follows .rel[a].dyn to ensure that the IRelative
554-
// relocations are processed last by the dynamic loader. We cannot place the
555-
// iplt section in .rel.dyn when Android relocation packing is enabled because
556-
// that would cause a section type mismatch. However, because the Android
557-
// dynamic loader reads .rel.plt after .rel.dyn, we can get the desired
558-
// behaviour by placing the iplt section in .rel.plt.
559-
in.relaIplt = std::make_unique<RelocationSection<ELFT>>(
560-
config->androidPackDynRelocs ? in.relaPlt->name : relaDynName,
561-
/*sort=*/false, /*threadCount=*/1);
562-
add(*in.relaIplt);
563-
564553
if ((config->emachine == EM_386 || config->emachine == EM_X86_64) &&
565554
(config->andFeatures & GNU_PROPERTY_X86_FEATURE_1_IBT)) {
566555
in.ibtPlt = std::make_unique<IBTPltSection>();
@@ -1071,20 +1060,18 @@ void PhdrEntry::add(OutputSection *sec) {
10711060
sec->ptLoad = this;
10721061
}
10731062

1074-
// The beginning and the ending of .rel[a].plt section are marked
1075-
// with __rel[a]_iplt_{start,end} symbols if it is a statically linked
1076-
// executable. The runtime needs these symbols in order to resolve
1077-
// all IRELATIVE relocs on startup. For dynamic executables, we don't
1078-
// need these symbols, since IRELATIVE relocs are resolved through GOT
1079-
// and PLT. For details, see http://www.airs.com/blog/archives/403.
1063+
// A statically linked position-dependent executable should only contain
1064+
// IRELATIVE relocations and no other dynamic relocations. Encapsulation symbols
1065+
// __rel[a]_iplt_{start,end} will be defined for .rel[a].dyn, to be
1066+
// processed by the libc runtime. Other executables or DSOs use dynamic tags
1067+
// instead.
10801068
template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() {
10811069
if (config->isPic)
10821070
return;
10831071

1084-
// By default, __rela_iplt_{start,end} belong to a dummy section 0
1085-
// because .rela.plt might be empty and thus removed from output.
1086-
// We'll override Out::elfHeader with In.relaIplt later when we are
1087-
// sure that .rela.plt exists in output.
1072+
// __rela_iplt_{start,end} are initially defined relative to dummy section 0.
1073+
// We'll override Out::elfHeader with relaDyn later when we are sure that
1074+
// .rela.dyn will be present in the output.
10881075
ElfSym::relaIpltStart = addOptionalRegular(
10891076
config->isRela ? "__rela_iplt_start" : "__rel_iplt_start",
10901077
Out::elfHeader, 0, STV_HIDDEN);
@@ -1110,11 +1097,11 @@ template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() {
11101097
ElfSym::globalOffsetTable->section = sec;
11111098
}
11121099

1113-
// .rela_iplt_{start,end} mark the start and the end of in.relaIplt.
1114-
if (ElfSym::relaIpltStart && in.relaIplt->isNeeded()) {
1115-
ElfSym::relaIpltStart->section = in.relaIplt.get();
1116-
ElfSym::relaIpltEnd->section = in.relaIplt.get();
1117-
ElfSym::relaIpltEnd->value = in.relaIplt->getSize();
1100+
// .rela_iplt_{start,end} mark the start and the end of .rel[a].dyn.
1101+
if (ElfSym::relaIpltStart && mainPart->relaDyn->isNeeded()) {
1102+
ElfSym::relaIpltStart->section = mainPart->relaDyn.get();
1103+
ElfSym::relaIpltEnd->section = mainPart->relaDyn.get();
1104+
ElfSym::relaIpltEnd->value = mainPart->relaDyn->getSize();
11181105
}
11191106

11201107
PhdrEntry *last = nullptr;
@@ -1470,14 +1457,6 @@ static void sortSection(OutputSection &osec,
14701457
if (name == ".init" || name == ".fini")
14711458
return;
14721459

1473-
// IRelative relocations that usually live in the .rel[a].dyn section should
1474-
// be processed last by the dynamic loader. To achieve that we add synthetic
1475-
// sections in the required order from the beginning so that the in.relaIplt
1476-
// section is placed last in an output section. Here we just do not apply
1477-
// sorting for an output section which holds the in.relaIplt section.
1478-
if (in.relaIplt->getParent() == &osec)
1479-
return;
1480-
14811460
// Sort input sections by priority using the list provided by
14821461
// --symbol-ordering-file or --shuffle-sections=. This is a least significant
14831462
// digit radix sort. The sections may be sorted stably again by a more
@@ -2196,7 +2175,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
21962175
finalizeSynthetic(in.mipsGot.get());
21972176
finalizeSynthetic(in.igotPlt.get());
21982177
finalizeSynthetic(in.gotPlt.get());
2199-
finalizeSynthetic(in.relaIplt.get());
22002178
finalizeSynthetic(in.relaPlt.get());
22012179
finalizeSynthetic(in.plt.get());
22022180
finalizeSynthetic(in.iplt.get());

lld/test/ELF/aarch64-gnu-ifunc.s

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,12 @@
1111
// CHECK-NEXT: Type: SHT_RELA
1212
// CHECK-NEXT: Flags [
1313
// CHECK-NEXT: SHF_ALLOC
14-
// CHECK-NEXT: SHF_INFO_LINK
1514
// CHECK-NEXT: ]
1615
// CHECK-NEXT: Address: [[RELA:.*]]
1716
// CHECK-NEXT: Offset: 0x158
1817
// CHECK-NEXT: Size: 48
1918
// CHECK-NEXT: Link: 0
20-
// CHECK-NEXT: Info: 4
19+
// CHECK-NEXT: Info: 0
2120
// CHECK-NEXT: AddressAlignment: 8
2221
// CHECK-NEXT: EntrySize: 24
2322
// CHECK-NEXT: }

lld/test/ELF/arm-gnu-ifunc.s

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,12 @@ _start:
3030
// CHECK-NEXT: Type: SHT_REL
3131
// CHECK-NEXT: Flags [
3232
// CHECK-NEXT: SHF_ALLOC
33-
// CHECK-NEXT: SHF_INFO_LINK
3433
// CHECK-NEXT: ]
3534
// CHECK-NEXT: Address: 0x100F4
3635
// CHECK-NEXT: Offset: 0xF4
3736
// CHECK-NEXT: Size: 16
3837
// CHECK-NEXT: Link:
39-
// CHECK-NEXT: Info: 4
38+
// CHECK-NEXT: Info: 0
4039
// CHECK: Name: .iplt
4140
// CHECK-NEXT: Type: SHT_PROGBITS
4241
// CHECK-NEXT: Flags [

lld/test/ELF/gnu-ifunc-i386.s

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,12 @@
1111
// CHECK-NEXT: Type: SHT_REL
1212
// CHECK-NEXT: Flags [
1313
// CHECK-NEXT: SHF_ALLOC
14-
// CHECK-NEXT: SHF_INFO_LINK
1514
// CHECK-NEXT: ]
1615
// CHECK-NEXT: Address: [[RELA:.*]]
1716
// CHECK-NEXT: Offset: 0xD4
1817
// CHECK-NEXT: Size: 16
1918
// CHECK-NEXT: Link: 0
20-
// CHECK-NEXT: Info: 4
19+
// CHECK-NEXT: Info: 0
2120
// CHECK-NEXT: AddressAlignment: 4
2221
// CHECK-NEXT: EntrySize: 8
2322
// CHECK-NEXT: }

lld/test/ELF/systemz-ifunc-nonpreemptible.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
# CHECK: Section Headers:
1111
# CHECK-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
1212
# CHECK-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0
13-
# CHECK-NEXT: [ 1] .rela.dyn RELA 0000000001000158 000158 000030 18 AI 0 4 8
13+
# CHECK-NEXT: [ 1] .rela.dyn RELA 0000000001000158 000158 000030 18 A 0 0 8
1414
# CHECK-NEXT: [ 2] .text PROGBITS 0000000001001188 000188 00001c 00 AX 0 0 4
1515
# CHECK-NEXT: [ 3] .iplt PROGBITS 00000000010011b0 0001b0 000040 00 AX 0 0 16
1616
# CHECK-NEXT: [ 4] .got.plt PROGBITS 00000000010021f0 0001f0 000010 00 WA 0 0 8

0 commit comments

Comments
 (0)