[llvm] [BOLT] Treat relr relocations like rela (PR #206830)
Fabian Parzefall via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 9 09:10:14 PDT 2026
https://github.com/pzfl updated https://github.com/llvm/llvm-project/pull/206830
>From 62a78b042f0299bc1b367053d7bca301af1cc987 Mon Sep 17 00:00:00 2001
From: Fabian Parzefall <parzefall at meta.com>
Date: Fri, 26 Jun 2026 11:40:36 -0700
Subject: [PATCH] [BOLT] Treat relr relocations like rela
The linker can emit certain relative .dyn.rela relocations in .dyn.relr.
This includes relocations for jumptables emitted for indirect goto.
The current processing recognizes these relocations as jump targets
only for relative relocations from .dyn.rela, but not from .dyn.relr.
Give .dyn.relr the same treatment, so CFG construction does not dismiss
blocks that are only reachable indirectly.
---
bolt/include/bolt/Rewrite/RewriteInstance.h | 5 ++
bolt/lib/Rewrite/RewriteInstance.cpp | 51 +++++++++++----------
bolt/test/X86/indirect-goto.test | 7 +++
3 files changed, 40 insertions(+), 23 deletions(-)
diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h
index 3873d944e01ba..2e63ca93c3e57 100644
--- a/bolt/include/bolt/Rewrite/RewriteInstance.h
+++ b/bolt/include/bolt/Rewrite/RewriteInstance.h
@@ -136,6 +136,11 @@ class RewriteInstance {
/// Read relocations from a given RELR section.
void readDynamicRelrRelocations(BinarySection &Section);
+ /// Process relative dynamic relocations targeting code. This happens in code
+ /// using indirect goto.
+ void handleRelativeDynamicRelocation(uint64_t RelOffset,
+ uint64_t ReferencedAddress);
+
/// Print relocation information.
void printRelocationInfo(const RelocationRef &Rel, StringRef SymbolName,
uint64_t SymbolAddress, uint64_t Addend,
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 92ca0028fb637..a12b83859669b 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -2808,30 +2808,13 @@ void RewriteInstance::readDynamicRelocations(const SectionRef &Section,
// Check if this relocation targets an address within a function. This
// happens with indirect goto.
const uint64_t ReferencedAddress = SymbolAddress + Addend;
- BinaryFunction *Func =
- BC->getBinaryFunctionContainingAddress(ReferencedAddress);
-
- if (Relocation::isRelative(RType) && SymbolAddress == 0) {
- if (Func) {
- if (!Func->isInConstantIsland(ReferencedAddress)) {
- if (const uint64_t ReferenceOffset =
- ReferencedAddress - Func->getAddress()) {
- assert(!BC->getBinaryFunctionContainingAddress(Rel.getOffset()) &&
- "Relative relocation to code only from data");
- Func->registerInternalRefDataRelocation(ReferenceOffset,
- Rel.getOffset());
- }
- } else {
- BC->errs() << "BOLT-ERROR: referenced address at 0x"
- << Twine::utohexstr(ReferencedAddress)
- << " is in constant island of function " << *Func << "\n";
- exit(1);
- }
+ if (Relocation::isRelative(RType)) {
+ if (SymbolAddress != 0) {
+ BC->errs() << "BOLT-ERROR: symbol address non zero for RELATIVE "
+ "relocation type\n";
+ exit(1);
}
- } else if (Relocation::isRelative(RType) && SymbolAddress != 0) {
- BC->errs() << "BOLT-ERROR: symbol address non zero for RELATIVE "
- "relocation type\n";
- exit(1);
+ handleRelativeDynamicRelocation(Rel.getOffset(), ReferencedAddress);
}
BC->addDynamicRelocation(Rel.getOffset(), Symbol, RType, Addend);
@@ -2864,6 +2847,7 @@ void RewriteInstance::readDynamicRelrRelocations(BinarySection &Section) {
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: R_*_RELATIVE relocation at 0x"
<< Twine::utohexstr(Address) << " to 0x"
<< Twine::utohexstr(Addend) << '\n';);
+ handleRelativeDynamicRelocation(Address, Addend);
BC->addDynamicRelocation(Address, nullptr, RType, Addend, /*Value=*/0,
/*IsRELR=*/true);
};
@@ -2891,6 +2875,27 @@ void RewriteInstance::readDynamicRelrRelocations(BinarySection &Section) {
}
}
+void RewriteInstance::handleRelativeDynamicRelocation(
+ uint64_t RelOffset, uint64_t ReferencedAddress) {
+ BinaryFunction *Func =
+ BC->getBinaryFunctionContainingAddress(ReferencedAddress);
+ if (!Func)
+ return;
+
+ if (Func->isInConstantIsland(ReferencedAddress)) {
+ BC->errs() << "BOLT-ERROR: referenced address at 0x"
+ << Twine::utohexstr(ReferencedAddress)
+ << " is in constant island of function " << *Func << "\n";
+ exit(1);
+ }
+
+ if (const uint64_t ReferenceOffset = ReferencedAddress - Func->getAddress()) {
+ assert(!BC->getBinaryFunctionContainingAddress(RelOffset) &&
+ "Relative relocation to code only from data");
+ Func->registerInternalRefDataRelocation(ReferenceOffset, RelOffset);
+ }
+}
+
void RewriteInstance::printRelocationInfo(const RelocationRef &Rel,
StringRef SymbolName,
uint64_t SymbolAddress,
diff --git a/bolt/test/X86/indirect-goto.test b/bolt/test/X86/indirect-goto.test
index c7dae07446dfd..38e8d9073a956 100644
--- a/bolt/test/X86/indirect-goto.test
+++ b/bolt/test/X86/indirect-goto.test
@@ -10,6 +10,13 @@ RUN: llvm-bolt %t.pie -o %t.pie.null --relocs=1 --print-cfg --print-only=main \
RUN: --strict \
RUN: 2>&1 | FileCheck %s
+## Check indirect goto works in binaries linked with relr
+RUN: %clang %cflags -fPIE -pie %S/../Inputs/indirect_goto.c -o %t.relr \
+RUN: -Wl,-z,pack-relative-relocs -Wl,-q
+RUN: llvm-bolt %t.relr -o %t.relr.null --relocs=1 --print-cfg --print-only=main \
+RUN: --strict \
+RUN: 2>&1 | FileCheck %s
+
## Check that all possible destinations are included as successors.
CHECK: jmpq *%rax # UNKNOWN CONTROL FLOW
CHECK: Successors: .Ltmp0, .Ltmp1, .Ltmp2
More information about the llvm-commits
mailing list