diff mbox series

RFC: x86: Fall back to lazy binding for unrelocated IFUNC symbol [BZ #23240]

Message ID 20180526135209.GA23818@intel.com
State New
Headers show
Series RFC: x86: Fall back to lazy binding for unrelocated IFUNC symbol [BZ #23240] | expand

Commit Message

H.J. Lu May 26, 2018, 1:52 p.m. UTC
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

Comments

Florian Weimer May 26, 2018, 9:02 p.m. UTC | #1
On 05/26/2018 03:52 PM, H.J. Lu wrote:
> +	      /* 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;

People perceive BIND_NOW as a security feature.  Silently disabling it 
in this way, perhaps due to an implementation change in another shared 
object, looks very wrong to me.

Maybe you could share the *concrete* problem you are actually trying to 
solve?

Thanks,
Florian
H.J. Lu May 27, 2018, 2:36 p.m. UTC | #2
On Sat, May 26, 2018 at 2:02 PM, Florian Weimer <fweimer@redhat.com> wrote:
> On 05/26/2018 03:52 PM, H.J. Lu wrote:
>>
>> +             /* 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;
>
>
> People perceive BIND_NOW as a security feature.  Silently disabling it in
> this way, perhaps due to an implementation change in another shared object,
> looks very wrong to me.

Sounds reasonable/

> Maybe you could share the *concrete* problem you are actually trying to
> solve?

I  am working on the CPU run-time library for C, which is on hjl/cpu-rt/master
branch at

https://github.com/hjl-tools/glibc

The goal is to make the latest x86-64 string/memory functions in glibc
available to the distros with older glibcs.  libcpu-rt-c.so doesn't requre
dynamic relocations and is binary compatible with all x86-64 libc.so.
One can use

# export LD_PRELOAD=..../libcpu-rt-c.so

to use the latest x86-64 string/memory functions.  But I got

[hjl@gnu-cfl-1 cpu-rt-c]$ LD_PRELOAD=./libcpu-rt-c.so ls /
ls: Relink `/lib64/libpthread.so.0' with `./libcpu-rt-c.so' for IFUNC
symbol `strlen'
ls: Relink `/lib64/libpthread.so.0' with `./libcpu-rt-c.so' for IFUNC
symbol `strchr'
ls: Relink `/lib64/libpthread.so.0' with `./libcpu-rt-c.so' for IFUNC
symbol `memset'
ls: Relink `/lib64/libpthread.so.0' with `./libcpu-rt-c.so' for IFUNC
symbol `strcmp'
ls: Relink `/lib64/libpthread.so.0' with `./libcpu-rt-c.so' for IFUNC
symbol `memcpy'
ls: Relink `/lib64/libdl.so.2' with `./libcpu-rt-c.so' for IFUNC symbol `strcpy'
ls: Relink `/lib64/libpcre2-8.so.0' with `./libcpu-rt-c.so' for IFUNC
symbol `strlen'
ls: Relink `/lib64/libpcre2-8.so.0' with `./libcpu-rt-c.so' for IFUNC
symbol `strchr'
ls: Relink `/lib64/libpcre2-8.so.0' with `./libcpu-rt-c.so' for IFUNC
symbol `memset'
ls: Relink `/lib64/libpcre2-8.so.0' with `./libcpu-rt-c.so' for IFUNC
symbol `memchr'
ls: Relink `/lib64/libpcre2-8.so.0' with `./libcpu-rt-c.so' for IFUNC
symbol `memcmp'
ls: Relink `/lib64/libpcre2-8.so.0' with `./libcpu-rt-c.so' for IFUNC
symbol `memcpy'
ls: Relink `/lib64/libpcre2-8.so.0' with `./libcpu-rt-c.so' for IFUNC
symbol `memmove'
ls: Relink `/lib64/libcap.so.2' with `./libcpu-rt-c.so' for IFUNC
symbol `strlen'
ls: Relink `/lib64/libcap.so.2' with `./libcpu-rt-c.so' for IFUNC
symbol `memset'
ls: Relink `/lib64/libcap.so.2' with `./libcpu-rt-c.so' for IFUNC
symbol `memcpy'
ls: Relink `/lib64/libselinux.so.1' with `./libcpu-rt-c.so' for IFUNC
symbol `strncpy'
ls: Relink `/lib64/libselinux.so.1' with `./libcpu-rt-c.so' for IFUNC
symbol `strncmp'
ls: Relink `/lib64/libselinux.so.1' with `./libcpu-rt-c.so' for IFUNC
symbol `strcpy'
ls: Relink `/lib64/libselinux.so.1' with `./libcpu-rt-c.so' for IFUNC
symbol `strlen'
ls: Relink `/lib64/libselinux.so.1' with `./libcpu-rt-c.so' for IFUNC
symbol `strchr'
ls: Relink `/lib64/libselinux.so.1' with `./libcpu-rt-c.so' for IFUNC
symbol `strrchr'
ls: Relink `/lib64/libselinux.so.1' with `./libcpu-rt-c.so' for IFUNC
symbol `memset'
ls: Relink `/lib64/libselinux.so.1' with `./libcpu-rt-c.so' for IFUNC
symbol `memcmp'
ls: Relink `/lib64/libselinux.so.1' with `./libcpu-rt-c.so' for IFUNC
symbol `strcmp'
ls: Relink `/lib64/libselinux.so.1' with `./libcpu-rt-c.so' for IFUNC
symbol `memcpy'
bin   dev  export  lib    libx32      media  mnt  opt   root  sbin  sys  usr
boot  etc  home    lib64  lost+found  misc   net  proc  run   srv   tmp  var
[hjl@gnu-cfl-1 cpu-rt-c]$

I'd like to avoid these messages.
Florian Weimer May 28, 2018, 9:27 a.m. UTC | #3
On 05/27/2018 04:36 PM, H.J. Lu wrote:

> I'd like to avoid these messages.

We could restrict the warning to LD_DEBUG=bindings.

Thanks,
Florian
Carlos O'Donell May 28, 2018, 1:45 p.m. UTC | #4
On 05/28/2018 05:27 AM, Florian Weimer wrote:
> On 05/27/2018 04:36 PM, H.J. Lu wrote:
> 
>> I'd like to avoid these messages.
> 
> We could restrict the warning to LD_DEBUG=bindings.

I agree that this would be a better solution.

Disabling BIND_NOW is the wrong thing to do in this case.

However, isn't the *real* problem that we lack correct depth-first
sorting based on relocation requirements?

Could we fix this technically in the future by improving the dynamic
loader? Keep in mind if you say "you can't solve circular dependencies"
the answer is "We can. We are allowed to break them in any way we want."
(which may still leave some applications broken at startup).

Cheers,
Carlos.
H.J. Lu May 28, 2018, 7:51 p.m. UTC | #5
On Mon, May 28, 2018 at 6:45 AM, Carlos O'Donell <carlos@redhat.com> wrote:
> On 05/28/2018 05:27 AM, Florian Weimer wrote:
>> On 05/27/2018 04:36 PM, H.J. Lu wrote:
>>
>>> I'd like to avoid these messages.
>>
>> We could restrict the warning to LD_DEBUG=bindings.
>
> I agree that this would be a better solution.
>
> Disabling BIND_NOW is the wrong thing to do in this case.
>

Here is the updated patch.  It fails to back lazy binding only
if GOT is writable.
Florian Weimer June 5, 2018, 7:24 p.m. UTC | #6
On 05/28/2018 09:51 PM, H.J. Lu wrote:
> Here is the updated patch.  It fails to back lazy binding only
> if GOT is writable.

I think this still sets a wrong incentive, as in “you need to have a 
writable GOT for full forwards compatibility with future library evolution”.

I think if we detect an IFUNC-based relocation against a 
not-yet-fully-relocated object, we need to delay this relocation 
processing and perform a second pass of all delayed relocations.  I have 
a patch which needs a little bit of work, but looks quite promising (to 
me at least).

Thanks,
Florian
Florian Weimer June 6, 2018, 2:04 p.m. UTC | #7
On 06/05/2018 09:24 PM, Florian Weimer wrote:
> On 05/28/2018 09:51 PM, H.J. Lu wrote:
>> Here is the updated patch.  It fails to back lazy binding only
>> if GOT is writable.
> 
> I think this still sets a wrong incentive, as in “you need to have a 
> writable GOT for full forwards compatibility with future library 
> evolution”.
> 
> I think if we detect an IFUNC-based relocation against a 
> not-yet-fully-relocated object, we need to delay this relocation 
> processing and perform a second pass of all delayed relocations.  I have 
> a patch which needs a little bit of work, but looks quite promising (to 
> me at least).

Here are my patches:

https://sourceware.org/ml/libc-alpha/2018-06/msg00076.html
https://sourceware.org/ml/libc-alpha/2018-06/msg00077.html

I hope they address your needs.

Thanks,
Florian
H.J. Lu June 6, 2018, 2:50 p.m. UTC | #8
On Wed, Jun 6, 2018 at 7:04 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 06/05/2018 09:24 PM, Florian Weimer wrote:
>>
>> On 05/28/2018 09:51 PM, H.J. Lu wrote:
>>>
>>> Here is the updated patch.  It fails to back lazy binding only
>>> if GOT is writable.
>>
>>
>> I think this still sets a wrong incentive, as in “you need to have a
>> writable GOT for full forwards compatibility with future library evolution”.
>>
>> I think if we detect an IFUNC-based relocation against a
>> not-yet-fully-relocated object, we need to delay this relocation processing
>> and perform a second pass of all delayed relocations.  I have a patch which
>> needs a little bit of work, but looks quite promising (to me at least).
>
>
> Here are my patches:
>
> https://sourceware.org/ml/libc-alpha/2018-06/msg00076.html
> https://sourceware.org/ml/libc-alpha/2018-06/msg00077.html
>
> I hope they address your needs.

Do you have a git branch I can use?
Florian Weimer June 6, 2018, 2:54 p.m. UTC | #9
On 06/06/2018 04:50 PM, H.J. Lu wrote:
> On Wed, Jun 6, 2018 at 7:04 AM, Florian Weimer <fweimer@redhat.com> wrote:
>> On 06/05/2018 09:24 PM, Florian Weimer wrote:
>>>
>>> On 05/28/2018 09:51 PM, H.J. Lu wrote:
>>>>
>>>> Here is the updated patch.  It fails to back lazy binding only
>>>> if GOT is writable.
>>>
>>>
>>> I think this still sets a wrong incentive, as in “you need to have a
>>> writable GOT for full forwards compatibility with future library evolution”.
>>>
>>> I think if we detect an IFUNC-based relocation against a
>>> not-yet-fully-relocated object, we need to delay this relocation processing
>>> and perform a second pass of all delayed relocations.  I have a patch which
>>> needs a little bit of work, but looks quite promising (to me at least).
>>
>>
>> Here are my patches:
>>
>> https://sourceware.org/ml/libc-alpha/2018-06/msg00076.html
>> https://sourceware.org/ml/libc-alpha/2018-06/msg00077.html
>>
>> I hope they address your needs.
> 
> Do you have a git branch I can use?

I've pushed it to fw/bug21242.

Florian
H.J. Lu June 6, 2018, 3:38 p.m. UTC | #10
On Wed, Jun 6, 2018 at 7:54 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 06/06/2018 04:50 PM, H.J. Lu wrote:
>>
>> On Wed, Jun 6, 2018 at 7:04 AM, Florian Weimer <fweimer@redhat.com> wrote:
>>>
>>> On 06/05/2018 09:24 PM, Florian Weimer wrote:
>>>>
>>>>
>>>> On 05/28/2018 09:51 PM, H.J. Lu wrote:
>>>>>
>>>>>
>>>>> Here is the updated patch.  It fails to back lazy binding only
>>>>> if GOT is writable.
>>>>
>>>>
>>>>
>>>> I think this still sets a wrong incentive, as in “you need to have a
>>>> writable GOT for full forwards compatibility with future library
>>>> evolution”.
>>>>
>>>> I think if we detect an IFUNC-based relocation against a
>>>> not-yet-fully-relocated object, we need to delay this relocation
>>>> processing
>>>> and perform a second pass of all delayed relocations.  I have a patch
>>>> which
>>>> needs a little bit of work, but looks quite promising (to me at least).
>>>
>>>
>>>
>>> Here are my patches:
>>>
>>> https://sourceware.org/ml/libc-alpha/2018-06/msg00076.html
>>> https://sourceware.org/ml/libc-alpha/2018-06/msg00077.html
>>>
>>> I hope they address your needs.
>>
>>
>> Do you have a git branch I can use?
>
>
> I've pushed it to fw/bug21242.
>

I pushed hjl/pr23240/fw, which is fw/bug21242 + tests for [BZ #23176] and
[BZ #23240].

1. On x86-64:

FAIL: elf/reldep6a

2. On i686:

FAIL: elf/ifuncpreload1
FAIL: elf/reldep6a

So your patches didn't fix:

1,. IFUNC on i686.
2.  Weak reference.
Florian Weimer June 6, 2018, 3:53 p.m. UTC | #11
On 06/06/2018 05:38 PM, H.J. Lu wrote:
> I pushed hjl/pr23240/fw, which is fw/bug21242 + tests for [BZ #23176] and
> [BZ #23240].
> 
> 1. On x86-64:
> 
> FAIL: elf/reldep6a

The crash happens because “weak” is undefined in reldep6mod1.so.

The “weak” function is defined in reldep6mod4.so.  But reldep6mod1.so is 
loaded before reldep6mod4.so:

      14289:     calling init: 
/home/fweimer/src/gnu/glibc/build/elf/reldep6mod1.so
…
      14289:     opening 
file=/home/fweimer/src/gnu/glibc/build/elf/reldep6mod4.so [0]; 
direct_opencount=1
      14289:
      14289:     binding file 
/home/fweimer/src/gnu/glibc/build/elf/reldep6mod4.so [0] to 
/home/fweimer/src/gnu/glibc/build/elf/reldep6mod1.so [0]: normal symbol 
`baz'

I think this is simply invalid.  I think that if you had a “weak == 
NULL” check in reldep6mod1.so, it would be false even after loading 
reldep6mod4.so because the address is not lazily bound.

Is this derived from the X server use case, where they load additional 
DSOs which provide definitions of functions which are lazily bound? 
That's just not compatible with BIND_NOW, and I don't see a compelling 
reason why it should be.  If it's just about fixing X, then we need to 
fix X, and not enhance the dynamic linker.

> 2. On i686:
> 
> FAIL: elf/ifuncpreload1
> FAIL: elf/reldep6a

There's no delayed processing for i686 yet.  I wanted to get consensus 
on the overall approach first.

Thanks,
Florian
H.J. Lu June 6, 2018, 4:10 p.m. UTC | #12
On Wed, Jun 6, 2018 at 8:53 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 06/06/2018 05:38 PM, H.J. Lu wrote:
>>
>> I pushed hjl/pr23240/fw, which is fw/bug21242 + tests for [BZ #23176] and
>> [BZ #23240].
>>
>> 1. On x86-64:
>>
>> FAIL: elf/reldep6a
>
>
> The crash happens because “weak” is undefined in reldep6mod1.so.
>
> The “weak” function is defined in reldep6mod4.so.  But reldep6mod1.so is
> loaded before reldep6mod4.so:
>
>      14289:     calling init:
> /home/fweimer/src/gnu/glibc/build/elf/reldep6mod1.so
> …
>      14289:     opening
> file=/home/fweimer/src/gnu/glibc/build/elf/reldep6mod4.so [0];
> direct_opencount=1
>      14289:
>      14289:     binding file
> /home/fweimer/src/gnu/glibc/build/elf/reldep6mod4.so [0] to
> /home/fweimer/src/gnu/glibc/build/elf/reldep6mod1.so [0]: normal symbol
> `baz'
>
> I think this is simply invalid.  I think that if you had a “weak == NULL”
> check in reldep6mod1.so, it would be false even after loading reldep6mod4.so
> because the address is not lazily bound.
>
> Is this derived from the X server use case, where they load additional DSOs

No idea.  It is in elf.

> which provide definitions of functions which are lazily bound? That's just
> not compatible with BIND_NOW, and I don't see a compelling reason why it
> should be.  If it's just about fixing X, then we need to fix X, and not
> enhance the dynamic linker.
>
>> 2. On i686:
>>
>> FAIL: elf/ifuncpreload1
>> FAIL: elf/reldep6a
>
>
> There's no delayed processing for i686 yet.  I wanted to get consensus on
> the overall approach first.
>
> Thanks,
> Florian
Florian Weimer June 6, 2018, 5:30 p.m. UTC | #13
On 06/06/2018 06:10 PM, H.J. Lu wrote:

>> Is this derived from the X server use case, where they load additional DSOs
> 
> No idea.  It is in elf.

So you have just run the elf testsuite with LD_BIND_NOW=1 and filed a 
bug because the test failed?

I'm not sure if such purely synthetic test cases make sense.  If you 
want to get rid of lazy binding, you should concentrate on actual issues 
in the GNU system (such as the X issue I mentioned).

Thanks,
Florian
diff mbox series

Patch

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)