[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