[PATCH 10/11] alpha: reject a non-zero addend on a reference to an IFUNC

Matt Turner <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
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.
---
 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-alpha/ifunc-addend-shared-local.d      |  3 +++
 ld/testsuite/ld-alpha/ifunc-addend-shared.d   | 11 ++++++++++
 8 files changed, 93 insertions(+)
 create mode 100644 ld/testsuite/ld-alpha/ifunc-addend-literal.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-addend-literal.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-addend-local.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-addend-refquad.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-addend-refquad.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-addend-shared-local.d
 create mode 100644 ld/testsuite/ld-alpha/ifunc-addend-shared.d

diff --git ./bfd/elf64-alpha.c ./bfd/elf64-alpha.c
index 09e3778f3a9..d8f1a3bbf48 100644
--- ./bfd/elf64-alpha.c
+++ ./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 ./ld/testsuite/ld-alpha/ifunc-addend-literal.d ./ld/testsuite/ld-alpha/ifunc-addend-literal.d
new file mode 100644
index 00000000000..2ea6b7df5a5
--- /dev/null
+++ ./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 ./ld/testsuite/ld-alpha/ifunc-addend-literal.s ./ld/testsuite/ld-alpha/ifunc-addend-literal.s
new file mode 100644
index 00000000000..c7c96d2f460
--- /dev/null
+++ ./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 ./ld/testsuite/ld-alpha/ifunc-addend-local.s ./ld/testsuite/ld-alpha/ifunc-addend-local.s
new file mode 100644
index 00000000000..1aa9138979a
--- /dev/null
+++ ./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 ./ld/testsuite/ld-alpha/ifunc-addend-refquad.d ./ld/testsuite/ld-alpha/ifunc-addend-refquad.d
new file mode 100644
index 00000000000..d4a912a9438
--- /dev/null
+++ ./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 ./ld/testsuite/ld-alpha/ifunc-addend-refquad.s ./ld/testsuite/ld-alpha/ifunc-addend-refquad.s
new file mode 100644
index 00000000000..95d6dfc1daa
--- /dev/null
+++ ./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 ./ld/testsuite/ld-alpha/ifunc-addend-shared-local.d ./ld/testsuite/ld-alpha/ifunc-addend-shared-local.d
new file mode 100644
index 00000000000..d3c25eb82aa
--- /dev/null
+++ ./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 ./ld/testsuite/ld-alpha/ifunc-addend-shared.d ./ld/testsuite/ld-alpha/ifunc-addend-shared.d
new file mode 100644
index 00000000000..31bc77ba4c9
--- /dev/null
+++ ./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
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.