[PATCH v2 3/3] configure: Allow LD to be LLD 13.0.0 or above [BZ #26558]

Fāng-ruì Sòng maskray@google.com
Sat Aug 7 00:47:59 GMT 2021


On 2021-08-05, H.J. Lu wrote:
>On Thu, Aug 5, 2021 at 9:43 AM Fāng-ruì Sòng <maskray@google.com> wrote:
>>
>> On Thu, Aug 5, 2021 at 9:34 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>> >
>> > On Thu, Aug 5, 2021 at 9:29 AM Fangrui Song via Libc-alpha
>> > <libc-alpha@sourceware.org> wrote:
>> > >
>> > > When using LLD (LLVM linker) as the linker, configure prints a confusing
>> > > message.
>> > >
>> > >     *** These critical programs are missing or too old: GNU ld
>> > >
>> > > LLD>=13.0.0 can build glibc --enable-static-pie. (8.0.0 needs one
>> > > workaround for -Wl,-defsym=_begin=0. 9.0.0 works with
>> > > --disable-static-pie).
>> > >
>> > > With BZ #28153 (glibc bug exposed by testing with LLD) fixed,
>> > > `make check` only has 2 more failures with LLD than with GNU ld:
>> > > BZ #28154 (LLD follows the PowerPC port of GNU ld for ifunc by
>> > > placing IRELATIVE relocations in .rela.dyn).
>> >
>> > This is an lld bug, similar to:
>> >
>> > https://sourceware.org/bugzilla/show_bug.cgi?id=13302
>> >
>> > Please fix it at least on x86.
>>
>> I am afraid that I disagree. The PowerPC port of GNU ld does the right
>
>This is just one opinion and it doesn't make it "the right thing".
>
>> thing and LLD follows suit.
>> R_*_IRELATIVE relocations should be eagerly resolved, so they belong
>> to .rela.dyn instead of .rela.plt.
>
>Ulrich and I designed/implemented IFUNC on x86 and for x86.  I consider
>x86 implementation of IFUC as the gold standard.

kib from FreeBSD said

"FreeBSD rtld does the initial pass over the plt relocations and handles
R_X86_64_JMP_SLOT only, If there are any R_X86_64_IRELATIVE relocks, we
mark the object as having such relocations. Then, we do the ireloc
processing, using the depth-first descend. We handle all IRELOCs for
dependent objects before doing it for dependee. There, we iterate over
all plt relocs to select IRELOCs."

I pondered at this comment

/*
  * The handling of R_MACHINE_IRELATIVE relocations and jumpslots
  * referencing STT_GNU_IFUNC symbols is postponed till the other
  * relocations are done.  The indirect functions specified as
  * ifunc are allowed to call other symbols, so we need to have
  * objects relocated before asking for resolution from indirects.
  *
  * The R_MACHINE_IRELATIVE slots are resolved in greedy fashion,
  * instead of the usual lazy handling of PLT slots.  It is
  * consistent with how GNU does it.
  */

and re-read https://sourceware.org/glibc/wiki/GNU_IFUNC

"This may work on x86_64 where the R_*_IRELATIVE relocations happen in
DT_JMPREL after the DT_REL* relocations, but that is no guarantee that it will
work on AArch64, PPC64, or other architectures that are slightly different.
Such fundamental limitations may be lifted at a future point."

I think adopting the FreeBSD approach can make IRELATIVE more robust, even for
x86. IRELATIVE is still eager resolved, just postponed after other relocations.
Fixing this property in glibc will improve rubustness/flexibility of ifunc
resolvers and freeing linkers the responsibility to order IRELATIVE in a
particular position.

Pioneering on one feature gives the designer respect, yet the designer can only
earn authority by demonstrating the consideration of all sort of implication.

>> The objection argument
>> https://sourceware.org/bugzilla/show_bug.cgi?id=28154#c3 is kinda
>> weak:
>>
>> > This requires both linker and ld.so changes.  The PR ld/13302 linker change doesn't require ld.so change.
>>
>> Working around the glibc ld.so issue on GNU ld side was probably
>> simpler, but that does not justify the GNU ld change.
>>
>> I mentioned at #c2 about the proper way on the glibc side.
>>
>> But our conflict here may be moot because in practice ifunc should not
>> have such PLT calls, they would be unreliable on other architectures
>> anyway.
>>
>> > > The set of dynamic symbols is the same with GNU ld and LLD,
>> > > modulo unused SHN_ABS version node symbols.
>> > >
>> > > For comparison, gold does not support --enable-static-pie
>> > > yet (--no-dynamic-linker is unsupported BZ #22221), yet
>> > > has 6 failures more than LLD. gold linked libc.so has
>> > > larger .dynsym differences with GNU ld and LLD
>> > > (ISTM non-default version symbols are changed to default versions
>> > > by a version script).
>> > >
>> > > ---
>> > >
>> > > I identified the lack of support of
>> > >
>> > > * version script on non-default version symbols
>> > > * copy relocations on non-default version symbols
>> > >
>> > > in an earlier snapshot of LLD 13.0.0 and fixed them.
>> > > The functionality of the LLD linked libc.so and ld.so looks pretty good.
>> > > ---
>> > >  configure    | 77 +++++++++++++++++++++++++++++++++++++++++++++++++---
>> > >  configure.ac | 20 ++++++++++----
>> > >  2 files changed, 88 insertions(+), 9 deletions(-)
>> > >
>> > > diff --git a/configure b/configure
>> > > index 9b966196d4..050f1a29cf 100755
>> > > --- a/configure
>> > > +++ b/configure
>> > > @@ -4664,9 +4664,10 @@ if test $ac_verc_fail = yes; then
>> > >  fi
>> > >
>> > >
>> > > -if test -n "`$LD --version | sed -n 's/^GNU \(gold\).*$/\1/p'`"; then
>> > > +case $($LD --version) in
>> > > +  "GNU gold"*)
>> > >    # Accept gold 1.14 or higher
>> > > -  for ac_prog in $LD
>> > > +    for ac_prog in $LD
>> > >  do
>> > >    # Extract the first word of "$ac_prog", so it can be a program name with args.
>> > >  set dummy $ac_prog; ac_word=$2
>> > > @@ -4729,8 +4730,75 @@ if test $ac_verc_fail = yes; then
>> > >    LD=: critic_missing="$critic_missing GNU gold"
>> > >  fi
>> > >
>> > > +    ;;
>> > > +  "LLD"*)
>> > > +  # Accept LLD 13.0.0 or higher
>> > > +    for ac_prog in $LD
>> > > +do
>> > > +  # Extract the first word of "$ac_prog", so it can be a program name with args.
>> > > +set dummy $ac_prog; ac_word=$2
>> > > +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
>> > > +$as_echo_n "checking for $ac_word... " >&6; }
>> > > +if ${ac_cv_prog_LD+:} false; then :
>> > > +  $as_echo_n "(cached) " >&6
>> > >  else
>> > > -  for ac_prog in $LD
>> > > +  if test -n "$LD"; then
>> > > +  ac_cv_prog_LD="$LD" # Let the user override the test.
>> > > +else
>> > > +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
>> > > +for as_dir in $PATH
>> > > +do
>> > > +  IFS=$as_save_IFS
>> > > +  test -z "$as_dir" && as_dir=.
>> > > +    for ac_exec_ext in '' $ac_executable_extensions; do
>> > > +  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
>> > > +    ac_cv_prog_LD="$ac_prog"
>> > > +    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
>> > > +    break 2
>> > > +  fi
>> > > +done
>> > > +  done
>> > > +IFS=$as_save_IFS
>> > > +
>> > > +fi
>> > > +fi
>> > > +LD=$ac_cv_prog_LD
>> > > +if test -n "$LD"; then
>> > > +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
>> > > +$as_echo "$LD" >&6; }
>> > > +else
>> > > +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
>> > > +$as_echo "no" >&6; }
>> > > +fi
>> > > +
>> > > +
>> > > +  test -n "$LD" && break
>> > > +done
>> > > +
>> > > +if test -z "$LD"; then
>> > > +  ac_verc_fail=yes
>> > > +else
>> > > +  # Found it, now check the version.
>> > > +  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $LD" >&5
>> > > +$as_echo_n "checking version of $LD... " >&6; }
>> > > +  ac_prog_version=`$LD --version 2>&1 | sed -n 's/^.*LLD.* \([0-9][0-9]*\.[0-9.]*\).*$/\1/p'`
>> > > +  case $ac_prog_version in
>> > > +    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
>> > > +    1[3-9].*|[2-9][0-9].*)
>> > > +       ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
>> > > +    *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
>> > > +
>> > > +  esac
>> > > +  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_prog_version" >&5
>> > > +$as_echo "$ac_prog_version" >&6; }
>> > > +fi
>> > > +if test $ac_verc_fail = yes; then
>> > > +  LD=: critic_missing="$critic_missing LLD"
>> > > +fi
>> > > +
>> > > +    ;;
>> > > +  *)
>> > > +    for ac_prog in $LD
>> > >  do
>> > >    # Extract the first word of "$ac_prog", so it can be a program name with args.
>> > >  set dummy $ac_prog; ac_word=$2
>> > > @@ -4793,7 +4861,8 @@ if test $ac_verc_fail = yes; then
>> > >    LD=: critic_missing="$critic_missing GNU ld"
>> > >  fi
>> > >
>> > > -fi
>> > > +    ;;
>> > > +esac
>> > >
>> > >  # These programs are version sensitive.
>> > >  for ac_prog in gnumake gmake make
>> > > diff --git a/configure.ac b/configure.ac
>> > > index 17a4c9a1ab..5632277f9c 100644
>> > > --- a/configure.ac
>> > > +++ b/configure.ac
>> > > @@ -995,18 +995,28 @@ AC_CHECK_PROG_VER(AS, $AS, --version,
>> > >                   [2.1[0-9][0-9]*|2.2[5-9]*|2.[3-9][0-9]*|[3-9].*|[1-9][0-9]*],
>> > >                   AS=: critic_missing="$critic_missing as")
>> > >
>> > > -if test -n "`$LD --version | sed -n 's/^GNU \(gold\).*$/\1/p'`"; then
>> > > +case $($LD --version) in
>> > > +  "GNU gold"*)
>> > >    # Accept gold 1.14 or higher
>> > > -  AC_CHECK_PROG_VER(LD, $LD, --version,
>> > > +    AC_CHECK_PROG_VER(LD, $LD, --version,
>> > >                     [GNU gold.* \([0-9][0-9]*\.[0-9.]*\)],
>> > >                     [1.1[4-9]*|1.[2-9][0-9]*|1.1[0-9][0-9]*|[2-9].*|[1-9][0-9]*],
>> > >                     LD=: critic_missing="$critic_missing GNU gold")
>> > > -else
>> > > -  AC_CHECK_PROG_VER(LD, $LD, --version,
>> > > +    ;;
>> > > +  "LLD"*)
>> > > +  # Accept LLD 13.0.0 or higher
>> > > +    AC_CHECK_PROG_VER(LD, $LD, --version,
>> > > +                   [LLD.* \([0-9][0-9]*\.[0-9.]*\)],
>> > > +                   [1[3-9].*|[2-9][0-9].*],
>> > > +                   LD=: critic_missing="$critic_missing LLD")
>> > > +    ;;
>> > > +  *)
>> > > +    AC_CHECK_PROG_VER(LD, $LD, --version,
>> > >                     [GNU ld.* \([0-9][0-9]*\.[0-9.]*\)],
>> > >                     [2.1[0-9][0-9]*|2.2[5-9]*|2.[3-9][0-9]*|[3-9].*|[1-9][0-9]*],
>> > >                     LD=: critic_missing="$critic_missing GNU ld")
>> > > -fi
>> > > +    ;;
>> > > +esac
>> > >
>> > >  # These programs are version sensitive.
>> > >  AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version,
>> > > --
>> > > 2.32.0.605.g8dce9f2422-goog
>
>
>
>--
>H.J.


More information about the Libc-alpha mailing list