[llvm] [BOLT][RISCV] Handle static IFUNC calls through .iplt (PR #207733)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 25 01:00:16 PDT 2026


https://github.com/Thrrreeee updated https://github.com/llvm/llvm-project/pull/207733

>From 38658d4b02b3253b2b7dc22787ce0957168b05cc Mon Sep 17 00:00:00 2001
From: Thrrreeeee <1379998393 at qq.com>
Date: Tue, 11 Aug 2026 19:44:27 +0800
Subject: [PATCH 1/4] [BOLT][RISCV] Handle static IFUNC calls through .iplt

---
 bolt/include/bolt/Rewrite/RewriteInstance.h |  10 +-
 bolt/lib/Core/AddressMap.cpp                |  53 +++++----
 bolt/lib/Core/Relocation.cpp                |   6 +-
 bolt/lib/Rewrite/RewriteInstance.cpp        | 119 +++++++++++++++-----
 bolt/test/RISCV/ifunc.s                     |  54 +++++++++
 5 files changed, 188 insertions(+), 54 deletions(-)
 create mode 100644 bolt/test/RISCV/ifunc.s

diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h
index 8299cc392eade..636c116768b57 100644
--- a/bolt/include/bolt/Rewrite/RewriteInstance.h
+++ b/bolt/include/bolt/Rewrite/RewriteInstance.h
@@ -309,9 +309,13 @@ class RewriteInstance {
   /// Write .eh_frame_hdr.
   void writeEHFrameHeader();
 
-  /// Disassemble and create function entries for PLT.
+  /// Disassemble and create function entries for PLT, except for RISC-V .iplt
+  /// which is processed after resolver secondary entries are registered.
   void disassemblePLT();
 
+  /// Disassemble and create function entries for one PLT \p Section.
+  void disassemblePLTSection(BinarySection &Section, uint64_t EntrySize);
+
   /// Auxiliary function to create .plt BinaryFunction on \p EntryAddres
   /// with the \p EntrySize size. \p TargetAddress is the .got entry
   /// associated address.
@@ -585,7 +589,8 @@ class RewriteInstance {
       {".plt"}, {".plt.got"}, {".iplt"}, {nullptr}};
 
   /// RISCV PLT sections.
-  const PLTSectionInfo RISCV_PLTSections[2] = {{".plt"}, {nullptr}};
+  const PLTSectionInfo RISCV_PLTSections[3] = {
+      {".plt"}, {".iplt", 16}, {nullptr}};
 
   /// Return PLT information for a section with \p SectionName or nullptr
   /// if the section is not PLT.
@@ -600,6 +605,7 @@ class RewriteInstance {
     case Triple::aarch64:
       PLTSI = AArch64_PLTSections;
       break;
+    case Triple::riscv32:
     case Triple::riscv64:
       PLTSI = RISCV_PLTSections;
       break;
diff --git a/bolt/lib/Core/AddressMap.cpp b/bolt/lib/Core/AddressMap.cpp
index f061fea494394..5f08e768a4dd6 100644
--- a/bolt/lib/Core/AddressMap.cpp
+++ b/bolt/lib/Core/AddressMap.cpp
@@ -18,19 +18,24 @@ namespace bolt {
 
 const char *const AddressMap::AddressSectionName = ".bolt.addr2addr_map";
 const char *const AddressMap::LabelSectionName = ".bolt.label2addr_map";
+// Label map keys encode host MCSymbol pointers as uint64_t values.
+static constexpr unsigned LabelMapValueSize = sizeof(uint64_t);
 
 static void emitAddress(MCStreamer &Streamer, uint64_t InputAddress,
-                        const MCSymbol *OutputLabel) {
-  Streamer.emitIntValue(InputAddress, 8);
-  Streamer.emitSymbolValue(OutputLabel, 8);
+                        const MCSymbol *OutputLabel, unsigned CodePointerSize) {
+  Streamer.emitIntValue(InputAddress, CodePointerSize);
+  Streamer.emitSymbolValue(OutputLabel, CodePointerSize);
 }
 
 static void emitLabel(MCStreamer &Streamer, const MCSymbol *OutputLabel) {
-  Streamer.emitIntValue(reinterpret_cast<uint64_t>(OutputLabel), 8);
-  Streamer.emitSymbolValue(OutputLabel, 8);
+  Streamer.emitIntValue(reinterpret_cast<uint64_t>(OutputLabel),
+                        LabelMapValueSize);
+  Streamer.emitSymbolValue(OutputLabel, LabelMapValueSize);
 }
 
 void AddressMap::emit(MCStreamer &Streamer, BinaryContext &BC) {
+  const unsigned CodePointerSize = BC.AsmInfo->getCodePointerSize();
+
   // Mark map sections as link-only to avoid allocation in the output file.
   const unsigned Flags = BinarySection::getFlags(/*IsReadOnly*/ true,
                                                  /*IsText*/ false,
@@ -56,7 +61,7 @@ void AddressMap::emit(MCStreamer &Streamer, BinaryContext &BC) {
 
       Streamer.switchSection(BC.getDataSection(AddressSectionName));
       for (auto [Offset, Symbol] : BB.getLocSyms())
-        emitAddress(Streamer, BFAddress + Offset, Symbol);
+        emitAddress(Streamer, BFAddress + Offset, Symbol, CodePointerSize);
     }
   }
 }
@@ -70,20 +75,20 @@ std::optional<AddressMap> AddressMap::parse(BinaryContext &BC) {
 
   AddressMap Parsed;
 
-  unsigned CodePointerSize = BC.AsmInfo->getCodePointerSize();
-  const size_t EntrySize = 2 * CodePointerSize;
+  const unsigned CodePointerSize = BC.AsmInfo->getCodePointerSize();
   auto parseSection =
-      [&](BinarySection &Section,
+      [&](BinarySection &Section, unsigned ValueSize,
           function_ref<void(uint64_t, uint64_t)> InsertCallback) {
         StringRef Buffer = Section.getOutputContents();
+        const size_t EntrySize = 2 * ValueSize;
         assert(Buffer.size() % EntrySize == 0 && "Unexpected address map size");
 
         DataExtractor DE(Buffer, BC.AsmInfo->isLittleEndian());
         DataExtractor::Cursor Cursor(0);
 
         while (Cursor && !DE.eof(Cursor)) {
-          const uint64_t Input = DE.getUnsigned(Cursor, CodePointerSize);
-          const uint64_t Output = DE.getUnsigned(Cursor, CodePointerSize);
+          const uint64_t Input = DE.getUnsigned(Cursor, ValueSize);
+          const uint64_t Output = DE.getUnsigned(Cursor, ValueSize);
           InsertCallback(Input, Output);
         }
 
@@ -92,23 +97,27 @@ std::optional<AddressMap> AddressMap::parse(BinaryContext &BC) {
       };
 
   if (AddressMapSection) {
+    const size_t EntrySize = 2 * CodePointerSize;
     Parsed.Address2AddressMap.reserve(AddressMapSection->getOutputSize() /
                                       EntrySize);
-    parseSection(*AddressMapSection, [&](uint64_t Input, uint64_t Output) {
-      if (!Parsed.Address2AddressMap.count(Input))
-        Parsed.Address2AddressMap.insert({Input, Output});
-    });
+    parseSection(*AddressMapSection, CodePointerSize,
+                 [&](uint64_t Input, uint64_t Output) {
+                   if (!Parsed.Address2AddressMap.count(Input))
+                     Parsed.Address2AddressMap.insert({Input, Output});
+                 });
   }
 
   if (LabelMapSection) {
+    const size_t EntrySize = 2 * LabelMapValueSize;
     Parsed.Label2AddrMap.reserve(LabelMapSection->getOutputSize() / EntrySize);
-    parseSection(*LabelMapSection, [&](uint64_t Input, uint64_t Output) {
-      assert(!Parsed.Label2AddrMap.count(
-                 reinterpret_cast<const MCSymbol *>(Input)) &&
-             "Duplicate label entry detected.");
-      Parsed.Label2AddrMap.insert(
-          {reinterpret_cast<const MCSymbol *>(Input), Output});
-    });
+    parseSection(*LabelMapSection, LabelMapValueSize,
+                 [&](uint64_t Input, uint64_t Output) {
+                   assert(!Parsed.Label2AddrMap.count(
+                              reinterpret_cast<const MCSymbol *>(Input)) &&
+                          "Duplicate label entry detected.");
+                   Parsed.Label2AddrMap.insert(
+                       {reinterpret_cast<const MCSymbol *>(Input), Output});
+                 });
   }
 
   return Parsed;
diff --git a/bolt/lib/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp
index cb6aaa552d05f..99e7610b68154 100644
--- a/bolt/lib/Core/Relocation.cpp
+++ b/bolt/lib/Core/Relocation.cpp
@@ -132,6 +132,7 @@ static bool isSupportedRISCV(uint32_t Type) {
   case ELF::R_RISCV_TPREL_LO12_S:
   case ELFReserved::R_RISCV_TPREL_I:
   case ELFReserved::R_RISCV_TPREL_S:
+  case ELF::R_RISCV_IRELATIVE:
     return true;
   }
 }
@@ -244,6 +245,9 @@ static size_t getSizeForTypeRISCV(uint32_t Type) {
   case ELF::R_RISCV_TLS_GD_HI20:
     // See extractValueRISCV for why this is necessary.
     return 8;
+  case ELF::R_RISCV_IRELATIVE:
+    // R_RISCV_IRELATIVE operates on a wordclass field.
+    return Relocation::Arch == Triple::riscv64 ? 8 : 4;
   }
 }
 
@@ -871,7 +875,7 @@ bool Relocation::isIRelative(uint32_t Type) {
     return Type == ELF::R_AARCH64_IRELATIVE;
   case Triple::riscv64:
   case Triple::riscv32:
-    llvm_unreachable("not implemented");
+    return Type == ELF::R_RISCV_IRELATIVE;
   case Triple::x86_64:
     return Type == ELF::R_X86_64_IRELATIVE;
   }
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 4486efe926d01..69bcab19954f2 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -1353,7 +1353,8 @@ void RewriteInstance::discoverFileObjects() {
   // that is a subject to dynamic relocation processing.
   processDynamicRelocations();
 
-  // Process PLT section.
+  // Process PLT sections. RISC-V .iplt is handled after function boundaries
+  // and resolver secondary entry points have been established.
   disassemblePLT();
 
   // See if we missed any functions marked by FDE.
@@ -1391,6 +1392,36 @@ void RewriteInstance::discoverFileObjects() {
   adjustFunctionBoundaries(MarkerSymbols);
   splitUnmarkedTailFunctions(MarkerSymbols);
 
+  // R_RISCV_IRELATIVE addends name resolver entry points. LLD may
+  // canonicalize the only IFUNC symbol to the IPLT entry, leaving the resolver
+  // without a symbol. Function sizes are not final when dynamic relocations
+  // are first read, so record these secondary entries after boundary
+  // adjustment.
+  if (BC->isRISCV()) {
+    for (const BinarySection &Section : BC->allocatableSections()) {
+      for (const Relocation &Rel : Section.dynamicRelocations()) {
+        if (!Rel.isIRelative() || !Rel.Addend)
+          continue;
+        BinaryFunction *BF = BC->getBinaryFunctionContainingAddress(Rel.Addend);
+        if (!BF || BF->getAddress() == Rel.Addend)
+          continue;
+        if (BF->isInConstantIsland(Rel.Addend)) {
+          BC->errs() << "BOLT-ERROR: IFUNC resolver at 0x"
+                     << Twine::utohexstr(Rel.Addend)
+                     << " is in constant island of function " << *BF << '\n';
+          exit(1);
+        }
+        BF->addEntryPointAtOffset(Rel.Addend - BF->getAddress());
+      }
+    }
+
+    if (BinarySection *IPLTSection = getSection(".iplt")) {
+      const PLTSectionInfo *PLTSI = getPLTSectionInfo(IPLTSection->getName());
+      assert(PLTSI && "missing RISC-V .iplt section information");
+      disassemblePLTSection(*IPLTSection, PLTSI->EntrySize);
+    }
+  }
+
   // Annotate functions with code/data markers in AArch64
   for (auto &[Address, Type] : MarkerSymbols) {
     auto *BF = BC->getBinaryFunctionContainingAddress(Address,
@@ -1886,11 +1917,13 @@ void RewriteInstance::createPLTBinaryFunction(uint64_t TargetAddress,
 
   MCSymbol *Symbol = Rel->Symbol;
   if (!Symbol) {
-    if (BC->isRISCV() || !Rel->Addend || !Rel->isIRelative())
+    if (!Rel->Addend || !Rel->isIRelative())
       return;
 
     // IFUNC trampoline without symbol
     BinaryFunction *TargetBF = BC->getBinaryFunctionAtAddress(Rel->Addend);
+    if (!TargetBF)
+      TargetBF = BC->getBinaryFunctionContainingAddress(Rel->Addend);
     if (!TargetBF) {
       BC->errs()
           << "BOLT-WARNING: Expected BF to be presented as IFUNC resolver at "
@@ -1898,7 +1931,9 @@ void RewriteInstance::createPLTBinaryFunction(uint64_t TargetAddress,
       return;
     }
 
-    Symbol = TargetBF->getSymbol();
+    const uint64_t ResolverOffset = Rel->Addend - TargetBF->getAddress();
+    Symbol = ResolverOffset ? TargetBF->addEntryPointAtOffset(ResolverOffset)
+                            : TargetBF->getSymbol();
   }
 
   ErrorOr<BinarySection &> Section = BC->getSectionForAddress(EntryAddress);
@@ -1910,6 +1945,23 @@ void RewriteInstance::createPLTBinaryFunction(uint64_t TargetAddress,
   else
     BF->addAlternativeName(Symbol->getName().str() + "@PLT");
   setPLTSymbol(BF, Symbol->getName());
+
+  if (Rel->isIRelative()) {
+    auto ResolverSyms = FileSymRefs.equal_range(Rel->Addend);
+    for (const SymbolRef &AliasSymbol : llvm::make_second_range(
+             llvm::make_range(ResolverSyms.first, ResolverSyms.second))) {
+      if (ELFSymbolRef(AliasSymbol).getELFType() != ELF::STT_GNU_IFUNC)
+        continue;
+      StringRef AliasName = cantFail(AliasSymbol.getName());
+      const std::string PLTName = AliasName.str() + "@PLT";
+      if (!BC->getBinaryDataByName(PLTName)) {
+        BF->addAlternativeName(PLTName);
+        BC->registerNameAtAddress(PLTName, EntryAddress, 0, EntrySize,
+                                  Section->getAlignment());
+      }
+      setPLTSymbol(BF, AliasName);
+    }
+  }
 }
 
 void RewriteInstance::disassemblePLTInstruction(const BinarySection &Section,
@@ -1998,8 +2050,9 @@ void RewriteInstance::disassemblePLTSectionRISCV(BinarySection &Section) {
     }
   };
 
-  // Skip the first special entry since no relocation points to it.
-  uint64_t InstrOffset = 32;
+  // Regular .plt has a first special entry with no relocations pointing to it,
+  // while static IFUNC .iplt entries start at the beginning of the section.
+  uint64_t InstrOffset = Section.getName() == ".iplt" ? 0 : 32;
 
   while (InstrOffset < SectionSize) {
     InstructionListType Instructions;
@@ -2061,36 +2114,41 @@ void RewriteInstance::disassemblePLTSectionX86(BinarySection &Section,
   }
 }
 
-void RewriteInstance::disassemblePLT() {
-  auto analyzeOnePLTSection = [&](BinarySection &Section, uint64_t EntrySize) {
-    if (BC->isAArch64())
-      return disassemblePLTSectionAArch64(Section);
-    if (BC->isRISCV())
-      return disassemblePLTSectionRISCV(Section);
-    if (BC->isX86())
-      return disassemblePLTSectionX86(Section, EntrySize);
-    llvm_unreachable("Unmplemented PLT");
-  };
+void RewriteInstance::disassemblePLTSection(BinarySection &Section,
+                                            uint64_t EntrySize) {
+  if (BC->isAArch64())
+    disassemblePLTSectionAArch64(Section);
+  else if (BC->isRISCV())
+    disassemblePLTSectionRISCV(Section);
+  else if (BC->isX86())
+    disassemblePLTSectionX86(Section, EntrySize);
+  else
+    llvm_unreachable("Unimplemented PLT");
+
+  BinaryFunction *PltBF;
+  auto BFIter = BC->getBinaryFunctions().find(Section.getAddress());
+  if (BFIter != BC->getBinaryFunctions().end()) {
+    PltBF = &BFIter->second;
+  } else {
+    // If we did not register any function at the start of the section, then it
+    // must be a general PLT entry. Add a function at the location.
+    PltBF = BC->createBinaryFunction("__BOLT_PSEUDO_" + Section.getName().str(),
+                                     Section, Section.getAddress(), 0,
+                                     EntrySize, Section.getAlignment());
+  }
+  PltBF->setPseudo(true);
+}
 
+void RewriteInstance::disassemblePLT() {
   for (BinarySection &Section : BC->allocatableSections()) {
     const PLTSectionInfo *PLTSI = getPLTSectionInfo(Section.getName());
     if (!PLTSI)
       continue;
 
-    analyzeOnePLTSection(Section, PLTSI->EntrySize);
+    if (BC->isRISCV() && Section.getName() == ".iplt")
+      continue;
 
-    BinaryFunction *PltBF;
-    auto BFIter = BC->getBinaryFunctions().find(Section.getAddress());
-    if (BFIter != BC->getBinaryFunctions().end()) {
-      PltBF = &BFIter->second;
-    } else {
-      // If we did not register any function at the start of the section,
-      // then it must be a general PLT entry. Add a function at the location.
-      PltBF = BC->createBinaryFunction(
-          "__BOLT_PSEUDO_" + Section.getName().str(), Section,
-          Section.getAddress(), 0, PLTSI->EntrySize, Section.getAlignment());
-    }
-    PltBF->setPseudo(true);
+    disassemblePLTSection(Section, PLTSI->EntrySize);
   }
 }
 
@@ -2797,7 +2855,10 @@ bool RewriteInstance::analyzeRelocation(
     // Section symbols are marked as ST_Debug.
     IsSectionRelocation = (cantFail(Symbol.getType()) == SymbolRef::ST_Debug);
     // Check for PLT entry registered with symbol name
-    if (!SymbolAddress && !IsWeakReference(Symbol) &&
+    const bool IsRISCVIFuncPLT =
+        BC->isRISCV() && RType == ELF::R_RISCV_CALL_PLT &&
+        ELFSymbolRef(Symbol).getELFType() == ELF::STT_GNU_IFUNC;
+    if ((!SymbolAddress || IsRISCVIFuncPLT) && !IsWeakReference(Symbol) &&
         (IsAArch64 || BC->isRISCV())) {
       const BinaryData *BD = BC->getPLTBinaryDataByName(SymbolName);
       SymbolAddress = BD ? BD->getAddress() : 0;
diff --git a/bolt/test/RISCV/ifunc.s b/bolt/test/RISCV/ifunc.s
new file mode 100644
index 0000000000000..43b26324dfb5c
--- /dev/null
+++ b/bolt/test/RISCV/ifunc.s
@@ -0,0 +1,54 @@
+## Check that BOLT recognizes a non-preemptible IFUNC IPLT entry and tracks an
+## otherwise unnamed resolver after the linker canonicalizes the IFUNC symbol
+## to the IPLT entry. Moving the containing function also verifies that the
+## IRELATIVE addend is updated to the resolver secondary entry, not the primary
+## function entry.
+
+# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax -o %t.64.o %s
+# RUN: ld.lld -q -o %t.64 %t.64.o
+# RUN: llvm-bolt %t.64 -o %t.64.bolt --use-old-text=0 --lite=0 \
+# RUN:   --print-disasm --print-only=_start 2>&1 | FileCheck %s \
+# RUN:   --check-prefix=BOLT \
+# RUN:   --implicit-check-not="Expected BF to be presented as IFUNC resolver"
+# RUN: llvm-readelf -Wr -Ws %t.64.bolt | FileCheck %s --check-prefix=ELF
+# RUN: llvm-objdump -d --no-show-raw-insn %t.64.bolt \
+# RUN:   | FileCheck %s --check-prefix=IPLT
+
+# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax -o %t.32.o %s
+# RUN: ld.lld -q -o %t.32 %t.32.o
+# RUN: llvm-bolt %t.32 -o %t.32.bolt --use-old-text=0 --lite=0 \
+# RUN:   --print-disasm --print-only=_start 2>&1 | FileCheck %s \
+# RUN:   --check-prefix=BOLT \
+# RUN:   --implicit-check-not="Expected BF to be presented as IFUNC resolver"
+# RUN: llvm-readelf -Wr -Ws %t.32.bolt | FileCheck %s --check-prefix=ELF
+# RUN: llvm-objdump -d --no-show-raw-insn %t.32.bolt \
+# RUN:   | FileCheck %s --check-prefix=IPLT
+
+# BOLT: Binary Function "_start
+# BOLT: auipc a0, %pcrel_hi(__ENTRY_func at 0x{{[0-9a-f]+}}@PLT)
+
+# ELF: R_RISCV_IRELATIVE {{ *}}[[#%x,RESOLVER:]]
+# ELF: {{0*}}[[#%x,RESOLVER-4]] 8 FUNC {{.*}} func
+
+# IPLT: Disassembly of section .iplt:
+# IPLT: <ifunc0>:
+# IPLT-NEXT: {{.*}} auipc t3,
+# IPLT-NEXT: {{.*}} l{{[dw]}} t3,
+
+  .text
+  .globl _start
+  .type _start, @function
+_start:
+1:
+  auipc a0, %pcrel_hi(ifunc0)
+  addi a0, a0, %pcrel_lo(1b)
+
+  .globl func
+  .type func, @function
+func:
+  ret
+
+  .globl ifunc0
+  .type ifunc0, @gnu_indirect_function
+ifunc0:
+  ret

>From 46afbaf4b9ff0c3df74731ddb4215a5b4a3280fd Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Fri, 14 Aug 2026 18:12:02 +0800
Subject: [PATCH 2/4] fix

---
 bolt/include/bolt/Rewrite/RewriteInstance.h |  9 +++--
 bolt/lib/Rewrite/RewriteInstance.cpp        | 45 +++++++++++++++------
 2 files changed, 38 insertions(+), 16 deletions(-)

diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h
index 636c116768b57..148007ec6154c 100644
--- a/bolt/include/bolt/Rewrite/RewriteInstance.h
+++ b/bolt/include/bolt/Rewrite/RewriteInstance.h
@@ -309,11 +309,14 @@ class RewriteInstance {
   /// Write .eh_frame_hdr.
   void writeEHFrameHeader();
 
-  /// Disassemble and create function entries for PLT, except for RISC-V .iplt
-  /// which is processed after resolver secondary entries are registered.
+  /// Disassemble and create function entries for PLT. RISC-V .iplt is
+  /// deliberately deferred until resolver secondary entries are registered;
+  /// x86 and AArch64 .iplt sections are processed here as before.
   void disassemblePLT();
 
-  /// Disassemble and create function entries for one PLT \p Section.
+  /// Disassemble and create function entries for one PLT \p Section. Keeping
+  /// the per-section work separate lets the deferred RISC-V .iplt path reuse
+  /// it without processing the other PLT sections twice.
   void disassemblePLTSection(BinarySection &Section, uint64_t EntrySize);
 
   /// Auxiliary function to create .plt BinaryFunction on \p EntryAddres
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 69bcab19954f2..0836f079cdb5b 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -1353,8 +1353,9 @@ void RewriteInstance::discoverFileObjects() {
   // that is a subject to dynamic relocation processing.
   processDynamicRelocations();
 
-  // Process PLT sections. RISC-V .iplt is handled after function boundaries
-  // and resolver secondary entry points have been established.
+  // Process all x86 and AArch64 PLT sections, including .iplt, here. RISC-V
+  // .iplt is deferred until function boundaries and resolver secondary entry
+  // points have been established.
   disassemblePLT();
 
   // See if we missed any functions marked by FDE.
@@ -1392,11 +1393,13 @@ void RewriteInstance::discoverFileObjects() {
   adjustFunctionBoundaries(MarkerSymbols);
   splitUnmarkedTailFunctions(MarkerSymbols);
 
-  // R_RISCV_IRELATIVE addends name resolver entry points. LLD may
-  // canonicalize the only IFUNC symbol to the IPLT entry, leaving the resolver
-  // without a symbol. Function sizes are not final when dynamic relocations
-  // are first read, so record these secondary entries after boundary
-  // adjustment.
+  // This is deliberately RISC-V-only. LLD may canonicalize the only IFUNC
+  // symbol to the IPLT entry, leaving the resolver named only by an
+  // R_RISCV_IRELATIVE addend at a non-zero offset in another function.
+  // Function sizes are not final when dynamic relocations are first read, so
+  // record exact secondary entries after boundary adjustment and only then
+  // process .iplt. x86 and AArch64 .iplt sections were already processed by
+  // disassemblePLT() above and retain their original ordering.
   if (BC->isRISCV()) {
     for (const BinarySection &Section : BC->allocatableSections()) {
       for (const Relocation &Rel : Section.dynamicRelocations()) {
@@ -1416,6 +1419,8 @@ void RewriteInstance::discoverFileObjects() {
     }
 
     if (BinarySection *IPLTSection = getSection(".iplt")) {
+      // Reuse the same per-section machinery as the normal PLT path now that
+      // every interior resolver has an exact secondary-entry symbol.
       const PLTSectionInfo *PLTSI = getPLTSectionInfo(IPLTSection->getName());
       assert(PLTSI && "missing RISC-V .iplt section information");
       disassemblePLTSection(*IPLTSection, PLTSI->EntrySize);
@@ -1920,9 +1925,12 @@ void RewriteInstance::createPLTBinaryFunction(uint64_t TargetAddress,
     if (!Rel->Addend || !Rel->isIRelative())
       return;
 
-    // IFUNC trampoline without symbol
+    // IFUNC trampoline without symbol. The existing x86 and AArch64 paths
+    // require the resolver to start a BinaryFunction. For RISC-V, deferred
+    // .iplt processing also permits the exact secondary entry registered
+    // above, which getBinaryFunctionAtAddress() does not return.
     BinaryFunction *TargetBF = BC->getBinaryFunctionAtAddress(Rel->Addend);
-    if (!TargetBF)
+    if (!TargetBF && BC->isRISCV())
       TargetBF = BC->getBinaryFunctionContainingAddress(Rel->Addend);
     if (!TargetBF) {
       BC->errs()
@@ -1931,9 +1939,12 @@ void RewriteInstance::createPLTBinaryFunction(uint64_t TargetAddress,
       return;
     }
 
-    const uint64_t ResolverOffset = Rel->Addend - TargetBF->getAddress();
-    Symbol = ResolverOffset ? TargetBF->addEntryPointAtOffset(ResolverOffset)
-                            : TargetBF->getSymbol();
+    Symbol = TargetBF->getSymbol();
+    if (BC->isRISCV()) {
+      const uint64_t ResolverOffset = Rel->Addend - TargetBF->getAddress();
+      if (ResolverOffset)
+        Symbol = TargetBF->addEntryPointAtOffset(ResolverOffset);
+    }
   }
 
   ErrorOr<BinarySection &> Section = BC->getSectionForAddress(EntryAddress);
@@ -1946,7 +1957,9 @@ void RewriteInstance::createPLTBinaryFunction(uint64_t TargetAddress,
     BF->addAlternativeName(Symbol->getName().str() + "@PLT");
   setPLTSymbol(BF, Symbol->getName());
 
-  if (Rel->isIRelative()) {
+  // Keep RISC-V alias recovery local to the new path so the established x86
+  // and AArch64 PLT naming behavior remains unchanged.
+  if (BC->isRISCV() && Rel->isIRelative()) {
     auto ResolverSyms = FileSymRefs.equal_range(Rel->Addend);
     for (const SymbolRef &AliasSymbol : llvm::make_second_range(
              llvm::make_range(ResolverSyms.first, ResolverSyms.second))) {
@@ -2145,6 +2158,9 @@ void RewriteInstance::disassemblePLT() {
     if (!PLTSI)
       continue;
 
+    // The LLD-generated RISC-V .iplt form handled here may depend on an
+    // unnamed resolver inside another function. x86 and AArch64 .iplt
+    // sections continue through this path.
     if (BC->isRISCV() && Section.getName() == ".iplt")
       continue;
 
@@ -2855,6 +2871,9 @@ bool RewriteInstance::analyzeRelocation(
     // Section symbols are marked as ST_Debug.
     IsSectionRelocation = (cantFail(Symbol.getType()) == SymbolRef::ST_Debug);
     // Check for PLT entry registered with symbol name
+    // LLD may give a defined RISC-V IFUNC symbol the .iplt entry address.
+    // R_RISCV_CALL_PLT must still resolve it through the registered @PLT
+    // BinaryData instead of treating that symbol value as a normal function.
     const bool IsRISCVIFuncPLT =
         BC->isRISCV() && RType == ELF::R_RISCV_CALL_PLT &&
         ELFSymbolRef(Symbol).getELFType() == ELF::STT_GNU_IFUNC;

>From 3dbfd5eb98e9b2db70237a19351e1b7e921f1cb3 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Tue, 25 Aug 2026 10:53:05 +0800
Subject: [PATCH 3/4] fix

---
 bolt/include/bolt/Rewrite/RewriteInstance.h |   5 +-
 bolt/lib/Rewrite/RewriteInstance.cpp        |  20 ++-
 bolt/test/RISCV/Inputs/ifunc-gnu-ld.yaml    | 160 ++++++++++++++++++++
 bolt/test/RISCV/ifunc-gnu-ld.test           |  15 ++
 start at the beginning of the section.      |  38 +++++
 5 files changed, 234 insertions(+), 4 deletions(-)
 create mode 100644 bolt/test/RISCV/Inputs/ifunc-gnu-ld.yaml
 create mode 100644 bolt/test/RISCV/ifunc-gnu-ld.test
 create mode 100644 start at the beginning of the section.

diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h
index 148007ec6154c..998f1f4f777e6 100644
--- a/bolt/include/bolt/Rewrite/RewriteInstance.h
+++ b/bolt/include/bolt/Rewrite/RewriteInstance.h
@@ -550,6 +550,9 @@ class RewriteInstance {
   std::optional<uint64_t> PLTRelocationsAddress;
   uint64_t PLTRelocationsSize{0};
 
+  /// True if a static RISC-V PLT was found through .rela.plt.
+  bool HasStaticRISCVPLT{false};
+
   /// True if relocation of specified type came from .rela.plt
   DenseMap<uint64_t, bool> IsJmpRelocation;
 
@@ -593,7 +596,7 @@ class RewriteInstance {
 
   /// RISCV PLT sections.
   const PLTSectionInfo RISCV_PLTSections[3] = {
-      {".plt"}, {".iplt", 16}, {nullptr}};
+      {".plt", 16}, {".iplt", 16}, {nullptr}};
 
   /// Return PLT information for a section with \p SectionName or nullptr
   /// if the section is not PLT.
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 0836f079cdb5b..8a50879d1cdfa 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -2063,9 +2063,11 @@ void RewriteInstance::disassemblePLTSectionRISCV(BinarySection &Section) {
     }
   };
 
-  // Regular .plt has a first special entry with no relocations pointing to it,
-  // while static IFUNC .iplt entries start at the beginning of the section.
-  uint64_t InstrOffset = Section.getName() == ".iplt" ? 0 : 32;
+  // A regular .plt has a first special entry with no relocations pointing to
+  // it. GNU ld's static IFUNC .plt and all .iplt sections are headerless.
+  const bool IsHeaderless = Section.getName() == ".iplt" ||
+                            (Section.getName() == ".plt" && HasStaticRISCVPLT);
+  uint64_t InstrOffset = IsHeaderless ? 0 : 32;
 
   while (InstrOffset < SectionSize) {
     InstructionListType Instructions;
@@ -2958,6 +2960,18 @@ bool RewriteInstance::analyzeRelocation(
 }
 
 void RewriteInstance::processDynamicRelocations() {
+  // A static RISC-V executable linked by GNU ld can have no PT_DYNAMIC and
+  // keep its IRELATIVE relocations in .rela.plt.
+  if (BC->isRISCV() && BC->IsStaticExecutable && !PLTRelocationsSize) {
+    ErrorOr<BinarySection &> PLTRelSectionOrErr =
+        BC->getUniqueSectionByName(".rela.plt");
+    if (PLTRelSectionOrErr) {
+      PLTRelocationsAddress = PLTRelSectionOrErr->getAddress();
+      PLTRelocationsSize = PLTRelSectionOrErr->getSize();
+      HasStaticRISCVPLT = true;
+    }
+  }
+
   // Read .relr.dyn section containing compressed R_*_RELATIVE relocations.
   if (DynamicRelrSize > 0) {
     ErrorOr<BinarySection &> DynamicRelrSectionOrErr =
diff --git a/bolt/test/RISCV/Inputs/ifunc-gnu-ld.yaml b/bolt/test/RISCV/Inputs/ifunc-gnu-ld.yaml
new file mode 100644
index 0000000000000..14f5373629af1
--- /dev/null
+++ b/bolt/test/RISCV/Inputs/ifunc-gnu-ld.yaml
@@ -0,0 +1,160 @@
+## Generated from the following source using llvm-mc and
+## riscv64-linux-gnu-ld -q:
+##
+##   .text
+##   .globl _start
+##   .type _start, @function
+## _start:
+##   call ifunc0
+##
+##   .globl func
+##   .type func, @function
+## func:
+##   ret
+##
+##   .globl ifunc0
+##   .type ifunc0, @gnu_indirect_function
+## ifunc0:
+##   ret
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_EXEC
+  Machine:         EM_RISCV
+  Entry:           0x100E0
+ProgramHeaders:
+  - Type:            PT_LOAD
+    Flags:           [ PF_X, PF_R ]
+    FirstSec:        .rela.plt
+    LastSec:         .text
+    VAddr:           0x10000
+    Align:           0x10000
+    Offset:          0x0
+  - Type:            PT_LOAD
+    Flags:           [ PF_W, PF_R ]
+    FirstSec:        .got.plt
+    LastSec:         .got.plt
+    VAddr:           0x200F0
+    Align:           0x10000
+    Offset:          0xF0
+Sections:
+  - Name:            .rela.plt
+    Type:            SHT_RELA
+    Flags:           [ SHF_ALLOC, SHF_INFO_LINK ]
+    Address:         0x100B0
+    AddressAlign:    0x8
+    Info:            .got.plt
+    Relocations:
+      - Offset:          0x200F0
+        Type:            R_RISCV_IRELATIVE
+        Addend:          65772
+  - Name:            .plt
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x100D0
+    AddressAlign:    0x10
+    Content:         170E0100033E0E0267030E0013000000
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    Address:         0x100E0
+    AddressAlign:    0x4
+    Content:         97000000E78000FF6780000067800000
+  - Name:            .got.plt
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    Address:         0x200F0
+    AddressAlign:    0x8
+    Content:         D000010000000000
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Flags:           [ SHF_INFO_LINK ]
+    Link:            .symtab
+    AddressAlign:    0x8
+    Info:            .text
+    Relocations:
+      - Offset:          0x100E0
+        Symbol:          ifunc0
+        Type:            R_RISCV_CALL_PLT
+      - Offset:          0x100E0
+        Type:            R_RISCV_RELAX
+  - Type:            SectionHeaderTable
+    Sections:
+      - Name:            .rela.plt
+      - Name:            .plt
+      - Name:            .text
+      - Name:            .rela.text
+      - Name:            .got.plt
+      - Name:            .symtab
+      - Name:            .strtab
+      - Name:            .shstrtab
+Symbols:
+  - Name:            .rela.plt
+    Type:            STT_SECTION
+    Section:         .rela.plt
+    Value:           0x100B0
+  - Name:            .plt
+    Type:            STT_SECTION
+    Section:         .plt
+    Value:           0x100D0
+  - Name:            .text
+    Type:            STT_SECTION
+    Section:         .text
+    Value:           0x100E0
+  - Name:            .got.plt
+    Type:            STT_SECTION
+    Section:         .got.plt
+    Value:           0x200F0
+  - Name:            ifunc.o
+    Type:            STT_FILE
+    Index:           SHN_ABS
+  - Name:            '$xrv64i2p1'
+    Section:         .text
+    Value:           0x100E0
+  - Name:            '__global_pointer$'
+    Index:           SHN_ABS
+    Binding:         STB_GLOBAL
+    Value:           0x208F8
+  - Name:            __SDATA_BEGIN__
+    Section:         .got.plt
+    Binding:         STB_GLOBAL
+    Value:           0x200F8
+  - Name:            ifunc0
+    Type:            STT_GNU_IFUNC
+    Section:         .text
+    Binding:         STB_GLOBAL
+    Value:           0x100EC
+  - Name:            _start
+    Type:            STT_FUNC
+    Section:         .text
+    Binding:         STB_GLOBAL
+    Value:           0x100E0
+  - Name:            __BSS_END__
+    Section:         .got.plt
+    Binding:         STB_GLOBAL
+    Value:           0x200F8
+  - Name:            __bss_start
+    Section:         .got.plt
+    Binding:         STB_GLOBAL
+    Value:           0x200F8
+  - Name:            func
+    Type:            STT_FUNC
+    Section:         .text
+    Binding:         STB_GLOBAL
+    Value:           0x100E8
+  - Name:            __DATA_BEGIN__
+    Section:         .got.plt
+    Binding:         STB_GLOBAL
+    Value:           0x200F8
+  - Name:            _edata
+    Section:         .got.plt
+    Binding:         STB_GLOBAL
+    Value:           0x200F8
+  - Name:            _end
+    Section:         .got.plt
+    Binding:         STB_GLOBAL
+    Value:           0x200F8
+...
diff --git a/bolt/test/RISCV/ifunc-gnu-ld.test b/bolt/test/RISCV/ifunc-gnu-ld.test
new file mode 100644
index 0000000000000..b5c5ceaa3f14a
--- /dev/null
+++ b/bolt/test/RISCV/ifunc-gnu-ld.test
@@ -0,0 +1,15 @@
+## Check the static IFUNC layout emitted by GNU ld: R_RISCV_IRELATIVE is in
+## .rela.plt and the headerless IFUNC entries are in .plt rather than .iplt.
+
+# RUN: yaml2obj %p/Inputs/ifunc-gnu-ld.yaml -o %t
+# RUN: llvm-bolt %t -o %t.bolt --use-old-text=0 --lite=0 \
+# RUN:   --print-disasm --print-only=_start 2>&1 | FileCheck %s \
+# RUN:   --check-prefix=BOLT \
+# RUN:   --implicit-check-not="Expected BF to be presented as IFUNC resolver"
+# RUN: llvm-readelf -Wr -Ws %t.bolt | FileCheck %s --check-prefix=ELF
+
+# BOLT: Binary Function "_start
+# BOLT: auipc ra, ifunc0 at PLT
+
+# ELF: R_RISCV_IRELATIVE {{ *}}[[#%x,RESOLVER:]]
+# ELF: {{0*}}[[#%x,RESOLVER]] 4 IFUNC {{.*}} ifunc0
diff --git a/start at the beginning of the section. b/start at the beginning of the section.
new file mode 100644
index 0000000000000..d9a38ad668850
--- /dev/null
+++ b/start at the beginning of the section.	
@@ -0,0 +1,38 @@
+diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
+index 2d7498422797..0c64a82c2346 100644
+--- a/bolt/lib/Rewrite/RewriteInstance.cpp
++++ b/bolt/lib/Rewrite/RewriteInstance.cpp
+@@ -2057,9 +2057,11 @@ void RewriteInstance::disassemblePLTSectionRISCV(BinarySection &Section) {
+     }
+   };
+ 
+-  // Regular .plt has a first special entry with no relocations pointing to it,
+-  // while static IFUNC .iplt entries start at the beginning of the section.
+-  uint64_t InstrOffset = Section.getName() == ".iplt" ? 0 : 32;
++  // A regular .plt has a first special entry with no relocations pointing to
++  // it. GNU ld's static IFUNC .plt and all .iplt sections are headerless.
++  const bool IsHeaderless = Section.getName() == ".iplt" ||
++                            (Section.getName() == ".plt" && HasStaticRISCVPLT);
++  uint64_t InstrOffset = IsHeaderless ? 0 : 32;
+ 
+   while (InstrOffset < SectionSize) {
+     InstructionListType Instructions;
+@@ -2939,6 +2941,18 @@ bool RewriteInstance::analyzeRelocation(
+ }
+ 
+ void RewriteInstance::processDynamicRelocations() {
++  // A static RISC-V executable linked by GNU ld can have no PT_DYNAMIC and
++  // keep its IRELATIVE relocations in .rela.plt.
++  if (BC->isRISCV() && BC->IsStaticExecutable && !PLTRelocationsSize) {
++    ErrorOr<BinarySection &> PLTRelSectionOrErr =
++        BC->getUniqueSectionByName(".rela.plt");
++    if (PLTRelSectionOrErr) {
++      PLTRelocationsAddress = PLTRelSectionOrErr->getAddress();
++      PLTRelocationsSize = PLTRelSectionOrErr->getSize();
++      HasStaticRISCVPLT = true;
++    }
++  }
++
+   // Read .relr.dyn section containing compressed R_*_RELATIVE relocations.
+   if (DynamicRelrSize > 0) {
+     ErrorOr<BinarySection &> DynamicRelrSectionOrErr =

>From 2d2e3f647cf1f20860f1292e5c803fc9e37cedde Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Tue, 25 Aug 2026 15:59:38 +0800
Subject: [PATCH 4/4] fix some comment

---
 bolt/lib/Rewrite/RewriteInstance.cpp   |  9 +++---
 bolt/test/RISCV/ifunc.s                | 11 +++++---
 start at the beginning of the section. | 38 --------------------------
 3 files changed, 12 insertions(+), 46 deletions(-)
 delete mode 100644 start at the beginning of the section.

diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 8a50879d1cdfa..c00c9492b350d 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -1969,7 +1969,7 @@ void RewriteInstance::createPLTBinaryFunction(uint64_t TargetAddress,
       const std::string PLTName = AliasName.str() + "@PLT";
       if (!BC->getBinaryDataByName(PLTName)) {
         BF->addAlternativeName(PLTName);
-        BC->registerNameAtAddress(PLTName, EntryAddress, 0, EntrySize,
+        BC->registerNameAtAddress(PLTName, EntryAddress, EntrySize,
                                   Section->getAlignment());
       }
       setPLTSymbol(BF, AliasName);
@@ -2845,6 +2845,7 @@ bool RewriteInstance::analyzeRelocation(
   };
 
   const bool IsAArch64 = BC->isAArch64();
+  const bool IsRISCV = BC->isRISCV();
 
   const size_t RelSize = Relocation::getSizeForType(RType);
 
@@ -2877,10 +2878,10 @@ bool RewriteInstance::analyzeRelocation(
     // R_RISCV_CALL_PLT must still resolve it through the registered @PLT
     // BinaryData instead of treating that symbol value as a normal function.
     const bool IsRISCVIFuncPLT =
-        BC->isRISCV() && RType == ELF::R_RISCV_CALL_PLT &&
+        IsRISCV && RType == ELF::R_RISCV_CALL_PLT &&
         ELFSymbolRef(Symbol).getELFType() == ELF::STT_GNU_IFUNC;
     if ((!SymbolAddress || IsRISCVIFuncPLT) && !IsWeakReference(Symbol) &&
-        (IsAArch64 || BC->isRISCV())) {
+        (IsAArch64 || IsRISCV)) {
       const BinaryData *BD = BC->getPLTBinaryDataByName(SymbolName);
       SymbolAddress = BD ? BD->getAddress() : 0;
     }
@@ -2940,7 +2941,7 @@ bool RewriteInstance::analyzeRelocation(
     if (SkipVerification)
       return true;
 
-    if (IsAArch64 || BC->isRISCV())
+    if (IsAArch64 || IsRISCV)
       return true;
 
     if (SymbolName == "__hot_start" || SymbolName == "__hot_end")
diff --git a/bolt/test/RISCV/ifunc.s b/bolt/test/RISCV/ifunc.s
index 43b26324dfb5c..1ee1f6e937825 100644
--- a/bolt/test/RISCV/ifunc.s
+++ b/bolt/test/RISCV/ifunc.s
@@ -1,11 +1,13 @@
 ## Check that BOLT recognizes a non-preemptible IFUNC IPLT entry and tracks an
-## otherwise unnamed resolver after the linker canonicalizes the IFUNC symbol
-## to the IPLT entry. Moving the containing function also verifies that the
-## IRELATIVE addend is updated to the resolver secondary entry, not the primary
-## function entry.
+## otherwise unnamed resolver after the linker canonicalizes the exported IFUNC
+## symbol to the IPLT entry. Moving the containing function also verifies that
+## the IRELATIVE addend is updated to the resolver secondary entry, not the
+## primary function entry. Discard local symbols because LLD may retain a local
+## alias for the resolver.
 
 # RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+relax -o %t.64.o %s
 # RUN: ld.lld -q -o %t.64 %t.64.o
+# RUN: llvm-objcopy --discard-all %t.64
 # RUN: llvm-bolt %t.64 -o %t.64.bolt --use-old-text=0 --lite=0 \
 # RUN:   --print-disasm --print-only=_start 2>&1 | FileCheck %s \
 # RUN:   --check-prefix=BOLT \
@@ -16,6 +18,7 @@
 
 # RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+relax -o %t.32.o %s
 # RUN: ld.lld -q -o %t.32 %t.32.o
+# RUN: llvm-objcopy --discard-all %t.32
 # RUN: llvm-bolt %t.32 -o %t.32.bolt --use-old-text=0 --lite=0 \
 # RUN:   --print-disasm --print-only=_start 2>&1 | FileCheck %s \
 # RUN:   --check-prefix=BOLT \
diff --git a/start at the beginning of the section. b/start at the beginning of the section.
deleted file mode 100644
index d9a38ad668850..0000000000000
--- a/start at the beginning of the section.	
+++ /dev/null
@@ -1,38 +0,0 @@
-diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
-index 2d7498422797..0c64a82c2346 100644
---- a/bolt/lib/Rewrite/RewriteInstance.cpp
-+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
-@@ -2057,9 +2057,11 @@ void RewriteInstance::disassemblePLTSectionRISCV(BinarySection &Section) {
-     }
-   };
- 
--  // Regular .plt has a first special entry with no relocations pointing to it,
--  // while static IFUNC .iplt entries start at the beginning of the section.
--  uint64_t InstrOffset = Section.getName() == ".iplt" ? 0 : 32;
-+  // A regular .plt has a first special entry with no relocations pointing to
-+  // it. GNU ld's static IFUNC .plt and all .iplt sections are headerless.
-+  const bool IsHeaderless = Section.getName() == ".iplt" ||
-+                            (Section.getName() == ".plt" && HasStaticRISCVPLT);
-+  uint64_t InstrOffset = IsHeaderless ? 0 : 32;
- 
-   while (InstrOffset < SectionSize) {
-     InstructionListType Instructions;
-@@ -2939,6 +2941,18 @@ bool RewriteInstance::analyzeRelocation(
- }
- 
- void RewriteInstance::processDynamicRelocations() {
-+  // A static RISC-V executable linked by GNU ld can have no PT_DYNAMIC and
-+  // keep its IRELATIVE relocations in .rela.plt.
-+  if (BC->isRISCV() && BC->IsStaticExecutable && !PLTRelocationsSize) {
-+    ErrorOr<BinarySection &> PLTRelSectionOrErr =
-+        BC->getUniqueSectionByName(".rela.plt");
-+    if (PLTRelSectionOrErr) {
-+      PLTRelocationsAddress = PLTRelSectionOrErr->getAddress();
-+      PLTRelocationsSize = PLTRelSectionOrErr->getSize();
-+      HasStaticRISCVPLT = true;
-+    }
-+  }
-+
-   // Read .relr.dyn section containing compressed R_*_RELATIVE relocations.
-   if (DynamicRelrSize > 0) {
-     ErrorOr<BinarySection &> DynamicRelrSectionOrErr =



More information about the llvm-commits mailing list