Skip to content

Commit f9bf9f9

Browse files
committed
[BOLT] Add .relr.dyn section support
Vladislav Khmelevsky, Advanced Software Technology Lab, Huawei Differential Revision: https://reviews.llvm.org/D146085
1 parent 62f09d7 commit f9bf9f9

File tree

6 files changed

+240
-5
lines changed

6 files changed

+240
-5
lines changed

bolt/include/bolt/Core/BinarySection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ class BinarySection {
275275
bool isTBSS() const { return isBSS() && isTLS(); }
276276
bool isVirtual() const { return ELFType == ELF::SHT_NOBITS; }
277277
bool isRela() const { return ELFType == ELF::SHT_RELA; }
278+
bool isRelr() const { return ELFType == ELF::SHT_RELR; }
278279
bool isWritable() const { return (ELFFlags & ELF::SHF_WRITE); }
279280
bool isAllocatable() const {
280281
if (isELF()) {

bolt/include/bolt/Core/Relocation.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ struct Relocation {
109109
/// Return code for a ABS 8-byte relocation
110110
static uint64_t getAbs64();
111111

112+
/// Return code for a RELATIVE relocation
113+
static uint64_t getRelative();
114+
112115
/// Return true if this relocation is PC-relative. Return false otherwise.
113116
bool isPCRelative() const { return isPCRelative(Type); }
114117

bolt/include/bolt/Rewrite/RewriteInstance.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ class RewriteInstance {
138138
/// Read relocations from a given section.
139139
void readDynamicRelocations(const object::SectionRef &Section, bool IsJmpRel);
140140

141+
/// Read relocations from a given RELR section.
142+
void readDynamicRelrRelocations(BinarySection &Section);
143+
141144
/// Print relocation information.
142145
void printRelocationInfo(const RelocationRef &Rel, StringRef SymbolName,
143146
uint64_t SymbolAddress, uint64_t Addend,
@@ -312,6 +315,9 @@ class RewriteInstance {
312315
/// Patch allocatable relocation sections.
313316
ELF_FUNCTION(void, patchELFAllocatableRelaSections);
314317

318+
/// Patch allocatable relr section.
319+
ELF_FUNCTION(void, patchELFAllocatableRelrSection);
320+
315321
/// Finalize memory image of section header string table.
316322
ELF_FUNCTION(void, finalizeSectionStringTable);
317323

@@ -486,6 +492,11 @@ class RewriteInstance {
486492
uint64_t DynamicRelocationsSize{0};
487493
uint64_t DynamicRelativeRelocationsCount{0};
488494

495+
// Location and size of .relr.dyn relocations.
496+
std::optional<uint64_t> DynamicRelrAddress;
497+
uint64_t DynamicRelrSize{0};
498+
uint64_t DynamicRelrEntrySize{0};
499+
489500
/// PLT relocations are special kind of dynamic relocations stored separately.
490501
std::optional<uint64_t> PLTRelocationsAddress;
491502
uint64_t PLTRelocationsSize{0};

bolt/lib/Core/Relocation.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,12 @@ uint64_t Relocation::getAbs64() {
642642
return ELF::R_X86_64_64;
643643
}
644644

645+
uint64_t Relocation::getRelative() {
646+
if (Arch == Triple::aarch64)
647+
return ELF::R_AARCH64_RELATIVE;
648+
return ELF::R_X86_64_RELATIVE;
649+
}
650+
645651
size_t Relocation::emit(MCStreamer *Streamer) const {
646652
const size_t Size = getSizeForType(Type);
647653
MCContext &Ctx = Streamer->getContext();

bolt/lib/Rewrite/RewriteInstance.cpp

Lines changed: 191 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2074,6 +2074,19 @@ bool RewriteInstance::analyzeRelocation(
20742074
}
20752075

20762076
void RewriteInstance::processDynamicRelocations() {
2077+
// Read .relr.dyn section containing compressed R_*_RELATIVE relocations.
2078+
if (DynamicRelrSize > 0) {
2079+
ErrorOr<BinarySection &> DynamicRelrSectionOrErr =
2080+
BC->getSectionForAddress(*DynamicRelrAddress);
2081+
if (!DynamicRelrSectionOrErr)
2082+
report_error("unable to find section corresponding to DT_RELR",
2083+
DynamicRelrSectionOrErr.getError());
2084+
if (DynamicRelrSectionOrErr->getSize() != DynamicRelrSize)
2085+
report_error("section size mismatch for DT_RELRSZ",
2086+
errc::executable_format_error);
2087+
readDynamicRelrRelocations(*DynamicRelrSectionOrErr);
2088+
}
2089+
20772090
// Read relocations for PLT - DT_JMPREL.
20782091
if (PLTRelocationsSize > 0) {
20792092
ErrorOr<BinarySection &> PLTRelSectionOrErr =
@@ -2372,6 +2385,60 @@ void RewriteInstance::readDynamicRelocations(const SectionRef &Section,
23722385
}
23732386
}
23742387

2388+
void RewriteInstance::readDynamicRelrRelocations(BinarySection &Section) {
2389+
assert(Section.isAllocatable() && "allocatable expected");
2390+
2391+
LLVM_DEBUG({
2392+
StringRef SectionName = Section.getName();
2393+
dbgs() << "BOLT-DEBUG: reading relocations in section " << SectionName
2394+
<< ":\n";
2395+
});
2396+
2397+
const uint64_t RType = Relocation::getRelative();
2398+
const uint8_t PSize = BC->AsmInfo->getCodePointerSize();
2399+
const uint64_t MaxDelta = ((CHAR_BIT * DynamicRelrEntrySize) - 1) * PSize;
2400+
2401+
auto ExtractAddendValue = [&](uint64_t Address) -> uint64_t {
2402+
ErrorOr<BinarySection &> Section = BC->getSectionForAddress(Address);
2403+
assert(Section && "cannot get section for data address from RELR");
2404+
DataExtractor DE = DataExtractor(Section->getContents(),
2405+
BC->AsmInfo->isLittleEndian(), PSize);
2406+
uint64_t Offset = Address - Section->getAddress();
2407+
return DE.getUnsigned(&Offset, PSize);
2408+
};
2409+
2410+
auto AddRelocation = [&](uint64_t Address) {
2411+
uint64_t Addend = ExtractAddendValue(Address);
2412+
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: R_*_RELATIVE relocation at 0x"
2413+
<< Twine::utohexstr(Address) << " to 0x"
2414+
<< Twine::utohexstr(Addend) << '\n';);
2415+
BC->addDynamicRelocation(Address, nullptr, RType, Addend);
2416+
};
2417+
2418+
DataExtractor DE = DataExtractor(Section.getContents(),
2419+
BC->AsmInfo->isLittleEndian(), PSize);
2420+
uint64_t Offset = 0, Address = 0;
2421+
uint64_t RelrCount = DynamicRelrSize / DynamicRelrEntrySize;
2422+
while (RelrCount--) {
2423+
assert(DE.isValidOffset(Offset));
2424+
uint64_t Entry = DE.getUnsigned(&Offset, DynamicRelrEntrySize);
2425+
if ((Entry & 1) == 0) {
2426+
AddRelocation(Entry);
2427+
Address = Entry + PSize;
2428+
} else {
2429+
const uint64_t StartAddress = Address;
2430+
while (Entry >>= 1) {
2431+
if (Entry & 1)
2432+
AddRelocation(Address);
2433+
2434+
Address += PSize;
2435+
}
2436+
2437+
Address = StartAddress + MaxDelta;
2438+
}
2439+
}
2440+
}
2441+
23752442
void RewriteInstance::printRelocationInfo(const RelocationRef &Rel,
23762443
StringRef SymbolName,
23772444
uint64_t SymbolAddress,
@@ -5203,6 +5270,101 @@ void RewriteInstance::patchELFSymTabs(ELFObjectFile<ELFT> *File) {
52035270
ELF::SHT_STRTAB);
52045271
}
52055272

5273+
template <typename ELFT>
5274+
void RewriteInstance::patchELFAllocatableRelrSection(
5275+
ELFObjectFile<ELFT> *File) {
5276+
if (!DynamicRelrAddress)
5277+
return;
5278+
5279+
raw_fd_ostream &OS = Out->os();
5280+
const uint8_t PSize = BC->AsmInfo->getCodePointerSize();
5281+
const uint64_t MaxDelta = ((CHAR_BIT * DynamicRelrEntrySize) - 1) * PSize;
5282+
5283+
auto FixAddend = [&](const BinarySection &Section, const Relocation &Rel) {
5284+
// Fix relocation symbol value in place if no static relocation found
5285+
// on the same address
5286+
if (Section.getRelocationAt(Rel.Offset))
5287+
return;
5288+
5289+
// No fixup needed if symbol address was not changed
5290+
const uint64_t Addend = getNewFunctionOrDataAddress(Rel.Addend);
5291+
if (!Addend)
5292+
return;
5293+
5294+
uint64_t FileOffset = Section.getOutputFileOffset();
5295+
if (!FileOffset)
5296+
FileOffset = Section.getInputFileOffset();
5297+
5298+
FileOffset += Rel.Offset;
5299+
OS.pwrite(reinterpret_cast<const char *>(&Addend), PSize, FileOffset);
5300+
};
5301+
5302+
// Fill new relative relocation offsets set
5303+
std::set<uint64_t> RelOffsets;
5304+
for (const BinarySection &Section : BC->allocatableSections()) {
5305+
const uint64_t SectionInputAddress = Section.getAddress();
5306+
uint64_t SectionAddress = Section.getOutputAddress();
5307+
if (!SectionAddress)
5308+
SectionAddress = SectionInputAddress;
5309+
5310+
for (const Relocation &Rel : Section.dynamicRelocations()) {
5311+
if (!Rel.isRelative())
5312+
continue;
5313+
5314+
uint64_t RelOffset =
5315+
getNewFunctionOrDataAddress(SectionInputAddress + Rel.Offset);
5316+
5317+
RelOffset = RelOffset == 0 ? SectionAddress + Rel.Offset : RelOffset;
5318+
assert((RelOffset & 1) == 0 && "Wrong relocation offset");
5319+
RelOffsets.emplace(RelOffset);
5320+
FixAddend(Section, Rel);
5321+
}
5322+
}
5323+
5324+
ErrorOr<BinarySection &> Section =
5325+
BC->getSectionForAddress(*DynamicRelrAddress);
5326+
assert(Section && "cannot get .relr.dyn section");
5327+
assert(Section->isRelr() && "Expected section to be SHT_RELR type");
5328+
uint64_t RelrDynOffset = Section->getInputFileOffset();
5329+
const uint64_t RelrDynEndOffset = RelrDynOffset + Section->getSize();
5330+
5331+
auto WriteRelr = [&](uint64_t Value) {
5332+
if (RelrDynOffset + DynamicRelrEntrySize > RelrDynEndOffset) {
5333+
errs() << "BOLT-ERROR: Offset overflow for relr.dyn section\n";
5334+
exit(1);
5335+
}
5336+
5337+
OS.pwrite(reinterpret_cast<const char *>(&Value), DynamicRelrEntrySize,
5338+
RelrDynOffset);
5339+
RelrDynOffset += DynamicRelrEntrySize;
5340+
};
5341+
5342+
for (auto RelIt = RelOffsets.begin(); RelIt != RelOffsets.end();) {
5343+
WriteRelr(*RelIt);
5344+
uint64_t Base = *RelIt++ + PSize;
5345+
while (1) {
5346+
uint64_t Bitmap = 0;
5347+
for (; RelIt != RelOffsets.end(); ++RelIt) {
5348+
const uint64_t Delta = *RelIt - Base;
5349+
if (Delta >= MaxDelta || Delta % PSize)
5350+
break;
5351+
5352+
Bitmap |= (1ULL << (Delta / PSize));
5353+
}
5354+
5355+
if (!Bitmap)
5356+
break;
5357+
5358+
WriteRelr((Bitmap << 1) | 1);
5359+
Base += MaxDelta;
5360+
}
5361+
}
5362+
5363+
// Fill the rest of the section with empty bitmap value
5364+
while (RelrDynOffset != RelrDynEndOffset)
5365+
WriteRelr(1);
5366+
}
5367+
52065368
template <typename ELFT>
52075369
void
52085370
RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
@@ -5294,8 +5456,11 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
52945456
}
52955457
};
52965458

5297-
// The dynamic linker expects R_*_RELATIVE relocations to be emitted first
5298-
writeRelocations(/* PatchRelative */ true);
5459+
// Place R_*_RELATIVE relocations in RELA section if RELR is not presented.
5460+
// The dynamic linker expects all R_*_RELATIVE relocations in RELA
5461+
// to be emitted first.
5462+
if (!DynamicRelrAddress)
5463+
writeRelocations(/* PatchRelative */ true);
52995464
writeRelocations(/* PatchRelative */ false);
53005465

53015466
auto fillNone = [&](uint64_t &Offset, uint64_t EndOffset) {
@@ -5501,6 +5666,15 @@ Error RewriteInstance::readELFDynamic(ELFObjectFile<ELFT> *File) {
55015666
case ELF::DT_RELACOUNT:
55025667
DynamicRelativeRelocationsCount = Dyn.getVal();
55035668
break;
5669+
case ELF::DT_RELR:
5670+
DynamicRelrAddress = Dyn.getPtr();
5671+
break;
5672+
case ELF::DT_RELRSZ:
5673+
DynamicRelrSize = Dyn.getVal();
5674+
break;
5675+
case ELF::DT_RELRENT:
5676+
DynamicRelrEntrySize = Dyn.getVal();
5677+
break;
55045678
}
55055679
}
55065680

@@ -5513,6 +5687,20 @@ Error RewriteInstance::readELFDynamic(ELFObjectFile<ELFT> *File) {
55135687
PLTRelocationsAddress.reset();
55145688
PLTRelocationsSize = 0;
55155689
}
5690+
5691+
if (!DynamicRelrAddress || !DynamicRelrSize) {
5692+
DynamicRelrAddress.reset();
5693+
DynamicRelrSize = 0;
5694+
} else if (!DynamicRelrEntrySize) {
5695+
errs() << "BOLT-ERROR: expected DT_RELRENT to be presented "
5696+
<< "in DYNAMIC section\n";
5697+
exit(1);
5698+
} else if (DynamicRelrSize % DynamicRelrEntrySize) {
5699+
errs() << "BOLT-ERROR: expected RELR table size to be divisible "
5700+
<< "by RELR entry size\n";
5701+
exit(1);
5702+
}
5703+
55165704
return Error::success();
55175705
}
55185706

@@ -5724,6 +5912,7 @@ void RewriteInstance::rewriteFile() {
57245912

57255913
if (BC->HasRelocations) {
57265914
patchELFAllocatableRelaSections();
5915+
patchELFAllocatableRelrSection();
57275916
patchELFGOT();
57285917
}
57295918

bolt/test/AArch64/constant_island_pie_update.s

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,51 @@
1-
// This test checks that the constant island value is updated if it
2-
// has dynamic relocation.
1+
// This test checks that the constant island offset and value is updated if
2+
// it has dynamic relocation. The tests checks both .rela.dyn and relr.dyn
3+
// dynamic relocations.
34
// Also check that we don't duplicate CI if it has dynamic relocations.
45

56
# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o
7+
// .rela.dyn
68
# RUN: %clang %cflags -fPIC -pie %t.o -o %t.rela.exe -nostdlib \
79
# RUN: -Wl,-q -Wl,-z,notext
810
# RUN: llvm-bolt %t.rela.exe -o %t.rela.bolt --use-old-text=0 --lite=0
911
# RUN: llvm-objdump -j .text -d %t.rela.bolt | FileCheck %s
1012
# RUN: llvm-readelf -rsW %t.rela.bolt | FileCheck --check-prefix=ELFCHECK %s
13+
// .relr.dyn
14+
# RUN: %clang %cflags -fPIC -pie %t.o -o %t.relr.exe -nostdlib \
15+
# RUN: -Wl,-q -Wl,-z,notext -Wl,--pack-dyn-relocs=relr
16+
# RUN: llvm-bolt %t.relr.exe -o %t.relr.bolt --use-old-text=0 --lite=0
17+
# RUN: llvm-objdump -j .text -d %t.relr.bolt | FileCheck %s
18+
# RUN: llvm-readelf -rsW %t.relr.bolt | FileCheck --check-prefix=ELFCHECK %s
19+
# RUN: llvm-readelf -SW %t.relr.bolt | FileCheck --check-prefix=RELRSZCHECK %s
1120

1221
// Check that the CI value was updated
1322
# CHECK: [[#%x,ADDR:]] <exitLocal>:
1423
# CHECK: {{.*}} <$d>:
1524
# CHECK-NEXT: {{.*}} .word 0x{{[0]+}}[[#ADDR]]
1625
# CHECK-NEXT: {{.*}} .word 0x00000000
26+
# CHECK-NEXT: {{.*}} .word 0x{{[0]+}}[[#ADDR]]
27+
# CHECK-NEXT: {{.*}} .word 0x00000000
28+
# CHECK-NEXT: {{.*}} .word 0x00000000
29+
# CHECK-NEXT: {{.*}} .word 0x00000000
30+
# CHECK-NEXT: {{.*}} .word 0x{{[0]+}}[[#ADDR]]
31+
# CHECK-NEXT: {{.*}} .word 0x00000000
32+
1733

1834
// Check that we've relaxed adr to adrp + add to refer external CI
1935
# CHECK: <addressDynCi>:
2036
# CHECK-NEXT: adrp
2137
# CHECK-NEXT: add
2238

23-
// Check that relocation offset was updated
39+
// Check that relocation offsets were updated
2440
# ELFCHECK: [[#%x,OFF:]] [[#%x,INFO_DYN:]] R_AARCH64_RELATIVE
41+
# ELFCHECK-NEXT: [[#OFF + 8]] {{0*}}[[#INFO_DYN]] R_AARCH64_RELATIVE
42+
# ELFCHECK-NEXT: [[#OFF + 24]] {{0*}}[[#INFO_DYN]] R_AARCH64_RELATIVE
2543
# ELFCHECK: {{.*}}[[#OFF]] {{.*}} $d
2644

45+
// Check that .relr.dyn size is 2 bytes to ensure that last 2 relocations were
46+
// encoded as a bitmap so the total section size for 3 relocations is 2 bytes.
47+
# RELRSZCHECK: .relr.dyn RELR [[#%x,ADDR:]] [[#%x,OFF:]] {{0*}}10
48+
2749
.text
2850
.align 4
2951
.local exitLocal
@@ -47,6 +69,9 @@ _start:
4769
bl exitLocal
4870
nop
4971
.Lci:
72+
.xword exitLocal
73+
.xword exitLocal
74+
.xword 0
5075
.xword exitLocal
5176
.size _start, .-_start
5277

0 commit comments

Comments
 (0)