public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* RFC: x86: Fall back to lazy binding for unrelocated IFUNC symbol [BZ #23240]
@ 2018-05-26 13:52 H.J. Lu
  2018-05-26 21:02 ` Florian Weimer
  0 siblings, 1 reply; 14+ messages in thread
From: H.J. Lu @ 2018-05-26 13:52 UTC (permalink / raw)
  To: GNU C Library

Since we can't call unrelocated IFUNC function to get the real function
addresss, this patch falls back to lazy binding for unrelocated IFUNC
symbol.

Any comments?

H.J.
---
	[BZ #23240]
	* elf/Makefile (tests-internal): Add ifuncpreload1
	(modules-names): Add ifuncpreloadmod1a and ifuncpreloadmod1b.
	($(objpfx)ifuncpreload1): New.
	($(objpfx)ifuncpreload1.out): Likewise.
	(ifuncpreload1-ENV): Likewise.
	* elf/ifuncpreload1.c: New file.
	* elf/ifuncpreloadmod1a.c: Likewise.
	* elf/ifuncpreloadmod1b.c: Likewise.
	* sysdeps/i386/dl-machine.h (elf_machine_runtime_setup): Always
	set up GOT.
	(elf_machine_rel): Fall back to lazy binding for unrelocated
	IFUNC symbol.
	* sysdeps/x86_64/dl-machine.h (elf_machine_runtime_setup): Always
	set up GOT.
	(elf_machine_rela): Fall back to lazy binding for unrelocated
	IFUNC symbol.
---
 elf/Makefile                | 10 ++++++--
 elf/ifuncpreload1.c         | 39 +++++++++++++++++++++++++++++
 elf/ifuncpreloadmod1a.c     | 23 +++++++++++++++++
 elf/ifuncpreloadmod1b.c     | 49 +++++++++++++++++++++++++++++++++++++
 sysdeps/i386/dl-machine.h   | 22 ++++++++++-------
 sysdeps/x86_64/dl-machine.h | 22 ++++++++++-------
 6 files changed, 145 insertions(+), 20 deletions(-)
 create mode 100644 elf/ifuncpreload1.c
 create mode 100644 elf/ifuncpreloadmod1a.c
 create mode 100644 elf/ifuncpreloadmod1b.c

diff --git a/elf/Makefile b/elf/Makefile
index 2dcd2b88e0..cb203d58b4 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -328,7 +328,7 @@ tests-internal += \
 	 ifuncmain1staticpic \
 	 ifuncmain2 ifuncmain2pic ifuncmain3 ifuncmain4 \
 	 ifuncmain5 ifuncmain5pic ifuncmain5staticpic \
-	 ifuncmain7 ifuncmain7pic
+	 ifuncmain7 ifuncmain7pic ifuncpreload1
 ifunc-test-modules = ifuncdep1 ifuncdep1pic ifuncdep2 ifuncdep2pic \
 		     ifuncdep5 ifuncdep5pic
 extra-test-objs += $(ifunc-test-modules:=.o)
@@ -339,7 +339,8 @@ ifunc-pie-tests = ifuncmain1pie ifuncmain1vispie ifuncmain1staticpie \
 tests-internal += $(ifunc-pie-tests)
 tests-pie += $(ifunc-pie-tests)
 endif
-modules-names += ifuncmod1 ifuncmod3 ifuncmod5 ifuncmod6
+modules-names += ifuncmod1 ifuncmod3 ifuncmod5 ifuncmod6 \
+		 ifuncpreloadmod1a ifuncpreloadmod1b
 endif
 endif
 
@@ -1454,3 +1455,8 @@ tst-libc_dlvsym-static-ENV = \
 $(objpfx)tst-libc_dlvsym-static.out: $(objpfx)tst-libc_dlvsym-dso.so
 
 $(objpfx)tst-big-note: $(objpfx)tst-big-note-lib.so
+
+$(objpfx)ifuncpreload1: $(objpfx)ifuncpreloadmod1a.so
+$(objpfx)ifuncpreload1.out: $(objpfx)ifuncpreloadmod1b.so
+ifuncpreload1-ENV = \
+  LD_PRELOAD=$(objpfx)ifuncpreloadmod1b.so LD_BIND_NOW=1
diff --git a/elf/ifuncpreload1.c b/elf/ifuncpreload1.c
new file mode 100644
index 0000000000..172df33ac3
--- /dev/null
+++ b/elf/ifuncpreload1.c
@@ -0,0 +1,39 @@
+/* Test for relocation over with IFUNC symbols.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <support/check.h>
+#include <support/support.h>
+#include <support/test-driver.h>
+
+extern void bar (char *, const char *, unsigned int);
+
+static int
+do_test (void)
+{
+  char dst[50];
+  const char src[] =
+    {
+      "This is a test"
+    };
+  bar (dst, src, sizeof (src));
+  if (__builtin_memcmp (dst, src, sizeof (src)) != 0)
+    __builtin_abort ();
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/elf/ifuncpreloadmod1a.c b/elf/ifuncpreloadmod1a.c
new file mode 100644
index 0000000000..be9f8832b8
--- /dev/null
+++ b/elf/ifuncpreloadmod1a.c
@@ -0,0 +1,23 @@
+/* Shared module to test for relocation over with IFUNC symbols.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+void
+bar (char *dst, const char *src, unsigned int size)
+{
+  __builtin_memmove (dst, src, size);
+}
diff --git a/elf/ifuncpreloadmod1b.c b/elf/ifuncpreloadmod1b.c
new file mode 100644
index 0000000000..1194ae20e4
--- /dev/null
+++ b/elf/ifuncpreloadmod1b.c
@@ -0,0 +1,49 @@
+/* Shared module to test for relocation over with IFUNC symbols.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stddef.h>
+
+void *
+my_memmove(void *dst_p, const void *src_p, size_t n)
+{
+  const char *src = src_p;
+  char *dst = dst_p;
+  char *ret = dst;
+  if (src < dst)
+    {
+      dst += n;
+      src += n;
+      while (n--)
+	*--dst = *--src;
+    }
+  else
+    while (n--)
+      *dst++ = *src++;
+  return ret;
+}
+
+void *memmove (void *, const void *, size_t)
+  __attribute__ ((ifunc ("resolve_memmove")));
+
+typedef void *(*memmove_t) (void *, const void *, size_t);
+
+static memmove_t
+resolve_memmove (void)
+{
+  return my_memmove;
+}
diff --git a/sysdeps/i386/dl-machine.h b/sysdeps/i386/dl-machine.h
index 1afdcbd9ea..4d0afad074 100644
--- a/sysdeps/i386/dl-machine.h
+++ b/sysdeps/i386/dl-machine.h
@@ -68,7 +68,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
   extern void _dl_runtime_resolve (Elf32_Word) attribute_hidden;
   extern void _dl_runtime_profile (Elf32_Word) attribute_hidden;
 
-  if (l->l_info[DT_JMPREL] && lazy)
+  /* Always set up GOT since we may have to fall back to lazy binding
+     even with non-lazy binding is requested.   */
+  if (l->l_info[DT_JMPREL])
     {
       /* The GOT entries for functions in the PLT have not yet been filled
 	 in.  Their initial contents will arrange when called to push an
@@ -332,16 +334,18 @@ elf_machine_rel (struct link_map *map, const Elf32_Rel *reloc,
 	      && sym_map->l_type != lt_executable
 	      && !sym_map->l_relocated)
 	    {
-	      const char *strtab
-		= (const char *) D_PTR (map, l_info[DT_STRTAB]);
-	      _dl_error_printf ("\
-%s: Relink `%s' with `%s' for IFUNC symbol `%s'\n",
-				RTLD_PROGNAME, map->l_name,
-				sym_map->l_name,
-				strtab + refsym->st_name);
+	      /* NB: The symbol reference is resolved to IFUNC symbol
+	         from a shared object which hasn't been relocated yet.
+		 Relocate the GOT entry to enable lazy binding.  */
+	      value = map->l_addr + *reloc_addr;
+	      /* Disable RELRO so that the GOT entry can updated by lazy
+		 binding later.  */
+	      if (map->l_info[DT_BIND_NOW] != NULL)
+		map->l_relro_size = 0;
 	    }
+	  else
 # endif
-	  value = ((Elf32_Addr (*) (void)) value) ();
+	    value = ((Elf32_Addr (*) (void)) value) ();
 	}
 
       switch (r_type)
diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
index 1942ed5061..2aff922f96 100644
--- a/sysdeps/x86_64/dl-machine.h
+++ b/sysdeps/x86_64/dl-machine.h
@@ -73,7 +73,9 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
   extern void _dl_runtime_profile_avx (ElfW(Word)) attribute_hidden;
   extern void _dl_runtime_profile_avx512 (ElfW(Word)) attribute_hidden;
 
-  if (l->l_info[DT_JMPREL] && lazy)
+  /* Always set up GOT since we may have to fall back to lazy binding
+     even with non-lazy binding is requested.   */
+  if (l->l_info[DT_JMPREL])
     {
       /* The GOT entries for functions in the PLT have not yet been filled
 	 in.  Their initial contents will arrange when called to push an
@@ -318,16 +320,18 @@ elf_machine_rela (struct link_map *map, const ElfW(Rela) *reloc,
 	      && sym_map->l_type != lt_executable
 	      && !sym_map->l_relocated)
 	    {
-	      const char *strtab
-		= (const char *) D_PTR (map, l_info[DT_STRTAB]);
-	      _dl_error_printf ("\
-%s: Relink `%s' with `%s' for IFUNC symbol `%s'\n",
-				RTLD_PROGNAME, map->l_name,
-				sym_map->l_name,
-				strtab + refsym->st_name);
+	      /* NB: The symbol reference is resolved to IFUNC symbol
+	         from a shared object which hasn't been relocated yet.
+		 Relocate the GOT entry to enable lazy binding.  */
+	      value = map->l_addr + *reloc_addr;
+	      /* Disable RELRO so that the GOT entry can updated by lazy
+		 binding later.  */
+	      if (map->l_info[DT_BIND_NOW] != NULL)
+		map->l_relro_size = 0;
 	    }
+	  else
 # endif
-	  value = ((ElfW(Addr) (*) (void)) value) ();
+	    value = ((ElfW(Addr) (*) (void)) value) ();
 	}
 
       switch (r_type)
-- 
2.17.0

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2018-06-06 17:31 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-26 13:52 RFC: x86: Fall back to lazy binding for unrelocated IFUNC symbol [BZ #23240] H.J. Lu
2018-05-26 21:02 ` Florian Weimer
2018-05-27 14:36   ` H.J. Lu
2018-05-28  9:27     ` Florian Weimer
2018-05-28 13:46       ` Carlos O'Donell
2018-05-28 19:51         ` H.J. Lu
2018-06-05 19:25           ` Florian Weimer
2018-06-06 14:04             ` Florian Weimer
2018-06-06 14:50               ` H.J. Lu
2018-06-06 14:54                 ` Florian Weimer
2018-06-06 15:38                   ` H.J. Lu
2018-06-06 15:53                     ` Florian Weimer
2018-06-06 16:10                       ` H.J. Lu
2018-06-06 17:31                         ` Florian Weimer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).