[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