[llvm-branch-commits] [lld] [ELF] Emit synthetic local in symbol table for non-preemptible IFUNC (PR #210616)

Fangrui Song via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sun Aug 2 12:40:11 PDT 2026


https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/210616

>From 029a8539653e75e8a8361618b2c3c064018bc741 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                    |  3 +--
 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(+), 8 deletions(-)

diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index f2d582874c043..30e5ca8806ad6 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1256,9 +1256,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 6bac881446fd0..86c2a17c8ed90 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 &section) {
+                                SectionBase &section) {
   Defined *s = makeDefined(ctx, section.file, name, STB_LOCAL, STV_DEFAULT,
                            type, value, size, &section);
   if (ctx.in.symTab)
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 19d4461348f3f..cbdadcceceaaf 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -1330,8 +1330,7 @@ template <typename ELFT> void writeEhdr(Ctx &, uint8_t *buf);
 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 &section);
+                           uint64_t value, uint64_t size, SectionBase &section);
 
 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 88e2b71363dfe..e70d32b2d6053 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