[llvm-branch-commits] [lld] [ELF] Emit synthetic local in symbol table for non-preemptible IFUNC (PR #210616)
Jessica Clarke via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sun Jul 19 09:34:00 PDT 2026
https://github.com/jrtc27 created https://github.com/llvm/llvm-project/pull/210616
Currently we create an internal alias of the original symbol and then
rewrite the latter to point to the IPLT entry, which means we lose
symbol table information for the actual resolver. In practice compilers
also emit a normal function symbol for the resolver due to how IFUNCs
are represented in GNU C so that at least shows up, but we shouldn't be
relying on it. By emitting a synthetic local we can keep having a symbol
for the resolver whilst still redirecting references to the IPLT entry.
---
<sub>Stack created with <a href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>
>From 07906cb5143fa2c0b7ab9b2a3420ca99e9f11577 Mon Sep 17 00:00:00 2001
From: Jessica Clarke <jrtc27 at jrtc27.com>
Date: Sun, 19 Jul 2026 15:45:23 +0100
Subject: [PATCH] [ELF] Emit synthetic local in symbol table for
non-preemptible IFUNC
Currently we create an internal alias of the original symbol and then
rewrite the latter to point to the IPLT entry, which means we lose
symbol table information for the actual resolver. In practice compilers
also emit a normal function symbol for the resolver due to how IFUNCs
are represented in GNU C so that at least shows up, but we shouldn't be
relying on it. By emitting a synthetic local we can keep having a symbol
for the resolver whilst still redirecting references to the IPLT entry.
---
lld/ELF/Relocations.cpp | 5 ++---
lld/ELF/SyntheticSections.cpp | 2 +-
lld/ELF/SyntheticSections.h | 2 +-
lld/test/ELF/gnu-ifunc-i386.s | 18 ++++++++++++++++++
.../ELF/ppc32-ifunc-nonpreemptible-nopic.s | 2 +-
lld/test/ELF/ppc32-ifunc-nonpreemptible-pic.s | 2 +-
6 files changed, 24 insertions(+), 7 deletions(-)
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 88657709b5e8b..a11920e904120 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1254,9 +1254,8 @@ static bool handleNonPreemptibleIfunc(Ctx &ctx, Symbol &sym, uint16_t flags) {
if (flags & HAS_DIRECT_RELOC) {
// Change the value to the IPLT and redirect all references to it.
auto &d = cast<Defined>(sym);
- auto *irelativeSym = makeDefined(
- ctx, d.file, d.getName(), std::as_const(d).binding, d.stOther,
- std::as_const(d).type, d.value, d.size, d.section);
+ auto *irelativeSym = addSyntheticLocal(ctx, d.getName(), d.type, d.value,
+ d.size, *d.section);
addIpltEntry(*irelativeSym);
ctx.irelativeSyms.push_back(irelativeSym);
sym.isInIplt = true;
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index fda7a835827ce..27a6cc17e9516 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -102,7 +102,7 @@ InputSection *elf::createInterpSection(Ctx &ctx) {
Defined *elf::addSyntheticLocal(Ctx &ctx, StringRef name, uint8_t type,
uint64_t value, uint64_t size,
- InputSectionBase §ion) {
+ SectionBase §ion) {
Defined *s = makeDefined(ctx, section.file, name, STB_LOCAL, STV_DEFAULT,
type, value, size, §ion);
if (ctx.in.symTab)
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 6e7df2461ba35..3cceb86b97ffe 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -1326,7 +1326,7 @@ template <typename ELFT> void writePhdrs(Ctx &, uint8_t *buf);
Defined *addSyntheticLocal(Ctx &ctx, StringRef name, uint8_t type,
uint64_t value, uint64_t size,
- InputSectionBase §ion);
+ SectionBase §ion);
void addVerneed(Ctx &, Symbol &ss);
diff --git a/lld/test/ELF/gnu-ifunc-i386.s b/lld/test/ELF/gnu-ifunc-i386.s
index 43b19b27ea4ec..f88a01cc4fb7c 100644
--- a/lld/test/ELF/gnu-ifunc-i386.s
+++ b/lld/test/ELF/gnu-ifunc-i386.s
@@ -38,6 +38,24 @@
// CHECK-NEXT: Section: Undefined
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
+// CHECK-NEXT: Name: bar
+// CHECK-NEXT: Value: 0x4010E4
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Local
+// CHECK-NEXT: Type: GNU_IFunc
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .text
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
+// CHECK-NEXT: Name: foo
+// CHECK-NEXT: Value: 0x4010E5
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Local
+// CHECK-NEXT: Type: GNU_IFunc
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .text
+// CHECK-NEXT: }
+// CHECK-NEXT: Symbol {
// CHECK-NEXT: Name: __rel_iplt_start
// CHECK-NEXT: Value: [[RELA]]
// CHECK-NEXT: Size: 0
diff --git a/lld/test/ELF/ppc32-ifunc-nonpreemptible-nopic.s b/lld/test/ELF/ppc32-ifunc-nonpreemptible-nopic.s
index fca98cd7011de..f37c3294442cb 100644
--- a/lld/test/ELF/ppc32-ifunc-nonpreemptible-nopic.s
+++ b/lld/test/ELF/ppc32-ifunc-nonpreemptible-nopic.s
@@ -16,7 +16,7 @@
# HEX-NEXT: 0x10020110 00000000 ....
# CHECK: Disassembly of section .text:
-# CHECK: <.text>:
+# CHECK: <func>:
# CHECK-NEXT: 100100e0: blr
# CHECK: <_start>:
# CHECK-NEXT: bl 0x100100f0
diff --git a/lld/test/ELF/ppc32-ifunc-nonpreemptible-pic.s b/lld/test/ELF/ppc32-ifunc-nonpreemptible-pic.s
index 328bb9caa3534..a58bf551cfae9 100644
--- a/lld/test/ELF/ppc32-ifunc-nonpreemptible-pic.s
+++ b/lld/test/ELF/ppc32-ifunc-nonpreemptible-pic.s
@@ -30,7 +30,7 @@
.long func
# CHECK: Disassembly of section .text:
-# CHECK: <.text>:
+# CHECK: <func>:
# CHECK-NEXT: 10188: blr
# CHECK: <_start>:
# CHECK-NEXT: bl 0x10190
More information about the llvm-branch-commits
mailing list