[llvm] [BOLT] Prevent rela.plt reordering (PR #219447)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 15 04:21:15 PDT 2026
https://github.com/maksimra updated https://github.com/llvm/llvm-project/pull/219447
>From 8e00280b0cbc5650b2e1f9c376864ed90932fb54 Mon Sep 17 00:00:00 2001
From: Maksim <rachinskii.mv at phystech.edu>
Date: Thu, 20 Aug 2026 15:12:48 +0300
Subject: [PATCH 1/2] [BOLT] Prevent rela.plt reordering
BOLT reorders .rela.plt entries without also updating the corresponding
PLT stub relocation indices. This patch prevent original order of jump
relative relocations.
---
bolt/include/bolt/Core/BinaryContext.h | 4 +-
bolt/include/bolt/Core/BinarySection.h | 7 +-
bolt/include/bolt/Core/Relocation.h | 25 +++-
bolt/include/bolt/Rewrite/RewriteInstance.h | 4 +-
bolt/lib/Core/BinaryContext.cpp | 5 +-
bolt/lib/Rewrite/RewriteInstance.cpp | 123 ++++++++++++--------
bolt/test/runtime/X86/rela-plt-order.c | 31 +++++
7 files changed, 140 insertions(+), 59 deletions(-)
create mode 100644 bolt/test/runtime/X86/rela-plt-order.c
diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h
index 92cd853870cae..7677fb83e1e04 100644
--- a/bolt/include/bolt/Core/BinaryContext.h
+++ b/bolt/include/bolt/Core/BinaryContext.h
@@ -1455,7 +1455,9 @@ 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,
- bool IsRELR = false);
+ bool IsRELR = false,
+ uint64_t JmpRelocationIndex =
+ Relocation::NoJmpRelocationIndex);
/// 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 4609105d8b5ba..0098933054e3b 100644
--- a/bolt/include/bolt/Core/BinarySection.h
+++ b/bolt/include/bolt/Core/BinarySection.h
@@ -367,9 +367,12 @@ 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,
- bool IsRELR = false) {
+ bool IsRELR = false,
+ uint64_t JmpRelocationIndex =
+ Relocation::NoJmpRelocationIndex) {
addDynamicRelocation(
- Relocation{Offset, Symbol, Type, Addend, Value, IsRELR});
+ Relocation{Offset, Symbol, Type, Addend, Value, IsRELR,
+ JmpRelocationIndex});
}
void addDynamicRelocation(const Relocation &Reloc) {
diff --git a/bolt/include/bolt/Core/Relocation.h b/bolt/include/bolt/Core/Relocation.h
index 9bc94d6484b70..1237314b994f3 100644
--- a/bolt/include/bolt/Core/Relocation.h
+++ b/bolt/include/bolt/Core/Relocation.h
@@ -37,17 +37,21 @@ namespace bolt {
/// Relocation class.
class Relocation {
public:
+ static constexpr uint64_t NoJmpRelocationIndex = uint64_t(-1);
+
Relocation(uint64_t Offset, MCSymbol *Symbol, uint32_t Type, uint64_t Addend,
- uint64_t Value, bool IsRELR = false)
+ uint64_t Value, bool IsRELR = false,
+ uint64_t JmpRelocationIndex = NoJmpRelocationIndex)
: Offset(Offset), Symbol(Symbol), Type(Type), Optional(false),
- IsRELR(IsRELR), Addend(Addend), Value(Value) {
+ IsRELR(IsRELR), Addend(Addend), Value(Value),
+ JmpRelocationIndex(JmpRelocationIndex) {
assert((isRelative() || !isRELR()) &&
"Only relative relocations can be relr.");
}
Relocation()
: Offset(0), Symbol(0), Type(0), Optional(0), IsRELR(0), Addend(0),
- Value(0) {}
+ Value(0), JmpRelocationIndex(NoJmpRelocationIndex) {}
static Triple::ArchType Arch; /// set by BinaryContext ctor.
@@ -79,6 +83,21 @@ class Relocation {
/// Used to validate relocation correctness.
uint64_t Value;
+private:
+ /// Original index in DT_JMPREL, or NoJmpRelocationIndex for relocations
+ /// originating from other relocation tables.
+ uint64_t JmpRelocationIndex;
+
+public:
+ bool isJmpRelocation() const {
+ return JmpRelocationIndex != NoJmpRelocationIndex;
+ }
+
+ uint64_t getJmpRelocationIndex() const {
+ assert(isJmpRelocation() && "not a DT_JMPREL relocation");
+ return JmpRelocationIndex;
+ }
+
/// Return size in bytes of the given relocation \p Type.
static size_t getSizeForType(uint32_t Type);
diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h
index a624c056ada14..de253c33520a2 100644
--- a/bolt/include/bolt/Rewrite/RewriteInstance.h
+++ b/bolt/include/bolt/Rewrite/RewriteInstance.h
@@ -522,8 +522,8 @@ class RewriteInstance {
std::optional<uint64_t> PLTRelocationsAddress;
uint64_t PLTRelocationsSize{0};
- /// True if relocation of specified type came from .rela.plt
- DenseMap<uint64_t, bool> IsJmpRelocation;
+ /// Number of relocations read from DT_JMPREL.
+ uint64_t NumJmpRelocations{0};
/// Index of specified symbol in the dynamic symbol table. NOTE Currently it
/// is filled and used only with the relocations-related symbols.
diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp
index d911f8191f791..ca61d70d594c9 100644
--- a/bolt/lib/Core/BinaryContext.cpp
+++ b/bolt/lib/Core/BinaryContext.cpp
@@ -2663,11 +2663,12 @@ 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, bool IsRELR) {
+ uint64_t Value, bool IsRELR,
+ uint64_t JmpRelocationIndex) {
ErrorOr<BinarySection &> Section = getSectionForAddress(Address);
assert(Section && "cannot find section for address");
Section->addDynamicRelocation(Address - Section->getAddress(), Symbol, Type,
- Addend, Value, IsRELR);
+ Addend, Value, IsRELR, JmpRelocationIndex);
}
bool BinaryContext::removeRelocationAt(uint64_t Address) {
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 51b19db0cbd9b..a73cdd85b0988 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -65,6 +65,7 @@
#include <memory>
#include <optional>
#include <system_error>
+#include <tuple>
#undef DEBUG_TYPE
#define DEBUG_TYPE "bolt"
@@ -2976,9 +2977,6 @@ void RewriteInstance::readDynamicRelocations(const SectionRef &Section,
<< " : + 0x" << Twine::utohexstr(Addend) << '\n'
);
- if (IsJmpRel)
- IsJmpRelocation[RType] = true;
-
if (Symbol)
SymbolIndex[Symbol] = getRelocationSymbol(InputFile, Rel);
@@ -2994,7 +2992,12 @@ void RewriteInstance::readDynamicRelocations(const SectionRef &Section,
handleRelativeDynamicRelocation(Rel.getOffset(), ReferencedAddress);
}
- BC->addDynamicRelocation(Rel.getOffset(), Symbol, RType, Addend);
+ const uint64_t JmpRelocationIndex =
+ IsJmpRel ? NumJmpRelocations++
+ : Relocation::NoJmpRelocationIndex;
+ BC->addDynamicRelocation(Rel.getOffset(), Symbol, RType, Addend,
+ /*Value=*/0, /*IsRELR=*/false,
+ JmpRelocationIndex);
}
}
@@ -6085,65 +6088,87 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
Offset += sizeof(*RelA);
};
- auto writeRelocations = [&](bool PatchRelative) {
- for (BinarySection &Section : BC->allocatableSections()) {
- const uint64_t SectionInputAddress = Section.getAddress();
- uint64_t SectionAddress = Section.getOutputAddress();
- if (!SectionAddress)
- SectionAddress = SectionInputAddress;
+ auto writeRelocation = [&](BinarySection &Section, const Relocation &Rel) {
+ const uint64_t SectionInputAddress = Section.getAddress();
+ uint64_t SectionAddress = Section.getOutputAddress();
+ if (!SectionAddress)
+ SectionAddress = SectionInputAddress;
- for (const Relocation &Rel : Section.dynamicRelocations()) {
- const bool IsRelative = Rel.isRelative();
- if (PatchRelative != IsRelative || Rel.isRELR())
- continue;
+ Elf_Rela NewRelA;
+ MCSymbol *Symbol = Rel.Symbol;
+ uint32_t SymbolIdx = 0;
+ uint64_t Addend = Rel.Addend;
+ uint64_t RelOffset =
+ getNewFunctionOrDataAddress(SectionInputAddress + Rel.Offset);
- if (IsRelative)
- ++DynamicRelativeRelocationsCount;
+ RelOffset = RelOffset == 0 ? SectionAddress + Rel.Offset : RelOffset;
+ if (Rel.Symbol) {
+ SymbolIdx = getOutputDynamicSymbolIndex(Symbol);
+ } else {
+ // Usually this case is used for R_*_(I)RELATIVE relocations
+ const uint64_t Address = getNewFunctionOrDataAddress(Addend);
+ if (Address)
+ Addend = Address;
+ }
- Elf_Rela NewRelA;
- MCSymbol *Symbol = Rel.Symbol;
- uint32_t SymbolIdx = 0;
- uint64_t Addend = Rel.Addend;
- uint64_t RelOffset =
- getNewFunctionOrDataAddress(SectionInputAddress + Rel.Offset);
+ NewRelA.setSymbolAndType(SymbolIdx, Rel.Type, EF.isMips64EL());
+ NewRelA.r_offset = RelOffset;
+ NewRelA.r_addend = Addend;
- RelOffset = RelOffset == 0 ? SectionAddress + Rel.Offset : RelOffset;
- if (Rel.Symbol) {
- SymbolIdx = getOutputDynamicSymbolIndex(Symbol);
- } else {
- // Usually this case is used for R_*_(I)RELATIVE relocations
- const uint64_t Address = getNewFunctionOrDataAddress(Addend);
- if (Address)
- Addend = Address;
- }
+ const bool IsJmpRel = Rel.isJmpRelocation();
+ uint64_t &Offset = IsJmpRel ? RelPltOffset : RelDynOffset;
+ const uint64_t &EndOffset = IsJmpRel ? RelPltEndOffset : RelDynEndOffset;
+ if (!Offset || !EndOffset) {
+ BC->errs() << "BOLT-ERROR: Invalid offsets for dynamic relocation\n";
+ exit(1);
+ }
- NewRelA.setSymbolAndType(SymbolIdx, Rel.Type, EF.isMips64EL());
- NewRelA.r_offset = RelOffset;
- NewRelA.r_addend = Addend;
+ if (Offset + sizeof(NewRelA) > EndOffset) {
+ BC->errs() << "BOLT-ERROR: Offset overflow for dynamic relocation\n";
+ exit(1);
+ }
- const bool IsJmpRel = IsJmpRelocation.contains(Rel.Type);
- uint64_t &Offset = IsJmpRel ? RelPltOffset : RelDynOffset;
- const uint64_t &EndOffset =
- IsJmpRel ? RelPltEndOffset : RelDynEndOffset;
- if (!Offset || !EndOffset) {
- BC->errs() << "BOLT-ERROR: Invalid offsets for dynamic relocation\n";
- exit(1);
- }
+ writeRela(&NewRelA, Offset);
+ };
- if (Offset + sizeof(NewRelA) > EndOffset) {
- BC->errs() << "BOLT-ERROR: Offset overflow for dynamic relocation\n";
- exit(1);
- }
+ auto writeDynRelocations = [&](bool PatchRelative) {
+ for (BinarySection &Section : BC->allocatableSections()) {
+ for (const Relocation &Rel : Section.dynamicRelocations()) {
+ if (Rel.isJmpRelocation())
+ continue;
+
+ const bool IsRelative = Rel.isRelative();
+ if (PatchRelative != IsRelative || Rel.isRELR())
+ continue;
- writeRela(&NewRelA, Offset);
+ if (IsRelative)
+ ++DynamicRelativeRelocationsCount;
+ writeRelocation(Section, Rel);
}
}
};
// The dynamic linker expects all R_*_RELATIVE relocations in RELA
// to be emitted first.
- writeRelocations(/* PatchRelative */ true);
- writeRelocations(/* PatchRelative */ false);
+ writeDynRelocations(/* PatchRelative */ true);
+ writeDynRelocations(/* PatchRelative */ false);
+
+ using OrderedJmpRel = std::tuple<uint64_t, BinarySection *, const Relocation *>;
+ std::vector<OrderedJmpRel> JmpRelocations;
+ for (BinarySection &Section : BC->allocatableSections()) {
+ for (const Relocation &Rel : Section.dynamicRelocations()) {
+ if (!Rel.isJmpRelocation())
+ continue;
+ assert(!Rel.isRELR() && "RELR relocation cannot belong to DT_JMPREL");
+ JmpRelocations.emplace_back(Rel.getJmpRelocationIndex(), &Section, &Rel);
+ }
+ }
+ llvm::sort(JmpRelocations, [](const OrderedJmpRel &A,
+ const OrderedJmpRel &B) {
+ return std::get<0>(A) < std::get<0>(B);
+ });
+ for (const OrderedJmpRel &Entry : JmpRelocations)
+ writeRelocation(*std::get<1>(Entry), *std::get<2>(Entry));
auto fillNone = [&](uint64_t &Offset, uint64_t EndOffset) {
if (!Offset)
diff --git a/bolt/test/runtime/X86/rela-plt-order.c b/bolt/test/runtime/X86/rela-plt-order.c
new file mode 100644
index 0000000000000..f5acaf00cdf3c
--- /dev/null
+++ b/bolt/test/runtime/X86/rela-plt-order.c
@@ -0,0 +1,31 @@
+// REQUIRES: x86_64-linux, gnu_ld
+//
+// RUN: split-file %s %t
+// RUN: %clang %cflags -fPIC -shared -o %t/libexample.so \
+// RUN: %t/example.c
+// RUN: %clang %cflags -fno-pie -no-pie -fuse-ld=bfd \
+// RUN: -Wl,--emit-relocs -Wl,-rpath,\$ORIGIN -o %t/main %t/main.c \
+// RUN: -L%t -lexample
+// RUN: llvm-bolt %t/main -o %t/main.bolt
+// RUN: llvm-readelf --dyn-relocations %t/main.bolt | FileCheck %s
+// RUN: %t/main.bolt
+
+// CHECK-LABEL: 'PLT' relocation section
+// CHECK: R_X86_64_JUMP_SLOT{{.*}}long_name
+// CHECK-NEXT: R_X86_64_IRELATIVE
+
+//--- main.c
+extern int long_name(void);
+
+__attribute__((target_clones("default,avx2"))) int foo(int x) { return x + 1; }
+
+int main(void) {
+ if (foo(1) != 2)
+ return 1;
+ if (long_name() != 0)
+ return 1;
+ return 0;
+}
+
+//--- example.c
+int long_name(void) { return 0; }
>From a93d6cbbae2e6c672da32b4d11c208eee046d405 Mon Sep 17 00:00:00 2001
From: Maksim <rachinskii.mv at phystech.edu>
Date: Tue, 15 Sep 2026 14:03:12 +0300
Subject: [PATCH 2/2] [BOLT] Review feedback
---
bolt/include/bolt/Core/BinaryContext.h | 2 +-
bolt/include/bolt/Core/BinarySection.h | 2 +-
bolt/include/bolt/Core/Relocation.h | 44 ++++++-------
bolt/include/bolt/Rewrite/RewriteInstance.h | 2 +-
bolt/lib/Core/BinaryContext.cpp | 2 +-
bolt/lib/Rewrite/RewriteInstance.cpp | 72 +++++++++++----------
bolt/test/runtime/X86/rela-plt-order.c | 14 ++--
7 files changed, 72 insertions(+), 66 deletions(-)
diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h
index 7677fb83e1e04..46cf3a0d7c68b 100644
--- a/bolt/include/bolt/Core/BinaryContext.h
+++ b/bolt/include/bolt/Core/BinaryContext.h
@@ -1456,7 +1456,7 @@ class BinaryContext {
void addDynamicRelocation(uint64_t Address, MCSymbol *Symbol, uint32_t Type,
uint64_t Addend, uint64_t Value = 0,
bool IsRELR = false,
- uint64_t JmpRelocationIndex =
+ uint32_t JmpRelocationIndex =
Relocation::NoJmpRelocationIndex);
/// Return a dynamic relocation registered at a given \p Address, or nullptr
diff --git a/bolt/include/bolt/Core/BinarySection.h b/bolt/include/bolt/Core/BinarySection.h
index 0098933054e3b..cc5ffcb8ca414 100644
--- a/bolt/include/bolt/Core/BinarySection.h
+++ b/bolt/include/bolt/Core/BinarySection.h
@@ -368,7 +368,7 @@ class BinarySection {
void addDynamicRelocation(uint64_t Offset, MCSymbol *Symbol, uint32_t Type,
uint64_t Addend, uint64_t Value = 0,
bool IsRELR = false,
- uint64_t JmpRelocationIndex =
+ uint32_t JmpRelocationIndex =
Relocation::NoJmpRelocationIndex) {
addDynamicRelocation(
Relocation{Offset, Symbol, Type, Addend, Value, IsRELR,
diff --git a/bolt/include/bolt/Core/Relocation.h b/bolt/include/bolt/Core/Relocation.h
index 1237314b994f3..02d18ff97cf98 100644
--- a/bolt/include/bolt/Core/Relocation.h
+++ b/bolt/include/bolt/Core/Relocation.h
@@ -37,21 +37,21 @@ namespace bolt {
/// Relocation class.
class Relocation {
public:
- static constexpr uint64_t NoJmpRelocationIndex = uint64_t(-1);
+ static constexpr uint32_t NoJmpRelocationIndex = (1u << 30) - 1;
Relocation(uint64_t Offset, MCSymbol *Symbol, uint32_t Type, uint64_t Addend,
uint64_t Value, bool IsRELR = false,
- uint64_t JmpRelocationIndex = NoJmpRelocationIndex)
- : Offset(Offset), Symbol(Symbol), Type(Type), Optional(false),
- IsRELR(IsRELR), Addend(Addend), Value(Value),
- JmpRelocationIndex(JmpRelocationIndex) {
+ uint32_t JmpRelocationIndex = NoJmpRelocationIndex)
+ : Offset(Offset), Symbol(Symbol), Addend(Addend), Value(Value),
+ Type(Type), JmpRelocationIndex(JmpRelocationIndex), Optional(false),
+ IsRELR(IsRELR) {
assert((isRelative() || !isRELR()) &&
"Only relative relocations can be relr.");
}
Relocation()
- : Offset(0), Symbol(0), Type(0), Optional(0), IsRELR(0), Addend(0),
- Value(0), JmpRelocationIndex(NoJmpRelocationIndex) {}
+ : Offset(0), Symbol(0), Addend(0), Value(0), Type(0),
+ JmpRelocationIndex(NoJmpRelocationIndex), Optional(0), IsRELR(0) {}
static Triple::ArchType Arch; /// set by BinaryContext ctor.
@@ -61,20 +61,6 @@ class Relocation {
/// The symbol this relocation is referring to.
MCSymbol *Symbol;
- /// Relocation type.
- uint32_t Type;
-
-private:
- /// Relocations added by optimizations can be optional, meaning they can be
- /// 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.
uint64_t Addend;
@@ -83,17 +69,29 @@ class Relocation {
/// Used to validate relocation correctness.
uint64_t Value;
+ /// Relocation type.
+ uint32_t Type;
+
private:
/// Original index in DT_JMPREL, or NoJmpRelocationIndex for relocations
/// originating from other relocation tables.
- uint64_t JmpRelocationIndex;
+ uint32_t JmpRelocationIndex : 30;
+
+ /// Relocations added by optimizations can be optional, meaning they can be
+ /// omitted under certain circumstances.
+ uint32_t Optional : 1;
+
+ /// 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.
+ uint32_t IsRELR : 1;
public:
bool isJmpRelocation() const {
return JmpRelocationIndex != NoJmpRelocationIndex;
}
- uint64_t getJmpRelocationIndex() const {
+ uint32_t getJmpRelocationIndex() const {
assert(isJmpRelocation() && "not a DT_JMPREL relocation");
return JmpRelocationIndex;
}
diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h
index bccb64207829e..77695bd7f3349 100644
--- a/bolt/include/bolt/Rewrite/RewriteInstance.h
+++ b/bolt/include/bolt/Rewrite/RewriteInstance.h
@@ -544,7 +544,7 @@ class RewriteInstance {
uint64_t PLTRelocationsSize{0};
/// Number of relocations read from DT_JMPREL.
- uint64_t NumJmpRelocations{0};
+ uint32_t NumJmpRelocations{0};
/// Index of specified symbol in the dynamic symbol table. NOTE Currently it
/// is filled and used only with the relocations-related symbols.
diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp
index 1aebbbf5fbff9..e9cbf2f44924a 100644
--- a/bolt/lib/Core/BinaryContext.cpp
+++ b/bolt/lib/Core/BinaryContext.cpp
@@ -2666,7 +2666,7 @@ 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, bool IsRELR,
- uint64_t JmpRelocationIndex) {
+ uint32_t JmpRelocationIndex) {
ErrorOr<BinarySection &> Section = getSectionForAddress(Address);
assert(Section && "cannot find section for address");
Section->addDynamicRelocation(Address - Section->getAddress(), Symbol, Type,
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 49d9f4859ff7d..6d2f2e416b70e 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -65,7 +65,6 @@
#include <memory>
#include <optional>
#include <system_error>
-#include <tuple>
#undef DEBUG_TYPE
#define DEBUG_TYPE "bolt"
@@ -2968,6 +2967,13 @@ void RewriteInstance::readDynamicRelocations(const SectionRef &Section,
});
for (const RelocationRef &Rel : Section.relocations()) {
+ uint32_t JmpRelocationIndex = Relocation::NoJmpRelocationIndex;
+ if (IsJmpRel) {
+ assert(NumJmpRelocations < Relocation::NoJmpRelocationIndex &&
+ "too many DT_JMPREL relocations");
+ JmpRelocationIndex = NumJmpRelocations++;
+ }
+
const uint32_t RType = Relocation::getType(Rel);
if (Relocation::isNone(RType))
continue;
@@ -2987,11 +2993,12 @@ void RewriteInstance::readDynamicRelocations(const SectionRef &Section,
(void)SymbolAddress;
}
+ const uint64_t RelOffset = Rel.getOffset();
LLVM_DEBUG(
SmallString<16> TypeName;
Rel.getTypeName(TypeName);
dbgs() << "BOLT-DEBUG: dynamic relocation at 0x"
- << Twine::utohexstr(Rel.getOffset()) << " : " << TypeName
+ << Twine::utohexstr(RelOffset) << " : " << TypeName
<< " : " << SymbolName << " : " << Twine::utohexstr(SymbolAddress)
<< " : + 0x" << Twine::utohexstr(Addend) << '\n'
);
@@ -3008,13 +3015,10 @@ void RewriteInstance::readDynamicRelocations(const SectionRef &Section,
"relocation type\n";
exit(1);
}
- handleRelativeDynamicRelocation(Rel.getOffset(), ReferencedAddress);
+ handleRelativeDynamicRelocation(RelOffset, ReferencedAddress);
}
- const uint64_t JmpRelocationIndex =
- IsJmpRel ? NumJmpRelocations++
- : Relocation::NoJmpRelocationIndex;
- BC->addDynamicRelocation(Rel.getOffset(), Symbol, RType, Addend,
+ BC->addDynamicRelocation(RelOffset, Symbol, RType, Addend,
/*Value=*/0, /*IsRELR=*/false,
JmpRelocationIndex);
}
@@ -6227,12 +6231,12 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
DynamicRelativeRelocationsCount = 0;
- auto writeRela = [&OS](const Elf_Rela *RelA, uint64_t &Offset) {
+ auto writeRela = [&OS](const Elf_Rela *RelA, uint64_t Offset) {
safePWrite(OS, reinterpret_cast<const char *>(RelA), sizeof(*RelA), Offset);
- Offset += sizeof(*RelA);
};
- auto writeRelocation = [&](BinarySection &Section, const Relocation &Rel) {
+ auto writeRelocation = [&](BinarySection &Section, const Relocation &Rel,
+ uint64_t Offset, uint64_t EndOffset) {
const uint64_t SectionInputAddress = Section.getAddress();
uint64_t SectionAddress = Section.getOutputAddress();
if (!SectionAddress)
@@ -6259,15 +6263,12 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
NewRelA.r_offset = RelOffset;
NewRelA.r_addend = Addend;
- const bool IsJmpRel = Rel.isJmpRelocation();
- uint64_t &Offset = IsJmpRel ? RelPltOffset : RelDynOffset;
- const uint64_t &EndOffset = IsJmpRel ? RelPltEndOffset : RelDynEndOffset;
if (!Offset || !EndOffset) {
BC->errs() << "BOLT-ERROR: Invalid offsets for dynamic relocation\n";
exit(1);
}
- if (Offset + sizeof(NewRelA) > EndOffset) {
+ if (Offset > EndOffset || EndOffset - Offset < sizeof(NewRelA)) {
BC->errs() << "BOLT-ERROR: Offset overflow for dynamic relocation\n";
exit(1);
}
@@ -6287,7 +6288,8 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
if (IsRelative)
++DynamicRelativeRelocationsCount;
- writeRelocation(Section, Rel);
+ writeRelocation(Section, Rel, RelDynOffset, RelDynEndOffset);
+ RelDynOffset += sizeof(Elf_Rela);
}
}
};
@@ -6297,24 +6299,7 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
writeDynRelocations(/* PatchRelative */ true);
writeDynRelocations(/* PatchRelative */ false);
- using OrderedJmpRel = std::tuple<uint64_t, BinarySection *, const Relocation *>;
- std::vector<OrderedJmpRel> JmpRelocations;
- for (BinarySection &Section : BC->allocatableSections()) {
- for (const Relocation &Rel : Section.dynamicRelocations()) {
- if (!Rel.isJmpRelocation())
- continue;
- assert(!Rel.isRELR() && "RELR relocation cannot belong to DT_JMPREL");
- JmpRelocations.emplace_back(Rel.getJmpRelocationIndex(), &Section, &Rel);
- }
- }
- llvm::sort(JmpRelocations, [](const OrderedJmpRel &A,
- const OrderedJmpRel &B) {
- return std::get<0>(A) < std::get<0>(B);
- });
- for (const OrderedJmpRel &Entry : JmpRelocations)
- writeRelocation(*std::get<1>(Entry), *std::get<2>(Entry));
-
- auto fillNone = [&](uint64_t &Offset, uint64_t EndOffset) {
+ auto fillNone = [&](uint64_t Offset, uint64_t EndOffset) {
if (!Offset)
return;
@@ -6322,15 +6307,32 @@ RewriteInstance::patchELFAllocatableRelaSections(ELFObjectFile<ELFT> *File) {
RelA.setSymbolAndType(0, Relocation::getNone(), EF.isMips64EL());
RelA.r_offset = 0;
RelA.r_addend = 0;
- while (Offset < EndOffset)
+ while (Offset < EndOffset) {
writeRela(&RelA, Offset);
+ Offset += sizeof(Elf_Rela);
+ }
assert(Offset == EndOffset && "Unexpected section overflow");
};
- // Fill the rest of the sections with R_*_NONE relocations
fillNone(RelDynOffset, RelDynEndOffset);
+
+ // Start with an empty DT_JMPREL table and patch relocations
+ // back into their original slots.
fillNone(RelPltOffset, RelPltEndOffset);
+
+ for (BinarySection &Section : BC->allocatableSections()) {
+ for (const Relocation &Rel : Section.dynamicRelocations()) {
+ if (!Rel.isJmpRelocation())
+ continue;
+ assert(!Rel.isRELR() && "RELR relocation cannot belong to DT_JMPREL");
+
+ const uint64_t Offset =
+ RelPltOffset + Rel.getJmpRelocationIndex() * sizeof(Elf_Rela);
+
+ writeRelocation(Section, Rel, Offset, RelPltEndOffset);
+ }
+ }
}
template <typename ELFT>
diff --git a/bolt/test/runtime/X86/rela-plt-order.c b/bolt/test/runtime/X86/rela-plt-order.c
index f5acaf00cdf3c..4a894ba8f6f6b 100644
--- a/bolt/test/runtime/X86/rela-plt-order.c
+++ b/bolt/test/runtime/X86/rela-plt-order.c
@@ -6,13 +6,19 @@
// RUN: %clang %cflags -fno-pie -no-pie -fuse-ld=bfd \
// RUN: -Wl,--emit-relocs -Wl,-rpath,\$ORIGIN -o %t/main %t/main.c \
// RUN: -L%t -lexample
+// RUN: llvm-readelf --dyn-relocations %t/main | \
+// RUN: sed -n "/'PLT' relocation section/,/^$/p" | \
+// RUN: awk '/^0/ { print $3, $5 }' > %t/main.plt
+// RUN: FileCheck %s --check-prefix=PLT-KINDS < %t/main.plt
// RUN: llvm-bolt %t/main -o %t/main.bolt
-// RUN: llvm-readelf --dyn-relocations %t/main.bolt | FileCheck %s
+// RUN: llvm-readelf --dyn-relocations %t/main.bolt | \
+// RUN: sed -n "/'PLT' relocation section/,/^$/p" | \
+// RUN: awk '/^0/ { print $3, $5 }' > %t/main.bolt.plt
+// RUN: diff %t/main.plt %t/main.bolt.plt
// RUN: %t/main.bolt
-// CHECK-LABEL: 'PLT' relocation section
-// CHECK: R_X86_64_JUMP_SLOT{{.*}}long_name
-// CHECK-NEXT: R_X86_64_IRELATIVE
+// PLT-KINDS-DAG: R_X86_64_JUMP_SLOT long_name
+// PLT-KINDS-DAG: R_X86_64_IRELATIVE
//--- main.c
extern int long_name(void);
More information about the llvm-commits
mailing list