[llvm] [BOLT][RISCV] Handle static IFUNC calls through .iplt (PR #207733)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 26 02:29:33 PDT 2026
https://github.com/Thrrreeee updated https://github.com/llvm/llvm-project/pull/207733
>From b50aff8fdee202de2f79f163af7518bbbe1fafbf Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Wed, 26 Aug 2026 15:56:14 +0800
Subject: [PATCH 1/3] [BOLT][RISCV] Handle static IFUNC calls through .iplt
---
bolt/include/bolt/Rewrite/RewriteInstance.h | 3 +-
bolt/lib/Core/Relocation.cpp | 1 +
bolt/lib/Rewrite/RewriteInstance.cpp | 67 ++++++++++++++++++---
bolt/test/RISCV/ifunc.s | 51 ++++++++++++++++
4 files changed, 114 insertions(+), 8 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..4d4ac70195bc2 100644
--- a/bolt/include/bolt/Rewrite/RewriteInstance.h
+++ b/bolt/include/bolt/Rewrite/RewriteInstance.h
@@ -585,7 +585,8 @@ class RewriteInstance {
{".plt"}, {".plt.got"}, {".iplt"}, {nullptr}};
/// RISCV PLT sections.
- const PLTSectionInfo RISCV_PLTSections[2] = {{".plt"}, {nullptr}};
+ const PLTSectionInfo RISCV_PLTSections[3] = {
+ {".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/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp
index cb6aaa552d05f..502f448f50c18 100644
--- a/bolt/lib/Core/Relocation.cpp
+++ b/bolt/lib/Core/Relocation.cpp
@@ -870,6 +870,7 @@ bool Relocation::isIRelative(uint32_t Type) {
case Triple::aarch64:
return Type == ELF::R_AARCH64_IRELATIVE;
case Triple::riscv64:
+ return Type == ELF::R_RISCV_IRELATIVE;
case Triple::riscv32:
llvm_unreachable("not implemented");
case Triple::x86_64:
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 4486efe926d01..a56fc34604ce6 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -1353,6 +1353,30 @@ void RewriteInstance::discoverFileObjects() {
// that is a subject to dynamic relocation processing.
processDynamicRelocations();
+ // LLD may canonicalize the only RISC-V IFUNC symbol to its IPLT entry,
+ // leaving the resolver identifiable only by an R_RISCV_IRELATIVE addend.
+ // Register every such resolver before PLT disassembly so .iplt can use the
+ // normal PLT processing path.
+ if (BC->TheTriple->isRISCV64()) {
+ for (const BinarySection &Section : BC->allocatableSections()) {
+ for (const Relocation &Rel : Section.dynamicRelocations()) {
+ if (!Rel.isIRelative() || !Rel.Addend ||
+ BC->getBinaryFunctionAtAddress(Rel.Addend))
+ continue;
+
+ ErrorOr<BinarySection &> ResolverSection =
+ BC->getSectionForAddress(Rel.Addend);
+ if (!ResolverSection || !ResolverSection->isText() ||
+ ResolverSection->isVirtual())
+ continue;
+
+ const std::string FunctionName =
+ "__BOLT_IFUNC_RESOLVERat" + Twine::utohexstr(Rel.Addend).str();
+ BC->createBinaryFunction(FunctionName, *ResolverSection, Rel.Addend, 0);
+ }
+ }
+ }
+
// Process PLT section.
disassemblePLT();
@@ -1886,10 +1910,10 @@ 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
+ // IFUNC trampoline without symbol.
BinaryFunction *TargetBF = BC->getBinaryFunctionAtAddress(Rel->Addend);
if (!TargetBF) {
BC->errs()
@@ -1910,6 +1934,25 @@ void RewriteInstance::createPLTBinaryFunction(uint64_t TargetAddress,
else
BF->addAlternativeName(Symbol->getName().str() + "@PLT");
setPLTSymbol(BF, Symbol->getName());
+
+ // 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))) {
+ 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, EntrySize,
+ Section->getAlignment());
+ }
+ setPLTSymbol(BF, AliasName);
+ }
+ }
}
void RewriteInstance::disassemblePLTInstruction(const BinarySection &Section,
@@ -1998,8 +2041,11 @@ void RewriteInstance::disassemblePLTSectionRISCV(BinarySection &Section) {
}
};
- // Skip the first special entry since no relocation points to it.
- uint64_t InstrOffset = 32;
+ // A regular .plt has a first special entry with no relocations pointing to
+ // it, while 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;
@@ -2769,6 +2815,7 @@ bool RewriteInstance::analyzeRelocation(
};
const bool IsAArch64 = BC->isAArch64();
+ const bool IsRISCV = BC->isRISCV();
const size_t RelSize = Relocation::getSizeForType(RType);
@@ -2797,8 +2844,14 @@ 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) &&
- (IsAArch64 || BC->isRISCV())) {
+ // 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->TheTriple->isRISCV64() && RType == ELF::R_RISCV_CALL_PLT &&
+ ELFSymbolRef(Symbol).getELFType() == ELF::STT_GNU_IFUNC;
+ if ((!SymbolAddress || IsRISCVIFuncPLT) && !IsWeakReference(Symbol) &&
+ (IsAArch64 || IsRISCV)) {
const BinaryData *BD = BC->getPLTBinaryDataByName(SymbolName);
SymbolAddress = BD ? BD->getAddress() : 0;
}
@@ -2858,7 +2911,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
new file mode 100644
index 0000000000000..bd638659d65cb
--- /dev/null
+++ b/bolt/test/RISCV/ifunc.s
@@ -0,0 +1,51 @@
+## Check that BOLT recognizes a non-preemptible IFUNC IPLT entry and tracks an
+## otherwise unnamed resolver after the linker canonicalizes the exported IFUNC
+## symbol to the IPLT entry. Function sizes model normal compiler output, while
+## discarding local symbols removes the resolver's remaining name. Moving the
+## synthesized resolver also verifies that the IRELATIVE addend is updated.
+
+# 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 \
+# RUN: --implicit-check-not="Expected BF to be presented as IFUNC resolver"
+# RUN: llvm-readelf -Wr -Ws %t.64.bolt > %t.64.dump
+# RUN: llvm-objdump -d --no-show-raw-insn %t.64.bolt >> %t.64.dump
+# RUN: FileCheck %s --input-file=%t.64.dump \
+# RUN: --check-prefixes=ELF,IPLT,RESOLVER
+
+# BOLT: Binary Function "_start
+# BOLT: auipc a0, %pcrel_hi(__BOLT_IFUNC_RESOLVERat{{[0-9a-f]+}}@PLT)
+
+# ELF: R_RISCV_IRELATIVE {{ *}}[[#%x,RESOLVER:]]
+# ELF: {{[0-9a-f]+}} 4 FUNC {{.*}} func
+
+# IPLT: Disassembly of section .iplt:
+# IPLT: <ifunc0>:
+# IPLT-NEXT: {{.*}} auipc t3,
+# IPLT-NEXT: {{.*}} ld t3,
+
+# RESOLVER: {{^ *}}[[#%x,RESOLVER]]:{{ *}}ret
+
+ .text
+ .globl _start
+ .type _start, @function
+_start:
+1:
+ auipc a0, %pcrel_hi(ifunc0)
+ addi a0, a0, %pcrel_lo(1b)
+ .size _start, .-_start
+
+ .globl func
+ .type func, @function
+func:
+ ret
+ .size func, .-func
+
+ .globl ifunc0
+ .type ifunc0, @gnu_indirect_function
+ifunc0:
+ ret
+ .size ifunc0, .-ifunc0
>From bb6d02ddbf098d7b364742d59dc020d1035d02ca Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Wed, 26 Aug 2026 17:13:51 +0800
Subject: [PATCH 2/3] fix
---
bolt/lib/Rewrite/RewriteInstance.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index a56fc34604ce6..955d6de0f017e 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -2043,8 +2043,7 @@ void RewriteInstance::disassemblePLTSectionRISCV(BinarySection &Section) {
// A regular .plt has a first special entry with no relocations pointing to
// it, while all .iplt sections are headerless.
- const bool IsHeaderless = Section.getName() == ".iplt" ||
- (Section.getName() == ".plt" && HasStaticRISCVPLT);
+ const bool IsHeaderless = Section.getName() == ".iplt"
uint64_t InstrOffset = IsHeaderless ? 0 : 32;
while (InstrOffset < SectionSize) {
>From c26117eb1dcb7ef8f89f4397535301c15e4e5251 Mon Sep 17 00:00:00 2001
From: shijinrui <shijinrui at bytedance.com>
Date: Wed, 26 Aug 2026 17:19:46 +0800
Subject: [PATCH 3/3] fix error
---
bolt/lib/Rewrite/RewriteInstance.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 955d6de0f017e..42105c1987f54 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -2043,7 +2043,7 @@ void RewriteInstance::disassemblePLTSectionRISCV(BinarySection &Section) {
// A regular .plt has a first special entry with no relocations pointing to
// it, while all .iplt sections are headerless.
- const bool IsHeaderless = Section.getName() == ".iplt"
+ const bool IsHeaderless = Section.getName() == ".iplt";
uint64_t InstrOffset = IsHeaderless ? 0 : 32;
while (InstrOffset < SectionSize) {
More information about the llvm-commits
mailing list