[PATCH 3/4] alpha: do not relax references to IFUNC symbols

Matt Turner <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
An IFUNC has no address until its resolver has run, so a reference to one
has to keep going through the GOT entry that R_ALPHA_IRELATIVE fills in at
startup.  Relaxation did not know that and turned a call to an IFUNC into a
direct branch:

  bsr ra,120000878 <__GI_library_func2+0x8>

which calls the resolver rather than the function it selects.  Because
relaxation also drops the GOT entry it no longer needs, the IRELATIVE
disappeared as well, leaving the space reserved for it as R_ALPHA_NONE
padding in .rela.iplt.  glibc's elf_irela rejects anything that is not
R_ALPHA_IRELATIVE, so such a binary would have died at startup rather than
merely calling the wrong function.

Skip relaxation for IFUNC symbols, both local and global.  Ordinary calls
in the same object are still relaxed.

With this the alpha ld-ifunc tests pass, so stop excluding the target from
them.  check-ld has no unexpected failures.
---
 bfd/elf64-alpha.c               | 12 ++++++++++++
 ld/testsuite/ld-ifunc/ifunc.exp |  1 -
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git ./bfd/elf64-alpha.c ./bfd/elf64-alpha.c
index 4e0c2d8901e..8815631752e 100644
--- ./bfd/elf64-alpha.c
+++ ./bfd/elf64-alpha.c
@@ -3971,6 +3971,14 @@ elf64_alpha_relax_section (bfd *abfd, asection *sec,
 		info.tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
 	    }
 
+	  /* An IFUNC has no address until its resolver has run, so every
+	     reference has to keep going through the GOT entry that
+	     R_ALPHA_IRELATIVE fills in at startup.  Relaxing one into a
+	     direct branch or a gp-relative address would bypass the
+	     resolver and call it instead of the function it selects.  */
+	  if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
+	    continue;
+
 	  info.h = NULL;
 	  info.other = isym->st_other;
 	  if (local_got_entries)
@@ -4020,6 +4028,10 @@ elf64_alpha_relax_section (bfd *abfd, asection *sec,
 	      symval = h->root.root.u.def.value;
 	    }
 
+	  /* As above, an IFUNC reference must keep going through the GOT.  */
+	  if (h->root.type == STT_GNU_IFUNC)
+	    continue;
+
 	  info.h = h;
 	  info.other = h->root.other;
 	  info.first_gotent = &h->got_entries;
diff --git ./ld/testsuite/ld-ifunc/ifunc.exp ./ld/testsuite/ld-ifunc/ifunc.exp
index 37cbf78840e..d0cbd633f35 100644
--- ./ld/testsuite/ld-ifunc/ifunc.exp
+++ ./ld/testsuite/ld-ifunc/ifunc.exp
@@ -24,7 +24,6 @@
 
 
 if { ![is_elf_format] || ![supports_gnu_osabi]
-     || [istarget alpha-*-*]
      || [istarget arc*-*-*]
      || [istarget am33*-*-*]
      || [istarget bfin-*-*]
-- 
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.