LLD and glibc

Message ID c0f2887b-8f57-f1e8-bd52-401b616770c0@linaro.org
State Not applicable
Headers
Series LLD and glibc |

Checks

Context Check Description
dj/TryBot-apply_patch fail Patch failed to apply to master at the time it was sent
dj/TryBot-32bit fail Patch series failed to apply

Commit Message

Adhemerval Zanella Netto Oct. 25, 2021, 2:53 p.m. UTC
  I tracked down the issues with lld on glibc and it seems slight better
than my previous attempt.

To use lld without having to mess with my toolchain installation, I was
trying to use -fuse-ld=lld plus -B option.  However it does not work
correctly with the LIBC_PROG_BINUTILS macro, since it issues the
passed CC with -print-prog-name=ld.  In this case gcc will always dump
the ld path, not the lld (it does work if I use -print-prog-name=lld).
I think this is a gcc issue since it should be agnostic whether
-fuse-ld is used, but I think we can try to workaround it on glibc
configure (use the -fuse-ld argument on -print-prog-name if the former
is presented).

So to actually use lld I had to adjust the links on my build-many-glibcs
built toolchain to explicit point to lld (both bin/x86_64-glibc-linux-gnu-ld
and x86_64-glibc-linux-gnu/bin/ld).

The new issue is the same H.J has reported some time earlier:

ld: error: cannot preempt symbol: foo_protected
>>> defined in /home/azanella/Projects/glibc/build/x86_64-linux-gnu-lld/elf/ifuncmod5.so
>>> referenced by ifuncmain5.c:22 (/home/azanella/Projects/glibc/glibc-git/elf/ifuncmain5.c:22)
>>>               /home/azanella/Projects/glibc/build/x86_64-linux-gnu-lld/elf/ifuncmain5.o:(get_foo_protected)

I think we should just disable the tests ldd does not support (with the
patch below) instead of get back of the discussion whether it should be
supported or not.

The good news is with release clang+llvm 13 and with the testcase patch
I could build and run make check successfully without any regression.

I am writing this because we need to fix both issues (configure with -fuse-ld
and the failure on make check) so we can start review the DT_RELR patchset [1]

[1] https://patchwork.sourceware.org/project/glibc/list/?series=3895

---
  

Comments

Fangrui Song Oct. 25, 2021, 4:53 p.m. UTC | #1
On 2021-10-25, Adhemerval Zanella wrote:
>I tracked down the issues with lld on glibc and it seems slight better
>than my previous attempt.
>
>To use lld without having to mess with my toolchain installation, I was
>trying to use -fuse-ld=lld plus -B option.  However it does not work
>correctly with the LIBC_PROG_BINUTILS macro, since it issues the
>passed CC with -print-prog-name=ld.  In this case gcc will always dump
>the ld path, not the lld (it does work if I use -print-prog-name=lld).
>I think this is a gcc issue since it should be agnostic whether
>-fuse-ld is used, but I think we can try to workaround it on glibc
>configure (use the -fuse-ld argument on -print-prog-name if the former
>is presented).
>
>So to actually use lld I had to adjust the links on my build-many-glibcs
>built toolchain to explicit point to lld (both bin/x86_64-glibc-linux-gnu-ld
>and x86_64-glibc-linux-gnu/bin/ld).
>
>The new issue is the same H.J has reported some time earlier:
>
>ld: error: cannot preempt symbol: foo_protected
>>>> defined in /home/azanella/Projects/glibc/build/x86_64-linux-gnu-lld/elf/ifuncmod5.so
>>>> referenced by ifuncmain5.c:22 (/home/azanella/Projects/glibc/glibc-git/elf/ifuncmain5.c:22)
>>>>               /home/azanella/Projects/glibc/build/x86_64-linux-gnu-lld/elf/ifuncmain5.o:(get_foo_protected)
>
>I think we should just disable the tests ldd does not support (with the
>patch below) instead of get back of the discussion whether it should be
>supported or not.
>
>The good news is with release clang+llvm 13 and with the testcase patch
>I could build and run make check successfully without any regression.
>
>I am writing this because we need to fix both issues (configure with -fuse-ld
>and the failure on make check) so we can start review the DT_RELR patchset [1]
>
>[1] https://patchwork.sourceware.org/project/glibc/list/?series=3895
>
>---
>
>diff --git a/elf/Makefile b/elf/Makefile
>index bdcf4cb885..7ddc4b39a3 100644
>--- a/elf/Makefile
>+++ b/elf/Makefile
>@@ -427,11 +427,14 @@ ifeq (yes,$(build-shared))
> tests += tst-ifunc-fault-lazy tst-ifunc-fault-bindnow
> # Note: sysdeps/x86_64/ifuncmain8.c uses ifuncmain8.
> tests-internal += \
>-        ifuncmain1 ifuncmain1pic ifuncmain1vis ifuncmain1vispic \
>+        ifuncmain1pic ifuncmain1vis ifuncmain1vispic \
>         ifuncmain1staticpic \
>         ifuncmain2 ifuncmain2pic ifuncmain3 ifuncmain4 \
>-        ifuncmain5 ifuncmain5pic ifuncmain5staticpic \
>+        ifuncmain5pic ifuncmain5staticpic \
>         ifuncmain7 ifuncmain7pic
>+ifeq (no,$(with-lld))
>+test-internal += ifuncmain1 ifuncmain5
>+endif
> ifeq (yes,$(have-gcc-ifunc))
> tests-internal += ifuncmain9 ifuncmain9pic
> endif
>@@ -451,7 +454,10 @@ endif
> tests-internal += $(ifunc-pie-tests)
> tests-pie += $(ifunc-pie-tests)
> endif
>-modules-names += ifuncmod1 ifuncmod3 ifuncmod5 ifuncmod6
>+modules-names += ifuncmod1 ifuncmod3 ifuncmod6
>+ifeq (no,$(with-lld))
>+modules-names += ifuncmod5 >+endif
> endif
> endif
>
>
>

ifuncmain1.c and ifuncmain5.c take the address of the function `foo_protected`.
If compiled with -fno-pic, the produced relocation is R_X86_64_PC32.

In gold and LLD, it is an error to reference an undefined function symbol
with a non-GOT-generating non-PLT-generating relocation from the main
executable (LLD call it "cannot preempt symbol: foo_protected").
This is to guard against risky canonical PLT entry which cannot work
with a protected definition
(https://maskray.me/blog/2021-01-09-copy-relocations-canonical-plt-entries-and-protected).

(I wonder why the test can link with GNU ld. We know it has some limited
support for "copy relocations on protected data symbols" "on x86 but I
don't know it does anything with function symbols. Anyway, protected
function symbols are quite broken in GCC that is why ifuncmod5.c uses
inline assembly instead of proper visibility attribute.)

I could not reproduce the link error because on most Linux
distributions, GCC is configured with enable-default-pie and
ifuncmain5.c is compiled with the implicit -fpie. If I manually compile
ifuncmain5.c with -fno-pic and re-link ifuncmain5 with LLD, I can see
the intended diagnostic "cannot preempt symbol: foo_protected".

You may want to take some of the description to make up a better commit
message.

Reviewed-by: Fangrui Song <maskray@google.com>
  

Patch

diff --git a/elf/Makefile b/elf/Makefile
index bdcf4cb885..7ddc4b39a3 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -427,11 +427,14 @@  ifeq (yes,$(build-shared))
 tests += tst-ifunc-fault-lazy tst-ifunc-fault-bindnow
 # Note: sysdeps/x86_64/ifuncmain8.c uses ifuncmain8.
 tests-internal += \
-        ifuncmain1 ifuncmain1pic ifuncmain1vis ifuncmain1vispic \
+        ifuncmain1pic ifuncmain1vis ifuncmain1vispic \
         ifuncmain1staticpic \
         ifuncmain2 ifuncmain2pic ifuncmain3 ifuncmain4 \
-        ifuncmain5 ifuncmain5pic ifuncmain5staticpic \
+        ifuncmain5pic ifuncmain5staticpic \
         ifuncmain7 ifuncmain7pic
+ifeq (no,$(with-lld))
+test-internal += ifuncmain1 ifuncmain5
+endif
 ifeq (yes,$(have-gcc-ifunc))
 tests-internal += ifuncmain9 ifuncmain9pic
 endif
@@ -451,7 +454,10 @@  endif
 tests-internal += $(ifunc-pie-tests)
 tests-pie += $(ifunc-pie-tests)
 endif
-modules-names += ifuncmod1 ifuncmod3 ifuncmod5 ifuncmod6
+modules-names += ifuncmod1 ifuncmod3 ifuncmod6
+ifeq (no,$(with-lld))
+modules-names += ifuncmod5
+endif
 endif
 endif