[llvm] [BOLT] Preserve relocation to rela/relr association (PR #206612)
Fabian Parzefall via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 30 11:46:23 PDT 2026
https://github.com/pzfl updated https://github.com/llvm/llvm-project/pull/206612
>From d968c40424ecef5cc84982482551fe1550c240bc Mon Sep 17 00:00:00 2001
From: Fabian Parzefall <parzefall at meta.com>
Date: Mon, 29 Jun 2026 15:43:20 -0700
Subject: [PATCH] [BOLT] Preserve relocation to rela/relr association
BOLT emits all dynamic relative relocations in .relr.dyn if it exists
in the input, including relative relocations from .rela.dyn. This
can fail for two reasons: first, relative relocations can target odd
addresses that are not word aligned. These can never be emitted as relr
relocations. Second, BOLT reuses the existing .relr.dyn section. Even
if a relative relocation from .rela.dyn can be emitted as relr, there
is simply no space in the existing .relr.dyn section. This causes an
overflow. Prevent this by emitting relative relocations in the same
section they originate from.
---
bolt/include/bolt/Core/BinaryContext.h | 3 +-
bolt/include/bolt/Core/BinarySection.h | 6 ++--
bolt/include/bolt/Core/Relocation.h | 17 +++++++++--
bolt/lib/Core/BinaryContext.cpp | 4 +--
bolt/lib/Rewrite/RewriteInstance.cpp | 11 +++----
bolt/test/X86/relr-odd-unaligned.c | 42 ++++++++++++++++++++++++++
6 files changed, 69 insertions(+), 14 deletions(-)
create mode 100644 bolt/test/X86/relr-odd-unaligned.c
diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h
index 5785941d54320..73ccb911039de 100644
--- a/bolt/include/bolt/Core/BinaryContext.h
+++ b/bolt/include/bolt/Core/BinaryContext.h
@@ -1409,7 +1409,8 @@ class BinaryContext {
/// Register dynamic relocation at \p Address.
void addDynamicRelocation(uint64_t Address, MCSymbol *Symbol, uint32_t Type,
- uint64_t Addend, uint64_t Value = 0);
+ uint64_t Addend, uint64_t Value = 0,
+ bool IsRELR = false);
/// Return a dynamic relocation registered at a given \p Address, or nullptr
/// if there is no dynamic relocation at such address.
diff --git a/bolt/include/bolt/Core/BinarySection.h b/bolt/include/bolt/Core/BinarySection.h
index 154a8d12de5ce..69da629c7395c 100644
--- a/bolt/include/bolt/Core/BinarySection.h
+++ b/bolt/include/bolt/Core/BinarySection.h
@@ -366,8 +366,10 @@ class BinarySection {
/// Add a dynamic relocation at the given /p Offset.
void addDynamicRelocation(uint64_t Offset, MCSymbol *Symbol, uint32_t Type,
- uint64_t Addend, uint64_t Value = 0) {
- addDynamicRelocation(Relocation{Offset, Symbol, Type, Addend, Value});
+ uint64_t Addend, uint64_t Value = 0,
+ bool IsRELR = false) {
+ addDynamicRelocation(
+ Relocation{Offset, Symbol, Type, Addend, Value, IsRELR});
}
void addDynamicRelocation(const Relocation &Reloc) {
diff --git a/bolt/include/bolt/Core/Relocation.h b/bolt/include/bolt/Core/Relocation.h
index 3fcf69d79dba2..9bc94d6484b70 100644
--- a/bolt/include/bolt/Core/Relocation.h
+++ b/bolt/include/bolt/Core/Relocation.h
@@ -38,12 +38,16 @@ namespace bolt {
class Relocation {
public:
Relocation(uint64_t Offset, MCSymbol *Symbol, uint32_t Type, uint64_t Addend,
- uint64_t Value)
+ uint64_t Value, bool IsRELR = false)
: Offset(Offset), Symbol(Symbol), Type(Type), Optional(false),
- Addend(Addend), Value(Value) {}
+ IsRELR(IsRELR), Addend(Addend), Value(Value) {
+ assert((isRelative() || !isRELR()) &&
+ "Only relative relocations can be relr.");
+ }
Relocation()
- : Offset(0), Symbol(0), Type(0), Optional(0), Addend(0), Value(0) {}
+ : Offset(0), Symbol(0), Type(0), Optional(0), IsRELR(0), Addend(0),
+ Value(0) {}
static Triple::ArchType Arch; /// set by BinaryContext ctor.
@@ -61,6 +65,11 @@ class Relocation {
/// omitted under certain circumstances.
bool Optional = false;
+ /// Track which relocations originate from a relr section. Emit these
+ /// exclusively into the relr section and do not accidentally promote relative
+ /// rela entries, because that would require growing the relr section.
+ bool IsRELR = false;
+
public:
/// The offset from the \p Symbol base used to compute the final
/// value of this relocation.
@@ -77,6 +86,8 @@ class Relocation {
bool isOptional() { return Optional; }
+ bool isRELR() const { return IsRELR; }
+
/// Return size of this relocation.
size_t getSize() const { return getSizeForType(Type); }
diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp
index eb9caca3ea16e..130c523bcda54 100644
--- a/bolt/lib/Core/BinaryContext.cpp
+++ b/bolt/lib/Core/BinaryContext.cpp
@@ -2462,11 +2462,11 @@ void BinaryContext::addRelocation(uint64_t Address, MCSymbol *Symbol,
void BinaryContext::addDynamicRelocation(uint64_t Address, MCSymbol *Symbol,
uint32_t Type, uint64_t Addend,
- uint64_t Value) {
+ uint64_t Value, bool IsRELR) {
ErrorOr<BinarySection &> Section = getSectionForAddress(Address);
assert(Section && "cannot find section for address");
Section->addDynamicRelocation(Address - Section->getAddress(), Symbol, Type,
- Addend, Value);
+ Addend, Value, IsRELR);
}
bool BinaryContext::removeRelocationAt(uint64_t Address) {
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 5e2ecd66b7f9d..9e00d48e03853 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -2859,7 +2859,8 @@ void RewriteInstance::readDynamicRelrRelocations(BinarySection &Section) {
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: R_*_RELATIVE relocation at 0x"
<< Twine::utohexstr(Address) << " to 0x"
<< Twine::utohexstr(Addend) << '\n';);
- BC->addDynamicRelocation(Address, nullptr, RType, Addend);
+ BC->addDynamicRelocation(Address, nullptr, RType, Addend, /*Value=*/0,
+ /*IsRELR=*/true);
};
DataExtractor DE(Section.getContents(), BC->AsmInfo->isLittleEndian());
@@ -5794,7 +5795,7 @@ void RewriteInstance::patchELFAllocatableRelrSection(
SectionAddress = SectionInputAddress;
for (const Relocation &Rel : Section.dynamicRelocations()) {
- if (!Rel.isRelative())
+ if (!Rel.isRELR())
continue;
uint64_t RelOffset =
@@ -5896,7 +5897,7 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
for (const Relocation &Rel : Section.dynamicRelocations()) {
const bool IsRelative = Rel.isRelative();
- if (PatchRelative != IsRelative)
+ if (PatchRelative != IsRelative || Rel.isRELR())
continue;
if (IsRelative)
@@ -5942,11 +5943,9 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
}
};
- // Place R_*_RELATIVE relocations in RELA section if RELR is not presented.
// The dynamic linker expects all R_*_RELATIVE relocations in RELA
// to be emitted first.
- if (!DynamicRelrAddress)
- writeRelocations(/* PatchRelative */ true);
+ writeRelocations(/* PatchRelative */ true);
writeRelocations(/* PatchRelative */ false);
auto fillNone = [&](uint64_t &Offset, uint64_t EndOffset) {
diff --git a/bolt/test/X86/relr-odd-unaligned.c b/bolt/test/X86/relr-odd-unaligned.c
new file mode 100644
index 0000000000000..48287e7d50151
--- /dev/null
+++ b/bolt/test/X86/relr-odd-unaligned.c
@@ -0,0 +1,42 @@
+// Binaries with relative relocations targeting odd addresses that are not word
+// aligned are handled correctly in the presence of a relr section.
+
+// RUN: %clang %cflags -fPIC -pie %s -o %t -Wl,-z,pack-relative-relocs -Wl,-q
+
+// The binary contains 2 relocations in .rela.dyn, one of them is at an odd
+// offset. It contains one relocation in .relr.dyn.
+//
+// RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=SANITY
+// SANITY: Relocations [
+// SANITY: Section {{.*}} .rela.dyn {
+// SANITY-DAG: 0x{{[0-9A-F]*[02468ACE]}} R_X86_64_RELATIVE
+// SANITY-DAG: 0x{{[0-9A-F]*[13579BDF]}} R_X86_64_RELATIVE
+// SANITY: }
+// SANITY: Section {{.*}} .relr.dyn {
+// SANITY: R_X86_64_RELATIVE
+// SANITY: }
+
+// Rewrite the binary with BOLT.
+//
+// RUN: llvm-bolt %t -o %t.bolt
+// RUN: llvm-readobj -r %t.bolt | FileCheck %s --check-prefix=SANITY
+
+struct __attribute__((packed)) S {
+ const char *Ptr;
+ char Pad;
+};
+
+/// Ends up in .data.rel.ro with section alignment 1. lld cannot turn these into
+/// relr relocations for two reasons: one of the relocations will be at an odd
+/// offset, which cannot be represented with a relr relocation. BOLT has to emit
+/// this one as rela. The other relocation will be at an even offset. lld
+/// (currently) only promotes rela to relr for input sections with alignment
+/// >= 2. BOLT can re-emit this one either as rela or promote it to an relr.
+/// However, BOLT (currently) cannot grow the relr section, which forces
+/// emissions as rela.
+__attribute__((aligned(1))) const struct S RO[] = {{"s1", 1}, {"s2", 2}};
+
+/// Ends up in .data with section alignment 8. Emits relr relocation.
+static void *RW = &RW;
+
+int main() { return (long)RO[0].Ptr + (long)RO[1].Ptr + (long)RW; }
More information about the llvm-commits
mailing list