[binutils-gdb] alpha: reject a non-zero addend on a reference to an IFUNC
Sam James
sjames@sourceware.org
Sat Sep 5 08:35:24 GMT 2026
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=b83e869cbe70fc7ba2809babc7ad851b95b509bd
commit b83e869cbe70fc7ba2809babc7ad851b95b509bd
Author: Matt Turner <mattst88@gmail.com>
Date: Mon Aug 31 22:33:17 2026 -0400
alpha: reject a non-zero addend on a reference to an IFUNC
An R_ALPHA_IRELATIVE carries the address of the resolver in its addend,
so there is no room in it for an offset from the symbol. A reference
that gets one, from an R_ALPHA_LITERAL or an R_ALPHA_REFQUAD, therefore
cannot have an addend. Nothing diagnosed that.
A reference that the dynamic linker resolves is not affected: it keeps
the addend of the symbolic relocation it gets instead, and a shared
library that takes the address of one of its own IFUNCs at an offset
still links. A local symbol in such a library does not bind dynamically,
though, so it is rejected there too.
Diff:
---
bfd/elf64-alpha.c | 21 +++++++++++++++++++++
ld/testsuite/ld-alpha/ifunc-addend-literal.d | 3 +++
ld/testsuite/ld-alpha/ifunc-addend-literal.s | 19 +++++++++++++++++++
ld/testsuite/ld-alpha/ifunc-addend-local.s | 13 +++++++++++++
ld/testsuite/ld-alpha/ifunc-addend-refquad.d | 3 +++
ld/testsuite/ld-alpha/ifunc-addend-refquad.s | 20 ++++++++++++++++++++
ld/testsuite/ld-alpha/ifunc-addend-shared-local.d | 3 +++
ld/testsuite/ld-alpha/ifunc-addend-shared.d | 11 +++++++++++
8 files changed, 93 insertions(+)
diff --git a/bfd/elf64-alpha.c b/bfd/elf64-alpha.c
index 09e3778f3a9..d8f1a3bbf48 100644
--- a/bfd/elf64-alpha.c
+++ b/bfd/elf64-alpha.c
@@ -4686,6 +4686,27 @@ elf64_alpha_relocate_section (struct bfd_link_info *info,
break;
}
+ /* An R_ALPHA_IRELATIVE carries the address of the resolver in its
+ addend, so there is no room in it for an offset from the symbol.
+ A reference the dynamic linker resolves is not affected: it keeps
+ the addend of the symbolic relocation it gets instead. */
+ if (addend != 0
+ && elf64_alpha_ifunc_reloc_p (r_type)
+ && elf64_alpha_ifunc_p (h, sym)
+ && (input_section->flags & SEC_ALLOC)
+ && (elf64_alpha_ifunc_irelplt_p (h, sym, info)
+ || (bfd_link_pic (info) && !dynamic_symbol_p)))
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: %s relocation against STT_GNU_IFUNC symbol `%s' has a "
+ "non-zero addend"),
+ input_bfd, howto->name,
+ elf64_alpha_sym_name (input_bfd, symtab_hdr, h, sym, sec));
+ ret_val = false;
+ continue;
+ }
+
switch (r_type)
{
case R_ALPHA_GPDISP:
diff --git a/ld/testsuite/ld-alpha/ifunc-addend-literal.d b/ld/testsuite/ld-alpha/ifunc-addend-literal.d
new file mode 100644
index 00000000000..2ea6b7df5a5
--- /dev/null
+++ b/ld/testsuite/ld-alpha/ifunc-addend-literal.d
@@ -0,0 +1,3 @@
+#source: ifunc-addend-literal.s
+#ld: -melf64alpha
+#error: \A[^\n]*: ELF_LITERAL relocation against STT_GNU_IFUNC symbol `global_ifunc' has a non-zero addend\n[^\n]*: final link failed[^\n]*\n?\Z
diff --git a/ld/testsuite/ld-alpha/ifunc-addend-literal.s b/ld/testsuite/ld-alpha/ifunc-addend-literal.s
new file mode 100644
index 00000000000..c7c96d2f460
--- /dev/null
+++ b/ld/testsuite/ld-alpha/ifunc-addend-literal.s
@@ -0,0 +1,19 @@
+ .text
+
+ .globl global_ifunc
+ .type global_ifunc, @gnu_indirect_function
+global_ifunc:
+ ret
+ ret
+
+ # An IRELATIVE's addend is the address of the resolver, so a
+ # reference to an IFUNC cannot carry an offset.
+ .globl _start
+ .ent _start
+_start:
+ ldgp $29, 0($27)
+ ldq $27, global_ifunc+4($29) !literal!1
+ jsr $26, ($27), 0 !lituse_jsr!1
+ ldgp $29, 0($26)
+ ret
+ .end _start
diff --git a/ld/testsuite/ld-alpha/ifunc-addend-local.s b/ld/testsuite/ld-alpha/ifunc-addend-local.s
new file mode 100644
index 00000000000..1aa9138979a
--- /dev/null
+++ b/ld/testsuite/ld-alpha/ifunc-addend-local.s
@@ -0,0 +1,13 @@
+ .text
+
+ .type local_ifunc, @gnu_indirect_function
+local_ifunc:
+ ret
+ ret
+
+ # A local symbol is not preemptible, so even in a shared library the
+ # reference becomes an R_ALPHA_IRELATIVE and cannot carry an offset.
+ .data
+ .globl ptr
+ptr:
+ .quad local_ifunc+4
diff --git a/ld/testsuite/ld-alpha/ifunc-addend-refquad.d b/ld/testsuite/ld-alpha/ifunc-addend-refquad.d
new file mode 100644
index 00000000000..d4a912a9438
--- /dev/null
+++ b/ld/testsuite/ld-alpha/ifunc-addend-refquad.d
@@ -0,0 +1,3 @@
+#source: ifunc-addend-refquad.s
+#ld: -melf64alpha
+#error: \A[^\n]*: REFQUAD relocation against STT_GNU_IFUNC symbol `global_ifunc' has a non-zero addend\n[^\n]*: final link failed[^\n]*\n?\Z
diff --git a/ld/testsuite/ld-alpha/ifunc-addend-refquad.s b/ld/testsuite/ld-alpha/ifunc-addend-refquad.s
new file mode 100644
index 00000000000..95d6dfc1daa
--- /dev/null
+++ b/ld/testsuite/ld-alpha/ifunc-addend-refquad.s
@@ -0,0 +1,20 @@
+ .text
+
+ .globl global_ifunc
+ .type global_ifunc, @gnu_indirect_function
+global_ifunc:
+ ret
+ ret
+
+ .globl _start
+ .ent _start
+_start:
+ ret
+ .end _start
+
+ # An IRELATIVE's addend is the address of the resolver, so a
+ # reference to an IFUNC cannot carry an offset.
+ .data
+ .globl ptr
+ptr:
+ .quad global_ifunc+4
diff --git a/ld/testsuite/ld-alpha/ifunc-addend-shared-local.d b/ld/testsuite/ld-alpha/ifunc-addend-shared-local.d
new file mode 100644
index 00000000000..d3c25eb82aa
--- /dev/null
+++ b/ld/testsuite/ld-alpha/ifunc-addend-shared-local.d
@@ -0,0 +1,3 @@
+#source: ifunc-addend-local.s
+#ld: -shared -melf64alpha
+#error: \A[^\n]*: REFQUAD relocation against STT_GNU_IFUNC symbol `local_ifunc' has a non-zero addend\n[^\n]*: final link failed[^\n]*\n?\Z
diff --git a/ld/testsuite/ld-alpha/ifunc-addend-shared.d b/ld/testsuite/ld-alpha/ifunc-addend-shared.d
new file mode 100644
index 00000000000..31bc77ba4c9
--- /dev/null
+++ b/ld/testsuite/ld-alpha/ifunc-addend-shared.d
@@ -0,0 +1,11 @@
+#source: ifunc-addend-refquad.s
+#ld: -shared -melf64alpha
+#readelf: -Wr
+
+# The IFUNC is preemptible here, so the dynamic linker resolves it and the
+# relocation keeps its addend. Nothing turns into an IRELATIVE, so the
+# addend is not rejected.
+Relocation section '\.rela\.dyn' .* contains 1 entry:
+#...
+[0-9a-f]+ +[0-9a-f]+ +R_ALPHA_REFQUAD .*global_ifunc \+ 4
+#pass
More information about the Binutils-cvs
mailing list