RFC: x86: Fall back to lazy binding for unrelocated IFUNC symbol [BZ #23240]
H.J. Lu
hongjiu.lu@intel.com
Sat May 26 13:52:00 GMT 2018
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
More information about the Libc-alpha
mailing list