unofficial mirror of libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/7] Fixing remaining lld issues
@ 2022-11-15 19:31 Adhemerval Zanella via Libc-alpha
  2022-11-15 19:31 ` [PATCH 1/7] configure: Move locale tools early Adhemerval Zanella via Libc-alpha
                   ` (6 more replies)
  0 siblings, 7 replies; 25+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2022-11-15 19:31 UTC (permalink / raw)
  To: libc-alpha, Fangrui Song

There are still some issue while trying to build and check glibc
with lld:

  - The vtables hardening are not enabled with --with-default-link=no
    (tst-relro-libc fails [1]) and with --with-default-link=yes also
    requires ld.bfd to be available [2].  Furthermore, only lld 15
    supports custom RELRO sections in linker script.  

  - elf/tst-audit25 assumes a specific symbol order, where lld and bfd
    differs slight.

First patch fixes an issue with --with-binutils, where the specified
linker is not used for some early checks.  It trigger additional
test failures with lld if --with-binutils is used to override the
default linker.

Second patch fixes tst-audit25 symbol order.

Third, forth, and fifth removes the --with-default-link by moving the
_IO_cleanup (used on exit) to call_function_static_weak, by replacing
libc_freeres_ptrs and libc_subfreeres with weak function calls, and by
refactoring the vtables hardening with a array placed directly on
RELRO segment.

Finally --with-default-link is removed and set-hooks.h mechanism
(which is a clunky interface) is moved to be Hurd-only.

I checked on all affected ABIs and did a full test on both x86_64
and aarch64.

[1] https://sourceware.org/bugzilla/show_bug.cgi?id=25812
[2] https://sourceware.org/git/?p=glibc.git;a=commit;h=2ae7990542e1955097aa21943e416dec70f867fa

Adhemerval Zanella (7):
  configure: Move locale tools early
  elf: Do not assume symbol order on tst-audit25{a,b}
  stdlib: Move _IO_cleanup to call_function_static_weak
  Move libc_freeres_ptrs and libc_subfreeres to weak functions
  libio: Remove the usage of __libc_IO_vtables
  Remove --with-default-link configure option
  Remove set-hooks.h from generic includes

 INSTALL                                       |    6 -
 Makerules                                     |   55 +-
 config.make.in                                |    1 -
 configure                                     | 2169 ++++++++---------
 configure.ac                                  |  245 +-
 crypt/md5-crypt.c                             |   10 +-
 crypt/sha256-crypt.c                          |   10 +-
 crypt/sha512-crypt.c                          |   10 +-
 elf/Makefile                                  |   23 +-
 elf/dl-libc.c                                 |    4 +-
 elf/tst-audit25.h                             |   46 +
 elf/tst-audit25a.c                            |   38 +-
 elf/tst-audit25b.c                            |   39 +-
 grp/fgetgrent.c                               |    8 +-
 gshadow/fgetsgent.c                           |    2 +-
 {include => hurd}/set-hooks.h                 |    0
 iconv/gconv_cache.c                           |    3 +-
 iconv/gconv_conf.c                            |    3 +-
 iconv/gconv_db.c                              |    6 +-
 iconv/gconv_dl.c                              |    5 +-
 iconvdata/extra-module.mk                     |    2 +-
 include/libc-symbols.h                        |   91 +-
 inet/getnameinfo.c                            |    8 +-
 inet/getnetgrent.c                            |    8 +-
 inet/rcmd.c                                   |    8 +-
 inet/rexec.c                                  |    8 +-
 intl/dcigettext.c                             |    3 +-
 intl/finddomain.c                             |    2 +-
 intl/loadmsgcat.c                             |    1 -
 intl/localealias.c                            |   15 +-
 libio/Makefile                                |    2 +
 libio/fileops.c                               |   81 +-
 libio/genops.c                                |   10 +-
 libio/iofopncook.c                            |   60 +-
 libio/iopopen.c                               |   25 -
 libio/iovsprintf.c                            |   26 +-
 libio/libio-macros.sym                        |    7 +
 libio/libioP.h                                |  312 ++-
 libio/memstream.c                             |   32 +-
 libio/obprintf.c                              |   34 +-
 libio/oldfileops.c                            |   23 -
 libio/oldiopopen.c                            |   23 -
 libio/stdio.c                                 |    3 +
 libio/strfile.h                               |    5 -
 libio/strops.c                                |   24 -
 libio/tst-vtables-interposed.c                |    5 +
 libio/vsnprintf.c                             |   29 +-
 libio/vswprintf.c                             |   30 +-
 libio/vtables.c                               |  502 ++++
 libio/wfileops.c                              |   79 +-
 libio/wmemstream.c                            |   32 +-
 libio/wstrops.c                               |   24 -
 locale/loadarchive.c                          |    2 +-
 locale/localeinfo.h                           |    4 +-
 locale/setlocale.c                            |    4 +-
 login/getutent.c                              |    8 +-
 login/getutid.c                               |    8 +-
 login/getutline.c                             |    8 +-
 malloc/set-freeres.c                          |  222 +-
 malloc/thread-freeres.c                       |    2 +-
 manual/install.texi                           |    6 -
 misc/efgcvt-template.c                        |    8 +-
 misc/efgcvt.c                                 |    1 +
 misc/fstab.c                                  |    3 +-
 misc/hsearch.c                                |    4 -
 misc/mntent.c                                 |    8 +-
 misc/qefgcvt.c                                |    1 +
 misc/unwind-link.c                            |    2 +-
 nptl/nptlfreeres.c                            |    1 -
 nscd/nscd_getgr_r.c                           |    3 +-
 nscd/nscd_gethst_r.c                          |    3 +-
 nscd/nscd_getpw_r.c                           |    3 +-
 nscd/nscd_getserv_r.c                         |    3 +-
 nscd/nscd_netgroup.c                          |    3 +-
 nss/getXXbyYY.c                               |   10 +-
 nss/getXXent.c                                |   10 +-
 nss/nss_action.c                              |    2 +-
 nss/nss_database.c                            |    2 +-
 nss/nss_module.c                              |    2 +-
 posix/regcomp.c                               |    3 +-
 posix/register-atfork.c                       |    3 +-
 pwd/fgetpwent.c                               |    8 +-
 resolv/gai_misc.c                             |    3 +-
 resolv/res-close.c                            |    2 -
 resolv/res_hconf.c                            |    9 +-
 resolv/resolv_conf.c                          |    3 +-
 resolv/tst-leaks2.c                           |    2 +
 rt/aio_misc.c                                 |    3 +-
 shadow/fgetspent.c                            |    8 +-
 stdio-common/reg-modifier.c                   |    3 +-
 stdio-common/reg-printf.c                     |    9 +-
 stdio-common/reg-type.c                       |    9 +-
 stdio-common/vfprintf-internal.c              |   60 +-
 stdlib/exit.c                                 |    6 +-
 stdlib/fmtmsg.c                               |    3 +-
 stdlib/setenv.c                               |    3 +-
 sunrpc/clnt_perr.c                            |    4 +-
 sunrpc/rpc_thread.c                           |    1 -
 sunrpc/tst-svc_register.c                     |    6 +-
 sysdeps/generic/set-freeres-fp.h              |   19 +
 sysdeps/generic/set-freeres-os.h              |   19 +
 sysdeps/generic/set-freeres-system.h          |   27 +
 .../ldbl-128ibm-compat/ieee128-qefgcvt.c      |    1 +
 .../ldbl-128ibm-compat/set-freeres-fp.h       |   22 +
 sysdeps/mach/hurd/bits/errno.h                |    1 -
 sysdeps/posix/getaddrinfo.c                   |    5 +-
 sysdeps/posix/ttyname.c                       |    8 +-
 sysdeps/unix/sysv/linux/check_pf.c            |    3 +-
 sysdeps/unix/sysv/linux/set-freeres-os.h      |   24 +
 sysdeps/unix/sysv/linux/ttyname.c             |    3 +-
 time/tzfile.c                                 |    8 +-
 time/tzset.c                                  |    3 +-
 112 files changed, 2618 insertions(+), 2203 deletions(-)
 create mode 100644 elf/tst-audit25.h
 rename {include => hurd}/set-hooks.h (100%)
 create mode 100644 libio/libio-macros.sym
 create mode 100644 sysdeps/generic/set-freeres-fp.h
 create mode 100644 sysdeps/generic/set-freeres-os.h
 create mode 100644 sysdeps/generic/set-freeres-system.h
 create mode 100644 sysdeps/ieee754/ldbl-128ibm-compat/set-freeres-fp.h
 create mode 100644 sysdeps/unix/sysv/linux/set-freeres-os.h

-- 
2.34.1


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

* [PATCH 1/7] configure: Move locale tools early
  2022-11-15 19:31 [PATCH 0/7] Fixing remaining lld issues Adhemerval Zanella via Libc-alpha
@ 2022-11-15 19:31 ` Adhemerval Zanella via Libc-alpha
  2022-11-15 19:31 ` [PATCH 2/7] elf: Do not assume symbol order on tst-audit25{a,b} Adhemerval Zanella via Libc-alpha
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 25+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2022-11-15 19:31 UTC (permalink / raw)
  To: libc-alpha, Fangrui Song

When using --with-binutils, the configure might not use the specified
linker or assembler while checking for expected support.  Move the
tools check early, before any compiler usage test.
---
 configure    | 2304 +++++++++++++++++++++++++-------------------------
 configure.ac |  238 +++---
 2 files changed, 1271 insertions(+), 1271 deletions(-)

diff --git a/configure b/configure
index cb0996d59e..9a8acc4ef7 100755
--- a/configure
+++ b/configure
@@ -635,6 +635,14 @@ CXX_CMATH_HEADER
 CXX_CSTDLIB_HEADER
 CXX_SYSINCLUDES
 SYSINCLUDES
+sysnames
+submachine
+multi_arch
+libc_cv_textrel_ifunc
+no_stack_protector
+stack_protector
+libc_cv_ssp
+libc_cv_with_fp
 PYTHON
 PYTHON_PROG
 AUTOCONF
@@ -654,14 +662,6 @@ LN_S
 INSTALL_DATA
 INSTALL_SCRIPT
 INSTALL_PROGRAM
-sysnames
-submachine
-multi_arch
-libc_cv_textrel_ifunc
-no_stack_protector
-stack_protector
-libc_cv_ssp
-libc_cv_with_fp
 base_machine
 have_tunables
 build_pt_chown
@@ -4025,709 +4025,646 @@ fi
 test -n "$base_machine" || base_machine=$machine
 
 
-# Determine whether to use fpu or nofpu sysdeps directories.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for use of fpu sysdeps directories" >&5
-$as_echo_n "checking for use of fpu sysdeps directories... " >&6; }
-if ${libc_cv_with_fp+:} false; then :
+### Locate tools.
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  cat > conftest.c <<EOF
-#if $with_fp_cond
-int dummy;
-#else
-# error "no hardware floating point"
-#endif
-EOF
-libc_cv_with_fp=no
-if ${CC-cc} $CFLAGS $CPPFLAGS -S conftest.c -o conftest.s \
-   1>&5 2>&5 ; then
-  libc_cv_with_fp=yes
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    rm -rf conftest.one conftest.two conftest.dir
+	    echo one > conftest.one
+	    echo two > conftest.two
+	    mkdir conftest.dir
+	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+	      test -s conftest.one && test -s conftest.two &&
+	      test -s conftest.dir/conftest.one &&
+	      test -s conftest.dir/conftest.two
+	    then
+	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	      break 3
+	    fi
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
 fi
-rm -f conftest*
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_with_fp" >&5
-$as_echo "$libc_cv_with_fp" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
 
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fstack-protector" >&5
-$as_echo_n "checking for -fstack-protector... " >&6; }
-if ${libc_cv_ssp+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -Werror -fstack-protector -xc /dev/null -S -o /dev/null'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  libc_cv_ssp=yes
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+if test "$INSTALL" = "${srcdir}/scripts/install-sh -c"; then
+  # The makefiles need to use a different form to find it in $srcdir.
+  INSTALL='\$(..)./scripts/install-sh -c'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
 else
-  libc_cv_ssp=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
 fi
 
+
+# Was a --with-binutils option given?
+if test -n "$path_binutils"; then
+    # Make absolute; ensure a single trailing slash.
+    path_binutils=`(cd $path_binutils; pwd) | sed 's%/*$%/%'`
+    CC="$CC -B$path_binutils"
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ssp" >&5
-$as_echo "$libc_cv_ssp" >&6; }
+case "$CC" in
+    *fuse-ld=lld*) LDNAME=ld.lld;;
+    *)             LDNAME=ld;;
+esac
+AS=`$CC -print-prog-name=as`
+LD=`$CC -print-prog-name=$LDNAME`
+AR=`$CC -print-prog-name=ar`
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fstack-protector-strong" >&5
-$as_echo_n "checking for -fstack-protector-strong... " >&6; }
-if ${libc_cv_ssp_strong+:} false; then :
+OBJCOPY=`$CC -print-prog-name=objcopy`
+
+GPROF=`$CC -print-prog-name=gprof`
+
+
+# Determine whether we are using GNU binutils.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $AS is GNU as" >&5
+$as_echo_n "checking whether $AS is GNU as... " >&6; }
+if ${libc_cv_prog_as_gnu+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -Werror -fstack-protector-strong -xc /dev/null -S -o /dev/null'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  libc_cv_ssp_strong=yes
+  # Most GNU programs take a -v and spit out some text including
+# the word 'GNU'.  Some try to read stdin, so give them /dev/null.
+if $AS -o conftest -v </dev/null 2>&1 | grep GNU > /dev/null 2>&1; then
+  libc_cv_prog_as_gnu=yes
 else
-  libc_cv_ssp_strong=no
+  libc_cv_prog_as_gnu=no
 fi
-
+rm -fr contest*
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ssp_strong" >&5
-$as_echo "$libc_cv_ssp_strong" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_prog_as_gnu" >&5
+$as_echo "$libc_cv_prog_as_gnu" >&6; }
+rm -f a.out
+gnu_as=$libc_cv_prog_as_gnu
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fstack-protector-all" >&5
-$as_echo_n "checking for -fstack-protector-all... " >&6; }
-if ${libc_cv_ssp_all+:} false; then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $LD is GNU ld" >&5
+$as_echo_n "checking whether $LD is GNU ld... " >&6; }
+if ${libc_cv_prog_ld_gnu+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -Werror -fstack-protector-all -xc /dev/null -S -o /dev/null'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then :
-  libc_cv_ssp_all=yes
+  # Most GNU programs take a -v and spit out some text including
+# the word 'GNU'.  Some try to read stdin, so give them /dev/null.
+if $LD -o conftest -v </dev/null 2>&1 | grep GNU > /dev/null 2>&1; then
+  libc_cv_prog_ld_gnu=yes
 else
-  libc_cv_ssp_all=no
-fi
-
+  libc_cv_prog_ld_gnu=no
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ssp_all" >&5
-$as_echo "$libc_cv_ssp_all" >&6; }
-
-stack_protector=
-no_stack_protector=
-if test "$libc_cv_ssp" = yes; then
-  no_stack_protector="-fno-stack-protector -DSTACK_PROTECTOR_LEVEL=0"
-  $as_echo "#define HAVE_CC_NO_STACK_PROTECTOR 1" >>confdefs.h
-
+rm -fr contest*
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_prog_ld_gnu" >&5
+$as_echo "$libc_cv_prog_ld_gnu" >&6; }
+gnu_ld=$libc_cv_prog_ld_gnu
 
-if test "$enable_stack_protector" = yes && test "$libc_cv_ssp" = yes; then
-  stack_protector="-fstack-protector"
-  $as_echo "#define STACK_PROTECTOR_LEVEL 1" >>confdefs.h
-
-elif test "$enable_stack_protector" = all && test "$libc_cv_ssp_all" = yes; then
-  stack_protector="-fstack-protector-all"
-  $as_echo "#define STACK_PROTECTOR_LEVEL 2" >>confdefs.h
-
-elif test "$enable_stack_protector" = strong && test "$libc_cv_ssp_strong" = yes; then
-  stack_protector="-fstack-protector-strong"
-  $as_echo "#define STACK_PROTECTOR_LEVEL 3" >>confdefs.h
 
+# Accept binutils 2.25 or newer.
+for ac_prog in $AS
+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_AS+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
-  stack_protector="-fno-stack-protector"
-  $as_echo "#define STACK_PROTECTOR_LEVEL 0" >>confdefs.h
-
-fi
-
-
-
-
-if test -n "$stack_protector"; then
-      no_ssp=-fno-stack-protector
+  if test -n "$AS"; then
+  ac_cv_prog_AS="$AS" # Let the user override the test.
 else
-  no_ssp=
-
-  if test "$enable_stack_protector" != no; then
-    as_fn_error $? "--enable-stack-protector=$enable_stack_protector specified, but specified level of stack protection is not supported by the compiler." "$LINENO" 5
+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_AS="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
   fi
-fi
+done
+  done
+IFS=$as_save_IFS
 
-# For the multi-arch option we need support in the assembler & linker.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for assembler and linker STT_GNU_IFUNC support" >&5
-$as_echo_n "checking for assembler and linker STT_GNU_IFUNC support... " >&6; }
-if ${libc_cv_ld_gnu_indirect_function+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat > conftest.S <<EOF
-.type foo,%gnu_indirect_function
-foo:
-.globl _start
-_start:
-.globl __start
-__start:
-.data
-#ifdef _LP64
-.quad foo
-#else
-.long foo
-#endif
-EOF
-libc_cv_ld_gnu_indirect_function=no
-if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS \
-	    -nostartfiles -nostdlib $no_ssp \
-	    -o conftest conftest.S 1>&5 2>&5; then
-  # Do a link to see if the backend supports IFUNC relocs.
-  $READELF -r conftest 1>&5
-  LC_ALL=C $READELF -Wr conftest | grep -q 'IRELATIVE\|R_SPARC_JMP_IREL' && {
-    libc_cv_ld_gnu_indirect_function=yes
-  }
 fi
-rm -f conftest*
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ld_gnu_indirect_function" >&5
-$as_echo "$libc_cv_ld_gnu_indirect_function" >&6; }
-
-# Check if gcc supports attribute ifunc as it is used in libc_ifunc macro.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc attribute ifunc support" >&5
-$as_echo_n "checking for gcc attribute ifunc support... " >&6; }
-if ${libc_cv_gcc_indirect_function+:} false; then :
-  $as_echo_n "(cached) " >&6
+AS=$ac_cv_prog_AS
+if test -n "$AS"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5
+$as_echo "$AS" >&6; }
 else
-  cat > conftest.c <<EOF
-extern int func (int);
-int used_func (int a)
-{
-  return a;
-}
-static void *resolver ()
-{
-  return &used_func;
-}
-extern __typeof (func) func __attribute__ ((ifunc ("resolver")));
-EOF
-libc_cv_gcc_indirect_function=no
-if ${CC-cc} -c conftest.c -o conftest.o 1>&5 \
-   2>&5 ; then
-  if $READELF -s conftest.o | grep IFUNC >/dev/null 2>&5; then
-    libc_cv_gcc_indirect_function=yes
-  fi
-fi
-rm -f conftest*
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_gcc_indirect_function" >&5
-$as_echo "$libc_cv_gcc_indirect_function" >&6; }
 
-# Check if linker supports textrel relocation with ifunc (used on elf/tests).
-# Note that it relies on libc_cv_ld_gnu_indirect_function test above.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker supports textrels along with ifunc" >&5
-$as_echo_n "checking whether the linker supports textrels along with ifunc... " >&6; }
-if ${libc_cv_textrel_ifunc+:} false; then :
-  $as_echo_n "(cached) " >&6
+
+  test -n "$AS" && break
+done
+
+if test -z "$AS"; then
+  ac_verc_fail=yes
 else
-  cat > conftest.S <<EOF
-.type foo,%gnu_indirect_function
-foo:
-.globl _start
-_start:
-.globl __start
-__start:
-.data
-#ifdef _LP64
-.quad foo
-#else
-.long foo
-#endif
-.text
-.globl address
-address:
-#ifdef _LP64
-.quad address
-#else
-.long address
-#endif
-EOF
-libc_cv_textrel_ifunc=no
-if test $libc_cv_ld_gnu_indirect_function = yes; then
-   if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -nostartfiles -nostdlib $no_ssp -pie -o conftest conftest.S'
-  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then
-     libc_cv_textrel_ifunc=yes
-   fi
+  # Found it, now check the version.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $AS" >&5
+$as_echo_n "checking version of $AS... " >&6; }
+  ac_prog_version=`$AS --version 2>&1 | sed -n 's/^.*GNU assembler.* \([0-9]*\.[0-9.]*\).*$/\1/p'`
+  case $ac_prog_version in
+    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
+    2.1[0-9][0-9]*|2.2[5-9]*|2.[3-9][0-9]*|[3-9].*|[1-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
-rm -f conftest*
+if test $ac_verc_fail = yes; then
+  AS=: critic_missing="$critic_missing as"
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_textrel_ifunc" >&5
-$as_echo "$libc_cv_textrel_ifunc" >&6; }
 
 
-# Check if CC supports attribute retain as it is used in attribute_used_retain macro.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU attribute retain support" >&5
-$as_echo_n "checking for GNU attribute retain support... " >&6; }
-if ${libc_cv_gnu_retain+:} false; then :
+libc_cv_with_lld=no
+case $($LD --version) in
+  "GNU gold"*)
+  # Accept gold 1.14 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
-  cat > conftest.c <<EOF
-static int var  __attribute__ ((used, retain, section ("__libc_atexit")));
-EOF
-libc_cv_gnu_retain=no
-if ${CC-cc} -Werror -c conftest.c -o /dev/null 1>&5 \
-   2>&5 ; then
-  libc_cv_gnu_retain=yes
+  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
-rm -f conftest*
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_gnu_retain" >&5
-$as_echo "$libc_cv_gnu_retain" >&6; }
-if test $libc_cv_gnu_retain = yes; then
-  $as_echo "#define HAVE_GNU_RETAIN 1" >>confdefs.h
-
+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
-config_vars="$config_vars
-have-gnu-retain = $libc_cv_gnu_retain"
 
-# Check if gcc warns about alias for function with incompatible types.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler warns about alias for function with incompatible types" >&5
-$as_echo_n "checking if compiler warns about alias for function with incompatible types... " >&6; }
-if ${libc_cv_gcc_incompatible_alias+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat > conftest.c <<EOF
-int __redirect_foo (const void *s, int c);
 
-__typeof (__redirect_foo) *foo_impl (void) __asm__ ("foo");
-__typeof (__redirect_foo) *foo_impl (void)
-{
-  return 0;
-}
+  test -n "$LD" && break
+done
 
-extern __typeof (__redirect_foo) foo_alias __attribute__ ((alias ("foo")));
-EOF
-libc_cv_gcc_incompatible_alias=yes
-if ${CC-cc} -Werror -c conftest.c -o conftest.o 1>&5 2>&5 ; then
-  libc_cv_gcc_incompatible_alias=no
+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/^.*GNU gold.* \([0-9][0-9]*\.[0-9.]*\).*$/\1/p'`
+  case $ac_prog_version in
+    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
+    1.1[4-9]*|1.[2-9][0-9]*|1.1[0-9][0-9]*|[2-9].*|[1-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
-rm -f conftest*
+if test $ac_verc_fail = yes; then
+  LD=: critic_missing="$critic_missing GNU gold"
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_gcc_incompatible_alias" >&5
-$as_echo "$libc_cv_gcc_incompatible_alias" >&6; }
 
-if test x"$libc_cv_ld_gnu_indirect_function" != xyes; then
-  if test x"$multi_arch" = xyes; then
-    as_fn_error $? "--enable-multi-arch support requires assembler and linker support" "$LINENO" 5
-  else
-    multi_arch=no
-  fi
-fi
-if test x"$libc_cv_gcc_indirect_function" != xyes; then
-  # GCC 8+ emits a warning for alias with incompatible types and it might
-  # fail to build ifunc resolvers aliases to either weak or internal
-  # symbols.  Disables multiarch build in this case.
-  if test x"$libc_cv_gcc_incompatible_alias" = xyes; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: gcc emits a warning for alias between functions of incompatible types" >&5
-$as_echo "$as_me: WARNING: gcc emits a warning for alias between functions of incompatible types" >&2;}
-    if test x"$multi_arch" = xyes; then
-      as_fn_error $? "--enable-multi-arch support requires a gcc with gnu-indirect-function support" "$LINENO" 5
-    fi
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Multi-arch is disabled." >&5
-$as_echo "$as_me: WARNING: Multi-arch is disabled." >&2;}
-    multi_arch=no
-  elif test x"$multi_arch" = xyes; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --enable-multi-arch support recommends a gcc with gnu-indirect-function support.
-Please use a gcc which supports it by default or configure gcc with --enable-gnu-indirect-function" >&5
-$as_echo "$as_me: WARNING: --enable-multi-arch support recommends a gcc with gnu-indirect-function support.
-Please use a gcc which supports it by default or configure gcc with --enable-gnu-indirect-function" >&2;}
+    ;;
+  "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
+  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
-multi_arch_d=
-if test x"$multi_arch" != xno; then
-  multi_arch_d=/multiarch
+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
 
-# Compute the list of sysdep directories for this configuration.
-# This can take a while to compute.
-sysdep_dir=$srcdir/sysdeps
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking sysdep dirs" >&5
-$as_echo_n "checking sysdep dirs... " >&6; }
-# Make sco3.2v4 become sco3.2.4 and sunos4.1.1_U1 become sunos4.1.1.U1.
-os="`echo $os | sed 's/\([0-9A-Z]\)[v_]\([0-9A-Z]\)/\1.\2/g'`"
-
-test "x$base_os" != x || case "$os" in
-gnu*)
-  base_os=mach/hurd ;;
-linux*)
-  base_os=unix/sysv ;;
-esac
 
-# For sunos4.1.1, try sunos4.1.1, then sunos4.1, then sunos4, then sunos.
-tail=$os
-ostry=$os
-while o=`echo $tail | sed 's/\.[^.]*$//'`; test $o != $tail; do
-  ostry="$ostry /$o"
-  tail=$o
+  test -n "$LD" && break
 done
-o=`echo $tail | sed 's/[0-9]*$//'`
-if test $o != $tail; then
-  ostry="$ostry /$o"
+
+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
-# For linux-gnu, try linux-gnu, then linux.
-o=`echo $tail | sed 's/-.*$//'`
-if test $o != $tail; then
-  ostry="$ostry /$o"
+if test $ac_verc_fail = yes; then
+  LD=: critic_missing="$critic_missing LLD"
 fi
 
-# For unix/sysv/sysv4, try unix/sysv/sysv4, then unix/sysv, then unix.
-base=
-tail=$base_os
-while b=`echo $tail | sed 's@^\(.*\)/\([^/]*\)$@& \1@'`; test -n "$b"; do
-  set $b
-  base="$base /$1"
-  tail="$2"
-done
-
-# For sparc/sparc32, try sparc/sparc32 and then sparc.
-mach=
-tail=$machine${submachine:+/$submachine}
-while m=`echo $tail | sed 's@^\(.*\)/\([^/]*\)$@& \1@'`; test -n "$m"; do
-  set $m
-  # Prepend the machine's FPU directory unless the architecture specific
-  # preconfigure disables it.
-  if test "$libc_cv_with_fp" = yes; then
-    maybe_fpu=/fpu
-  else
-    maybe_fpu=/nofpu
+    libc_cv_with_lld=yes
+    ;;
+  *)
+    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
+  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
-  # For each machine term, try it with and then without /multiarch.
-  for try_fpu in $maybe_fpu ''; do
-    for try_multi in $multi_arch_d ''; do
-      mach="$mach /$1$try_fpu$try_multi"
-    done
-  done
-  tail="$2"
 done
-
-
-# Find what sysdep directories exist.
-sysnames=
-for b in $base ''; do
-  for m0 in $mach ''; do
-    for v in /$vendor ''; do
-      test "$v" = / && continue
-      for o in /$ostry ''; do
-	test "$o" = / && continue
-	for m in $mach ''; do
-	  try_suffix="$m0$b$v$o$m"
-	  if test -n "$try_suffix"; then
-	    try_srcdir="${srcdir}/"
-	    try="sysdeps$try_suffix"
-	    test -n "$enable_debug_configure" &&
-	    echo "$0 DEBUG: try $try" >&2
-	    if test -d "$try_srcdir$try"; then
-	      sysnames="$sysnames $try"
-	      { test -n "$o" || test -n "$b"; } && os_used=t
-	      { test -n "$m" || test -n "$m0"; } && machine_used=t
-	      case x${m0:-$m} in
-	      x*/$submachine) submachine_used=t ;;
-	      esac
-	    fi
-	  fi
-	done
-      done
-    done
   done
-done
-
-# If the assembler supports gnu_indirect_function symbol type and the
-# architecture supports multi-arch, we enable multi-arch by default.
-case $sysnames in
-*"$multi_arch_d"*)
-  ;;
-*)
-  test x"$multi_arch" = xdefault && multi_arch=no
-  ;;
-esac
-if test x"$multi_arch" != xno; then
-  $as_echo "#define USE_MULTIARCH 1" >>confdefs.h
-
-fi
-
+IFS=$as_save_IFS
 
-if test -z "$os_used" && test "$os" != none; then
-  as_fn_error $? "Operating system $os is not supported." "$LINENO" 5
 fi
-if test -z "$machine_used" && test "$machine" != none; then
-  as_fn_error $? "The $machine is not supported." "$LINENO" 5
 fi
-if test -z "$submachine_used" && test -n "$submachine"; then
-  as_fn_error $? "The $submachine subspecies of $host_cpu is not supported." "$LINENO" 5
+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
 
 
-# We have now validated the configuration.
+  test -n "$LD" && break
+done
 
-# Expand the list of system names into a full list of directories
-# from each element's parent name and Implies file (if present).
-set $sysnames
-names=
-while test $# -gt 0; do
-  name=$1
-  shift
+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/^.*GNU ld.* \([0-9][0-9]*\.[0-9.]*\).*$/\1/p'`
+  case $ac_prog_version in
+    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
+    2.1[0-9][0-9]*|2.2[5-9]*|2.[3-9][0-9]*|[3-9].*|[1-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;;
 
-  case " $names " in *" $name "*)
-    # Already in the list.
-    continue
   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 GNU ld"
+fi
 
-  # Report each name as we discover it, so there is no long pause in output.
-  echo $ECHO_N "$name $ECHO_C" >&6
-
-  name_base=`echo $name | sed -e 's@\(.*sysdeps\)/.*@\1@'`
-
-  case $name in
-    /*) xsrcdir= ;;
-    *)  xsrcdir=$srcdir/ ;;
-  esac
-  test -n "$enable_debug_configure" &&
-  echo "DEBUG: name/Implies $xsrcdir$name/Implies" >&2
+    ;;
+esac
+config_vars="$config_vars
+with-lld = $libc_cv_with_lld"
 
-  for implies_file in Implies Implies-before Implies-after; do
-    implies_type=`echo $implies_file | sed s/-/_/`
-    eval ${implies_type}=
-    if test -f $xsrcdir$name/$implies_file; then
-      # Collect more names from the `Implies' file (removing comments).
-      implied_candidate="`sed 's/#.*$//' < $xsrcdir$name/$implies_file`"
-      for x in $implied_candidate; do
-	found=no
-	if test -d $xsrcdir$name_base/$x; then
-	  eval "${implies_type}=\"\$${implies_type} \$name_base/\$x\""
-	  found=yes
-	fi
-	try="sysdeps/$x"
-	try_srcdir=$srcdir/
-	test -n "$enable_debug_configure" &&
-	 echo "DEBUG: $name $implies_file $x try() {$try_srcdir}$try" >&2
-	if test $try != $xsrcdir$name_base/$x && test -d $try_srcdir$try;
-	then
-	  eval "${implies_type}=\"\$${implies_type} \$try\""
-	  found=yes
-	fi
-	if test $found = no; then
-	  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $name/$implies_file specifies nonexistent $x" >&5
-$as_echo "$as_me: WARNING: $name/$implies_file specifies nonexistent $x" >&2;}
-	fi
-      done
-    fi
+# These programs are version sensitive.
+for ac_prog in gnumake gmake make
+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_MAKE+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$MAKE"; then
+  ac_cv_prog_MAKE="$MAKE" # 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_MAKE="$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
 
-  # Add NAME to the list of names.
-  names="$names $name"
-
-  # Find the parent of NAME, using the empty string if it has none.
-  parent="`echo $name | sed -n -e 's=/[^/]*$==' -e '/sysdeps$/q' -e p`"
+fi
+fi
+MAKE=$ac_cv_prog_MAKE
+if test -n "$MAKE"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAKE" >&5
+$as_echo "$MAKE" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
 
-  test -n "$enable_debug_configure" &&
-    echo "DEBUG: $name Implies='$Implies' rest='$*' parent='$parent' \
-Implies_before='$Implies_before' Implies_after='$Implies_after'" >&2
 
-  # Add the names implied by NAME, and NAME's parent (if it has one), to
-  # the list of names to be processed (the argument list).  We prepend the
-  # implied names to the list and append the parent.  We want implied
-  # directories to come before further directories inferred from the
-  # configuration components; this ensures that for sysv4, unix/common
-  # (implied by unix/sysv/sysv4) comes before unix/sysv (in ostry (here $*)
-  # after sysv4).
-  sysnames="`echo $Implies $* $Implies_before $parent $Implies_after`"
-  test -n "$sysnames" && set $sysnames
+  test -n "$MAKE" && break
 done
 
-# Add the default directories.
-default_sysnames="sysdeps/generic"
-sysnames="$names $default_sysnames"
-
-# The other names were emitted during the scan.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $default_sysnames" >&5
-$as_echo "$default_sysnames" >&6; }
+if test -z "$MAKE"; then
+  ac_verc_fail=yes
+else
+  # Found it, now check the version.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $MAKE" >&5
+$as_echo_n "checking version of $MAKE... " >&6; }
+  ac_prog_version=`$MAKE --version 2>&1 | sed -n 's/^.*GNU Make[^0-9]*\([0-9][0-9.]*\).*$/\1/p'`
+  case $ac_prog_version in
+    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
+    [4-9].* | [1-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
+  critic_missing="$critic_missing make"
+fi
 
-### Locate tools.
 
-# Find a good install program.  We prefer a C program (faster),
-# so one script is as good as another.  But avoid the broken or
-# incompatible versions:
-# SysV /etc/install, /usr/sbin/install
-# SunOS /usr/etc/install
-# IRIX /sbin/install
-# AIX /bin/install
-# AmigaOS /C/install, which installs bootblocks on floppy discs
-# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
-# AFS /usr/afsws/bin/install, which mishandles nonexistent args
-# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
-# OS/2's system install, which has a completely different semantic
-# ./install, which can be erroneously created by make from ./install.sh.
-# Reject install programs that cannot install multiple files.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
-$as_echo_n "checking for a BSD-compatible install... " >&6; }
-if test -z "$INSTALL"; then
-if ${ac_cv_path_install+:} false; then :
+for ac_prog in gnumsgfmt gmsgfmt msgfmt
+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_MSGFMT+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+  if test -n "$MSGFMT"; then
+  ac_cv_prog_MSGFMT="$MSGFMT" # 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=.
-    # Account for people who put trailing slashes in PATH elements.
-case $as_dir/ in #((
-  ./ | .// | /[cC]/* | \
-  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
-  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
-  /usr/ucb/* ) ;;
-  *)
-    # OSF1 and SCO ODT 3.0 have their own names for install.
-    # Don't use installbsd from OSF since it installs stuff as root
-    # by default.
-    for ac_prog in ginstall scoinst install; do
-      for ac_exec_ext in '' $ac_executable_extensions; do
-	if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
-	  if test $ac_prog = install &&
-	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
-	    # AIX install.  It has an incompatible calling convention.
-	    :
-	  elif test $ac_prog = install &&
-	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
-	    # program-specific install script used by HP pwplus--don't use.
-	    :
-	  else
-	    rm -rf conftest.one conftest.two conftest.dir
-	    echo one > conftest.one
-	    echo two > conftest.two
-	    mkdir conftest.dir
-	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
-	      test -s conftest.one && test -s conftest.two &&
-	      test -s conftest.dir/conftest.one &&
-	      test -s conftest.dir/conftest.two
-	    then
-	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
-	      break 3
-	    fi
-	  fi
-	fi
-      done
-    done
-    ;;
-esac
-
+    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_MSGFMT="$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
 
-rm -rf conftest.one conftest.two conftest.dir
-
-fi
-  if test "${ac_cv_path_install+set}" = set; then
-    INSTALL=$ac_cv_path_install
-  else
-    # As a last resort, use the slow shell script.  Don't cache a
-    # value for INSTALL within a source directory, because that will
-    # break other packages using the cache if that directory is
-    # removed, or if the value is a relative name.
-    INSTALL=$ac_install_sh
-  fi
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
-$as_echo "$INSTALL" >&6; }
-
-# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
-# It thinks the first close brace ends the variable substitution.
-test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
-
-test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
-
-test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
-
-if test "$INSTALL" = "${srcdir}/scripts/install-sh -c"; then
-  # The makefiles need to use a different form to find it in $srcdir.
-  INSTALL='\$(..)./scripts/install-sh -c'
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
-$as_echo_n "checking whether ln -s works... " >&6; }
-LN_S=$as_ln_s
-if test "$LN_S" = "ln -s"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+MSGFMT=$ac_cv_prog_MSGFMT
+if test -n "$MSGFMT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5
+$as_echo "$MSGFMT" >&6; }
 else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
-$as_echo "no, using $LN_S" >&6; }
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
 
-# Was a --with-binutils option given?
-if test -n "$path_binutils"; then
-    # Make absolute; ensure a single trailing slash.
-    path_binutils=`(cd $path_binutils; pwd) | sed 's%/*$%/%'`
-    CC="$CC -B$path_binutils"
-fi
-case "$CC" in
-    *fuse-ld=lld*) LDNAME=ld.lld;;
-    *)             LDNAME=ld;;
-esac
-AS=`$CC -print-prog-name=as`
-LD=`$CC -print-prog-name=$LDNAME`
-AR=`$CC -print-prog-name=ar`
-
-OBJCOPY=`$CC -print-prog-name=objcopy`
+  test -n "$MSGFMT" && break
+done
 
-GPROF=`$CC -print-prog-name=gprof`
+if test -z "$MSGFMT"; then
+  ac_verc_fail=yes
+else
+  # Found it, now check the version.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $MSGFMT" >&5
+$as_echo_n "checking version of $MSGFMT... " >&6; }
+  ac_prog_version=`$MSGFMT --version 2>&1 | sed -n 's/^.*GNU gettext.* \([0-9]*\.[0-9.]*\).*$/\1/p'`
+  case $ac_prog_version in
+    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
+    0.10.3[6-9]* | 0.10.[4-9][0-9]* | 0.1[1-9]* | 0.[2-9][0-9]* | [1-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
+  MSGFMT=: aux_missing="$aux_missing msgfmt"
+fi
 
-# Determine whether we are using GNU binutils.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $AS is GNU as" >&5
-$as_echo_n "checking whether $AS is GNU as... " >&6; }
-if ${libc_cv_prog_as_gnu+:} false; then :
+for ac_prog in makeinfo
+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_MAKEINFO+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  # Most GNU programs take a -v and spit out some text including
-# the word 'GNU'.  Some try to read stdin, so give them /dev/null.
-if $AS -o conftest -v </dev/null 2>&1 | grep GNU > /dev/null 2>&1; then
-  libc_cv_prog_as_gnu=yes
+  if test -n "$MAKEINFO"; then
+  ac_cv_prog_MAKEINFO="$MAKEINFO" # Let the user override the test.
 else
-  libc_cv_prog_as_gnu=no
+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_MAKEINFO="$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
-rm -fr contest*
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_prog_as_gnu" >&5
-$as_echo "$libc_cv_prog_as_gnu" >&6; }
-rm -f a.out
-gnu_as=$libc_cv_prog_as_gnu
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $LD is GNU ld" >&5
-$as_echo_n "checking whether $LD is GNU ld... " >&6; }
-if ${libc_cv_prog_ld_gnu+:} false; then :
-  $as_echo_n "(cached) " >&6
+MAKEINFO=$ac_cv_prog_MAKEINFO
+if test -n "$MAKEINFO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAKEINFO" >&5
+$as_echo "$MAKEINFO" >&6; }
 else
-  # Most GNU programs take a -v and spit out some text including
-# the word 'GNU'.  Some try to read stdin, so give them /dev/null.
-if $LD -o conftest -v </dev/null 2>&1 | grep GNU > /dev/null 2>&1; then
-  libc_cv_prog_ld_gnu=yes
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$MAKEINFO" && break
+done
+
+if test -z "$MAKEINFO"; then
+  ac_verc_fail=yes
 else
-  libc_cv_prog_ld_gnu=no
+  # Found it, now check the version.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $MAKEINFO" >&5
+$as_echo_n "checking version of $MAKEINFO... " >&6; }
+  ac_prog_version=`$MAKEINFO --version 2>&1 | sed -n 's/^.*GNU texinfo.* \([0-9][0-9.]*\).*$/\1/p'`
+  case $ac_prog_version in
+    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
+    4.[7-9]*|4.[1-9][0-9]*|[5-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
-rm -fr contest*
+if test $ac_verc_fail = yes; then
+  MAKEINFO=: aux_missing="$aux_missing makeinfo"
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_prog_ld_gnu" >&5
-$as_echo "$libc_cv_prog_ld_gnu" >&6; }
-gnu_ld=$libc_cv_prog_ld_gnu
-
 
-# Accept binutils 2.25 or newer.
-for ac_prog in $AS
+for ac_prog in sed
 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_AS+:} false; then :
+if ${ac_cv_prog_SED+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$AS"; then
-  ac_cv_prog_AS="$AS" # Let the user override the test.
+  if test -n "$SED"; then
+  ac_cv_prog_SED="$SED" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
@@ -4736,7 +4673,7 @@ do
   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_AS="$ac_prog"
+    ac_cv_prog_SED="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -4746,29 +4683,29 @@ IFS=$as_save_IFS
 
 fi
 fi
-AS=$ac_cv_prog_AS
-if test -n "$AS"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5
-$as_echo "$AS" >&6; }
+SED=$ac_cv_prog_SED
+if test -n "$SED"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SED" >&5
+$as_echo "$SED" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
 
-  test -n "$AS" && break
+  test -n "$SED" && break
 done
 
-if test -z "$AS"; then
+if test -z "$SED"; then
   ac_verc_fail=yes
 else
   # Found it, now check the version.
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $AS" >&5
-$as_echo_n "checking version of $AS... " >&6; }
-  ac_prog_version=`$AS --version 2>&1 | sed -n 's/^.*GNU assembler.* \([0-9]*\.[0-9.]*\).*$/\1/p'`
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $SED" >&5
+$as_echo_n "checking version of $SED... " >&6; }
+  ac_prog_version=`$SED --version 2>&1 | sed -n 's/^.*GNU sed[^0-9]* \([0-9]*\.[0-9.]*\).*$/\1/p'`
   case $ac_prog_version in
     '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
-    2.1[0-9][0-9]*|2.2[5-9]*|2.[3-9][0-9]*|[3-9].*|[1-9][0-9]*)
+    3.0[2-9]*|3.[1-9]*|[4-9]*)
        ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
     *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
 
@@ -4777,25 +4714,20 @@ $as_echo_n "checking version of $AS... " >&6; }
 $as_echo "$ac_prog_version" >&6; }
 fi
 if test $ac_verc_fail = yes; then
-  AS=: critic_missing="$critic_missing as"
+  SED=: aux_missing="$aux_missing sed"
 fi
 
-
-libc_cv_with_lld=no
-case $($LD --version) in
-  "GNU gold"*)
-  # Accept gold 1.14 or higher
-    for ac_prog in $LD
+for ac_prog in gawk
 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 :
+if ${ac_cv_prog_AWK+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$LD"; then
-  ac_cv_prog_LD="$LD" # Let the user override the test.
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
@@ -4804,7 +4736,7 @@ do
   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"
+    ac_cv_prog_AWK="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -4814,29 +4746,29 @@ 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; }
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
 
-  test -n "$LD" && break
+  test -n "$AWK" && break
 done
 
-if test -z "$LD"; then
+if test -z "$AWK"; 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/^.*GNU gold.* \([0-9][0-9]*\.[0-9.]*\).*$/\1/p'`
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $AWK" >&5
+$as_echo_n "checking version of $AWK... " >&6; }
+  ac_prog_version=`$AWK --version 2>&1 | sed -n 's/^.*GNU Awk[^0-9]*\([0-9][0-9.]*\).*$/\1/p'`
   case $ac_prog_version in
     '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
-    1.1[4-9]*|1.[2-9][0-9]*|1.1[0-9][0-9]*|[2-9].*|[1-9][0-9]*)
+    3.1.[2-9]*|3.[2-9]*|[4-9]*)
        ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
     *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
 
@@ -4845,23 +4777,20 @@ $as_echo_n "checking version of $LD... " >&6; }
 $as_echo "$ac_prog_version" >&6; }
 fi
 if test $ac_verc_fail = yes; then
-  LD=: critic_missing="$critic_missing GNU gold"
+  critic_missing="$critic_missing gawk"
 fi
 
-    ;;
-  "LLD"*)
-  # Accept LLD 13.0.0 or higher
-    for ac_prog in $LD
+for ac_prog in bison
 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 :
+if ${ac_cv_prog_BISON+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$LD"; then
-  ac_cv_prog_LD="$LD" # Let the user override the test.
+  if test -n "$BISON"; then
+  ac_cv_prog_BISON="$BISON" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
@@ -4870,7 +4799,7 @@ do
   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"
+    ac_cv_prog_BISON="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -4880,29 +4809,29 @@ 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; }
+BISON=$ac_cv_prog_BISON
+if test -n "$BISON"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BISON" >&5
+$as_echo "$BISON" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
 
-  test -n "$LD" && break
+  test -n "$BISON" && break
 done
 
-if test -z "$LD"; then
+if test -z "$BISON"; 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'`
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $BISON" >&5
+$as_echo_n "checking version of $BISON... " >&6; }
+  ac_prog_version=`$BISON --version 2>&1 | sed -n 's/^.*bison (GNU Bison) \([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].*)
+    2.7*|[3-9].*|[1-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;;
 
@@ -4911,23 +4840,53 @@ $as_echo_n "checking version of $LD... " >&6; }
 $as_echo "$ac_prog_version" >&6; }
 fi
 if test $ac_verc_fail = yes; then
-  LD=: critic_missing="$critic_missing LLD"
+  critic_missing="$critic_missing bison"
 fi
 
-    libc_cv_with_lld=yes
-    ;;
-  *)
-    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 if $CC is sufficient to build libc" >&5
+$as_echo_n "checking if $CC is sufficient to build libc... " >&6; }
+if ${libc_cv_compiler_ok+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+#if !defined __GNUC__ || __GNUC__ < 6 || (__GNUC__ == 6 && __GNUC_MINOR__ < 2)
+#error insufficient compiler
+#endif
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  libc_cv_compiler_ok=yes
+else
+  libc_cv_compiler_ok=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_compiler_ok" >&5
+$as_echo "$libc_cv_compiler_ok" >&6; }
+if test $libc_cv_compiler_ok != yes; then :
+  critic_missing="$critic_missing compiler"
+fi
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}nm", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nm; 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 :
+if ${ac_cv_prog_NM+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$LD"; then
-  ac_cv_prog_LD="$LD" # Let the user override the test.
+  if test -n "$NM"; then
+  ac_cv_prog_NM="$NM" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
@@ -4936,7 +4895,7 @@ do
   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"
+    ac_cv_prog_NM="${ac_tool_prefix}nm"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -4945,58 +4904,29 @@ 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; }
+fi
+NM=$ac_cv_prog_NM
+if test -n "$NM"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NM" >&5
+$as_echo "$NM" >&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/^.*GNU ld.* \([0-9][0-9]*\.[0-9.]*\).*$/\1/p'`
-  case $ac_prog_version in
-    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
-    2.1[0-9][0-9]*|2.2[5-9]*|2.[3-9][0-9]*|[3-9].*|[1-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 GNU ld"
-fi
-
-    ;;
-esac
-config_vars="$config_vars
-with-lld = $libc_cv_with_lld"
-
-# These programs are version sensitive.
-for ac_prog in gnumake gmake make
-do
-  # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
+if test -z "$ac_cv_prog_NM"; then
+  ac_ct_NM=$NM
+  # Extract the first word of "nm", so it can be a program name with args.
+set dummy nm; 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_MAKE+:} false; then :
+if ${ac_cv_prog_ac_ct_NM+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$MAKE"; then
-  ac_cv_prog_MAKE="$MAKE" # Let the user override the test.
+  if test -n "$ac_ct_NM"; then
+  ac_cv_prog_ac_ct_NM="$ac_ct_NM" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
@@ -5005,7 +4935,7 @@ do
   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_MAKE="$ac_prog"
+    ac_cv_prog_ac_ct_NM="nm"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -5015,52 +4945,43 @@ IFS=$as_save_IFS
 
 fi
 fi
-MAKE=$ac_cv_prog_MAKE
-if test -n "$MAKE"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAKE" >&5
-$as_echo "$MAKE" >&6; }
+ac_ct_NM=$ac_cv_prog_ac_ct_NM
+if test -n "$ac_ct_NM"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NM" >&5
+$as_echo "$ac_ct_NM" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
-
-  test -n "$MAKE" && break
-done
-
-if test -z "$MAKE"; then
-  ac_verc_fail=yes
+  if test "x$ac_ct_NM" = x; then
+    NM="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    NM=$ac_ct_NM
+  fi
 else
-  # Found it, now check the version.
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $MAKE" >&5
-$as_echo_n "checking version of $MAKE... " >&6; }
-  ac_prog_version=`$MAKE --version 2>&1 | sed -n 's/^.*GNU Make[^0-9]*\([0-9][0-9.]*\).*$/\1/p'`
-  case $ac_prog_version in
-    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
-    [4-9].* | [1-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
-  critic_missing="$critic_missing make"
+  NM="$ac_cv_prog_NM"
 fi
 
 
-for ac_prog in gnumsgfmt gmsgfmt msgfmt
+if test "x$maintainer" = "xyes"; then
+  for ac_prog in autoconf
 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_MSGFMT+:} false; then :
+if ${ac_cv_prog_AUTOCONF+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$MSGFMT"; then
-  ac_cv_prog_MSGFMT="$MSGFMT" # Let the user override the test.
+  if test -n "$AUTOCONF"; then
+  ac_cv_prog_AUTOCONF="$AUTOCONF" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
@@ -5069,7 +4990,7 @@ do
   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_MSGFMT="$ac_prog"
+    ac_cv_prog_AUTOCONF="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -5079,51 +5000,58 @@ IFS=$as_save_IFS
 
 fi
 fi
-MSGFMT=$ac_cv_prog_MSGFMT
-if test -n "$MSGFMT"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5
-$as_echo "$MSGFMT" >&6; }
+AUTOCONF=$ac_cv_prog_AUTOCONF
+if test -n "$AUTOCONF"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AUTOCONF" >&5
+$as_echo "$AUTOCONF" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
 
-  test -n "$MSGFMT" && break
+  test -n "$AUTOCONF" && break
 done
+test -n "$AUTOCONF" || AUTOCONF="no"
 
-if test -z "$MSGFMT"; then
-  ac_verc_fail=yes
+  case "x$AUTOCONF" in
+  xno|x|x:) AUTOCONF=no ;;
+  *)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking   whether $AUTOCONF${ACFLAGS:+ }$ACFLAGS works" >&5
+$as_echo_n "checking   whether $AUTOCONF${ACFLAGS:+ }$ACFLAGS works... " >&6; }
+if ${libc_cv_autoconf_works+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
-  # Found it, now check the version.
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $MSGFMT" >&5
-$as_echo_n "checking version of $MSGFMT... " >&6; }
-  ac_prog_version=`$MSGFMT --version 2>&1 | sed -n 's/^.*GNU gettext.* \([0-9]*\.[0-9.]*\).*$/\1/p'`
-  case $ac_prog_version in
-    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
-    0.10.3[6-9]* | 0.10.[4-9][0-9]* | 0.1[1-9]* | 0.[2-9][0-9]* | [1-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; }
+      if (cd $srcdir; $AUTOCONF $ACFLAGS configure.ac > /dev/null 2>&1); then
+      libc_cv_autoconf_works=yes
+    else
+      libc_cv_autoconf_works=no
+    fi
 fi
-if test $ac_verc_fail = yes; then
-  MSGFMT=: aux_missing="$aux_missing msgfmt"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_autoconf_works" >&5
+$as_echo "$libc_cv_autoconf_works" >&6; }
+    test $libc_cv_autoconf_works = yes || AUTOCONF=no
+    ;;
+  esac
+  if test "x$AUTOCONF" = xno; then
+    aux_missing="$aux_missing autoconf"
+  fi
+else
+  AUTOCONF=no
 fi
 
-for ac_prog in makeinfo
+# Check for python3 if available, or else python.
+for ac_prog in python3 python
 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_MAKEINFO+:} false; then :
+if ${ac_cv_prog_PYTHON_PROG+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$MAKEINFO"; then
-  ac_cv_prog_MAKEINFO="$MAKEINFO" # Let the user override the test.
+  if test -n "$PYTHON_PROG"; then
+  ac_cv_prog_PYTHON_PROG="$PYTHON_PROG" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
@@ -5132,7 +5060,7 @@ do
   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_MAKEINFO="$ac_prog"
+    ac_cv_prog_PYTHON_PROG="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -5142,29 +5070,29 @@ IFS=$as_save_IFS
 
 fi
 fi
-MAKEINFO=$ac_cv_prog_MAKEINFO
-if test -n "$MAKEINFO"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAKEINFO" >&5
-$as_echo "$MAKEINFO" >&6; }
+PYTHON_PROG=$ac_cv_prog_PYTHON_PROG
+if test -n "$PYTHON_PROG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_PROG" >&5
+$as_echo "$PYTHON_PROG" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
 
-  test -n "$MAKEINFO" && break
+  test -n "$PYTHON_PROG" && break
 done
 
-if test -z "$MAKEINFO"; then
+if test -z "$PYTHON_PROG"; then
   ac_verc_fail=yes
 else
   # Found it, now check the version.
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $MAKEINFO" >&5
-$as_echo_n "checking version of $MAKEINFO... " >&6; }
-  ac_prog_version=`$MAKEINFO --version 2>&1 | sed -n 's/^.*GNU texinfo.* \([0-9][0-9.]*\).*$/\1/p'`
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $PYTHON_PROG" >&5
+$as_echo_n "checking version of $PYTHON_PROG... " >&6; }
+  ac_prog_version=`$PYTHON_PROG --version 2>&1 | sed -n 's/^.*Python \([0-9][0-9.]*\).*$/\1/p'`
   case $ac_prog_version in
     '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
-    4.[7-9]*|4.[1-9][0-9]*|[5-9].*)
+    3.[4-9]*|3.[1-9][0-9]*|[4-9].*|[1-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;;
 
@@ -5173,474 +5101,546 @@ $as_echo_n "checking version of $MAKEINFO... " >&6; }
 $as_echo "$ac_prog_version" >&6; }
 fi
 if test $ac_verc_fail = yes; then
-  MAKEINFO=: aux_missing="$aux_missing makeinfo"
+  critic_missing="$critic_missing python"
 fi
 
-for ac_prog in sed
-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_SED+:} false; then :
+PYTHON="$PYTHON_PROG -B"
+
+
+test -n "$critic_missing" && as_fn_error $? "
+*** These critical programs are missing or too old:$critic_missing
+*** Check the INSTALL file for required versions." "$LINENO" 5
+
+test -n "$aux_missing" && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING:
+*** These auxiliary programs are missing or incompatible versions:$aux_missing
+*** some features or tests will be disabled.
+*** Check the INSTALL file for required versions." >&5
+$as_echo "$as_me: WARNING:
+*** These auxiliary programs are missing or incompatible versions:$aux_missing
+*** some features or tests will be disabled.
+*** Check the INSTALL file for required versions." >&2;}
+
+
+# Determine whether to use fpu or nofpu sysdeps directories.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for use of fpu sysdeps directories" >&5
+$as_echo_n "checking for use of fpu sysdeps directories... " >&6; }
+if ${libc_cv_with_fp+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$SED"; then
-  ac_cv_prog_SED="$SED" # 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_SED="$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
-
+  cat > conftest.c <<EOF
+#if $with_fp_cond
+int dummy;
+#else
+# error "no hardware floating point"
+#endif
+EOF
+libc_cv_with_fp=no
+if ${CC-cc} $CFLAGS $CPPFLAGS -S conftest.c -o conftest.s \
+   1>&5 2>&5 ; then
+  libc_cv_with_fp=yes
 fi
+rm -f conftest*
 fi
-SED=$ac_cv_prog_SED
-if test -n "$SED"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $SED" >&5
-$as_echo "$SED" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_with_fp" >&5
+$as_echo "$libc_cv_with_fp" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fstack-protector" >&5
+$as_echo_n "checking for -fstack-protector... " >&6; }
+if ${libc_cv_ssp+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+  if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -Werror -fstack-protector -xc /dev/null -S -o /dev/null'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  libc_cv_ssp=yes
+else
+  libc_cv_ssp=no
 fi
 
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ssp" >&5
+$as_echo "$libc_cv_ssp" >&6; }
 
-  test -n "$SED" && break
-done
-
-if test -z "$SED"; then
-  ac_verc_fail=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fstack-protector-strong" >&5
+$as_echo_n "checking for -fstack-protector-strong... " >&6; }
+if ${libc_cv_ssp_strong+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
-  # Found it, now check the version.
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $SED" >&5
-$as_echo_n "checking version of $SED... " >&6; }
-  ac_prog_version=`$SED --version 2>&1 | sed -n 's/^.*GNU sed[^0-9]* \([0-9]*\.[0-9.]*\).*$/\1/p'`
-  case $ac_prog_version in
-    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
-    3.0[2-9]*|3.[1-9]*|[4-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; }
+  if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -Werror -fstack-protector-strong -xc /dev/null -S -o /dev/null'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  libc_cv_ssp_strong=yes
+else
+  libc_cv_ssp_strong=no
 fi
-if test $ac_verc_fail = yes; then
-  SED=: aux_missing="$aux_missing sed"
+
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ssp_strong" >&5
+$as_echo "$libc_cv_ssp_strong" >&6; }
 
-for ac_prog in gawk
-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_AWK+:} false; then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fstack-protector-all" >&5
+$as_echo_n "checking for -fstack-protector-all... " >&6; }
+if ${libc_cv_ssp_all+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$AWK"; then
-  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+  if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -Werror -fstack-protector-all -xc /dev/null -S -o /dev/null'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  libc_cv_ssp_all=yes
 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_AWK="$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
+  libc_cv_ssp_all=no
+fi
 
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ssp_all" >&5
+$as_echo "$libc_cv_ssp_all" >&6; }
+
+stack_protector=
+no_stack_protector=
+if test "$libc_cv_ssp" = yes; then
+  no_stack_protector="-fno-stack-protector -DSTACK_PROTECTOR_LEVEL=0"
+  $as_echo "#define HAVE_CC_NO_STACK_PROTECTOR 1" >>confdefs.h
+
 fi
-AWK=$ac_cv_prog_AWK
-if test -n "$AWK"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
-$as_echo "$AWK" >&6; }
+
+if test "$enable_stack_protector" = yes && test "$libc_cv_ssp" = yes; then
+  stack_protector="-fstack-protector"
+  $as_echo "#define STACK_PROTECTOR_LEVEL 1" >>confdefs.h
+
+elif test "$enable_stack_protector" = all && test "$libc_cv_ssp_all" = yes; then
+  stack_protector="-fstack-protector-all"
+  $as_echo "#define STACK_PROTECTOR_LEVEL 2" >>confdefs.h
+
+elif test "$enable_stack_protector" = strong && test "$libc_cv_ssp_strong" = yes; then
+  stack_protector="-fstack-protector-strong"
+  $as_echo "#define STACK_PROTECTOR_LEVEL 3" >>confdefs.h
+
 else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+  stack_protector="-fno-stack-protector"
+  $as_echo "#define STACK_PROTECTOR_LEVEL 0" >>confdefs.h
+
 fi
 
 
-  test -n "$AWK" && break
-done
 
-if test -z "$AWK"; then
-  ac_verc_fail=yes
+
+if test -n "$stack_protector"; then
+      no_ssp=-fno-stack-protector
 else
-  # Found it, now check the version.
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $AWK" >&5
-$as_echo_n "checking version of $AWK... " >&6; }
-  ac_prog_version=`$AWK --version 2>&1 | sed -n 's/^.*GNU Awk[^0-9]*\([0-9][0-9.]*\).*$/\1/p'`
-  case $ac_prog_version in
-    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
-    3.1.[2-9]*|3.[2-9]*|[4-9]*)
-       ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
-    *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
+  no_ssp=
 
-  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
-  critic_missing="$critic_missing gawk"
+  if test "$enable_stack_protector" != no; then
+    as_fn_error $? "--enable-stack-protector=$enable_stack_protector specified, but specified level of stack protection is not supported by the compiler." "$LINENO" 5
+  fi
 fi
 
-for ac_prog in bison
-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_BISON+:} false; then :
+# For the multi-arch option we need support in the assembler & linker.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for assembler and linker STT_GNU_IFUNC support" >&5
+$as_echo_n "checking for assembler and linker STT_GNU_IFUNC support... " >&6; }
+if ${libc_cv_ld_gnu_indirect_function+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$BISON"; then
-  ac_cv_prog_BISON="$BISON" # Let the user override the test.
+  cat > conftest.S <<EOF
+.type foo,%gnu_indirect_function
+foo:
+.globl _start
+_start:
+.globl __start
+__start:
+.data
+#ifdef _LP64
+.quad foo
+#else
+.long foo
+#endif
+EOF
+libc_cv_ld_gnu_indirect_function=no
+if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS \
+	    -nostartfiles -nostdlib $no_ssp \
+	    -o conftest conftest.S 1>&5 2>&5; then
+  # Do a link to see if the backend supports IFUNC relocs.
+  $READELF -r conftest 1>&5
+  LC_ALL=C $READELF -Wr conftest | grep -q 'IRELATIVE\|R_SPARC_JMP_IREL' && {
+    libc_cv_ld_gnu_indirect_function=yes
+  }
+fi
+rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ld_gnu_indirect_function" >&5
+$as_echo "$libc_cv_ld_gnu_indirect_function" >&6; }
+
+# Check if gcc supports attribute ifunc as it is used in libc_ifunc macro.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc attribute ifunc support" >&5
+$as_echo_n "checking for gcc attribute ifunc support... " >&6; }
+if ${libc_cv_gcc_indirect_function+:} false; then :
+  $as_echo_n "(cached) " >&6
 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_BISON="$ac_prog"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
+  cat > conftest.c <<EOF
+extern int func (int);
+int used_func (int a)
+{
+  return a;
+}
+static void *resolver ()
+{
+  return &used_func;
+}
+extern __typeof (func) func __attribute__ ((ifunc ("resolver")));
+EOF
+libc_cv_gcc_indirect_function=no
+if ${CC-cc} -c conftest.c -o conftest.o 1>&5 \
+   2>&5 ; then
+  if $READELF -s conftest.o | grep IFUNC >/dev/null 2>&5; then
+    libc_cv_gcc_indirect_function=yes
   fi
-done
-  done
-IFS=$as_save_IFS
-
 fi
+rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_gcc_indirect_function" >&5
+$as_echo "$libc_cv_gcc_indirect_function" >&6; }
+
+# Check if linker supports textrel relocation with ifunc (used on elf/tests).
+# Note that it relies on libc_cv_ld_gnu_indirect_function test above.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker supports textrels along with ifunc" >&5
+$as_echo_n "checking whether the linker supports textrels along with ifunc... " >&6; }
+if ${libc_cv_textrel_ifunc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat > conftest.S <<EOF
+.type foo,%gnu_indirect_function
+foo:
+.globl _start
+_start:
+.globl __start
+__start:
+.data
+#ifdef _LP64
+.quad foo
+#else
+.long foo
+#endif
+.text
+.globl address
+address:
+#ifdef _LP64
+.quad address
+#else
+.long address
+#endif
+EOF
+libc_cv_textrel_ifunc=no
+if test $libc_cv_ld_gnu_indirect_function = yes; then
+   if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS -nostartfiles -nostdlib $no_ssp -pie -o conftest conftest.S'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+     libc_cv_textrel_ifunc=yes
+   fi
 fi
-BISON=$ac_cv_prog_BISON
-if test -n "$BISON"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BISON" >&5
-$as_echo "$BISON" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+rm -f conftest*
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_textrel_ifunc" >&5
+$as_echo "$libc_cv_textrel_ifunc" >&6; }
 
 
-  test -n "$BISON" && break
-done
-
-if test -z "$BISON"; then
-  ac_verc_fail=yes
+# Check if CC supports attribute retain as it is used in attribute_used_retain macro.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU attribute retain support" >&5
+$as_echo_n "checking for GNU attribute retain support... " >&6; }
+if ${libc_cv_gnu_retain+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
-  # Found it, now check the version.
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $BISON" >&5
-$as_echo_n "checking version of $BISON... " >&6; }
-  ac_prog_version=`$BISON --version 2>&1 | sed -n 's/^.*bison (GNU Bison) \([0-9]*\.[0-9.]*\).*$/\1/p'`
-  case $ac_prog_version in
-    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
-    2.7*|[3-9].*|[1-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; }
+  cat > conftest.c <<EOF
+static int var  __attribute__ ((used, retain, section ("__libc_atexit")));
+EOF
+libc_cv_gnu_retain=no
+if ${CC-cc} -Werror -c conftest.c -o /dev/null 1>&5 \
+   2>&5 ; then
+  libc_cv_gnu_retain=yes
 fi
-if test $ac_verc_fail = yes; then
-  critic_missing="$critic_missing bison"
+rm -f conftest*
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_gnu_retain" >&5
+$as_echo "$libc_cv_gnu_retain" >&6; }
+if test $libc_cv_gnu_retain = yes; then
+  $as_echo "#define HAVE_GNU_RETAIN 1" >>confdefs.h
 
+fi
+config_vars="$config_vars
+have-gnu-retain = $libc_cv_gnu_retain"
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC is sufficient to build libc" >&5
-$as_echo_n "checking if $CC is sufficient to build libc... " >&6; }
-if ${libc_cv_compiler_ok+:} false; then :
+# Check if gcc warns about alias for function with incompatible types.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler warns about alias for function with incompatible types" >&5
+$as_echo_n "checking if compiler warns about alias for function with incompatible types... " >&6; }
+if ${libc_cv_gcc_incompatible_alias+:} false; then :
   $as_echo_n "(cached) " >&6
 else
+  cat > conftest.c <<EOF
+int __redirect_foo (const void *s, int c);
 
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
+__typeof (__redirect_foo) *foo_impl (void) __asm__ ("foo");
+__typeof (__redirect_foo) *foo_impl (void)
 {
-
-#if !defined __GNUC__ || __GNUC__ < 6 || (__GNUC__ == 6 && __GNUC_MINOR__ < 2)
-#error insufficient compiler
-#endif
-  ;
   return 0;
 }
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
-  libc_cv_compiler_ok=yes
-else
-  libc_cv_compiler_ok=no
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
+
+extern __typeof (__redirect_foo) foo_alias __attribute__ ((alias ("foo")));
+EOF
+libc_cv_gcc_incompatible_alias=yes
+if ${CC-cc} -Werror -c conftest.c -o conftest.o 1>&5 2>&5 ; then
+  libc_cv_gcc_incompatible_alias=no
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_compiler_ok" >&5
-$as_echo "$libc_cv_compiler_ok" >&6; }
-if test $libc_cv_compiler_ok != yes; then :
-  critic_missing="$critic_missing compiler"
+rm -f conftest*
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_gcc_incompatible_alias" >&5
+$as_echo "$libc_cv_gcc_incompatible_alias" >&6; }
 
-if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}nm", so it can be a program name with args.
-set dummy ${ac_tool_prefix}nm; 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_NM+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$NM"; then
-  ac_cv_prog_NM="$NM" # 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_NM="${ac_tool_prefix}nm"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
+if test x"$libc_cv_ld_gnu_indirect_function" != xyes; then
+  if test x"$multi_arch" = xyes; then
+    as_fn_error $? "--enable-multi-arch support requires assembler and linker support" "$LINENO" 5
+  else
+    multi_arch=no
   fi
-done
-  done
-IFS=$as_save_IFS
-
 fi
+if test x"$libc_cv_gcc_indirect_function" != xyes; then
+  # GCC 8+ emits a warning for alias with incompatible types and it might
+  # fail to build ifunc resolvers aliases to either weak or internal
+  # symbols.  Disables multiarch build in this case.
+  if test x"$libc_cv_gcc_incompatible_alias" = xyes; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: gcc emits a warning for alias between functions of incompatible types" >&5
+$as_echo "$as_me: WARNING: gcc emits a warning for alias between functions of incompatible types" >&2;}
+    if test x"$multi_arch" = xyes; then
+      as_fn_error $? "--enable-multi-arch support requires a gcc with gnu-indirect-function support" "$LINENO" 5
+    fi
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Multi-arch is disabled." >&5
+$as_echo "$as_me: WARNING: Multi-arch is disabled." >&2;}
+    multi_arch=no
+  elif test x"$multi_arch" = xyes; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --enable-multi-arch support recommends a gcc with gnu-indirect-function support.
+Please use a gcc which supports it by default or configure gcc with --enable-gnu-indirect-function" >&5
+$as_echo "$as_me: WARNING: --enable-multi-arch support recommends a gcc with gnu-indirect-function support.
+Please use a gcc which supports it by default or configure gcc with --enable-gnu-indirect-function" >&2;}
+  fi
 fi
-NM=$ac_cv_prog_NM
-if test -n "$NM"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NM" >&5
-$as_echo "$NM" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+multi_arch_d=
+if test x"$multi_arch" != xno; then
+  multi_arch_d=/multiarch
 fi
 
+# Compute the list of sysdep directories for this configuration.
+# This can take a while to compute.
+sysdep_dir=$srcdir/sysdeps
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking sysdep dirs" >&5
+$as_echo_n "checking sysdep dirs... " >&6; }
+# Make sco3.2v4 become sco3.2.4 and sunos4.1.1_U1 become sunos4.1.1.U1.
+os="`echo $os | sed 's/\([0-9A-Z]\)[v_]\([0-9A-Z]\)/\1.\2/g'`"
+
+test "x$base_os" != x || case "$os" in
+gnu*)
+  base_os=mach/hurd ;;
+linux*)
+  base_os=unix/sysv ;;
+esac
 
+# For sunos4.1.1, try sunos4.1.1, then sunos4.1, then sunos4, then sunos.
+tail=$os
+ostry=$os
+while o=`echo $tail | sed 's/\.[^.]*$//'`; test $o != $tail; do
+  ostry="$ostry /$o"
+  tail=$o
+done
+o=`echo $tail | sed 's/[0-9]*$//'`
+if test $o != $tail; then
+  ostry="$ostry /$o"
 fi
-if test -z "$ac_cv_prog_NM"; then
-  ac_ct_NM=$NM
-  # Extract the first word of "nm", so it can be a program name with args.
-set dummy nm; 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_ac_ct_NM+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_NM"; then
-  ac_cv_prog_ac_ct_NM="$ac_ct_NM" # 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_ac_ct_NM="nm"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
+# For linux-gnu, try linux-gnu, then linux.
+o=`echo $tail | sed 's/-.*$//'`
+if test $o != $tail; then
+  ostry="$ostry /$o"
+fi
+
+# For unix/sysv/sysv4, try unix/sysv/sysv4, then unix/sysv, then unix.
+base=
+tail=$base_os
+while b=`echo $tail | sed 's@^\(.*\)/\([^/]*\)$@& \1@'`; test -n "$b"; do
+  set $b
+  base="$base /$1"
+  tail="$2"
+done
+
+# For sparc/sparc32, try sparc/sparc32 and then sparc.
+mach=
+tail=$machine${submachine:+/$submachine}
+while m=`echo $tail | sed 's@^\(.*\)/\([^/]*\)$@& \1@'`; test -n "$m"; do
+  set $m
+  # Prepend the machine's FPU directory unless the architecture specific
+  # preconfigure disables it.
+  if test "$libc_cv_with_fp" = yes; then
+    maybe_fpu=/fpu
+  else
+    maybe_fpu=/nofpu
   fi
+  # For each machine term, try it with and then without /multiarch.
+  for try_fpu in $maybe_fpu ''; do
+    for try_multi in $multi_arch_d ''; do
+      mach="$mach /$1$try_fpu$try_multi"
+    done
+  done
+  tail="$2"
 done
+
+
+# Find what sysdep directories exist.
+sysnames=
+for b in $base ''; do
+  for m0 in $mach ''; do
+    for v in /$vendor ''; do
+      test "$v" = / && continue
+      for o in /$ostry ''; do
+	test "$o" = / && continue
+	for m in $mach ''; do
+	  try_suffix="$m0$b$v$o$m"
+	  if test -n "$try_suffix"; then
+	    try_srcdir="${srcdir}/"
+	    try="sysdeps$try_suffix"
+	    test -n "$enable_debug_configure" &&
+	    echo "$0 DEBUG: try $try" >&2
+	    if test -d "$try_srcdir$try"; then
+	      sysnames="$sysnames $try"
+	      { test -n "$o" || test -n "$b"; } && os_used=t
+	      { test -n "$m" || test -n "$m0"; } && machine_used=t
+	      case x${m0:-$m} in
+	      x*/$submachine) submachine_used=t ;;
+	      esac
+	    fi
+	  fi
+	done
+      done
+    done
   done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_NM=$ac_cv_prog_ac_ct_NM
-if test -n "$ac_ct_NM"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NM" >&5
-$as_echo "$ac_ct_NM" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
+done
 
-  if test "x$ac_ct_NM" = x; then
-    NM="false"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
+# If the assembler supports gnu_indirect_function symbol type and the
+# architecture supports multi-arch, we enable multi-arch by default.
+case $sysnames in
+*"$multi_arch_d"*)
+  ;;
+*)
+  test x"$multi_arch" = xdefault && multi_arch=no
+  ;;
 esac
-    NM=$ac_ct_NM
-  fi
-else
-  NM="$ac_cv_prog_NM"
-fi
+if test x"$multi_arch" != xno; then
+  $as_echo "#define USE_MULTIARCH 1" >>confdefs.h
 
+fi
 
-if test "x$maintainer" = "xyes"; then
-  for ac_prog in autoconf
-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_AUTOCONF+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$AUTOCONF"; then
-  ac_cv_prog_AUTOCONF="$AUTOCONF" # 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_AUTOCONF="$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
 
+if test -z "$os_used" && test "$os" != none; then
+  as_fn_error $? "Operating system $os is not supported." "$LINENO" 5
 fi
+if test -z "$machine_used" && test "$machine" != none; then
+  as_fn_error $? "The $machine is not supported." "$LINENO" 5
 fi
-AUTOCONF=$ac_cv_prog_AUTOCONF
-if test -n "$AUTOCONF"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AUTOCONF" >&5
-$as_echo "$AUTOCONF" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+if test -z "$submachine_used" && test -n "$submachine"; then
+  as_fn_error $? "The $submachine subspecies of $host_cpu is not supported." "$LINENO" 5
 fi
 
 
-  test -n "$AUTOCONF" && break
-done
-test -n "$AUTOCONF" || AUTOCONF="no"
+# We have now validated the configuration.
 
-  case "x$AUTOCONF" in
-  xno|x|x:) AUTOCONF=no ;;
-  *)
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking   whether $AUTOCONF${ACFLAGS:+ }$ACFLAGS works" >&5
-$as_echo_n "checking   whether $AUTOCONF${ACFLAGS:+ }$ACFLAGS works... " >&6; }
-if ${libc_cv_autoconf_works+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-      if (cd $srcdir; $AUTOCONF $ACFLAGS configure.ac > /dev/null 2>&1); then
-      libc_cv_autoconf_works=yes
-    else
-      libc_cv_autoconf_works=no
-    fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_autoconf_works" >&5
-$as_echo "$libc_cv_autoconf_works" >&6; }
-    test $libc_cv_autoconf_works = yes || AUTOCONF=no
-    ;;
+# Expand the list of system names into a full list of directories
+# from each element's parent name and Implies file (if present).
+set $sysnames
+names=
+while test $# -gt 0; do
+  name=$1
+  shift
+
+  case " $names " in *" $name "*)
+    # Already in the list.
+    continue
   esac
-  if test "x$AUTOCONF" = xno; then
-    aux_missing="$aux_missing autoconf"
-  fi
-else
-  AUTOCONF=no
-fi
 
-# Check for python3 if available, or else python.
-for ac_prog in python3 python
-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_PYTHON_PROG+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$PYTHON_PROG"; then
-  ac_cv_prog_PYTHON_PROG="$PYTHON_PROG" # 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_PYTHON_PROG="$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
+  # Report each name as we discover it, so there is no long pause in output.
+  echo $ECHO_N "$name $ECHO_C" >&6
 
-fi
-fi
-PYTHON_PROG=$ac_cv_prog_PYTHON_PROG
-if test -n "$PYTHON_PROG"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON_PROG" >&5
-$as_echo "$PYTHON_PROG" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
+  name_base=`echo $name | sed -e 's@\(.*sysdeps\)/.*@\1@'`
 
+  case $name in
+    /*) xsrcdir= ;;
+    *)  xsrcdir=$srcdir/ ;;
+  esac
+  test -n "$enable_debug_configure" &&
+  echo "DEBUG: name/Implies $xsrcdir$name/Implies" >&2
 
-  test -n "$PYTHON_PROG" && break
-done
+  for implies_file in Implies Implies-before Implies-after; do
+    implies_type=`echo $implies_file | sed s/-/_/`
+    eval ${implies_type}=
+    if test -f $xsrcdir$name/$implies_file; then
+      # Collect more names from the `Implies' file (removing comments).
+      implied_candidate="`sed 's/#.*$//' < $xsrcdir$name/$implies_file`"
+      for x in $implied_candidate; do
+	found=no
+	if test -d $xsrcdir$name_base/$x; then
+	  eval "${implies_type}=\"\$${implies_type} \$name_base/\$x\""
+	  found=yes
+	fi
+	try="sysdeps/$x"
+	try_srcdir=$srcdir/
+	test -n "$enable_debug_configure" &&
+	 echo "DEBUG: $name $implies_file $x try() {$try_srcdir}$try" >&2
+	if test $try != $xsrcdir$name_base/$x && test -d $try_srcdir$try;
+	then
+	  eval "${implies_type}=\"\$${implies_type} \$try\""
+	  found=yes
+	fi
+	if test $found = no; then
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $name/$implies_file specifies nonexistent $x" >&5
+$as_echo "$as_me: WARNING: $name/$implies_file specifies nonexistent $x" >&2;}
+	fi
+      done
+    fi
+  done
 
-if test -z "$PYTHON_PROG"; then
-  ac_verc_fail=yes
-else
-  # Found it, now check the version.
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of $PYTHON_PROG" >&5
-$as_echo_n "checking version of $PYTHON_PROG... " >&6; }
-  ac_prog_version=`$PYTHON_PROG --version 2>&1 | sed -n 's/^.*Python \([0-9][0-9.]*\).*$/\1/p'`
-  case $ac_prog_version in
-    '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
-    3.[4-9]*|3.[1-9][0-9]*|[4-9].*|[1-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;;
+  # Add NAME to the list of names.
+  names="$names $name"
 
-  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
-  critic_missing="$critic_missing python"
-fi
+  # Find the parent of NAME, using the empty string if it has none.
+  parent="`echo $name | sed -n -e 's=/[^/]*$==' -e '/sysdeps$/q' -e p`"
 
-PYTHON="$PYTHON_PROG -B"
+  test -n "$enable_debug_configure" &&
+    echo "DEBUG: $name Implies='$Implies' rest='$*' parent='$parent' \
+Implies_before='$Implies_before' Implies_after='$Implies_after'" >&2
 
+  # Add the names implied by NAME, and NAME's parent (if it has one), to
+  # the list of names to be processed (the argument list).  We prepend the
+  # implied names to the list and append the parent.  We want implied
+  # directories to come before further directories inferred from the
+  # configuration components; this ensures that for sysv4, unix/common
+  # (implied by unix/sysv/sysv4) comes before unix/sysv (in ostry (here $*)
+  # after sysv4).
+  sysnames="`echo $Implies $* $Implies_before $parent $Implies_after`"
+  test -n "$sysnames" && set $sysnames
+done
 
-test -n "$critic_missing" && as_fn_error $? "
-*** These critical programs are missing or too old:$critic_missing
-*** Check the INSTALL file for required versions." "$LINENO" 5
+# Add the default directories.
+default_sysnames="sysdeps/generic"
+sysnames="$names $default_sysnames"
 
-test -n "$aux_missing" && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING:
-*** These auxiliary programs are missing or incompatible versions:$aux_missing
-*** some features or tests will be disabled.
-*** Check the INSTALL file for required versions." >&5
-$as_echo "$as_me: WARNING:
-*** These auxiliary programs are missing or incompatible versions:$aux_missing
-*** some features or tests will be disabled.
-*** Check the INSTALL file for required versions." >&2;}
+# The other names were emitted during the scan.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $default_sysnames" >&5
+$as_echo "$default_sysnames" >&6; }
 
 # if using special system headers, find out the compiler's sekrit
 # header directory and add that to the list.  NOTE: Only does the right
diff --git a/configure.ac b/configure.ac
index 20b5e8043f..5709c7a0cf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -560,6 +560,125 @@ fi
 test -n "$base_machine" || base_machine=$machine
 AC_SUBST(base_machine)
 
+### Locate tools.
+
+AC_PROG_INSTALL
+if test "$INSTALL" = "${srcdir}/scripts/install-sh -c"; then
+  # The makefiles need to use a different form to find it in $srcdir.
+  INSTALL='\$(..)./scripts/install-sh -c'
+fi
+AC_PROG_LN_S
+
+LIBC_PROG_BINUTILS
+
+# Accept binutils 2.25 or newer.
+AC_CHECK_PROG_VER(AS, $AS, --version,
+		  [GNU assembler.* \([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]*],
+		  AS=: critic_missing="$critic_missing as")
+
+libc_cv_with_lld=no
+case $($LD --version) in
+  "GNU gold"*)
+  # Accept gold 1.14 or higher
+    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")
+    ;;
+  "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")
+    libc_cv_with_lld=yes
+    ;;
+  *)
+    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")
+    ;;
+esac
+LIBC_CONFIG_VAR([with-lld], [$libc_cv_with_lld])
+
+# These programs are version sensitive.
+AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version,
+  [GNU Make[^0-9]*\([0-9][0-9.]*\)],
+  [[4-9].* | [1-9][0-9]*], critic_missing="$critic_missing make")
+
+AC_CHECK_PROG_VER(MSGFMT, gnumsgfmt gmsgfmt msgfmt, --version,
+  [GNU gettext.* \([0-9]*\.[0-9.]*\)],
+  [0.10.3[6-9]* | 0.10.[4-9][0-9]* | 0.1[1-9]* | 0.[2-9][0-9]* | [1-9].*],
+  MSGFMT=: aux_missing="$aux_missing msgfmt")
+AC_CHECK_PROG_VER(MAKEINFO, makeinfo, --version,
+  [GNU texinfo.* \([0-9][0-9.]*\)],
+  [4.[7-9]*|4.[1-9][0-9]*|[5-9].*],
+  MAKEINFO=: aux_missing="$aux_missing makeinfo")
+AC_CHECK_PROG_VER(SED, sed, --version,
+  [GNU sed[^0-9]* \([0-9]*\.[0-9.]*\)],
+  [3.0[2-9]*|3.[1-9]*|[4-9]*],
+  SED=: aux_missing="$aux_missing sed")
+AC_CHECK_PROG_VER(AWK, gawk, --version,
+  [GNU Awk[^0-9]*\([0-9][0-9.]*\)],
+  [3.1.[2-9]*|3.[2-9]*|[4-9]*], critic_missing="$critic_missing gawk")
+AC_CHECK_PROG_VER(BISON, bison, --version,
+  [bison (GNU Bison) \([0-9]*\.[0-9.]*\)],
+  [2.7*|[3-9].*|[1-9][0-9]*], critic_missing="$critic_missing bison")
+
+AC_CACHE_CHECK([if $CC is sufficient to build libc], libc_cv_compiler_ok, [
+AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[]], [[
+#if !defined __GNUC__ || __GNUC__ < 6 || (__GNUC__ == 6 && __GNUC_MINOR__ < 2)
+#error insufficient compiler
+#endif]])],
+	       [libc_cv_compiler_ok=yes],
+	       [libc_cv_compiler_ok=no])])
+AS_IF([test $libc_cv_compiler_ok != yes],
+      [critic_missing="$critic_missing compiler"])
+
+AC_CHECK_TOOL(NM, nm, false)
+
+if test "x$maintainer" = "xyes"; then
+  AC_CHECK_PROGS(AUTOCONF, autoconf, no)
+  case "x$AUTOCONF" in
+  xno|x|x:) AUTOCONF=no ;;
+  *)
+    AC_CACHE_CHECK(dnl
+  whether $AUTOCONF${ACFLAGS:+ }$ACFLAGS works, libc_cv_autoconf_works, [dnl
+    if (cd $srcdir; $AUTOCONF $ACFLAGS configure.ac > /dev/null 2>&1); then
+      libc_cv_autoconf_works=yes
+    else
+      libc_cv_autoconf_works=no
+    fi])
+    test $libc_cv_autoconf_works = yes || AUTOCONF=no
+    ;;
+  esac
+  if test "x$AUTOCONF" = xno; then
+    aux_missing="$aux_missing autoconf"
+  fi
+else
+  AUTOCONF=no
+fi
+
+# Check for python3 if available, or else python.
+AC_CHECK_PROG_VER(PYTHON_PROG, python3 python, --version,
+  [Python \([0-9][0-9.]*\)],
+  [3.[4-9]*|3.[1-9][0-9]*|[4-9].*|[1-9][0-9]*],
+  critic_missing="$critic_missing python")
+PYTHON="$PYTHON_PROG -B"
+AC_SUBST(PYTHON)
+
+test -n "$critic_missing" && AC_MSG_ERROR([
+*** These critical programs are missing or too old:$critic_missing
+*** Check the INSTALL file for required versions.])
+
+test -n "$aux_missing" && AC_MSG_WARN([
+*** These auxiliary programs are missing or incompatible versions:$aux_missing
+*** some features or tests will be disabled.
+*** Check the INSTALL file for required versions.])
+
+
 # Determine whether to use fpu or nofpu sysdeps directories.
 AC_CACHE_CHECK([for use of fpu sysdeps directories],
 	       libc_cv_with_fp, [dnl
@@ -991,125 +1110,6 @@ AC_SUBST(sysnames)
 # The other names were emitted during the scan.
 AC_MSG_RESULT($default_sysnames)
 
-
-### Locate tools.
-
-AC_PROG_INSTALL
-if test "$INSTALL" = "${srcdir}/scripts/install-sh -c"; then
-  # The makefiles need to use a different form to find it in $srcdir.
-  INSTALL='\$(..)./scripts/install-sh -c'
-fi
-AC_PROG_LN_S
-
-LIBC_PROG_BINUTILS
-
-# Accept binutils 2.25 or newer.
-AC_CHECK_PROG_VER(AS, $AS, --version,
-		  [GNU assembler.* \([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]*],
-		  AS=: critic_missing="$critic_missing as")
-
-libc_cv_with_lld=no
-case $($LD --version) in
-  "GNU gold"*)
-  # Accept gold 1.14 or higher
-    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")
-    ;;
-  "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")
-    libc_cv_with_lld=yes
-    ;;
-  *)
-    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")
-    ;;
-esac
-LIBC_CONFIG_VAR([with-lld], [$libc_cv_with_lld])
-
-# These programs are version sensitive.
-AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version,
-  [GNU Make[^0-9]*\([0-9][0-9.]*\)],
-  [[4-9].* | [1-9][0-9]*], critic_missing="$critic_missing make")
-
-AC_CHECK_PROG_VER(MSGFMT, gnumsgfmt gmsgfmt msgfmt, --version,
-  [GNU gettext.* \([0-9]*\.[0-9.]*\)],
-  [0.10.3[6-9]* | 0.10.[4-9][0-9]* | 0.1[1-9]* | 0.[2-9][0-9]* | [1-9].*],
-  MSGFMT=: aux_missing="$aux_missing msgfmt")
-AC_CHECK_PROG_VER(MAKEINFO, makeinfo, --version,
-  [GNU texinfo.* \([0-9][0-9.]*\)],
-  [4.[7-9]*|4.[1-9][0-9]*|[5-9].*],
-  MAKEINFO=: aux_missing="$aux_missing makeinfo")
-AC_CHECK_PROG_VER(SED, sed, --version,
-  [GNU sed[^0-9]* \([0-9]*\.[0-9.]*\)],
-  [3.0[2-9]*|3.[1-9]*|[4-9]*],
-  SED=: aux_missing="$aux_missing sed")
-AC_CHECK_PROG_VER(AWK, gawk, --version,
-  [GNU Awk[^0-9]*\([0-9][0-9.]*\)],
-  [3.1.[2-9]*|3.[2-9]*|[4-9]*], critic_missing="$critic_missing gawk")
-AC_CHECK_PROG_VER(BISON, bison, --version,
-  [bison (GNU Bison) \([0-9]*\.[0-9.]*\)],
-  [2.7*|[3-9].*|[1-9][0-9]*], critic_missing="$critic_missing bison")
-
-AC_CACHE_CHECK([if $CC is sufficient to build libc], libc_cv_compiler_ok, [
-AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[]], [[
-#if !defined __GNUC__ || __GNUC__ < 6 || (__GNUC__ == 6 && __GNUC_MINOR__ < 2)
-#error insufficient compiler
-#endif]])],
-	       [libc_cv_compiler_ok=yes],
-	       [libc_cv_compiler_ok=no])])
-AS_IF([test $libc_cv_compiler_ok != yes],
-      [critic_missing="$critic_missing compiler"])
-
-AC_CHECK_TOOL(NM, nm, false)
-
-if test "x$maintainer" = "xyes"; then
-  AC_CHECK_PROGS(AUTOCONF, autoconf, no)
-  case "x$AUTOCONF" in
-  xno|x|x:) AUTOCONF=no ;;
-  *)
-    AC_CACHE_CHECK(dnl
-  whether $AUTOCONF${ACFLAGS:+ }$ACFLAGS works, libc_cv_autoconf_works, [dnl
-    if (cd $srcdir; $AUTOCONF $ACFLAGS configure.ac > /dev/null 2>&1); then
-      libc_cv_autoconf_works=yes
-    else
-      libc_cv_autoconf_works=no
-    fi])
-    test $libc_cv_autoconf_works = yes || AUTOCONF=no
-    ;;
-  esac
-  if test "x$AUTOCONF" = xno; then
-    aux_missing="$aux_missing autoconf"
-  fi
-else
-  AUTOCONF=no
-fi
-
-# Check for python3 if available, or else python.
-AC_CHECK_PROG_VER(PYTHON_PROG, python3 python, --version,
-  [Python \([0-9][0-9.]*\)],
-  [3.[4-9]*|3.[1-9][0-9]*|[4-9].*|[1-9][0-9]*],
-  critic_missing="$critic_missing python")
-PYTHON="$PYTHON_PROG -B"
-AC_SUBST(PYTHON)
-
-test -n "$critic_missing" && AC_MSG_ERROR([
-*** These critical programs are missing or too old:$critic_missing
-*** Check the INSTALL file for required versions.])
-
-test -n "$aux_missing" && AC_MSG_WARN([
-*** These auxiliary programs are missing or incompatible versions:$aux_missing
-*** some features or tests will be disabled.
-*** Check the INSTALL file for required versions.])
-
 # if using special system headers, find out the compiler's sekrit
 # header directory and add that to the list.  NOTE: Only does the right
 # thing on a system that doesn't need fixincludes.  (Not presently a problem.)
-- 
2.34.1


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

* [PATCH 2/7] elf: Do not assume symbol order on tst-audit25{a,b}
  2022-11-15 19:31 [PATCH 0/7] Fixing remaining lld issues Adhemerval Zanella via Libc-alpha
  2022-11-15 19:31 ` [PATCH 1/7] configure: Move locale tools early Adhemerval Zanella via Libc-alpha
@ 2022-11-15 19:31 ` Adhemerval Zanella via Libc-alpha
  2022-12-12 12:36   ` Adhemerval Zanella Netto via Libc-alpha
  2022-11-15 19:31 ` [PATCH 3/7] stdlib: Move _IO_cleanup to call_function_static_weak Adhemerval Zanella via Libc-alpha
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 25+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2022-11-15 19:31 UTC (permalink / raw)
  To: libc-alpha, Fangrui Song

The static linker might impose any order or internal function
position, so change the test to check if the audit prints the
symbol only once in any order.
---
 elf/tst-audit25.h  | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 elf/tst-audit25a.c | 38 ++++++++++++++++++++++++--------------
 elf/tst-audit25b.c | 39 +++++++++++++++++++++++++--------------
 3 files changed, 95 insertions(+), 28 deletions(-)
 create mode 100644 elf/tst-audit25.h

diff --git a/elf/tst-audit25.h b/elf/tst-audit25.h
new file mode 100644
index 0000000000..9b08c43c32
--- /dev/null
+++ b/elf/tst-audit25.h
@@ -0,0 +1,46 @@
+/* Check LD_AUDIT and LD_BIND_NOW.  Common definitions.
+   Copyright (C) 2022 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
+   <https://www.gnu.org/licenses/>.  */
+
+static void
+compare_output (void *buffer, size_t length, const char *ref[], size_t reflen)
+{
+  FILE *in = fmemopen (buffer, length, "r");
+  TEST_VERIFY_EXIT (in != NULL);
+  char *line = NULL;
+  size_t linelen = 0;
+
+  bool found[reflen];
+  for (int i = 0; i < reflen; i++)
+    found[i] = false;
+
+  while (xgetline (&line, &linelen, in))
+    {
+      for (int i = 0; i < reflen; i++)
+	if (strcmp (line, ref[i]) == 0)
+	  {
+	    TEST_COMPARE (found[i], false);
+	    found[i] = true;
+	  }
+    }
+
+  for (int i = 0; i < reflen; i++)
+    TEST_COMPARE (found[i], true);
+
+  free (line);
+  fclose (in);
+}
diff --git a/elf/tst-audit25a.c b/elf/tst-audit25a.c
index c2cff8541b..9d2b316576 100644
--- a/elf/tst-audit25a.c
+++ b/elf/tst-audit25a.c
@@ -29,6 +29,8 @@
 #include <support/support.h>
 #include <sys/auxv.h>
 
+#include "tst-audit25.h"
+
 static int restart;
 #define CMDLINE_OPTIONS \
   { "restart", no_argument, &restart, 1 },
@@ -82,13 +84,17 @@ do_test (int argc, char *argv[])
     /* tst-audit25a is build with -Wl,-z,lazy and tst-audit25mod1 with
        -Wl,-z,now; so only tst_audit25mod3_func1 should be expected to
        have LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT.  */
-    TEST_COMPARE_STRING (result.err.buffer,
-			 "la_symbind: tst_audit25mod3_func1 1\n"
-			 "la_symbind: tst_audit25mod1_func1 0\n"
-			 "la_symbind: tst_audit25mod1_func2 0\n"
-			 "la_symbind: tst_audit25mod2_func1 0\n"
-			 "la_symbind: tst_audit25mod4_func1 0\n"
-			 "la_symbind: tst_audit25mod2_func2 0\n");
+    const char *expected[] =
+      {
+	"la_symbind: tst_audit25mod1_func1 0\n",
+	"la_symbind: tst_audit25mod1_func2 0\n",
+	"la_symbind: tst_audit25mod2_func1 0\n",
+	"la_symbind: tst_audit25mod2_func2 0\n",
+	"la_symbind: tst_audit25mod3_func1 1\n",
+	"la_symbind: tst_audit25mod4_func1 0\n",
+      };
+    compare_output (result.err.buffer, result.err.length,
+		    expected, array_length(expected));
 
     support_capture_subprocess_free (&result);
   }
@@ -103,13 +109,17 @@ do_test (int argc, char *argv[])
     /* With LD_BIND_NOW all symbols are expected to have
        LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT.  Also the resolution
        order is done in breadth-first order.  */
-    TEST_COMPARE_STRING (result.err.buffer,
-			 "la_symbind: tst_audit25mod4_func1 1\n"
-			 "la_symbind: tst_audit25mod3_func1 1\n"
-			 "la_symbind: tst_audit25mod1_func1 1\n"
-			 "la_symbind: tst_audit25mod2_func1 1\n"
-			 "la_symbind: tst_audit25mod1_func2 1\n"
-			 "la_symbind: tst_audit25mod2_func2 1\n");
+    const char *expected[] =
+      {
+	  "la_symbind: tst_audit25mod1_func1 1\n",
+	  "la_symbind: tst_audit25mod1_func2 1\n",
+	  "la_symbind: tst_audit25mod2_func1 1\n",
+	  "la_symbind: tst_audit25mod2_func2 1\n",
+	  "la_symbind: tst_audit25mod3_func1 1\n",
+	  "la_symbind: tst_audit25mod4_func1 1\n",
+      };
+    compare_output (result.err.buffer, result.err.length,
+		    expected, array_length(expected));
 
     support_capture_subprocess_free (&result);
   }
diff --git a/elf/tst-audit25b.c b/elf/tst-audit25b.c
index 46391770fd..e1422049b1 100644
--- a/elf/tst-audit25b.c
+++ b/elf/tst-audit25b.c
@@ -16,6 +16,7 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <array_length.h>
 #include <errno.h>
 #include <getopt.h>
 #include <limits.h>
@@ -28,6 +29,8 @@
 #include <support/support.h>
 #include <sys/auxv.h>
 
+#include "tst-audit25.h"
+
 static int restart;
 #define CMDLINE_OPTIONS \
   { "restart", no_argument, &restart, 1 },
@@ -81,13 +84,17 @@ do_test (int argc, char *argv[])
        tst-audit25mod2 is built with -Wl,-z,lazy.  So only
        tst_audit25mod4_func1 (called by tst_audit25mod2_func1) should not
        have LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT.  */
-    TEST_COMPARE_STRING (result.err.buffer,
-			 "la_symbind: tst_audit25mod3_func1 1\n"
-			 "la_symbind: tst_audit25mod1_func1 1\n"
-			 "la_symbind: tst_audit25mod2_func1 1\n"
-			 "la_symbind: tst_audit25mod1_func2 1\n"
-			 "la_symbind: tst_audit25mod2_func2 1\n"
-			 "la_symbind: tst_audit25mod4_func1 0\n");
+    const char *expected[] =
+      {
+	"la_symbind: tst_audit25mod3_func1 1\n",
+	"la_symbind: tst_audit25mod1_func1 1\n",
+	"la_symbind: tst_audit25mod2_func1 1\n",
+	"la_symbind: tst_audit25mod1_func2 1\n",
+	"la_symbind: tst_audit25mod2_func2 1\n",
+	"la_symbind: tst_audit25mod4_func1 0\n",
+      };
+    compare_output (result.err.buffer, result.err.length,
+		    expected, array_length(expected));
 
     support_capture_subprocess_free (&result);
   }
@@ -102,13 +109,17 @@ do_test (int argc, char *argv[])
     /* With LD_BIND_NOW all symbols are expected to have
        LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT.  Also the resolution
        order is done in breadth-first order.  */
-    TEST_COMPARE_STRING (result.err.buffer,
-			 "la_symbind: tst_audit25mod4_func1 1\n"
-			 "la_symbind: tst_audit25mod3_func1 1\n"
-			 "la_symbind: tst_audit25mod1_func1 1\n"
-			 "la_symbind: tst_audit25mod2_func1 1\n"
-			 "la_symbind: tst_audit25mod1_func2 1\n"
-			 "la_symbind: tst_audit25mod2_func2 1\n");
+    const char *expected[] =
+      {
+	"la_symbind: tst_audit25mod4_func1 1\n",
+	"la_symbind: tst_audit25mod3_func1 1\n",
+	"la_symbind: tst_audit25mod1_func1 1\n",
+	"la_symbind: tst_audit25mod2_func1 1\n",
+	"la_symbind: tst_audit25mod1_func2 1\n",
+	"la_symbind: tst_audit25mod2_func2 1\n",
+      };
+    compare_output (result.err.buffer, result.err.length,
+		    expected, array_length(expected));
 
     support_capture_subprocess_free (&result);
   }
-- 
2.34.1


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

* [PATCH 3/7] stdlib: Move _IO_cleanup to call_function_static_weak
  2022-11-15 19:31 [PATCH 0/7] Fixing remaining lld issues Adhemerval Zanella via Libc-alpha
  2022-11-15 19:31 ` [PATCH 1/7] configure: Move locale tools early Adhemerval Zanella via Libc-alpha
  2022-11-15 19:31 ` [PATCH 2/7] elf: Do not assume symbol order on tst-audit25{a,b} Adhemerval Zanella via Libc-alpha
@ 2022-11-15 19:31 ` Adhemerval Zanella via Libc-alpha
  2022-12-12 10:52   ` Florian Weimer via Libc-alpha
  2022-11-15 19:31 ` [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions Adhemerval Zanella via Libc-alpha
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 25+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2022-11-15 19:31 UTC (permalink / raw)
  To: libc-alpha, Fangrui Song

---
 Makerules      | 3 ---
 libio/genops.c | 2 --
 stdlib/exit.c  | 6 ++----
 3 files changed, 2 insertions(+), 9 deletions(-)

diff --git a/Makerules b/Makerules
index a41491429e..3226b7a12b 100644
--- a/Makerules
+++ b/Makerules
@@ -568,9 +568,6 @@ $(common-objpfx)shlib.lds: $(common-objpfx)config.make $(..)Makerules
 		 PROVIDE(__start___libc_subfreeres = .);\
 		 __libc_subfreeres : { *(__libc_subfreeres) }\
 		 PROVIDE(__stop___libc_subfreeres = .);\
-		 PROVIDE(__start___libc_atexit = .);\
-		 __libc_atexit : { *(__libc_atexit) }\
-		 PROVIDE(__stop___libc_atexit = .);\
 		 PROVIDE(__start___libc_IO_vtables = .);\
 		 __libc_IO_vtables : { *(__libc_IO_vtables) }\
 		 PROVIDE(__stop___libc_IO_vtables = .);\
diff --git a/libio/genops.c b/libio/genops.c
index 1b629eb695..8a7fc4f7c5 100644
--- a/libio/genops.c
+++ b/libio/genops.c
@@ -1115,5 +1115,3 @@ _IO_list_resetlock (void)
 #endif
 }
 libc_hidden_def (_IO_list_resetlock)
-
-text_set_element(__libc_atexit, _IO_cleanup);
diff --git a/stdlib/exit.c b/stdlib/exit.c
index 10c44e1449..98579fbda8 100644
--- a/stdlib/exit.c
+++ b/stdlib/exit.c
@@ -20,11 +20,9 @@
 #include <unistd.h>
 #include <pointer_guard.h>
 #include <libc-lock.h>
+#include <libio/libioP.h>
 #include "exit.h"
 
-#include "set-hooks.h"
-DEFINE_HOOK (__libc_atexit, (void))
-
 /* Initialize the flag that indicates exit function processing
    is complete. See concurrency notes in stdlib/exit.h where
    __exit_funcs_lock is declared.  */
@@ -128,7 +126,7 @@ __run_exit_handlers (int status, struct exit_function_list **listp,
   __libc_lock_unlock (__exit_funcs_lock);
 
   if (run_list_atexit)
-    RUN_HOOK (__libc_atexit, ());
+    call_function_static_weak (_IO_cleanup);
 
   _exit (status);
 }
-- 
2.34.1


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

* [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions
  2022-11-15 19:31 [PATCH 0/7] Fixing remaining lld issues Adhemerval Zanella via Libc-alpha
                   ` (2 preceding siblings ...)
  2022-11-15 19:31 ` [PATCH 3/7] stdlib: Move _IO_cleanup to call_function_static_weak Adhemerval Zanella via Libc-alpha
@ 2022-11-15 19:31 ` Adhemerval Zanella via Libc-alpha
  2022-12-12 10:55   ` Florian Weimer via Libc-alpha
                     ` (4 more replies)
  2022-11-15 19:31 ` [PATCH 5/7] libio: Remove the usage of __libc_IO_vtables Adhemerval Zanella via Libc-alpha
                   ` (2 subsequent siblings)
  6 siblings, 5 replies; 25+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2022-11-15 19:31 UTC (permalink / raw)
  To: libc-alpha, Fangrui Song

They are both used by __libc_freeres to free all library malloc
allocated resources to help tooling like mtrace or valgrind on
memory leak tracking.

The previous scheme use linker markers and linker script entries
to consolidate the free routines function pointers on RELRO segment
and to be freed buffers on BSS.

This patch adds specific free functions for libc_freeres_ptrs
buffers and adds a new function pointer array with all required
free functions.  The function pointer array is used instead of
a chain of call_function_static_weak because it leads to better
code generation on most ABIs.

It allows to remove both the internal macros and the linker
script sections requirement.

Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
---
 Makerules                                     |   7 -
 crypt/md5-crypt.c                             |  10 +-
 crypt/sha256-crypt.c                          |  10 +-
 crypt/sha512-crypt.c                          |  10 +-
 elf/Makefile                                  |   1 +
 elf/dl-libc.c                                 |   4 +-
 grp/fgetgrent.c                               |   8 +-
 gshadow/fgetsgent.c                           |   2 +-
 iconv/gconv_cache.c                           |   3 +-
 iconv/gconv_conf.c                            |   3 +-
 iconv/gconv_db.c                              |   6 +-
 iconv/gconv_dl.c                              |   5 +-
 include/libc-symbols.h                        |  73 ------
 inet/getnameinfo.c                            |   8 +-
 inet/getnetgrent.c                            |   8 +-
 inet/rcmd.c                                   |   8 +-
 inet/rexec.c                                  |   8 +-
 intl/dcigettext.c                             |   3 +-
 intl/finddomain.c                             |   2 +-
 intl/loadmsgcat.c                             |   1 -
 intl/localealias.c                            |  15 +-
 libio/genops.c                                |   8 +-
 locale/loadarchive.c                          |   2 +-
 locale/localeinfo.h                           |   4 +-
 locale/setlocale.c                            |   4 +-
 login/getutent.c                              |   8 +-
 login/getutid.c                               |   8 +-
 login/getutline.c                             |   8 +-
 malloc/set-freeres.c                          | 222 ++++++++++++++++--
 malloc/thread-freeres.c                       |   2 +-
 misc/efgcvt-template.c                        |   8 +-
 misc/efgcvt.c                                 |   1 +
 misc/fstab.c                                  |   3 +-
 misc/hsearch.c                                |   4 -
 misc/mntent.c                                 |   8 +-
 misc/qefgcvt.c                                |   1 +
 misc/unwind-link.c                            |   2 +-
 nscd/nscd_getgr_r.c                           |   3 +-
 nscd/nscd_gethst_r.c                          |   3 +-
 nscd/nscd_getpw_r.c                           |   3 +-
 nscd/nscd_getserv_r.c                         |   3 +-
 nscd/nscd_netgroup.c                          |   3 +-
 nss/getXXbyYY.c                               |  10 +-
 nss/getXXent.c                                |  10 +-
 nss/nss_action.c                              |   2 +-
 nss/nss_database.c                            |   2 +-
 nss/nss_module.c                              |   2 +-
 posix/regcomp.c                               |   3 +-
 posix/register-atfork.c                       |   3 +-
 pwd/fgetpwent.c                               |   8 +-
 resolv/gai_misc.c                             |   3 +-
 resolv/res-close.c                            |   2 -
 resolv/res_hconf.c                            |   9 +-
 resolv/resolv_conf.c                          |   3 +-
 resolv/tst-leaks2.c                           |   2 +
 rt/aio_misc.c                                 |   3 +-
 shadow/fgetspent.c                            |   8 +-
 stdio-common/reg-modifier.c                   |   3 +-
 stdio-common/reg-printf.c                     |   9 +-
 stdio-common/reg-type.c                       |   9 +-
 stdlib/fmtmsg.c                               |   3 +-
 stdlib/setenv.c                               |   3 +-
 sunrpc/clnt_perr.c                            |   4 +-
 sunrpc/rpc_thread.c                           |   1 -
 sunrpc/tst-svc_register.c                     |   6 +-
 sysdeps/generic/set-freeres-fp.h              |  19 ++
 sysdeps/generic/set-freeres-os.h              |  19 ++
 sysdeps/generic/set-freeres-system.h          |  27 +++
 .../ldbl-128ibm-compat/ieee128-qefgcvt.c      |   1 +
 .../ldbl-128ibm-compat/set-freeres-fp.h       |  22 ++
 sysdeps/posix/getaddrinfo.c                   |   5 +-
 sysdeps/posix/ttyname.c                       |   8 +-
 sysdeps/unix/sysv/linux/check_pf.c            |   3 +-
 sysdeps/unix/sysv/linux/set-freeres-os.h      |  24 ++
 sysdeps/unix/sysv/linux/ttyname.c             |   3 +-
 time/tzfile.c                                 |   8 +-
 time/tzset.c                                  |   3 +-
 77 files changed, 547 insertions(+), 206 deletions(-)
 create mode 100644 sysdeps/generic/set-freeres-fp.h
 create mode 100644 sysdeps/generic/set-freeres-os.h
 create mode 100644 sysdeps/generic/set-freeres-system.h
 create mode 100644 sysdeps/ieee754/ldbl-128ibm-compat/set-freeres-fp.h
 create mode 100644 sysdeps/unix/sysv/linux/set-freeres-os.h

diff --git a/Makerules b/Makerules
index 3226b7a12b..962b2cd90c 100644
--- a/Makerules
+++ b/Makerules
@@ -560,14 +560,7 @@ $(common-objpfx)shlib.lds: $(common-objpfx)config.make $(..)Makerules
 		  -Wl,--verbose 2>/dev/null | \
 	  sed > $@T \
 	      -e '/^=========/,/^=========/!d;/^=========/d' \
-	      -e 's/^.*\*(\.dynbss).*$$/& \
-		 PROVIDE(__start___libc_freeres_ptrs = .); \
-		 *(__libc_freeres_ptrs) \
-		 PROVIDE(__stop___libc_freeres_ptrs = .);/'\
 	      -e 's@^.*\*(\.jcr).*$$@& \
-		 PROVIDE(__start___libc_subfreeres = .);\
-		 __libc_subfreeres : { *(__libc_subfreeres) }\
-		 PROVIDE(__stop___libc_subfreeres = .);\
 		 PROVIDE(__start___libc_IO_vtables = .);\
 		 __libc_IO_vtables : { *(__libc_IO_vtables) }\
 		 PROVIDE(__stop___libc_IO_vtables = .);\
diff --git a/crypt/md5-crypt.c b/crypt/md5-crypt.c
index 7c4fb9fb97..9660cdd698 100644
--- a/crypt/md5-crypt.c
+++ b/crypt/md5-crypt.c
@@ -299,10 +299,7 @@ __md5_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
   return buffer;
 }
 
-#ifndef _LIBC
-# define libc_freeres_ptr(decl) decl
-#endif
-libc_freeres_ptr (static char *buffer);
+static char *buffer;
 
 char *
 __md5_crypt (const char *key, const char *salt)
@@ -330,7 +327,10 @@ __md5_crypt (const char *key, const char *salt)
 static void
 __attribute__ ((__destructor__))
 free_mem (void)
+#else
+void
+__md5_crypt_freemem (void)
+#endif
 {
   free (buffer);
 }
-#endif
diff --git a/crypt/sha256-crypt.c b/crypt/sha256-crypt.c
index a98a968a8b..75fd582429 100644
--- a/crypt/sha256-crypt.c
+++ b/crypt/sha256-crypt.c
@@ -386,10 +386,7 @@ __sha256_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
   return buffer;
 }
 
-#ifndef _LIBC
-# define libc_freeres_ptr(decl) decl
-#endif
-libc_freeres_ptr (static char *buffer);
+static char *buffer;
 
 /* This entry point is equivalent to the `crypt' function in Unix
    libcs.  */
@@ -422,7 +419,10 @@ __sha256_crypt (const char *key, const char *salt)
 static void
 __attribute__ ((__destructor__))
 free_mem (void)
+#else
+void
+__sha256_crypt_freemem (void)
+#endif
 {
   free (buffer);
 }
-#endif
diff --git a/crypt/sha512-crypt.c b/crypt/sha512-crypt.c
index ea13527c09..ae6ecaef16 100644
--- a/crypt/sha512-crypt.c
+++ b/crypt/sha512-crypt.c
@@ -408,10 +408,7 @@ __sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
   return buffer;
 }
 
-#ifndef _LIBC
-# define libc_freeres_ptr(decl) decl
-#endif
-libc_freeres_ptr (static char *buffer);
+static char *buffer;
 
 /* This entry point is equivalent to the `crypt' function in Unix
    libcs.  */
@@ -444,7 +441,10 @@ __sha512_crypt (const char *key, const char *salt)
 static void
 __attribute__ ((__destructor__))
 free_mem (void)
+#else
+void
+__sha512_crypt_freemem (void)
+#endif
 {
   free (buffer);
 }
-#endif
diff --git a/elf/Makefile b/elf/Makefile
index eca7b28ab5..6de2ca6d6c 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -612,6 +612,7 @@ $(objpfx)tst-relro-libc.out: tst-relro-symbols.py $(..)/scripts/glibcelf.py \
 	    --required=_IO_wmem_jumps \
 	    --required=_IO_wstr_jumps \
 	    --required=_IO_wstrn_jumps \
+	    --required=__libc_freeres_funcs \
 	    --optional=_IO_old_cookie_jumps \
 	    --optional=_IO_old_file_jumps \
 	    --optional=_IO_old_proc_jumps \
diff --git a/elf/dl-libc.c b/elf/dl-libc.c
index 266e068da6..06bce2f6dd 100644
--- a/elf/dl-libc.c
+++ b/elf/dl-libc.c
@@ -228,7 +228,7 @@ __libc_dlclose (void *map)
 }
 
 
-static bool __libc_freeres_fn_section
+static bool
 free_slotinfo (struct dtv_slotinfo_list **elemp)
 {
   size_t cnt;
@@ -256,7 +256,7 @@ free_slotinfo (struct dtv_slotinfo_list **elemp)
 }
 
 
-libc_freeres_fn (free_mem)
+void __libc_freemem (void)
 {
   struct link_map *l;
   struct r_search_path_elem *d;
diff --git a/grp/fgetgrent.c b/grp/fgetgrent.c
index fd2b4d32d6..df04530b04 100644
--- a/grp/fgetgrent.c
+++ b/grp/fgetgrent.c
@@ -25,7 +25,7 @@
 /* We need to protect the dynamic buffer handling.  */
 __libc_lock_define_initialized (static, lock);
 
-libc_freeres_ptr (static char *buffer);
+static char *buffer;
 
 /* Read one entry from the given stream.  */
 struct group *
@@ -82,3 +82,9 @@ fgetgrent (FILE *stream)
 
   return result;
 }
+
+void
+__libc_fgetgrent_freemem (void)
+{
+  free (buffer);
+}
diff --git a/gshadow/fgetsgent.c b/gshadow/fgetsgent.c
index 02f9c7d643..4d9282e560 100644
--- a/gshadow/fgetsgent.c
+++ b/gshadow/fgetsgent.c
@@ -28,7 +28,7 @@
 /* We need to protect the dynamic buffer handling.  */
 __libc_lock_define_initialized (static, lock);
 
-libc_freeres_ptr (static char *buffer);
+static char *buffer;
 
 /* Read one shadow entry from the given stream.  */
 struct sgrp *
diff --git a/iconv/gconv_cache.c b/iconv/gconv_cache.c
index 8d47545c41..e250228561 100644
--- a/iconv/gconv_cache.c
+++ b/iconv/gconv_cache.c
@@ -449,7 +449,8 @@ __gconv_release_cache (struct __gconv_step *steps, size_t nsteps)
 
 
 /* Free all resources if necessary.  */
-libc_freeres_fn (free_mem)
+void
+__gconv_cache_freemem (void)
 {
   if (cache_malloced)
     free (gconv_cache);
diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c
index f069e28323..608109c040 100644
--- a/iconv/gconv_conf.c
+++ b/iconv/gconv_conf.c
@@ -530,7 +530,8 @@ __gconv_load_conf (void)
 
 
 /* Free all resources if necessary.  */
-libc_freeres_fn (free_mem)
+void
+__gconv_conf_freemem (void)
 {
   if (__gconv_path_elem != NULL && __gconv_path_elem != &empty_path_elem)
     free ((void *) __gconv_path_elem);
diff --git a/iconv/gconv_db.c b/iconv/gconv_db.c
index 4943c954a3..7aeae5993c 100644
--- a/iconv/gconv_db.c
+++ b/iconv/gconv_db.c
@@ -169,7 +169,7 @@ add_derivation (const char *fromset, const char *toset,
      not all memory will be freed.  */
 }
 
-static void __libc_freeres_fn_section
+static void
 free_derivation (void *p)
 {
   struct known_derivation *deriv = (struct known_derivation *) p;
@@ -793,7 +793,6 @@ __gconv_close_transform (struct __gconv_step *steps, size_t nsteps)
 
 /* Free the modules mentioned.  */
 static void
-__libc_freeres_fn_section
 free_modules_db (struct gconv_module *node)
 {
   if (node->left != NULL)
@@ -812,7 +811,8 @@ free_modules_db (struct gconv_module *node)
 
 
 /* Free all resources if necessary.  */
-libc_freeres_fn (free_mem)
+void
+__gconv_db_freemem (void)
 {
   /* First free locale memory.  This needs to be done before freeing
      derivations, as ctype cleanup functions dereference steps arrays which we
diff --git a/iconv/gconv_dl.c b/iconv/gconv_dl.c
index 5ed982636a..6cc05e42fc 100644
--- a/iconv/gconv_dl.c
+++ b/iconv/gconv_dl.c
@@ -184,7 +184,7 @@ __gconv_release_shlib (struct __gconv_loaded_object *handle)
 
 
 /* We run this if we debug the memory allocation.  */
-static void __libc_freeres_fn_section
+static void
 do_release_all (void *nodep)
 {
   struct __gconv_loaded_object *obj = (struct __gconv_loaded_object *) nodep;
@@ -196,7 +196,8 @@ do_release_all (void *nodep)
   free (obj);
 }
 
-libc_freeres_fn (free_mem)
+void
+__gconv_dl_freemem (void)
 {
   __tdestroy (loaded, do_release_all);
   loaded = NULL;
diff --git a/include/libc-symbols.h b/include/libc-symbols.h
index f4437ff6ad..a1d422131f 100644
--- a/include/libc-symbols.h
+++ b/include/libc-symbols.h
@@ -237,79 +237,6 @@ requires at runtime the shared libraries from the glibc version used \
 for linking")
 #endif
 
-/* Resource Freeing Hooks:
-
-   Normally a process exits and the OS cleans up any allocated
-   memory.  However, when tooling like mtrace or valgrind is monitoring
-   the process we need to free all resources that are part of the
-   process in order to provide the consistency required to track
-   memory leaks.
-
-   A single public API exists and is __libc_freeres(), and this is used
-   by applications like valgrind to freee resouces.
-
-   There are 3 cases:
-
-   (a) __libc_freeres
-
-	In this case all you need to do is define the freeing routine:
-
-	foo.c:
-	libfoo_freeres_fn (foo_freeres)
-	{
-	  complex_free (mem);
-	}
-
-	This ensures the function is called at the right point to free
-	resources.
-
-   (b) __libc_freeres_ptr
-
-	The framework for (a) iterates over the list of pointers-to-free
-	in (b) and frees them.
-
-	foo.c:
-	libc_freeres_ptr (static char *foo_buffer);
-
-	Freeing these resources alaways happens last and is equivalent
-	to registering a function that does 'free (foo_buffer)'.
-
-   (c) Explicit lists of free routines to call or objects to free.
-
-	It is the intended goal to remove (a) and (b) which have some
-	non-determinism based on link order, and instead use explicit
-	lists of functions and frees to resolve cleanup ordering issues
-	and make it easy to debug and maintain.
-
-	As of today the following subsystems use (c):
-
-	Per-thread cleanup:
-	* malloc/thread-freeres.c
-
-	libdl cleanup:
-	* dlfcn/dlfreeres.c
-
-	libpthread cleanup:
-	* nptl/nptlfreeres.c
-
-	So if you need any shutdown routines to run you should add them
-	directly to the appropriate subsystem's shutdown list.  */
-
-/* Resource pointers to free in libc.so.  */
-#define libc_freeres_ptr(decl) \
-  __make_section_unallocated ("__libc_freeres_ptrs, \"aw\", %nobits") \
-  decl __attribute__ ((section ("__libc_freeres_ptrs" __sec_comment)))
-
-/* Resource freeing functions from libc.so go in this section.  */
-#define __libc_freeres_fn_section \
-  __attribute__ ((__used__, section ("__libc_freeres_fn")))
-
-/* Resource freeing functions for libc.so.  */
-#define libc_freeres_fn(name) \
-  static void name (void) __attribute_used__ __libc_freeres_fn_section;	\
-  text_set_element (__libc_subfreeres, name);				\
-  static void name (void)
-
 /* Declare SYMBOL to be TYPE (`function' or `object') of SIZE bytes
    alias to ORIGINAL, when the assembler supports such declarations
    (such as in ELF).
diff --git a/inet/getnameinfo.c b/inet/getnameinfo.c
index 4733be6f5b..6b1cf206c4 100644
--- a/inet/getnameinfo.c
+++ b/inet/getnameinfo.c
@@ -77,7 +77,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 # define min(x,y) (((x) > (y)) ? (y) : (x))
 #endif /* min */
 
-libc_freeres_ptr (static char *domain);
+static char *domain;
 
 /* Former NI_IDN_ALLOW_UNASSIGNED, NI_IDN_USE_STD3_ASCII_RULES flags,
    now ignored.  */
@@ -556,3 +556,9 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host,
   return 0;
 }
 libc_hidden_def (getnameinfo)
+
+void
+__libc_getnameinfo_freemem (void)
+{
+  free (domain);
+}
diff --git a/inet/getnetgrent.c b/inet/getnetgrent.c
index e354194b72..00549d046d 100644
--- a/inet/getnetgrent.c
+++ b/inet/getnetgrent.c
@@ -21,7 +21,7 @@
 #include <libc-lock.h>
 
 /* Static buffer for return value.  We allocate it when needed.  */
-libc_freeres_ptr (static char *buffer);
+static char *buffer;
 /* All three strings should fit in a block of 1kB size.  */
 #define BUFSIZE 1024
 
@@ -47,3 +47,9 @@ getnetgrent (char **hostp, char **userp, char **domainp)
 
   return __getnetgrent_r (hostp, userp, domainp, buffer, BUFSIZE);
 }
+
+void
+__libc_getnetgrent_freemem (void)
+{
+  free (buffer);
+}
diff --git a/inet/rcmd.c b/inet/rcmd.c
index 2b95fa11d8..40326ab501 100644
--- a/inet/rcmd.c
+++ b/inet/rcmd.c
@@ -98,7 +98,7 @@ int iruserok (uint32_t raddr, int superuser, const char *ruser,
 
 libc_hidden_proto (iruserok_af)
 
-libc_freeres_ptr(static char *ahostbuf);
+static char *ahostbuf;
 
 int
 rcmd_af (char **ahost, u_short rport, const char *locuser, const char *remuser,
@@ -817,3 +817,9 @@ __validuser2_sa (FILE *hostf, struct sockaddr *ra, size_t ralen,
 
     return retval;
 }
+
+void
+__libc_rcmd_freemem (void)
+{
+  free (ahostbuf);
+}
diff --git a/inet/rexec.c b/inet/rexec.c
index 064e979d68..354c73ddc6 100644
--- a/inet/rexec.c
+++ b/inet/rexec.c
@@ -42,7 +42,7 @@
 #include <sys/uio.h>
 
 int	rexecoptions;
-libc_freeres_ptr (static char *ahostbuf);
+static char *ahostbuf;
 
 int
 rexec_af (char **ahost, int rport, const char *name, const char *pass,
@@ -196,3 +196,9 @@ rexec (char **ahost, int rport, const char *name, const char *pass,
 {
 	return rexec_af(ahost, rport, name, pass, cmd, fd2p, AF_INET);
 }
+
+void
+__libc_rexec_freemem (void)
+{
+  free (ahostbuf);
+}
diff --git a/intl/dcigettext.c b/intl/dcigettext.c
index 1fc074a414..bfac152908 100644
--- a/intl/dcigettext.c
+++ b/intl/dcigettext.c
@@ -1671,7 +1671,8 @@ mempcpy (void *dest, const void *src, size_t n)
 #ifdef _LIBC
 /* If we want to free all resources we have to do some work at
    program's end.  */
-libc_freeres_fn (free_mem)
+void
+__intl_freemem (void)
 {
   void *old;
 
diff --git a/intl/finddomain.c b/intl/finddomain.c
index 416e28ad76..58de876e28 100644
--- a/intl/finddomain.c
+++ b/intl/finddomain.c
@@ -185,7 +185,7 @@ out:
 #ifdef _LIBC
 /* This is called from iconv/gconv_db.c's free_mem, as locales must
    be freed before freeing gconv steps arrays.  */
-void __libc_freeres_fn_section
+void
 _nl_finddomain_subfreeres (void)
 {
   struct loaded_l10nfile *runp = _nl_loaded_domains;
diff --git a/intl/loadmsgcat.c b/intl/loadmsgcat.c
index 98d5f53232..0b98f233dd 100644
--- a/intl/loadmsgcat.c
+++ b/intl/loadmsgcat.c
@@ -1284,7 +1284,6 @@ _nl_load_domain (struct loaded_l10nfile *domain_file,
 
 #ifdef _LIBC
 void
-__libc_freeres_fn_section
 _nl_unload_domain (struct loaded_domain *domain)
 {
   size_t i;
diff --git a/intl/localealias.c b/intl/localealias.c
index b36092363a..4bf068d0ea 100644
--- a/intl/localealias.c
+++ b/intl/localealias.c
@@ -126,14 +126,10 @@ struct alias_map
 };
 
 
-#ifndef _LIBC
-# define libc_freeres_ptr(decl) decl
-#endif
-
-libc_freeres_ptr (static char *string_space);
+static char *string_space;
 static size_t string_space_act;
 static size_t string_space_max;
-libc_freeres_ptr (static struct alias_map *map);
+static struct alias_map *map;
 static size_t nmap;
 static size_t maxmap;
 
@@ -439,3 +435,10 @@ alias_compare (const struct alias_map *map1, const struct alias_map *map2)
   return c1 - c2;
 #endif
 }
+
+void
+__libc_localealias_freemem (void)
+{
+  free (string_space);
+  free (map);
+}
diff --git a/libio/genops.c b/libio/genops.c
index 8a7fc4f7c5..b3a0603a0a 100644
--- a/libio/genops.c
+++ b/libio/genops.c
@@ -765,8 +765,8 @@ weak_alias (_IO_flush_all_linebuffered, _flushlbf)
    actual buffer because this will happen anyway once the program
    terminated.  If we do want to look for memory leaks we have to free
    the buffers.  Whether something is freed is determined by the
-   function sin the libc_freeres section.  Those are called as part of
-   the atexit routine, just like _IO_cleanup.  The problem is we do
+   function called by __libc_freeres (those are not called as part of
+   the atexit routine, different from  _IO_cleanup).  The problem is we do
    not know whether the freeres code is called first or _IO_cleanup.
    if the former is the case, we set the DEALLOC_BUFFER variable to
    true and _IO_unbuffer_all will take care of the rest.  If
@@ -844,8 +844,8 @@ _IO_unbuffer_all (void)
 #endif
 }
 
-
-libc_freeres_fn (buffer_free)
+void
+__libio_freemem (void)
 {
   dealloc_buffers = true;
 
diff --git a/locale/loadarchive.c b/locale/loadarchive.c
index fcc4913319..60ae1daa2c 100644
--- a/locale/loadarchive.c
+++ b/locale/loadarchive.c
@@ -498,7 +498,7 @@ _nl_load_locale_from_archive (int category, const char **namep)
   return lia->data[category];
 }
 
-void __libc_freeres_fn_section
+void
 _nl_archive_subfreeres (void)
 {
   struct locale_in_archive *lia;
diff --git a/locale/localeinfo.h b/locale/localeinfo.h
index fd43033a19..1bf4215e71 100644
--- a/locale/localeinfo.h
+++ b/locale/localeinfo.h
@@ -381,10 +381,10 @@ extern struct __locale_data *_nl_load_locale_from_archive (int category,
 							   const char **namep)
      attribute_hidden;
 
-/* Subroutine of setlocale's __libc_subfreeres hook.  */
+/* Subroutine of setlocale's free resource.  */
 extern void _nl_archive_subfreeres (void) attribute_hidden;
 
-/* Subroutine of gconv-db's __libc_subfreeres hook.  */
+/* Subroutine of gconv-db's free resource.  */
 extern void _nl_locale_subfreeres (void) attribute_hidden;
 
 /* Validate the contents of a locale file and set up the in-core
diff --git a/locale/setlocale.c b/locale/setlocale.c
index 56c14d8533..d1e773f46a 100644
--- a/locale/setlocale.c
+++ b/locale/setlocale.c
@@ -468,7 +468,7 @@ setlocale (int category, const char *locale)
 }
 libc_hidden_def (setlocale)
 
-static void __libc_freeres_fn_section
+static void
 free_category (int category,
 	       struct __locale_data *here, struct __locale_data *c_data)
 {
@@ -498,7 +498,7 @@ free_category (int category,
 
 /* This is called from iconv/gconv_db.c's free_mem, as locales must
    be freed before freeing gconv steps arrays.  */
-void __libc_freeres_fn_section
+void
 _nl_locale_subfreeres (void)
 {
 #ifdef NL_CURRENT_INDIRECT
diff --git a/login/getutent.c b/login/getutent.c
index 8d2f1207f8..4ee31eade3 100644
--- a/login/getutent.c
+++ b/login/getutent.c
@@ -20,7 +20,7 @@
 
 
 /* Local buffer to store the result.  */
-libc_freeres_ptr (static struct utmp *buffer);
+static struct utmp *buffer;
 
 
 struct utmp *
@@ -42,3 +42,9 @@ __getutent (void)
 }
 libc_hidden_def (__getutent)
 weak_alias (__getutent, getutent)
+
+void
+__libc_getutent_freemem (void)
+{
+  free (buffer);
+}
diff --git a/login/getutid.c b/login/getutid.c
index 303c178db1..680c4f6855 100644
--- a/login/getutid.c
+++ b/login/getutid.c
@@ -20,7 +20,7 @@
 
 
 /* Local buffer to store the result.  */
-libc_freeres_ptr (static struct utmp *buffer);
+static struct utmp *buffer;
 
 struct utmp *
 __getutid (const struct utmp *id)
@@ -40,3 +40,9 @@ __getutid (const struct utmp *id)
 }
 libc_hidden_def (__getutid)
 weak_alias (__getutid, getutid)
+
+void
+__libc_getutid_freemem (void)
+{
+  free (buffer);
+}
diff --git a/login/getutline.c b/login/getutline.c
index 661eff3a3c..12f7994de1 100644
--- a/login/getutline.c
+++ b/login/getutline.c
@@ -20,7 +20,7 @@
 
 
 /* Local buffer to store the result.  */
-libc_freeres_ptr (static struct utmp *buffer);
+static struct utmp *buffer;
 
 
 struct utmp *
@@ -41,3 +41,9 @@ __getutline (const struct utmp *line)
 }
 libc_hidden_def (__getutline)
 weak_alias (__getutline, getutline)
+
+void
+__libc_getutline_freemem (void)
+{
+  free (buffer);
+}
diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c
index be8c2a35fc..ce5d010133 100644
--- a/malloc/set-freeres.c
+++ b/malloc/set-freeres.c
@@ -15,32 +15,210 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
+#include <array_length.h>
 #include <atomic.h>
 #include <stdlib.h>
-#include <set-hooks.h>
 #include <libc-internal.h>
 #include <unwind-link.h>
 #include <dlfcn/dlerror.h>
 #include <ldsodefs.h>
+#include <set-freeres-system.h>
 
 #include "../nss/nsswitch.h"
 #include "../libio/libioP.h"
 
-DEFINE_HOOK (__libc_subfreeres, (void));
-
-symbol_set_define (__libc_freeres_ptrs);
-
-extern void __libpthread_freeres (void)
-#if PTHREAD_IN_LIBC && defined SHARED
-/* It is possible to call __libpthread_freeres directly in shared
-   builds with an integrated libpthread.  */
-  attribute_hidden
-#else
-  __attribute__ ((weak))
-#endif
-  ;
-
-void __libc_freeres_fn_section
+/* Resource Freeing Hooks:
+
+   Normally a process exits and the OS cleans up any allocated
+   memory.  However, when tooling like mtrace or valgrind is monitoring
+   the process we need to free all resources that are part of the
+   process in order to provide the consistency required to track
+   memory leaks.
+
+   A single public API exists and is __libc_freeres(), and this is used
+   by applications like valgrind to freee resouces.
+
+   Each free routines must be explicit listed below, with the care to define
+   weak functions for external symbol if applicable.   */
+
+/* From libc.so.  */
+extern void __libc_freemem (void) weak_function;
+extern void __hdestroy (void) weak_function;
+extern void __gconv_cache_freemem (void) weak_function;
+extern void __gconv_conf_freemem (void) weak_function;
+extern void __gconv_db_freemem (void) weak_function;
+extern void __gconv_dl_freemem (void) weak_function;
+extern void __intl_freemem (void) weak_function;
+extern void __libio_freemem (void) weak_function;
+extern void __libc_fstab_freemem (void) weak_function;
+extern void __nscd_gr_map_freemem (void) weak_function;
+extern void __nscd_hst_map_freemem (void) weak_function;
+extern void __nscd_pw_map_freemem (void) weak_function;
+extern void __nscd_serv_map_freemem (void) weak_function;
+extern void __nscd_group_map_freemem (void) weak_function;
+extern void __libc_regcomp_freemem (void) weak_function;
+extern void __libc_atfork_freemem (void) weak_function;
+extern void __libc_resolv_conf_freemem (void) weak_function;
+extern void __libc_resolv_res_hconf_freemem (void) weak_function;
+extern void __res_thread_freeres (void) weak_function;
+extern void __libc_printf_freemem (void) weak_function;
+extern void __libc_fmtmsg_freemem (void) weak_function;
+extern void __libc_setenv_freemem (void) weak_function;
+extern void __rpc_freemem (void) weak_function;
+extern void __rpc_thread_destroy (void) weak_function;
+extern void __libc_getaddrinfo_freemem (void) weak_function;
+extern void __libc_tzset_freemem (void) weak_function;
+extern void __libc_fgetgrent_freemem (void) weak_function;
+extern void __libc_getnameinfo_freemem (void) weak_function;
+extern void __libc_getnetgrent_freemem (void) weak_function;
+extern void __libc_rcmd_freemem (void) weak_function;
+extern void __libc_rexec_freemem (void) weak_function;
+extern void __libc_localealias_freemem (void) weak_function;
+extern void __libc_getutent_freemem (void) weak_function;
+extern void __libc_getutid_freemem (void) weak_function;
+extern void __libc_getutline_freemem (void) weak_function;
+extern void __libc_mntent_freemem (void) weak_function;
+extern void __libc_fgetpwent_freemem (void) weak_function;
+extern void __libc_fgetspent_freemem (void) weak_function;
+extern void __libc_reg_printf_freemem (void) weak_function;
+extern void __libc_reg_type_freemem (void) weak_function;
+extern void __libc_tzfile_freemem (void) weak_function;
+/* From misc/efgcvt-template.c  */
+extern void __libc_efgcvt_freemem (void) weak_function;
+extern void __libc_qefgcvt_freemem (void) weak_function;
+/* From nss/getXXbyYY.c  */
+extern void __libc_getgrgid_freemem (void) weak_function;
+extern void __libc_getgrnam_freemem (void) weak_function;
+extern void __libc_getpwnam_freemem (void) weak_function;
+extern void __libc_getpwuid_freemem (void) weak_function;
+extern void __libc_getspnam_freemem (void) weak_function;
+extern void __libc_getaliasbyname_freemem (void) weak_function;
+extern void __libc_gethostbyaddr_freemem (void) weak_function;
+extern void __libc_gethostbyname_freemem (void) weak_function;
+extern void __libc_gethostbyname2_freemem (void) weak_function;
+extern void __libc_getnetbyaddr_freemem (void) weak_function;
+extern void __libc_getnetbyname_freemem (void) weak_function;
+extern void __libc_getprotobynumber_freemem (void) weak_function;
+extern void __libc_getprotobyname_freemem (void) weak_function;
+extern void __libc_getrpcbyname_freemem (void) weak_function;
+extern void __libc_getrpcbynumber_freemem (void) weak_function;
+extern void __libc_getservbyname_freemem (void) weak_function;
+extern void __libc_getservbyport_freemem (void) weak_function;;
+/* From nss/getXXent.c */
+extern void __libc_getgrent_freemem (void) weak_function;
+extern void __libc_getpwent_freemem (void) weak_function;
+extern void __libc_getspent_freemem (void) weak_function;
+extern void __libc_getaliasent_freemem (void) weak_function;
+extern void __libc_gethostent_freemem (void) weak_function;
+extern void __libc_getnetent_freemem (void) weak_function;
+extern void __libc_getprotoent_freemem (void) weak_function;
+extern void __libc_getrpcent_freemem (void) weak_function;
+extern void __libc_getservent_freemem (void) weak_function;
+
+/* From either libc.so or libpthread.so  */
+extern void __libpthread_freeres (void) weak_function;
+/* From either libc.so or libanl.so  */
+extern void __gai_freemem (void) weak_function;
+/* From either libc.so or librt.so  */
+extern void __aio_freemem (void) weak_function;
+
+/* From libcrypto.so.  */
+extern void __md5_crypt_freemem (void) weak_function;
+extern void __sha256_crypt_freemem (void) weak_function;
+extern void __sha512_crypt_freemem (void) weak_function;
+
+static void (*__libc_freeres_funcs[])(void) attribute_relro =
+{
+  __libc_freemem,
+  __hdestroy,
+  __gconv_cache_freemem,
+  __gconv_conf_freemem,
+  __gconv_db_freemem,
+  __gconv_dl_freemem,
+  __intl_freemem,
+  __libio_freemem,
+  __libc_fstab_freemem,
+  __nscd_gr_map_freemem,
+  __nscd_hst_map_freemem,
+  __nscd_pw_map_freemem,
+  __nscd_serv_map_freemem,
+  __nscd_group_map_freemem,
+  __libc_regcomp_freemem,
+  __libc_atfork_freemem,
+  /* __res_thread_freeres deallocates the per-thread resolv_context, which
+     in turn drop the reference count of the current global object.  So
+     it need to be before __libc_resolv_conf_freemem.  */
+  __res_thread_freeres,
+  __libc_resolv_res_hconf_freemem,
+  __libc_resolv_conf_freemem,
+  __libc_printf_freemem,
+  __libc_fmtmsg_freemem,
+  __libc_setenv_freemem,
+  __rpc_freemem,
+  __rpc_thread_destroy,
+  __libc_getaddrinfo_freemem,
+  __libc_tzset_freemem,
+  __libc_fgetgrent_freemem,
+  __libc_getnameinfo_freemem,
+  __libc_getnetgrent_freemem,
+  __libc_rcmd_freemem,
+  __libc_rexec_freemem,
+  __libc_localealias_freemem,
+  __libc_getutent_freemem,
+  __libc_getutid_freemem,
+  __libc_getutline_freemem,
+  __libc_mntent_freemem,
+  __libc_fgetpwent_freemem,
+  __libc_fgetspent_freemem,
+  __libc_reg_printf_freemem,
+  __libc_reg_type_freemem,
+  __libc_tzfile_freemem,
+
+  __libc_efgcvt_freemem,
+  __libc_qefgcvt_freemem,
+
+  __libc_getgrgid_freemem,
+  __libc_getgrnam_freemem,
+  __libc_getpwnam_freemem,
+  __libc_getpwuid_freemem,
+  __libc_getspnam_freemem,
+  __libc_getaliasbyname_freemem,
+  __libc_gethostbyaddr_freemem,
+  __libc_gethostbyname_freemem,
+  __libc_gethostbyname2_freemem,
+  __libc_getnetbyaddr_freemem,
+  __libc_getnetbyname_freemem,
+  __libc_getprotobynumber_freemem,
+  __libc_getprotobyname_freemem,
+  __libc_getrpcbyname_freemem,
+  __libc_getrpcbynumber_freemem,
+  __libc_getservbyname_freemem,
+  __libc_getservbyport_freemem,
+
+  __libc_getgrent_freemem,
+  __libc_getpwent_freemem,
+  __libc_getspent_freemem,
+  __libc_getaliasent_freemem,
+  __libc_gethostent_freemem,
+  __libc_getnetent_freemem,
+  __libc_getprotoent_freemem,
+  __libc_getrpcent_freemem,
+  __libc_getservent_freemem,
+
+  __gai_freemem,
+
+  __aio_freemem,
+
+  __libpthread_freeres,
+
+  __md5_crypt_freemem,
+  __sha256_crypt_freemem,
+  __sha512_crypt_freemem,
+
+  SET_FREERES_SYSTEM_FUNCS
+};
+
+void
 __libc_freeres (void)
 {
   /* This function might be called from different places.  So better
@@ -49,8 +227,6 @@ __libc_freeres (void)
 
   if (!atomic_compare_and_exchange_bool_acq (&already_called, 1, 0))
     {
-      void *const *p;
-
       call_function_static_weak (__nss_module_freeres);
       call_function_static_weak (__nss_action_freeres);
       call_function_static_weak (__nss_database_freeres);
@@ -58,9 +234,9 @@ __libc_freeres (void)
       _IO_cleanup ();
 
       /* We run the resource freeing after IO cleanup.  */
-      RUN_HOOK (__libc_subfreeres, ());
-
-      call_function_static_weak (__libpthread_freeres);
+      for (int i = 0; i < array_length (__libc_freeres_funcs); i++)
+	if (__libc_freeres_funcs[i] != NULL)
+	  __libc_freeres_funcs[i] ();
 
 #ifdef SHARED
       __libc_unwind_link_freeres ();
@@ -71,10 +247,6 @@ __libc_freeres (void)
 #ifdef SHARED
       GLRO (dl_libc_freeres) ();
 #endif
-
-      for (p = symbol_set_first_element (__libc_freeres_ptrs);
-           !symbol_set_end_p (__libc_freeres_ptrs, p); ++p)
-        free (*p);
     }
 }
 libc_hidden_def (__libc_freeres)
diff --git a/malloc/thread-freeres.c b/malloc/thread-freeres.c
index b22e1d789f..11bf290aa6 100644
--- a/malloc/thread-freeres.c
+++ b/malloc/thread-freeres.c
@@ -27,7 +27,7 @@
 
 /* Thread shutdown function.  Note that this function must be called
    for threads during shutdown for correctness reasons.  Unlike
-   __libc_subfreeres, skipping calls to it is not a valid optimization.
+   __libc_freeres, skipping calls to it is not a valid optimization.
    This is called directly from pthread_create as the thread exits.  */
 void
 __libc_thread_freeres (void)
diff --git a/misc/efgcvt-template.c b/misc/efgcvt-template.c
index 87a90e78d4..8ed4896a0c 100644
--- a/misc/efgcvt-template.c
+++ b/misc/efgcvt-template.c
@@ -38,7 +38,7 @@
 
 static char FCVT_BUFFER[MAXDIG];
 static char ECVT_BUFFER[MAXDIG];
-libc_freeres_ptr (static char *FCVT_BUFPTR);
+static char *FCVT_BUFPTR;
 
 char *
 __FCVT (FLOAT_TYPE value, int ndigit, int *decpt, int *sign)
@@ -73,3 +73,9 @@ __GCVT (FLOAT_TYPE value, int ndigit, char *buf)
   SPRINTF (buf, "%.*" FLOAT_FMT_FLAG "g", MIN (ndigit, NDIGIT_MAX), value);
   return buf;
 }
+
+void
+__EFGCVT_FREEMEM (void)
+{
+  free (FCVT_BUFPTR);
+}
diff --git a/misc/efgcvt.c b/misc/efgcvt.c
index 95f1443d60..33bee945d5 100644
--- a/misc/efgcvt.c
+++ b/misc/efgcvt.c
@@ -24,6 +24,7 @@
 #define __GCVT __gcvt
 #define __ECVT_R __ecvt_r
 #define __FCVT_R __fcvt_r
+#define __EFGCVT_FREEMEM __libc_efgcvt_freemem
 #include <efgcvt-dbl-macros.h>
 #include <efgcvt-template.c>
 
diff --git a/misc/fstab.c b/misc/fstab.c
index 952f7adc36..f55657ee17 100644
--- a/misc/fstab.c
+++ b/misc/fstab.c
@@ -177,7 +177,8 @@ fstab_convert (struct fstab_state *state)
 
 /* Make sure the memory is freed if the programs ends while in
    memory-debugging mode and something actually was allocated.  */
-libc_freeres_fn (fstab_free)
+void
+__libc_fstab_freemem (void)
 {
   char *buffer;
 
diff --git a/misc/hsearch.c b/misc/hsearch.c
index 3b7be37f81..37994b053e 100644
--- a/misc/hsearch.c
+++ b/misc/hsearch.c
@@ -46,7 +46,3 @@ __hdestroy (void)
   __hdestroy_r (&htab);
 }
 weak_alias (__hdestroy, hdestroy)
-
-/* Make sure the table is freed if we want to free everything before
-   exiting.  */
-text_set_element (__libc_subfreeres, __hdestroy);
diff --git a/misc/mntent.c b/misc/mntent.c
index 44e54df669..61d29b5f0e 100644
--- a/misc/mntent.c
+++ b/misc/mntent.c
@@ -28,7 +28,7 @@ struct mntent_buffer
 
 /* We don't want to allocate the static buffer all the time since it
    is not always used (in fact, rather infrequently).  */
-libc_freeres_ptr (static void *mntent_buffer);
+static void *mntent_buffer;
 
 static void *
 allocate (void *closure)
@@ -56,3 +56,9 @@ getmntent (FILE *stream)
   return __getmntent_r (stream, &buffer->m,
 			buffer->buffer, sizeof (buffer->buffer));
 }
+
+void
+__libc_mntent_freemem (void)
+{
+  free (mntent_buffer);
+}
diff --git a/misc/qefgcvt.c b/misc/qefgcvt.c
index f48e0b6016..b1f2833725 100644
--- a/misc/qefgcvt.c
+++ b/misc/qefgcvt.c
@@ -24,6 +24,7 @@
 #define __GCVT __qgcvt
 #define __ECVT_R __qecvt_r
 #define __FCVT_R __qfcvt_r
+#define __EFGCVT_FREEMEM __libc_qefgcvt_freemem
 #include <efgcvt-ldbl-macros.h>
 #include <efgcvt-template.c>
 
diff --git a/misc/unwind-link.c b/misc/unwind-link.c
index e8653bbaf1..0e01eed7fc 100644
--- a/misc/unwind-link.c
+++ b/misc/unwind-link.c
@@ -131,7 +131,7 @@ __libc_unwind_link_after_fork (void)
     }
 }
 
-void __libc_freeres_fn_section
+void
 __libc_unwind_link_freeres (void)
 {
   if (global_libgcc_handle != NULL)
diff --git a/nscd/nscd_getgr_r.c b/nscd/nscd_getgr_r.c
index bde3b588a0..5afa258c19 100644
--- a/nscd/nscd_getgr_r.c
+++ b/nscd/nscd_getgr_r.c
@@ -68,7 +68,8 @@ libc_locked_map_ptr (,__gr_map_handle) attribute_hidden;
 /* Note that we only free the structure if necessary.  The memory
    mapping is not removed since it is not visible to the malloc
    handling.  */
-libc_freeres_fn (gr_map_free)
+void
+__nscd_gr_map_freemem (void)
 {
   if (__gr_map_handle.mapped != NO_MAPPING)
     {
diff --git a/nscd/nscd_gethst_r.c b/nscd/nscd_gethst_r.c
index 31d13580a1..a537364a75 100644
--- a/nscd/nscd_gethst_r.c
+++ b/nscd/nscd_gethst_r.c
@@ -81,7 +81,8 @@ libc_locked_map_ptr (, __hst_map_handle) attribute_hidden;
 /* Note that we only free the structure if necessary.  The memory
    mapping is not removed since it is not visible to the malloc
    handling.  */
-libc_freeres_fn (hst_map_free)
+void
+__nscd_hst_map_freemem (void)
 {
   if (__hst_map_handle.mapped != NO_MAPPING)
     {
diff --git a/nscd/nscd_getpw_r.c b/nscd/nscd_getpw_r.c
index 82fdd17d8c..52256b58c4 100644
--- a/nscd/nscd_getpw_r.c
+++ b/nscd/nscd_getpw_r.c
@@ -67,7 +67,8 @@ libc_locked_map_ptr (static, map_handle);
 /* Note that we only free the structure if necessary.  The memory
    mapping is not removed since it is not visible to the malloc
    handling.  */
-libc_freeres_fn (pw_map_free)
+void
+__nscd_pw_map_freemem (void)
 {
   if (map_handle.mapped != NO_MAPPING)
     {
diff --git a/nscd/nscd_getserv_r.c b/nscd/nscd_getserv_r.c
index de843b3363..92c80fe8fe 100644
--- a/nscd/nscd_getserv_r.c
+++ b/nscd/nscd_getserv_r.c
@@ -62,7 +62,8 @@ libc_locked_map_ptr (, __serv_map_handle) attribute_hidden;
 /* Note that we only free the structure if necessary.  The memory
    mapping is not removed since it is not visible to the malloc
    handling.  */
-libc_freeres_fn (serv_map_free)
+void
+__nscd_serv_map_freemem (void)
 {
   if (__serv_map_handle.mapped != NO_MAPPING)
     {
diff --git a/nscd/nscd_netgroup.c b/nscd/nscd_netgroup.c
index 11b7f3214c..33c0096f86 100644
--- a/nscd/nscd_netgroup.c
+++ b/nscd/nscd_netgroup.c
@@ -31,7 +31,8 @@ libc_locked_map_ptr (static, map_handle);
 /* Note that we only free the structure if necessary.  The memory
    mapping is not removed since it is not visible to the malloc
    handling.  */
-libc_freeres_fn (pw_map_free)
+void
+__nscd_group_map_freemem (void)
 {
   if (map_handle.mapped != NO_MAPPING)
     {
diff --git a/nss/getXXbyYY.c b/nss/getXXbyYY.c
index 35a3a81e2b..566a510b5a 100644
--- a/nss/getXXbyYY.c
+++ b/nss/getXXbyYY.c
@@ -58,6 +58,9 @@
 #define APPEND_R1(name) name##_r
 #define INTERNAL(name) INTERNAL1 (name)
 #define INTERNAL1(name) __##name
+#define APPEND_FREEMEM_NAME1(name) __libc_##name##_freemem
+#define APPEND_FREEMEM_NAME(name) APPEND_FREEMEM_NAME1(name)
+#define FREEMEM_NAME APPEND_FREEMEM_NAME (FUNCTION_NAME)
 
 /* Sometimes we need to store error codes in the `h_errno' variable.  */
 #ifdef NEED_H_ERRNO
@@ -86,8 +89,13 @@ extern int INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf,
 __libc_lock_define_initialized (static, lock);
 
 /* This points to the static buffer used.  */
-libc_freeres_ptr (static char *buffer);
+static char *buffer;
 
+void
+FREEMEM_NAME (void)
+{
+  free (buffer);
+}
 
 LOOKUP_TYPE *
 FUNCTION_NAME (ADD_PARAMS)
diff --git a/nss/getXXent.c b/nss/getXXent.c
index 35720a05dd..39d15ea9c5 100644
--- a/nss/getXXent.c
+++ b/nss/getXXent.c
@@ -43,6 +43,9 @@
 #define APPEND_R1(name) name##_r
 #define INTERNAL(name) INTERNAL1 (name)
 #define INTERNAL1(name) __##name
+#define APPEND_FREEMEM_NAME1(name) __libc_##name##_freemem
+#define APPEND_FREEMEM_NAME(name) APPEND_FREEMEM_NAME1(name)
+#define FREEMEM_NAME APPEND_FREEMEM_NAME (GETFUNC_NAME)
 
 /* Sometimes we need to store error codes in the `h_errno' variable.  */
 #ifdef NEED_H_ERRNO
@@ -62,8 +65,13 @@ extern int INTERNAL (REENTRANT_GETNAME) (LOOKUP_TYPE *resbuf, char *buffer,
 __libc_lock_define_initialized (static, lock);
 
 /* This points to the static buffer used.  */
-libc_freeres_ptr (static char *buffer);
+static char *buffer;
 
+void
+FREEMEM_NAME (void)
+{
+  free (buffer);
+}
 
 LOOKUP_TYPE *
 GETFUNC_NAME (void)
diff --git a/nss/nss_action.c b/nss/nss_action.c
index babea4e735..893880790f 100644
--- a/nss/nss_action.c
+++ b/nss/nss_action.c
@@ -102,7 +102,7 @@ __nss_action_allocate (struct nss_action *actions, size_t count)
   return result;
 }
 
-void __libc_freeres_fn_section
+void
 __nss_action_freeres (void)
 {
   struct nss_action_list_wrapper *current = nss_actions;
diff --git a/nss/nss_database.c b/nss/nss_database.c
index f2ed2f2c25..7e5b7f362b 100644
--- a/nss/nss_database.c
+++ b/nss/nss_database.c
@@ -495,7 +495,7 @@ __nss_database_get_noreload (enum nss_database db)
   return result;
 }
 
-void __libc_freeres_fn_section
+void
 __nss_database_freeres (void)
 {
   free (global_database_state);
diff --git a/nss/nss_module.c b/nss/nss_module.c
index 444facb9b8..ed224018b1 100644
--- a/nss/nss_module.c
+++ b/nss/nss_module.c
@@ -416,7 +416,7 @@ __nss_module_disable_loading (void)
   __libc_lock_unlock (nss_module_list_lock);
 }
 
-void __libc_freeres_fn_section
+void
 __nss_module_freeres (void)
 {
   struct nss_module *current = nss_module_list;
diff --git a/posix/regcomp.c b/posix/regcomp.c
index 84fc1cc82b..634dccf03f 100644
--- a/posix/regcomp.c
+++ b/posix/regcomp.c
@@ -710,7 +710,8 @@ re_comp (const char *s)
 }
 
 #ifdef _LIBC
-libc_freeres_fn (free_mem)
+void
+__libc_regcomp_freemem (void)
 {
   __regfree (&re_comp_buf);
 }
diff --git a/posix/register-atfork.c b/posix/register-atfork.c
index c039fb454f..d386731b92 100644
--- a/posix/register-atfork.c
+++ b/posix/register-atfork.c
@@ -217,7 +217,8 @@ __run_postfork_handlers (enum __run_fork_handler_type who, _Bool do_locking,
 }
 
 
-libc_freeres_fn (free_mem)
+void
+__libc_atfork_freemem (void)
 {
   lll_lock (atfork_lock, LLL_PRIVATE);
 
diff --git a/pwd/fgetpwent.c b/pwd/fgetpwent.c
index 1ddc98a0d0..f93a045bcd 100644
--- a/pwd/fgetpwent.c
+++ b/pwd/fgetpwent.c
@@ -25,7 +25,7 @@
 /* We need to protect the dynamic buffer handling.  */
 __libc_lock_define_initialized (static, lock);
 
-libc_freeres_ptr (static char *buffer);
+static char *buffer;
 
 /* Read one entry from the given stream.  */
 struct passwd *
@@ -82,3 +82,9 @@ fgetpwent (FILE *stream)
 
   return result;
 }
+
+void
+__libc_fgetpwent_freemem (void)
+{
+  free (buffer);
+}
diff --git a/resolv/gai_misc.c b/resolv/gai_misc.c
index 8ce3c778eb..5de7470fab 100644
--- a/resolv/gai_misc.c
+++ b/resolv/gai_misc.c
@@ -434,7 +434,8 @@ handle_requests (void *arg)
 
 
 /* Free allocated resources.  */
-libc_freeres_fn (free_res)
+void
+__gai_freemem (void)
 {
   size_t row;
 
diff --git a/resolv/res-close.c b/resolv/res-close.c
index dd116ea5c0..55e49b6db0 100644
--- a/resolv/res-close.c
+++ b/resolv/res-close.c
@@ -140,5 +140,3 @@ __res_thread_freeres (void)
   /* Make sure we do a full re-initialization the next time.  */
   _res.options = 0;
 }
-/* Also must be called when the main thread exits.  */
-text_set_element (__libc_subfreeres, __res_thread_freeres);
diff --git a/resolv/res_hconf.c b/resolv/res_hconf.c
index dd09a2a255..c6dc47ac5b 100644
--- a/resolv/res_hconf.c
+++ b/resolv/res_hconf.c
@@ -330,7 +330,6 @@ _res_hconf_init (void)
 #if IS_IN (libc)
 # if defined SIOCGIFCONF && defined SIOCGIFNETMASK
 /* List of known interfaces.  */
-libc_freeres_ptr (
 static struct netaddr
 {
   int addrtype;
@@ -342,7 +341,13 @@ static struct netaddr
       uint32_t	mask;
     } ipv4;
   } u;
-} *ifaddrs);
+} *ifaddrs;
+
+void
+__libc_resolv_res_hconf_freemem (void)
+{
+  free (ifaddrs);
+}
 # endif
 
 /* Reorder addresses returned in a hostent such that the first address
diff --git a/resolv/resolv_conf.c b/resolv/resolv_conf.c
index 6dd552bb47..2fb6b36839 100644
--- a/resolv/resolv_conf.c
+++ b/resolv/resolv_conf.c
@@ -654,7 +654,8 @@ __resolv_conf_detach (struct __res_state *resp)
 }
 
 /* Deallocate the global data.  */
-libc_freeres_fn (freeres)
+void
+__libc_resolv_conf_freemem (void)
 {
   /* No locking because this function is supposed to be called when
      the process has turned single-threaded.  */
diff --git a/resolv/tst-leaks2.c b/resolv/tst-leaks2.c
index 160d4728d5..48d643dcde 100644
--- a/resolv/tst-leaks2.c
+++ b/resolv/tst-leaks2.c
@@ -23,6 +23,8 @@
 #include <resolv.h>
 #include <support/check.h>
 
+void __libc_freeres (void);
+
 static int
 do_test (void)
 {
diff --git a/rt/aio_misc.c b/rt/aio_misc.c
index b4304d0a6f..a96ed4f51b 100644
--- a/rt/aio_misc.c
+++ b/rt/aio_misc.c
@@ -694,7 +694,8 @@ handle_fildes_io (void *arg)
 
 
 /* Free allocated resources.  */
-libc_freeres_fn (free_res)
+void
+__aio_freemem (void)
 {
   size_t row;
 
diff --git a/shadow/fgetspent.c b/shadow/fgetspent.c
index 5f75e31c29..f354ff3bb4 100644
--- a/shadow/fgetspent.c
+++ b/shadow/fgetspent.c
@@ -28,7 +28,7 @@
 /* We need to protect the dynamic buffer handling.  */
 __libc_lock_define_initialized (static, lock);
 
-libc_freeres_ptr (static char *buffer);
+static char *buffer;
 
 /* Read one shadow entry from the given stream.  */
 struct spwd *
@@ -85,3 +85,9 @@ fgetspent (FILE *stream)
 
   return result;
 }
+
+void
+__libc_fgetspent_freemem (void)
+{
+  free (buffer);
+}
diff --git a/stdio-common/reg-modifier.c b/stdio-common/reg-modifier.c
index fa1cd2ac3c..b8232b5ff8 100644
--- a/stdio-common/reg-modifier.c
+++ b/stdio-common/reg-modifier.c
@@ -183,7 +183,8 @@ __handle_registered_modifier_wc (const unsigned int **format,
 }
 
 
-libc_freeres_fn (free_mem)
+void
+__libc_printf_freemem (void)
 {
   if (__printf_modifier_table != NULL)
     {
diff --git a/stdio-common/reg-printf.c b/stdio-common/reg-printf.c
index 5f4c6a24c2..f3075e8fb6 100644
--- a/stdio-common/reg-printf.c
+++ b/stdio-common/reg-printf.c
@@ -24,8 +24,7 @@
 
 
 /* Array of functions indexed by format character.  */
-libc_freeres_ptr (printf_arginfo_size_function **__printf_arginfo_table)
-  attribute_hidden;
+printf_arginfo_size_function **__printf_arginfo_table attribute_hidden;
 printf_function **__printf_function_table attribute_hidden;
 
 __libc_lock_define_initialized (static, lock)
@@ -79,3 +78,9 @@ __register_printf_function (int spec, printf_function converter,
 				      (printf_arginfo_size_function*) arginfo);
 }
 weak_alias (__register_printf_function, register_printf_function)
+
+void
+__libc_reg_printf_freemem (void)
+{
+  free (__printf_arginfo_table);
+}
diff --git a/stdio-common/reg-type.c b/stdio-common/reg-type.c
index f308db6323..3612f57655 100644
--- a/stdio-common/reg-type.c
+++ b/stdio-common/reg-type.c
@@ -22,8 +22,7 @@
 
 
 /* Array of functions indexed by format character.  */
-libc_freeres_ptr (printf_va_arg_function **__printf_va_arg_table)
-  attribute_hidden;
+printf_va_arg_function **__printf_va_arg_table attribute_hidden;
 
 __libc_lock_define_initialized (static, lock);
 
@@ -59,3 +58,9 @@ __register_printf_type (printf_va_arg_function fct)
   return result;
 }
 weak_alias (__register_printf_type, register_printf_type)
+
+void
+__libc_reg_type_freemem (void)
+{
+  free (__printf_va_arg_table);
+}
diff --git a/stdlib/fmtmsg.c b/stdlib/fmtmsg.c
index 787a263d63..7561a2936b 100644
--- a/stdlib/fmtmsg.c
+++ b/stdlib/fmtmsg.c
@@ -361,7 +361,8 @@ __addseverity (int severity, const char *string)
 weak_alias (__addseverity, addseverity)
 
 
-libc_freeres_fn (free_mem)
+void
+__libc_fmtmsg_freemem (void)
 {
   struct severity_info *runp = severity_list;
 
diff --git a/stdlib/setenv.c b/stdlib/setenv.c
index 2176cbac31..e44d41019c 100644
--- a/stdlib/setenv.c
+++ b/stdlib/setenv.c
@@ -323,7 +323,8 @@ clearenv (void)
   return 0;
 }
 #ifdef _LIBC
-libc_freeres_fn (free_mem)
+void
+__libc_setenv_freemem (void)
 {
   /* Remove all traces.  */
   clearenv ();
diff --git a/sunrpc/clnt_perr.c b/sunrpc/clnt_perr.c
index 67499fd03f..c3d13722df 100644
--- a/sunrpc/clnt_perr.c
+++ b/sunrpc/clnt_perr.c
@@ -389,8 +389,8 @@ auth_errmsg (enum auth_stat stat)
 }
 
 
-libc_freeres_fn (free_mem)
+void
+__rpc_freemem (void)
 {
-  /* Not libc_freeres_ptr, since buf is a macro.  */
   free (buf);
 }
diff --git a/sunrpc/rpc_thread.c b/sunrpc/rpc_thread.c
index 0abe6dc172..a04b7ec47f 100644
--- a/sunrpc/rpc_thread.c
+++ b/sunrpc/rpc_thread.c
@@ -37,7 +37,6 @@ __rpc_thread_destroy (void)
 		thread_rpc_vars = NULL;
 	}
 }
-text_set_element (__libc_subfreeres, __rpc_thread_destroy);
 
 /*
  * Initialize RPC multi-threaded operation
diff --git a/sunrpc/tst-svc_register.c b/sunrpc/tst-svc_register.c
index 41c5398ab6..4f3c31c504 100644
--- a/sunrpc/tst-svc_register.c
+++ b/sunrpc/tst-svc_register.c
@@ -276,9 +276,9 @@ do_test (void)
               else
                 /* This is arguably a bug: Regular process termination
                    does not unregister the service with rpcbind.  The
-                   unset rpcbind call happens from a __libc_subfreeres
-                   callback, and this only happens when running under
-                   memory debuggers such as valgrind.  */
+                   unset rpcbind call happens from a __libc_freeres,
+                   and this only happens when running under memory debuggers
+		   such as valgrind.  */
                 TEST_VERIFY (!state.unset_called);
             }
           else
diff --git a/sysdeps/generic/set-freeres-fp.h b/sysdeps/generic/set-freeres-fp.h
new file mode 100644
index 0000000000..ddd0a48a20
--- /dev/null
+++ b/sysdeps/generic/set-freeres-fp.h
@@ -0,0 +1,19 @@
+/* System specific resource deallocation.  Generic version.
+   Copyright (C) 2020-2022 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
+   <https://www.gnu.org/licenses/>.  */
+
+#define SET_FREERES_FP_FUNCS
diff --git a/sysdeps/generic/set-freeres-os.h b/sysdeps/generic/set-freeres-os.h
new file mode 100644
index 0000000000..834fa7cc57
--- /dev/null
+++ b/sysdeps/generic/set-freeres-os.h
@@ -0,0 +1,19 @@
+/* System specific resource deallocation.  Generic version.
+   Copyright (C) 2020-2022 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
+   <https://www.gnu.org/licenses/>.  */
+
+#define SET_FREERES_OS_FUNCS
diff --git a/sysdeps/generic/set-freeres-system.h b/sysdeps/generic/set-freeres-system.h
new file mode 100644
index 0000000000..cc0d69b3b4
--- /dev/null
+++ b/sysdeps/generic/set-freeres-system.h
@@ -0,0 +1,27 @@
+/* System specific resource deallocation.  Generic version.
+   Copyright (C) 2020-2022 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
+   <https://www.gnu.org/licenses/>.  */
+
+/* Each system may define weak functions to free any resource allocated with
+   malloc to avoid interfere with mtrace.  */
+
+#include <set-freeres-os.h>
+#include <set-freeres-fp.h>
+
+#define SET_FREERES_SYSTEM_FUNCS	\
+  SET_FREERES_OS_FUNCS			\
+  SET_FREERES_FP_FUNCS
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-qefgcvt.c b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-qefgcvt.c
index 9703069b95..67e7afd86a 100644
--- a/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-qefgcvt.c
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/ieee128-qefgcvt.c
@@ -42,6 +42,7 @@ typeof (qfcvt_r) ___qfcvtieee128_r;
 #define __GCVT ___qgcvtieee128
 #define __ECVT_R ___qecvtieee128_r
 #define __FCVT_R ___qfcvtieee128_r
+#define __EFGCVT_FREEMEM __libc_efgcvtieee128_freemem
 #include <efgcvt-ldbl-macros.h>
 #include <efgcvt-template.c>
 
diff --git a/sysdeps/ieee754/ldbl-128ibm-compat/set-freeres-fp.h b/sysdeps/ieee754/ldbl-128ibm-compat/set-freeres-fp.h
new file mode 100644
index 0000000000..b652b11f64
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm-compat/set-freeres-fp.h
@@ -0,0 +1,22 @@
+/* System specific resource deallocation. Long double 128 IBM version.
+   Copyright (C) 2022 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
+   <https://www.gnu.org/licenses/>.  */
+
+void __libc_efgcvtieee128_freemem (void) weak_function;
+
+#define SET_FREERES_FP_FUNCS \
+  __libc_efgcvtieee128_freemem
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 5cda9bb072..bdc56d9781 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -1761,7 +1761,8 @@ check_gaiconf_mtime (const struct __stat64_t64 *st)
 #endif
 
 
-libc_freeres_fn(fini)
+void
+__libc_getaddrinfo_freemem (void)
 {
   if (labels != default_labels)
     {
@@ -2233,7 +2234,7 @@ no_file:
 
   /* If we previously read the file but it is gone now, free the old data and
      use the builtin one.  Leave the reload flag alone.  */
-  fini ();
+  __libc_getaddrinfo_freemem ();
 }
 
 
diff --git a/sysdeps/posix/ttyname.c b/sysdeps/posix/ttyname.c
index fd41f7fb24..32ada6c1f1 100644
--- a/sysdeps/posix/ttyname.c
+++ b/sysdeps/posix/ttyname.c
@@ -31,7 +31,13 @@ static char *getttyname (int fd, dev_t mydev, ino_t myino,
 			 int save, int *dostat);
 
 
-libc_freeres_ptr (static char *getttyname_name);
+static char *getttyname_name;
+
+void
+__ttyname_freemem (void)
+{
+  free (getttyname_name);
+}
 
 static char *
 getttyname (int fd, dev_t mydev, ino_t myino, int save, int *dostat)
diff --git a/sysdeps/unix/sysv/linux/check_pf.c b/sysdeps/unix/sysv/linux/check_pf.c
index 0b77a2d897..bdda4e890d 100644
--- a/sysdeps/unix/sysv/linux/check_pf.c
+++ b/sysdeps/unix/sysv/linux/check_pf.c
@@ -362,7 +362,8 @@ __check_pf (bool *seen_ipv4, bool *seen_ipv6,
 }
 
 /* Free the cache if it has been allocated.  */
-libc_freeres_fn (freecache)
+void
+__check_pf_freemem (void)
 {
   if (cache)
     __free_in6ai (cache->in6ai);
diff --git a/sysdeps/unix/sysv/linux/set-freeres-os.h b/sysdeps/unix/sysv/linux/set-freeres-os.h
new file mode 100644
index 0000000000..864a31a123
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/set-freeres-os.h
@@ -0,0 +1,24 @@
+/* System specific resource deallocation.  Linux version.
+   Copyright (C) 2020-2022 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
+   <https://www.gnu.org/licenses/>.  */
+
+void __check_pf_freemem (void) weak_function;
+void __ttyname_freemem (void) weak_function;
+
+#define SET_FREERES_OS_FUNCS	\
+  __check_pf_freemem,		\
+  __ttyname_freemem,
diff --git a/sysdeps/unix/sysv/linux/ttyname.c b/sysdeps/unix/sysv/linux/ttyname.c
index 947c1f72a1..77313f8577 100644
--- a/sysdeps/unix/sysv/linux/ttyname.c
+++ b/sysdeps/unix/sysv/linux/ttyname.c
@@ -24,7 +24,8 @@
 
 static char *ttyname_buf = NULL;
 
-libc_freeres_fn (free_mem)
+void
+__ttyname_freemem (void)
 {
   free (ttyname_buf);
 }
diff --git a/time/tzfile.c b/time/tzfile.c
index dd75848ba9..454c70178b 100644
--- a/time/tzfile.c
+++ b/time/tzfile.c
@@ -50,7 +50,7 @@ struct leap
   };
 
 static size_t num_transitions;
-libc_freeres_ptr (static __time64_t *transitions);
+static __time64_t *transitions;
 static unsigned char *type_idxs;
 static size_t num_types;
 static struct ttinfo *types;
@@ -777,3 +777,9 @@ __tzfile_compute (__time64_t timer, int use_localtime,
 	}
     }
 }
+
+void
+__libc_tzfile_freemem (void)
+{
+  free (transitions);
+}
diff --git a/time/tzset.c b/time/tzset.c
index a06142bb58..b8b1ee2662 100644
--- a/time/tzset.c
+++ b/time/tzset.c
@@ -610,7 +610,8 @@ __tz_convert (__time64_t timer, int use_localtime, struct tm *tp)
 }
 
 
-libc_freeres_fn (free_mem)
+void
+__libc_tzset_freemem (void)
 {
   while (tzstring_list != NULL)
     {
-- 
2.34.1


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

* [PATCH 5/7] libio: Remove the usage of __libc_IO_vtables
  2022-11-15 19:31 [PATCH 0/7] Fixing remaining lld issues Adhemerval Zanella via Libc-alpha
                   ` (3 preceding siblings ...)
  2022-11-15 19:31 ` [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions Adhemerval Zanella via Libc-alpha
@ 2022-11-15 19:31 ` Adhemerval Zanella via Libc-alpha
  2022-12-12 11:40   ` Florian Weimer via Libc-alpha
  2022-11-15 19:31 ` [PATCH 6/7] Remove --with-default-link configure option Adhemerval Zanella via Libc-alpha
  2022-11-15 19:31 ` [PATCH 7/7] Remove set-hooks.h from generic includes Adhemerval Zanella via Libc-alpha
  6 siblings, 1 reply; 25+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2022-11-15 19:31 UTC (permalink / raw)
  To: libc-alpha, Fangrui Song

The libio vtables are all moved to an array and the IO_validate_vtable
checks if the vtable is within the array, instead of using special
ELF section and linker scripts directives.

To avoid static linking namespace issues and to pulling all vtables
referenced objects, all function pointers are set to weak references.
This also leads to slight small static objects that uses printf-like
family.

Checked on x86_64-linux-gnu, i686-linux-gnu, and aarch64-linux-gnu.
---
 Makerules                        |  24 --
 elf/Makefile                     |  20 +-
 include/libc-symbols.h           |  18 +-
 libio/Makefile                   |   2 +
 libio/fileops.c                  |  81 +----
 libio/iofopncook.c               |  60 +---
 libio/iopopen.c                  |  25 --
 libio/iovsprintf.c               |  26 +-
 libio/libio-macros.sym           |   7 +
 libio/libioP.h                   | 312 ++++++++++++-------
 libio/memstream.c                |  32 +-
 libio/obprintf.c                 |  34 +--
 libio/oldfileops.c               |  23 --
 libio/oldiopopen.c               |  23 --
 libio/stdio.c                    |   3 +
 libio/strfile.h                  |   5 -
 libio/strops.c                   |  24 --
 libio/tst-vtables-interposed.c   |   5 +
 libio/vsnprintf.c                |  29 +-
 libio/vswprintf.c                |  30 +-
 libio/vtables.c                  | 502 +++++++++++++++++++++++++++++++
 libio/wfileops.c                 |  79 +----
 libio/wmemstream.c               |  32 +-
 libio/wstrops.c                  |  24 --
 stdio-common/vfprintf-internal.c |  60 +---
 25 files changed, 770 insertions(+), 710 deletions(-)
 create mode 100644 libio/libio-macros.sym

diff --git a/Makerules b/Makerules
index 962b2cd90c..41fc8db4ba 100644
--- a/Makerules
+++ b/Makerules
@@ -544,34 +544,10 @@ $(LINK.o) -shared -static-libgcc -Wl,-O1 $(sysdep-LDFLAGS) \
 	  -L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link)
 endef
 
-ifeq (yes,$(use-default-link))
 # If the linker is good enough, we can let it use its default linker script.
 # In the long term the custom linker script will be removed.
 shlib-lds =
 shlib-lds-flags =
-else
-# binutils only position loadable notes into the first page for binaries,
-# not for shared objects
-# lld --verbose does not dump a linker script.  Use -fuse-ld=bfd.
-$(common-objpfx)shlib.lds: $(common-objpfx)config.make $(..)Makerules
-	$(LINK.o) -shared -Wl,-O1 \
-		  -nostdlib -nostartfiles -fuse-ld=bfd \
-		  $(sysdep-LDFLAGS) $(rtld-LDFLAGS) $(LDFLAGS.so) \
-		  -Wl,--verbose 2>/dev/null | \
-	  sed > $@T \
-	      -e '/^=========/,/^=========/!d;/^=========/d' \
-	      -e 's@^.*\*(\.jcr).*$$@& \
-		 PROVIDE(__start___libc_IO_vtables = .);\
-		 __libc_IO_vtables : { *(__libc_IO_vtables) }\
-		 PROVIDE(__stop___libc_IO_vtables = .);\
-		 /DISCARD/ : { *(.gnu.glibc-stub.*) }@'
-	test -s $@T
-	mv -f $@T $@
-common-generated += shlib.lds
-
-shlib-lds = $(common-objpfx)shlib.lds
-shlib-lds-flags = -T $(shlib-lds)
-endif
 
 define build-shlib
 $(build-shlib-helper) -o $@ $(shlib-lds-flags) \
diff --git a/elf/Makefile b/elf/Makefile
index 6de2ca6d6c..8527e659dc 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -595,27 +595,11 @@ $(objpfx)tst-relro-ldso.out: tst-relro-symbols.py $(..)/scripts/glibcelf.py \
 $(objpfx)tst-relro-libc.out: tst-relro-symbols.py $(..)/scripts/glibcelf.py \
   $(common-objpfx)libc.so
 	$(PYTHON) tst-relro-symbols.py $(common-objpfx)libc.so \
-	    --required=_IO_cookie_jumps \
 	    --required=_IO_file_jumps \
-	    --required=_IO_file_jumps_maybe_mmap \
-	    --required=_IO_file_jumps_mmap \
-	    --required=_IO_helper_jumps \
-	    --required=_IO_mem_jumps \
-	    --required=_IO_obstack_jumps \
-	    --required=_IO_proc_jumps \
-	    --required=_IO_str_chk_jumps \
-	    --required=_IO_str_jumps \
-	    --required=_IO_strn_jumps \
 	    --required=_IO_wfile_jumps \
-	    --required=_IO_wfile_jumps_maybe_mmap \
-	    --required=_IO_wfile_jumps_mmap \
-	    --required=_IO_wmem_jumps \
-	    --required=_IO_wstr_jumps \
-	    --required=_IO_wstrn_jumps \
+	    --required=__io_vtables \
+	    --required=__io_vtables_size \
 	    --required=__libc_freeres_funcs \
-	    --optional=_IO_old_cookie_jumps \
-	    --optional=_IO_old_file_jumps \
-	    --optional=_IO_old_proc_jumps \
 	  > $@ 2>&1; $(evaluate-test)
 
 ifeq ($(run-built-tests),yes)
diff --git a/include/libc-symbols.h b/include/libc-symbols.h
index a1d422131f..02fbfe91f0 100644
--- a/include/libc-symbols.h
+++ b/include/libc-symbols.h
@@ -243,20 +243,26 @@ for linking")
    This is only necessary when defining something in assembly, or playing
    funny alias games where the size should be other than what the compiler
    thinks it is.  */
-#ifdef __ASSEMBLER__
-# define declare_object_symbol_alias(symbol, original, size) \
+#define declare_object_symbol_alias(symbol, original, size) \
   declare_object_symbol_alias_1 (symbol, original, size)
+#ifdef __ASSEMBLER__
 # define declare_object_symbol_alias_1(symbol, original, s_size) \
    strong_alias (original, symbol) ASM_LINE_SEP \
    .type C_SYMBOL_NAME (symbol), %object ASM_LINE_SEP \
    .size C_SYMBOL_NAME (symbol), s_size ASM_LINE_SEP
 #else /* Not __ASSEMBLER__.  */
 # ifdef HAVE_ASM_SET_DIRECTIVE
-#  define declare_symbol_alias_1_alias(symbol, original) \
-     ".set " __SYMBOL_PREFIX #symbol ", " __SYMBOL_PREFIX #original
+#  define declare_object_symbol_alias_1(symbol, original, size) \
+     asm (".global " __SYMBOL_PREFIX # symbol "\n" \
+	  ".type " __SYMBOL_PREFIX # symbol ", %object\n" \
+	  ".set " __SYMBOL_PREFIX #symbol ", " __SYMBOL_PREFIX original "\n" \
+	  ".size " __SYMBOL_PREFIX #symbol ", " #size "\n");
 # else
-#  define declare_symbol_alias_1_alias(symbol, original) \
-     __SYMBOL_PREFIX #symbol " = " __SYMBOL_PREFIX #original
+#  define declare_object_symbol_alias_1(symbol, original, size) \
+     asm (".global " __SYMBOL_PREFIX # symbol "\n" \
+	  ".type " __SYMBOL_PREFIX # symbol ", %object\n" \
+	  __SYMBOL_PREFIX #symbol " = " __SYMBOL_PREFIX original "\n" \
+	  ".size " __SYMBOL_PREFIX #symbol ", " #size "\n");
 # endif /* HAVE_ASM_SET_DIRECTIVE */
 #endif /* __ASSEMBLER__ */
 
diff --git a/libio/Makefile b/libio/Makefile
index 64398ab1ee..fc67aea9e2 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -51,6 +51,8 @@ routines	:=							      \
 									      \
 	libc_fatal fmemopen oldfmemopen vtables
 
+gen-as-const-headers += libio-macros.sym
+
 tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc   \
 	tst_wprintf2 tst-widetext test-fmemopen tst-ext tst-ext2 \
 	tst-fgetws tst-ungetwc1 tst-ungetwc2 tst-swscanf tst-sscanf	      \
diff --git a/libio/fileops.c b/libio/fileops.c
index 41c18be789..87027d5adb 100644
--- a/libio/fileops.c
+++ b/libio/fileops.c
@@ -815,7 +815,7 @@ _IO_new_file_sync (FILE *fp)
 }
 libc_hidden_ver (_IO_new_file_sync, _IO_file_sync)
 
-static int
+int
 _IO_file_sync_mmap (FILE *fp)
 {
   if (fp->_IO_read_ptr != fp->_IO_read_end)
@@ -1109,7 +1109,7 @@ _IO_file_seekoff_mmap (FILE *fp, off64_t offset, int dir, int mode)
   return offset;
 }
 
-static off64_t
+off64_t
 _IO_file_seekoff_maybe_mmap (FILE *fp, off64_t offset, int dir,
 			     int mode)
 {
@@ -1360,7 +1360,7 @@ _IO_file_xsgetn (FILE *fp, void *data, size_t n)
 }
 libc_hidden_def (_IO_file_xsgetn)
 
-static size_t
+size_t
 _IO_file_xsgetn_mmap (FILE *fp, void *data, size_t n)
 {
   size_t have;
@@ -1405,7 +1405,7 @@ _IO_file_xsgetn_mmap (FILE *fp, void *data, size_t n)
   return s - (char *) data;
 }
 
-static size_t
+size_t
 _IO_file_xsgetn_maybe_mmap (FILE *fp, void *data, size_t n)
 {
   /* We only get here if this is the first attempt to read something.
@@ -1428,76 +1428,3 @@ versioned_symbol (libc, _IO_new_file_seekoff, _IO_file_seekoff, GLIBC_2_1);
 versioned_symbol (libc, _IO_new_file_underflow, _IO_file_underflow, GLIBC_2_1);
 versioned_symbol (libc, _IO_new_file_write, _IO_file_write, GLIBC_2_1);
 versioned_symbol (libc, _IO_new_file_xsputn, _IO_file_xsputn, GLIBC_2_1);
-
-const struct _IO_jump_t _IO_file_jumps libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_file_finish),
-  JUMP_INIT(overflow, _IO_file_overflow),
-  JUMP_INIT(underflow, _IO_file_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_default_pbackfail),
-  JUMP_INIT(xsputn, _IO_file_xsputn),
-  JUMP_INIT(xsgetn, _IO_file_xsgetn),
-  JUMP_INIT(seekoff, _IO_new_file_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_new_file_setbuf),
-  JUMP_INIT(sync, _IO_new_file_sync),
-  JUMP_INIT(doallocate, _IO_file_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_new_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_file_close),
-  JUMP_INIT(stat, _IO_file_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-libc_hidden_data_def (_IO_file_jumps)
-
-const struct _IO_jump_t _IO_file_jumps_mmap libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_file_finish),
-  JUMP_INIT(overflow, _IO_file_overflow),
-  JUMP_INIT(underflow, _IO_file_underflow_mmap),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_default_pbackfail),
-  JUMP_INIT(xsputn, _IO_new_file_xsputn),
-  JUMP_INIT(xsgetn, _IO_file_xsgetn_mmap),
-  JUMP_INIT(seekoff, _IO_file_seekoff_mmap),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, (_IO_setbuf_t) _IO_file_setbuf_mmap),
-  JUMP_INIT(sync, _IO_file_sync_mmap),
-  JUMP_INIT(doallocate, _IO_file_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_new_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_file_close_mmap),
-  JUMP_INIT(stat, _IO_file_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
-const struct _IO_jump_t _IO_file_jumps_maybe_mmap libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_file_finish),
-  JUMP_INIT(overflow, _IO_file_overflow),
-  JUMP_INIT(underflow, _IO_file_underflow_maybe_mmap),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_default_pbackfail),
-  JUMP_INIT(xsputn, _IO_new_file_xsputn),
-  JUMP_INIT(xsgetn, _IO_file_xsgetn_maybe_mmap),
-  JUMP_INIT(seekoff, _IO_file_seekoff_maybe_mmap),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, (_IO_setbuf_t) _IO_file_setbuf_mmap),
-  JUMP_INIT(sync, _IO_new_file_sync),
-  JUMP_INIT(doallocate, _IO_file_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_new_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_file_close),
-  JUMP_INIT(stat, _IO_file_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
diff --git a/libio/iofopncook.c b/libio/iofopncook.c
index 6c27610319..338cb31c79 100644
--- a/libio/iofopncook.c
+++ b/libio/iofopncook.c
@@ -30,7 +30,7 @@
 #include <shlib-compat.h>
 #include <pointer_guard.h>
 
-static ssize_t
+ssize_t
 _IO_cookie_read (FILE *fp, void *buf, ssize_t size)
 {
   struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
@@ -43,7 +43,7 @@ _IO_cookie_read (FILE *fp, void *buf, ssize_t size)
   return read_cb (cfile->__cookie, buf, size);
 }
 
-static ssize_t
+ssize_t
 _IO_cookie_write (FILE *fp, const void *buf, ssize_t size)
 {
   struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
@@ -63,7 +63,7 @@ _IO_cookie_write (FILE *fp, const void *buf, ssize_t size)
   return n;
 }
 
-static off64_t
+off64_t
 _IO_cookie_seek (FILE *fp, off64_t offset, int dir)
 {
   struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
@@ -77,7 +77,7 @@ _IO_cookie_seek (FILE *fp, off64_t offset, int dir)
 	  ? _IO_pos_BAD : offset);
 }
 
-static int
+int
 _IO_cookie_close (FILE *fp)
 {
   struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp;
@@ -91,7 +91,7 @@ _IO_cookie_close (FILE *fp)
 }
 
 
-static off64_t
+off64_t
 _IO_cookie_seekoff (FILE *fp, off64_t offset, int dir, int mode)
 {
   /* We must force the fileops code to always use seek to determine
@@ -100,31 +100,6 @@ _IO_cookie_seekoff (FILE *fp, off64_t offset, int dir, int mode)
   return _IO_file_seekoff (fp, offset, dir, mode);
 }
 
-
-static const struct _IO_jump_t _IO_cookie_jumps libio_vtable = {
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_file_finish),
-  JUMP_INIT(overflow, _IO_file_overflow),
-  JUMP_INIT(underflow, _IO_file_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_default_pbackfail),
-  JUMP_INIT(xsputn, _IO_file_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_cookie_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_file_setbuf),
-  JUMP_INIT(sync, _IO_file_sync),
-  JUMP_INIT(doallocate, _IO_file_doallocate),
-  JUMP_INIT(read, _IO_cookie_read),
-  JUMP_INIT(write, _IO_cookie_write),
-  JUMP_INIT(seek, _IO_cookie_seek),
-  JUMP_INIT(close, _IO_cookie_close),
-  JUMP_INIT(stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue),
-};
-
-
 /* Copy the callbacks from SOURCE to *TARGET, with pointer
    mangling.  */
 static void
@@ -209,7 +184,7 @@ versioned_symbol (libc, _IO_fopencookie, fopencookie, GLIBC_2_2);
 
 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
 
-static off64_t
+off64_t
 attribute_compat_text_section
 _IO_old_cookie_seek (FILE *fp, off64_t offset, int dir)
 {
@@ -226,29 +201,6 @@ _IO_old_cookie_seek (FILE *fp, off64_t offset, int dir)
   return (ret == -1) ? _IO_pos_BAD : ret;
 }
 
-static const struct _IO_jump_t _IO_old_cookie_jumps libio_vtable = {
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_file_finish),
-  JUMP_INIT(overflow, _IO_file_overflow),
-  JUMP_INIT(underflow, _IO_file_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_default_pbackfail),
-  JUMP_INIT(xsputn, _IO_file_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_cookie_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_file_setbuf),
-  JUMP_INIT(sync, _IO_file_sync),
-  JUMP_INIT(doallocate, _IO_file_doallocate),
-  JUMP_INIT(read, _IO_cookie_read),
-  JUMP_INIT(write, _IO_cookie_write),
-  JUMP_INIT(seek, _IO_old_cookie_seek),
-  JUMP_INIT(close, _IO_cookie_close),
-  JUMP_INIT(stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue),
-};
-
 FILE *
 attribute_compat_text_section
 _IO_old_fopencookie (void *cookie, const char *mode,
diff --git a/libio/iopopen.c b/libio/iopopen.c
index 06778cf110..5ed30a817b 100644
--- a/libio/iopopen.c
+++ b/libio/iopopen.c
@@ -45,8 +45,6 @@ struct _IO_proc_file
 };
 typedef struct _IO_proc_file _IO_proc_file;
 
-static const struct _IO_jump_t _IO_proc_jumps;
-
 static struct _IO_proc_file *proc_file_chain;
 
 #ifdef _IO_MTSAFE_IO
@@ -291,29 +289,6 @@ _IO_new_proc_close (FILE *fp)
   return wstatus;
 }
 
-static const struct _IO_jump_t _IO_proc_jumps libio_vtable = {
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_new_file_finish),
-  JUMP_INIT(overflow, _IO_new_file_overflow),
-  JUMP_INIT(underflow, _IO_new_file_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_default_pbackfail),
-  JUMP_INIT(xsputn, _IO_new_file_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_new_file_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_new_file_setbuf),
-  JUMP_INIT(sync, _IO_new_file_sync),
-  JUMP_INIT(doallocate, _IO_file_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_new_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_new_proc_close),
-  JUMP_INIT(stat, _IO_file_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
 strong_alias (_IO_new_popen, __new_popen)
 versioned_symbol (libc, _IO_new_popen, _IO_popen, GLIBC_2_1);
 versioned_symbol (libc, __new_popen, popen, GLIBC_2_1);
diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c
index 72c67bf27b..ca73de9313 100644
--- a/libio/iovsprintf.c
+++ b/libio/iovsprintf.c
@@ -27,7 +27,7 @@
 #include "libioP.h"
 #include "strfile.h"
 
-static int __THROW
+int __THROW
 _IO_str_chk_overflow (FILE *fp, int c)
 {
   /* If we get here, the user-supplied buffer would be overrun by
@@ -35,30 +35,6 @@ _IO_str_chk_overflow (FILE *fp, int c)
   __chk_fail ();
 }
 
-static const struct _IO_jump_t _IO_str_chk_jumps libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_str_finish),
-  JUMP_INIT(overflow, _IO_str_chk_overflow),
-  JUMP_INIT(underflow, _IO_str_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_str_pbackfail),
-  JUMP_INIT(xsputn, _IO_default_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_str_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_default_setbuf),
-  JUMP_INIT(sync, _IO_default_sync),
-  JUMP_INIT(doallocate, _IO_default_doallocate),
-  JUMP_INIT(read, _IO_default_read),
-  JUMP_INIT(write, _IO_default_write),
-  JUMP_INIT(seek, _IO_default_seek),
-  JUMP_INIT(close, _IO_default_close),
-  JUMP_INIT(stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
 /* This function is called by regular vsprintf with maxlen set to -1,
    and by vsprintf_chk with maxlen set to the size of the output
    string.  In the former case, _IO_str_chk_overflow will never be
diff --git a/libio/libio-macros.sym b/libio/libio-macros.sym
new file mode 100644
index 0000000000..cfb5cf2841
--- /dev/null
+++ b/libio/libio-macros.sym
@@ -0,0 +1,7 @@
+#include <libioP.h>
+
+--
+
+IO_JUMP_T_SIZE		sizeof (struct _IO_jump_t)
+IO_FILE_JUMPS_OFFSET	sizeof (struct _IO_jump_t) * IO_FILE_JUMPS
+IO_WFILE_JUMPS_OFFSET	sizeof (struct _IO_jump_t) * IO_WFILE_JUMPS
diff --git a/libio/libioP.h b/libio/libioP.h
index 3a5498bd65..63d2145963 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -431,57 +431,105 @@ libc_hidden_proto (_IO_enable_locks)
 
 /* Default jumptable functions. */
 
-extern int _IO_default_underflow (FILE *) __THROW;
-extern int _IO_default_uflow (FILE *);
+extern int _IO_default_underflow (FILE *) __THROW weak_function;
+extern int _IO_default_uflow (FILE *) weak_function;
 libc_hidden_proto (_IO_default_uflow)
-extern wint_t _IO_wdefault_uflow (FILE *);
+extern wint_t _IO_wdefault_uflow (FILE *) weak_function;
 libc_hidden_proto (_IO_wdefault_uflow)
-extern int _IO_default_doallocate (FILE *) __THROW;
+extern int _IO_default_doallocate (FILE *) __THROW weak_function;
 libc_hidden_proto (_IO_default_doallocate)
-extern int _IO_wdefault_doallocate (FILE *) __THROW;
+extern int _IO_wdefault_doallocate (FILE *) __THROW weak_function;
 libc_hidden_proto (_IO_wdefault_doallocate)
-extern void _IO_default_finish (FILE *, int) __THROW;
+extern void _IO_default_finish (FILE *, int) __THROW weak_function;
 libc_hidden_proto (_IO_default_finish)
-extern void _IO_wdefault_finish (FILE *, int) __THROW;
+extern void _IO_wdefault_finish (FILE *, int) __THROW weak_function;
 libc_hidden_proto (_IO_wdefault_finish)
-extern int _IO_default_pbackfail (FILE *, int) __THROW;
+extern int _IO_default_pbackfail (FILE *, int) __THROW weak_function;
 libc_hidden_proto (_IO_default_pbackfail)
-extern wint_t _IO_wdefault_pbackfail (FILE *, wint_t) __THROW;
+extern wint_t _IO_wdefault_pbackfail (FILE *, wint_t) __THROW weak_function;
 libc_hidden_proto (_IO_wdefault_pbackfail)
-extern FILE* _IO_default_setbuf (FILE *, char *, ssize_t);
-extern size_t _IO_default_xsputn (FILE *, const void *, size_t);
+extern FILE* _IO_default_setbuf (FILE *, char *, ssize_t) weak_function;
+extern size_t _IO_default_xsputn (FILE *, const void *, size_t) weak_function;
 libc_hidden_proto (_IO_default_xsputn)
-extern size_t _IO_wdefault_xsputn (FILE *, const void *, size_t);
+extern size_t _IO_wdefault_xsputn (FILE *, const void *, size_t)
+     weak_function;
 libc_hidden_proto (_IO_wdefault_xsputn)
-extern size_t _IO_default_xsgetn (FILE *, void *, size_t);
+extern size_t _IO_default_xsgetn (FILE *, void *, size_t) weak_function;
 libc_hidden_proto (_IO_default_xsgetn)
-extern size_t _IO_wdefault_xsgetn (FILE *, void *, size_t);
+extern size_t _IO_wdefault_xsgetn (FILE *, void *, size_t) weak_function;
 libc_hidden_proto (_IO_wdefault_xsgetn)
 extern off64_t _IO_default_seekoff (FILE *, off64_t, int, int)
-     __THROW;
-extern off64_t _IO_default_seekpos (FILE *, off64_t, int);
-extern ssize_t _IO_default_write (FILE *, const void *, ssize_t);
-extern ssize_t _IO_default_read (FILE *, void *, ssize_t);
+     __THROW weak_function;
+extern off64_t _IO_default_seekpos (FILE *, off64_t, int) weak_function;
+extern ssize_t _IO_default_write (FILE *, const void *, ssize_t)
+     weak_function;
+extern ssize_t _IO_default_read (FILE *, void *, ssize_t) weak_function;
 extern int _IO_default_stat (FILE *, void *) __THROW;
-extern off64_t _IO_default_seek (FILE *, off64_t, int) __THROW;
-extern int _IO_default_sync (FILE *) __THROW;
+extern off64_t _IO_default_seek (FILE *, off64_t, int) __THROW weak_function;
+extern int _IO_default_sync (FILE *) __THROW weak_function;
 #define _IO_default_close ((_IO_close_t) _IO_default_sync)
-extern int _IO_default_showmanyc (FILE *) __THROW;
-extern void _IO_default_imbue (FILE *, void *) __THROW;
-
-extern const struct _IO_jump_t _IO_file_jumps;
-libc_hidden_proto (_IO_file_jumps)
-extern const struct _IO_jump_t _IO_file_jumps_mmap attribute_hidden;
-extern const struct _IO_jump_t _IO_file_jumps_maybe_mmap attribute_hidden;
-extern const struct _IO_jump_t _IO_wfile_jumps;
-libc_hidden_proto (_IO_wfile_jumps)
-extern const struct _IO_jump_t _IO_wfile_jumps_mmap attribute_hidden;
-extern const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap attribute_hidden;
-extern const struct _IO_jump_t _IO_old_file_jumps attribute_hidden;
-extern const struct _IO_jump_t _IO_streambuf_jumps;
-extern const struct _IO_jump_t _IO_old_proc_jumps attribute_hidden;
-extern const struct _IO_jump_t _IO_str_jumps attribute_hidden;
-extern const struct _IO_jump_t _IO_wstr_jumps attribute_hidden;
+extern int _IO_default_showmanyc (FILE *) __THROW weak_function;
+extern void _IO_default_imbue (FILE *, void *) __THROW weak_function;
+
+enum
+{
+  IO_STR_JUMPS              = 0,
+  IO_WSTR_JUMPS             = 1,
+  IO_STRN_JUMPS             = 2,
+  IO_WSTRN_JUMPS            = 3,
+  IO_FILE_JUMPS             = 4,
+  IO_FILE_JUMPS_MMAP        = 5,
+  IO_FILE_JUMPS_MAYBE_MMAP  = 6,
+  IO_WFILE_JUMPS            = 7,
+  IO_WFILE_JUMPS_MMAP       = 8,
+  IO_WFILE_JUMPS_MAYBE_MMAP = 9,
+  IO_COOKIE_JUMPS           = 10,
+  IO_PROC_JUMPS             = 11,
+  IO_STR_CHK_JUMPS          = 12,
+  IO_OBSTACK_JUMPS          = 13,
+  IO_HELPER_JUMPS           = 14,
+  IO_WHELPER_JUMPS          = 15,
+  IO_MEM_JUMPS              = 16,
+  IO_WMEM_JUMPS             = 17,
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
+  IO_OLD_FILE_JUMPS         = 18,
+  IO_OLD_PROC_JUMPS         = 19,
+#endif
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
+  IO_OLD_COOKIED_JUMPS      = 20,
+#endif
+};
+
+extern const struct _IO_jump_t __io_vtables[] attribute_hidden;
+extern const size_t __io_vtables_size attribute_hidden;
+#define _IO_str_jumps			(__io_vtables[IO_STR_JUMPS])
+#define _IO_wstr_jumps			(__io_vtables[IO_WSTR_JUMPS])
+#define _IO_strn_jumps			(__io_vtables[IO_STRN_JUMPS])
+#define _IO_wstrn_jumps			(__io_vtables[IO_WSTRN_JUMPS])
+#define _IO_file_jumps			(__io_vtables[IO_FILE_JUMPS])
+#define _IO_file_jumps_mmap		(__io_vtables[IO_FILE_JUMPS_MMAP])
+#define _IO_file_jumps_maybe_mmap	(__io_vtables[IO_FILE_JUMPS_MAYBE_MMAP])
+#define _IO_wfile_jumps			(__io_vtables[IO_WFILE_JUMPS])
+#define _IO_wfile_jumps_mmap		(__io_vtables[IO_WFILE_JUMPS_MMAP])
+#define _IO_wfile_jumps_maybe_mmap	(__io_vtables[IO_WFILE_JUMPS_MAYBE_MMAP])
+#define _IO_cookie_jumps		(__io_vtables[IO_COOKIE_JUMPS])
+#define _IO_proc_jumps			(__io_vtables[IO_PROC_JUMPS])
+#define _IO_str_chk_jumps		(__io_vtables[IO_STR_CHK_JUMPS])
+#define _IO_obstack_jumps		(__io_vtables[IO_OBSTACK_JUMPS])
+#define _IO_helper_jumps		(__io_vtables[IO_HELPER_JUMPS])
+#define _IO_whelper_jumps		(__io_vtables[IO_WHELPER_JUMPS])
+#define _IO_mem_jumps			(__io_vtables[IO_MEM_JUMPS])
+#define _IO_wmem_jumps			(__io_vtables[IO_WMEM_JUMPS])
+#define _IO_old_file_jumps		(__io_vtables[IO_OLD_FILE_JUMPS])
+#define _IO_old_proc_jumps		(__io_vtables[IO_OLD_PROC_JUMPS])
+#define _IO_old_cookie_jumps		(__io_vtables[IO_OLD_COOKIED_JUMPS])
+
+#ifdef SHARED
+# define libio_static_fn_required(name)
+#else
+# define libio_static_fn_required(name) __asm (".globl " #name);
+#endif
+
 extern int _IO_do_write (FILE *, const char *, size_t);
 libc_hidden_proto (_IO_do_write)
 extern int _IO_new_do_write (FILE *, const char *, size_t);
@@ -540,65 +588,77 @@ extern void _IO_old_init (FILE *fp, int flags) __THROW;
 
 /* Jumptable functions for files. */
 
-extern int _IO_file_doallocate (FILE *) __THROW;
+extern int _IO_file_doallocate (FILE *) __THROW weak_function;
 libc_hidden_proto (_IO_file_doallocate)
-extern FILE* _IO_file_setbuf (FILE *, char *, ssize_t);
+extern FILE* _IO_file_setbuf (FILE *, char *, ssize_t) weak_function;
 libc_hidden_proto (_IO_file_setbuf)
-extern off64_t _IO_file_seekoff (FILE *, off64_t, int, int);
+extern off64_t _IO_file_seekoff (FILE *, off64_t, int, int) weak_function;
 libc_hidden_proto (_IO_file_seekoff)
 extern off64_t _IO_file_seekoff_mmap (FILE *, off64_t, int, int)
-     __THROW;
-extern size_t _IO_file_xsputn (FILE *, const void *, size_t);
+     __THROW weak_function;
+extern size_t _IO_file_xsputn (FILE *, const void *, size_t) weak_function;
 libc_hidden_proto (_IO_file_xsputn)
-extern size_t _IO_file_xsgetn (FILE *, void *, size_t);
+extern size_t _IO_file_xsgetn (FILE *, void *, size_t) weak_function;
 libc_hidden_proto (_IO_file_xsgetn)
-extern int _IO_file_stat (FILE *, void *) __THROW;
+extern int _IO_file_stat (FILE *, void *) __THROW weak_function;
 libc_hidden_proto (_IO_file_stat)
-extern int _IO_file_close (FILE *) __THROW;
+extern int _IO_file_close (FILE *) __THROW weak_function;
 libc_hidden_proto (_IO_file_close)
-extern int _IO_file_close_mmap (FILE *) __THROW;
-extern int _IO_file_underflow (FILE *);
+extern int _IO_file_close_mmap (FILE *) __THROW weak_function;
+extern int _IO_file_underflow (FILE *) weak_function;
 libc_hidden_proto (_IO_file_underflow)
-extern int _IO_file_underflow_mmap (FILE *);
-extern int _IO_file_underflow_maybe_mmap (FILE *);
-extern int _IO_file_overflow (FILE *, int);
+extern int _IO_file_underflow_mmap (FILE *) weak_function;
+extern int _IO_file_underflow_maybe_mmap (FILE *) weak_function;
+extern int _IO_file_overflow (FILE *, int) weak_function;
 libc_hidden_proto (_IO_file_overflow)
 #define _IO_file_is_open(__fp) ((__fp)->_fileno != -1)
-extern FILE* _IO_file_attach (FILE *, int);
+extern FILE* _IO_file_attach (FILE *, int) weak_function;
 libc_hidden_proto (_IO_file_attach)
-extern FILE* _IO_file_open (FILE *, const char *, int, int, int, int);
+extern FILE* _IO_file_open (FILE *, const char *, int, int, int, int)
+     weak_function;
 libc_hidden_proto (_IO_file_open)
-extern FILE* _IO_file_fopen (FILE *, const char *, const char *, int);
+extern FILE* _IO_file_fopen (FILE *, const char *, const char *, int)
+     weak_function;
 libc_hidden_proto (_IO_file_fopen)
-extern ssize_t _IO_file_write (FILE *, const void *, ssize_t);
-extern ssize_t _IO_file_read (FILE *, void *, ssize_t);
+extern ssize_t _IO_file_write (FILE *, const void *, ssize_t) weak_function;
+extern ssize_t _IO_file_read (FILE *, void *, ssize_t) weak_function;
 libc_hidden_proto (_IO_file_read)
-extern int _IO_file_sync (FILE *);
+extern int _IO_file_sync (FILE *) weak_function;
 libc_hidden_proto (_IO_file_sync)
-extern int _IO_file_close_it (FILE *);
+extern int _IO_file_close_it (FILE *) weak_function;
 libc_hidden_proto (_IO_file_close_it)
-extern off64_t _IO_file_seek (FILE *, off64_t, int) __THROW;
+extern off64_t _IO_file_seek (FILE *, off64_t, int) __THROW weak_function;
 libc_hidden_proto (_IO_file_seek)
-extern void _IO_file_finish (FILE *, int);
+extern void _IO_file_finish (FILE *, int) weak_function;
 libc_hidden_proto (_IO_file_finish)
 
-extern FILE* _IO_new_file_attach (FILE *, int);
-extern int _IO_new_file_close_it (FILE *);
-extern void _IO_new_file_finish (FILE *, int);
+extern FILE* _IO_new_file_attach (FILE *, int) weak_function;
+extern int _IO_new_file_close_it (FILE *) weak_function;
+extern void _IO_new_file_finish (FILE *, int) weak_function;
 extern FILE* _IO_new_file_fopen (FILE *, const char *, const char *,
-				     int);
+				 int) weak_function;
 extern void _IO_no_init (FILE *, int, int, struct _IO_wide_data *,
-			 const struct _IO_jump_t *) __THROW;
+			 const struct _IO_jump_t *) __THROW weak_function;
 extern void _IO_new_file_init_internal (struct _IO_FILE_plus *)
-  __THROW attribute_hidden;
-extern FILE* _IO_new_file_setbuf (FILE *, char *, ssize_t);
-extern FILE* _IO_file_setbuf_mmap (FILE *, char *, ssize_t);
-extern int _IO_new_file_sync (FILE *);
-extern int _IO_new_file_underflow (FILE *);
-extern int _IO_new_file_overflow (FILE *, int);
-extern off64_t _IO_new_file_seekoff (FILE *, off64_t, int, int);
-extern ssize_t _IO_new_file_write (FILE *, const void *, ssize_t);
-extern size_t _IO_new_file_xsputn (FILE *, const void *, size_t);
+  __THROW attribute_hidden weak_function;
+extern FILE* _IO_new_file_setbuf (FILE *, char *, ssize_t) weak_function;
+extern FILE* _IO_file_setbuf_mmap (FILE *, char *, ssize_t) weak_function;
+extern int _IO_new_file_sync (FILE *) weak_function;
+extern int _IO_file_sync_mmap (FILE *) attribute_hidden weak_function;
+extern size_t  _IO_file_xsgetn_maybe_mmap (FILE *fp, void *data, size_t n)
+  attribute_hidden weak_function;
+extern size_t _IO_file_xsgetn_mmap (FILE *fp, void *data, size_t n)
+  attribute_hidden weak_function;
+extern off64_t _IO_file_seekoff_maybe_mmap (FILE *fp, off64_t offset, int dir,
+					    int mode)
+     attribute_hidden weak_function;
+extern int _IO_new_file_underflow (FILE *) weak_function;
+extern int _IO_new_file_overflow (FILE *, int) weak_function;
+extern off64_t _IO_new_file_seekoff (FILE *, off64_t, int, int) weak_function;
+extern ssize_t _IO_new_file_write (FILE *, const void *, ssize_t)
+     weak_function;
+extern size_t _IO_new_file_xsputn (FILE *, const void *, size_t)
+     weak_function;
 
 extern FILE* _IO_old_file_setbuf (FILE *, char *, ssize_t);
 extern off64_t _IO_old_file_seekoff (FILE *, off64_t, int, int);
@@ -614,54 +674,97 @@ extern int _IO_old_file_sync (FILE *);
 extern int _IO_old_file_close_it (FILE *);
 extern void _IO_old_file_finish (FILE *, int);
 
-extern int _IO_wfile_doallocate (FILE *) __THROW;
-extern size_t _IO_wfile_xsputn (FILE *, const void *, size_t);
+extern int _IO_wfile_doallocate (FILE *) __THROW weak_function;
+extern size_t _IO_wfile_xsputn (FILE *, const void *, size_t) weak_function;
 libc_hidden_proto (_IO_wfile_xsputn)
-extern FILE* _IO_wfile_setbuf (FILE *, wchar_t *, ssize_t);
-extern wint_t _IO_wfile_sync (FILE *);
+extern FILE* _IO_wfile_setbuf (FILE *, wchar_t *, ssize_t) weak_function;
+extern wint_t _IO_wfile_sync (FILE *) weak_function;
 libc_hidden_proto (_IO_wfile_sync)
-extern wint_t _IO_wfile_underflow (FILE *);
+extern wint_t _IO_wfile_underflow (FILE *) weak_function;
 libc_hidden_proto (_IO_wfile_underflow)
-extern wint_t _IO_wfile_overflow (FILE *, wint_t);
+extern wint_t _IO_wfile_overflow (FILE *, wint_t) weak_function;
 libc_hidden_proto (_IO_wfile_overflow)
-extern off64_t _IO_wfile_seekoff (FILE *, off64_t, int, int);
+extern off64_t _IO_wfile_seekoff (FILE *, off64_t, int, int) weak_function;
 libc_hidden_proto (_IO_wfile_seekoff)
+extern wint_t _IO_wfile_underflow_maybe_mmap (FILE *fp)
+     attribute_hidden weak_function;
+extern wint_t _IO_wfile_underflow_mmap (FILE *fp)
+     attribute_hidden weak_function;
 
 /* Jumptable functions for proc_files. */
 extern FILE* _IO_proc_open (FILE *, const char *, const char *)
-     __THROW;
+     __THROW weak_function;
 extern FILE* _IO_new_proc_open (FILE *, const char *, const char *)
-     __THROW;
-extern FILE* _IO_old_proc_open (FILE *, const char *, const char *);
-extern int _IO_proc_close (FILE *) __THROW;
-extern int _IO_new_proc_close (FILE *) __THROW;
-extern int _IO_old_proc_close (FILE *);
+     __THROW weak_function;
+extern FILE* _IO_old_proc_open (FILE *, const char *, const char *)
+     weak_function;
+extern int _IO_proc_close (FILE *) __THROW weak_function;
+extern int _IO_new_proc_close (FILE *) __THROW weak_function;
+extern int _IO_old_proc_close (FILE *) weak_function;
 
 /* Jumptable functions for strfiles. */
-extern int _IO_str_underflow (FILE *) __THROW;
+extern int _IO_str_underflow (FILE *) __THROW weak_function weak_function;
 libc_hidden_proto (_IO_str_underflow)
-extern int _IO_str_overflow (FILE *, int) __THROW;
+extern int _IO_str_overflow (FILE *, int) __THROW weak_function;
 libc_hidden_proto (_IO_str_overflow)
-extern int _IO_str_pbackfail (FILE *, int) __THROW;
+extern int _IO_str_pbackfail (FILE *, int) __THROW weak_function;
 libc_hidden_proto (_IO_str_pbackfail)
-extern off64_t _IO_str_seekoff (FILE *, off64_t, int, int) __THROW;
+extern off64_t _IO_str_seekoff (FILE *, off64_t, int, int) __THROW
+  weak_function;
 libc_hidden_proto (_IO_str_seekoff)
-extern void _IO_str_finish (FILE *, int) __THROW;
+extern void _IO_str_finish (FILE *, int) __THROW weak_function;
+extern int _IO_str_chk_overflow (FILE *fp, int c) __THROW
+  attribute_hidden weak_function;
+
+/* Jumptable functions for fopencookie.  */
+extern ssize_t _IO_cookie_read (FILE *fp, void *buf, ssize_t size)
+  attribute_hidden weak_function;
+extern ssize_t _IO_cookie_write (FILE *fp, const void *buf, ssize_t size)
+  attribute_hidden weak_function;
+extern off64_t _IO_cookie_seek (FILE *fp, off64_t offset, int dir)
+  attribute_hidden weak_function;
+extern int _IO_cookie_close (FILE *fp) attribute_hidden;
+extern off64_t _IO_cookie_seekoff (FILE *fp, off64_t offset, int dir, int mode)
+  attribute_hidden weak_function;
+extern off64_t _IO_old_cookie_seek (FILE *fp, off64_t offset, int dir)
+  attribute_hidden weak_function;
+
+/* Jumptable functions for obstack.  */
+extern int __IO_obstack_overflow (FILE *fp, int c) attribute_hidden
+  weak_function;
+extern size_t __IO_obstack_xsputn (FILE *fp, const void *data, size_t n)
+  attribute_hidden weak_function;
+extern wint_t _IO_wstrn_overflow (FILE *fp, wint_t c) __THROW
+  attribute_hidden weak_function;
+
+/* Jumptable functions for open_{w}memstream.  */
+extern int _IO_mem_sync (FILE* fp) __THROW attribute_hidden weak_function;
+extern void _IO_mem_finish (FILE* fp, int) __THROW attribute_hidden
+  weak_function;
+extern int _IO_wmem_sync (FILE* fp) __THROW attribute_hidden weak_function;
+extern void _IO_wmem_finish (FILE* fp, int) __THROW attribute_hidden
+  weak_function;
 
 /* Other strfile functions */
 struct _IO_strfile_;
-extern ssize_t _IO_str_count (FILE *) __THROW;
+extern ssize_t _IO_str_count (FILE *) __THROW weak_function;
+extern int _IO_strn_overflow (FILE *fp, int c) __THROW attribute_hidden
+  weak_function;
 
 /* And the wide character versions.  */
 extern void _IO_wstr_init_static (FILE *, wchar_t *, size_t, wchar_t *)
      __THROW;
-extern ssize_t _IO_wstr_count (FILE *) __THROW;
-extern wint_t _IO_wstr_overflow (FILE *, wint_t) __THROW;
-extern wint_t _IO_wstr_underflow (FILE *) __THROW;
+extern ssize_t _IO_wstr_count (FILE *) __THROW weak_function;
+extern wint_t _IO_wstr_overflow (FILE *, wint_t) __THROW weak_function;
+extern wint_t _IO_wstr_underflow (FILE *) __THROW weak_function;
 extern off64_t _IO_wstr_seekoff (FILE *, off64_t, int, int)
-     __THROW;
-extern wint_t _IO_wstr_pbackfail (FILE *, wint_t) __THROW;
-extern void _IO_wstr_finish (FILE *, int) __THROW;
+     __THROW weak_function;
+extern wint_t _IO_wstr_pbackfail (FILE *, wint_t) __THROW weak_function;
+extern void _IO_wstr_finish (FILE *, int) __THROW weak_function;
+
+/* Helper functions.  */
+int _IO_helper_overflow (FILE *s, int c) weak_function;
+int _IO_whelper_overflow (FILE *s, int c) weak_function;
 
 /* Internal versions of v*printf that take an additional flags
    parameter.  */
@@ -892,14 +995,6 @@ _IO_acquire_lock_fct (FILE **p)
   } while (0)
 #endif
 
-/* Collect all vtables in a special section for vtable verification.
-   These symbols cover the extent of this section.  */
-symbol_set_declare (__libc_IO_vtables)
-
-/* libio vtables need to carry this attribute so that they pass
-   validation.  */
-#define libio_vtable __attribute__ ((section ("__libc_IO_vtables")))
-
 #ifdef SHARED
 /* If equal to &_IO_vtable_check (with pointer guard protection),
    unknown vtable pointers are valid.  This function pointer is solely
@@ -934,12 +1029,9 @@ void _IO_vtable_check (void) attribute_hidden;
 static inline const struct _IO_jump_t *
 IO_validate_vtable (const struct _IO_jump_t *vtable)
 {
-  /* Fast path: The vtable pointer is within the __libc_IO_vtables
-     section.  */
-  uintptr_t section_length = __stop___libc_IO_vtables - __start___libc_IO_vtables;
   uintptr_t ptr = (uintptr_t) vtable;
-  uintptr_t offset = ptr - (uintptr_t) __start___libc_IO_vtables;
-  if (__glibc_unlikely (offset >= section_length))
+  uintptr_t offset = ptr - (uintptr_t) &__io_vtables;
+  if (__glibc_unlikely (offset >= __io_vtables_size))
     /* The vtable pointer is not in the expected section.  Use the
        slow path, which will terminate the process if necessary.  */
     _IO_vtable_check ();
diff --git a/libio/memstream.c b/libio/memstream.c
index 1ae8cd9544..b5b5254a34 100644
--- a/libio/memstream.c
+++ b/libio/memstream.c
@@ -29,34 +29,6 @@ struct _IO_FILE_memstream
 };
 
 
-static int _IO_mem_sync (FILE* fp) __THROW;
-static void _IO_mem_finish (FILE* fp, int) __THROW;
-
-
-static const struct _IO_jump_t _IO_mem_jumps libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT (finish, _IO_mem_finish),
-  JUMP_INIT (overflow, _IO_str_overflow),
-  JUMP_INIT (underflow, _IO_str_underflow),
-  JUMP_INIT (uflow, _IO_default_uflow),
-  JUMP_INIT (pbackfail, _IO_str_pbackfail),
-  JUMP_INIT (xsputn, _IO_default_xsputn),
-  JUMP_INIT (xsgetn, _IO_default_xsgetn),
-  JUMP_INIT (seekoff, _IO_str_seekoff),
-  JUMP_INIT (seekpos, _IO_default_seekpos),
-  JUMP_INIT (setbuf, _IO_default_setbuf),
-  JUMP_INIT (sync, _IO_mem_sync),
-  JUMP_INIT (doallocate, _IO_default_doallocate),
-  JUMP_INIT (read, _IO_default_read),
-  JUMP_INIT (write, _IO_default_write),
-  JUMP_INIT (seek, _IO_default_seek),
-  JUMP_INIT (close, _IO_default_close),
-  JUMP_INIT (stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
 /* Open a stream that writes into a malloc'd buffer that is expanded as
    necessary.  *BUFLOC and *SIZELOC are updated with the buffer's location
    and the number of characters written on fflush or fclose.  */
@@ -105,7 +77,7 @@ libc_hidden_def (__open_memstream)
 weak_alias (__open_memstream, open_memstream)
 
 
-static int
+int
 _IO_mem_sync (FILE *fp)
 {
   struct _IO_FILE_memstream *mp = (struct _IO_FILE_memstream *) fp;
@@ -123,7 +95,7 @@ _IO_mem_sync (FILE *fp)
 }
 
 
-static void
+void
 _IO_mem_finish (FILE *fp, int dummy)
 {
   struct _IO_FILE_memstream *mp = (struct _IO_FILE_memstream *) fp;
diff --git a/libio/obprintf.c b/libio/obprintf.c
index c220be9adc..1b3f074826 100644
--- a/libio/obprintf.c
+++ b/libio/obprintf.c
@@ -35,8 +35,8 @@ struct _IO_obstack_file
 };
 
 
-static int
-_IO_obstack_overflow (FILE *fp, int c)
+int
+__IO_obstack_overflow (FILE *fp, int c)
 {
   struct obstack *obstack = ((struct _IO_obstack_file *) fp)->obstack;
   int size;
@@ -58,8 +58,8 @@ _IO_obstack_overflow (FILE *fp, int c)
 }
 
 
-static size_t
-_IO_obstack_xsputn (FILE *fp, const void *data, size_t n)
+size_t
+__IO_obstack_xsputn (FILE *fp, const void *data, size_t n)
 {
   struct obstack *obstack = ((struct _IO_obstack_file *) fp)->obstack;
 
@@ -89,32 +89,6 @@ _IO_obstack_xsputn (FILE *fp, const void *data, size_t n)
 }
 
 
-/* the jump table.  */
-const struct _IO_jump_t _IO_obstack_jumps libio_vtable attribute_hidden =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, NULL),
-  JUMP_INIT(overflow, _IO_obstack_overflow),
-  JUMP_INIT(underflow, NULL),
-  JUMP_INIT(uflow, NULL),
-  JUMP_INIT(pbackfail, NULL),
-  JUMP_INIT(xsputn, _IO_obstack_xsputn),
-  JUMP_INIT(xsgetn, NULL),
-  JUMP_INIT(seekoff, NULL),
-  JUMP_INIT(seekpos, NULL),
-  JUMP_INIT(setbuf, NULL),
-  JUMP_INIT(sync, NULL),
-  JUMP_INIT(doallocate, NULL),
-  JUMP_INIT(read, NULL),
-  JUMP_INIT(write, NULL),
-  JUMP_INIT(seek, NULL),
-  JUMP_INIT(close, NULL),
-  JUMP_INIT(stat, NULL),
-  JUMP_INIT(showmanyc, NULL),
-  JUMP_INIT(imbue, NULL)
-};
-
-
 int
 __obstack_vprintf_internal (struct obstack *obstack, const char *format,
 			    va_list args, unsigned int mode_flags)
diff --git a/libio/oldfileops.c b/libio/oldfileops.c
index ea3b864447..371c7479c6 100644
--- a/libio/oldfileops.c
+++ b/libio/oldfileops.c
@@ -716,29 +716,6 @@ _IO_old_file_xsputn (FILE *f, const void *data, size_t n)
   return n - to_do;
 }
 
-
-const struct _IO_jump_t _IO_old_file_jumps libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_old_file_finish),
-  JUMP_INIT(overflow, _IO_old_file_overflow),
-  JUMP_INIT(underflow, _IO_old_file_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_default_pbackfail),
-  JUMP_INIT(xsputn, _IO_old_file_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_old_file_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_old_file_setbuf),
-  JUMP_INIT(sync, _IO_old_file_sync),
-  JUMP_INIT(doallocate, _IO_file_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_old_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_file_close),
-  JUMP_INIT(stat, _IO_file_stat)
-};
-
 compat_symbol (libc, _IO_old_do_write, _IO_do_write, GLIBC_2_0);
 compat_symbol (libc, _IO_old_file_attach, _IO_file_attach, GLIBC_2_0);
 compat_symbol (libc, _IO_old_file_close_it, _IO_file_close_it, GLIBC_2_0);
diff --git a/libio/oldiopopen.c b/libio/oldiopopen.c
index f9149413e8..206a0f3858 100644
--- a/libio/oldiopopen.c
+++ b/libio/oldiopopen.c
@@ -208,29 +208,6 @@ _IO_old_proc_close (FILE *fp)
   return wstatus;
 }
 
-const struct _IO_jump_t _IO_old_proc_jumps libio_vtable = {
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_old_file_finish),
-  JUMP_INIT(overflow, _IO_old_file_overflow),
-  JUMP_INIT(underflow, _IO_old_file_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_default_pbackfail),
-  JUMP_INIT(xsputn, _IO_old_file_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_old_file_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_old_file_setbuf),
-  JUMP_INIT(sync, _IO_old_file_sync),
-  JUMP_INIT(doallocate, _IO_file_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_old_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_old_proc_close),
-  JUMP_INIT(stat, _IO_file_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
 strong_alias (_IO_old_popen, __old_popen)
 compat_symbol (libc, _IO_old_popen, _IO_popen, GLIBC_2_0);
 compat_symbol (libc, __old_popen, popen, GLIBC_2_0);
diff --git a/libio/stdio.c b/libio/stdio.c
index e65ee86b24..356d41d277 100644
--- a/libio/stdio.c
+++ b/libio/stdio.c
@@ -33,3 +33,6 @@
 FILE *stdin = (FILE *) &_IO_2_1_stdin_;
 FILE *stdout = (FILE *) &_IO_2_1_stdout_;
 FILE *stderr = (FILE *) &_IO_2_1_stderr_;
+
+libio_static_fn_required (_IO_file_open);
+libio_static_fn_required (_IO_file_doallocate);
diff --git a/libio/strfile.h b/libio/strfile.h
index fa44ebc7e7..f2ce1ff6f3 100644
--- a/libio/strfile.h
+++ b/libio/strfile.h
@@ -70,9 +70,6 @@ typedef struct
   char overflow_buf[64];
 } _IO_strnfile;
 
-extern const struct _IO_jump_t _IO_strn_jumps attribute_hidden;
-
-
 typedef struct
 {
   _IO_strfile f;
@@ -81,8 +78,6 @@ typedef struct
   wchar_t overflow_buf[64];
 } _IO_wstrnfile;
 
-extern const struct _IO_jump_t _IO_wstrn_jumps attribute_hidden;
-
 /* Initialize an _IO_strfile SF to read from narrow string STRING, and
    return the corresponding FILE object.  It is not necessary to fclose
    the FILE when it is no longer needed.  */
diff --git a/libio/strops.c b/libio/strops.c
index 1cd0bf6c3d..4e2243b8d9 100644
--- a/libio/strops.c
+++ b/libio/strops.c
@@ -352,27 +352,3 @@ _IO_str_finish (FILE *fp, int dummy)
 
   _IO_default_finish (fp, 0);
 }
-
-const struct _IO_jump_t _IO_str_jumps libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_str_finish),
-  JUMP_INIT(overflow, _IO_str_overflow),
-  JUMP_INIT(underflow, _IO_str_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_str_pbackfail),
-  JUMP_INIT(xsputn, _IO_default_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_str_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_default_setbuf),
-  JUMP_INIT(sync, _IO_default_sync),
-  JUMP_INIT(doallocate, _IO_default_doallocate),
-  JUMP_INIT(read, _IO_default_read),
-  JUMP_INIT(write, _IO_default_write),
-  JUMP_INIT(seek, _IO_default_seek),
-  JUMP_INIT(close, _IO_default_close),
-  JUMP_INIT(stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
diff --git a/libio/tst-vtables-interposed.c b/libio/tst-vtables-interposed.c
index 9d03fa0ec2..66f79dddb5 100644
--- a/libio/tst-vtables-interposed.c
+++ b/libio/tst-vtables-interposed.c
@@ -21,7 +21,12 @@
 /* Provide an interposed definition of the standard file handles with
    our own vtable.  stdout/stdin/stderr will not work as a result, but
    a succesful test does not print anything, so this is fine.  */
+#include "libioP.h"
+#undef _IO_file_jumps
 #define _IO_file_jumps jumps
+#undef _IO_wfile_jumps
+extern const struct _IO_jump_t _IO_wfile_jumps;
+#define _IO_wfile_jumps _IO_wfile_jumps
 #include "stdfiles.c"
 
 static int
diff --git a/libio/vsnprintf.c b/libio/vsnprintf.c
index 8dae66761d..dd0280f60b 100644
--- a/libio/vsnprintf.c
+++ b/libio/vsnprintf.c
@@ -27,9 +27,7 @@
 #include "libioP.h"
 #include "strfile.h"
 
-static int _IO_strn_overflow (FILE *fp, int c) __THROW;
-
-static int
+int
 _IO_strn_overflow (FILE *fp, int c)
 {
   /* When we come to here this means the user supplied buffer is
@@ -64,31 +62,6 @@ _IO_strn_overflow (FILE *fp, int c)
 }
 
 
-const struct _IO_jump_t _IO_strn_jumps libio_vtable attribute_hidden =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_str_finish),
-  JUMP_INIT(overflow, _IO_strn_overflow),
-  JUMP_INIT(underflow, _IO_str_underflow),
-  JUMP_INIT(uflow, _IO_default_uflow),
-  JUMP_INIT(pbackfail, _IO_str_pbackfail),
-  JUMP_INIT(xsputn, _IO_default_xsputn),
-  JUMP_INIT(xsgetn, _IO_default_xsgetn),
-  JUMP_INIT(seekoff, _IO_str_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_default_setbuf),
-  JUMP_INIT(sync, _IO_default_sync),
-  JUMP_INIT(doallocate, _IO_default_doallocate),
-  JUMP_INIT(read, _IO_default_read),
-  JUMP_INIT(write, _IO_default_write),
-  JUMP_INIT(seek, _IO_default_seek),
-  JUMP_INIT(close, _IO_default_close),
-  JUMP_INIT(stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
-
 int
 __vsnprintf_internal (char *string, size_t maxlen, const char *format,
 		      va_list args, unsigned int mode_flags)
diff --git a/libio/vswprintf.c b/libio/vswprintf.c
index 5a9ccdff3e..2b31aa411c 100644
--- a/libio/vswprintf.c
+++ b/libio/vswprintf.c
@@ -27,10 +27,7 @@
 #include "libioP.h"
 #include "strfile.h"
 
-
-static wint_t _IO_wstrn_overflow (FILE *fp, wint_t c) __THROW;
-
-static wint_t
+wint_t
 _IO_wstrn_overflow (FILE *fp, wint_t c)
 {
   /* When we come to here this means the user supplied buffer is
@@ -63,31 +60,6 @@ _IO_wstrn_overflow (FILE *fp, wint_t c)
 }
 
 
-const struct _IO_jump_t _IO_wstrn_jumps libio_vtable attribute_hidden =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_wstr_finish),
-  JUMP_INIT(overflow, (_IO_overflow_t) _IO_wstrn_overflow),
-  JUMP_INIT(underflow, (_IO_underflow_t) _IO_wstr_underflow),
-  JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
-  JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
-  JUMP_INIT(xsputn, _IO_wdefault_xsputn),
-  JUMP_INIT(xsgetn, _IO_wdefault_xsgetn),
-  JUMP_INIT(seekoff, _IO_wstr_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_default_setbuf),
-  JUMP_INIT(sync, _IO_default_sync),
-  JUMP_INIT(doallocate, _IO_wdefault_doallocate),
-  JUMP_INIT(read, _IO_default_read),
-  JUMP_INIT(write, _IO_default_write),
-  JUMP_INIT(seek, _IO_default_seek),
-  JUMP_INIT(close, _IO_default_close),
-  JUMP_INIT(stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
-
 int
 __vswprintf_internal (wchar_t *string, size_t maxlen, const wchar_t *format,
 		      va_list args, unsigned int mode_flags)
diff --git a/libio/vtables.c b/libio/vtables.c
index e3809c28ce..7c66cf8c19 100644
--- a/libio/vtables.c
+++ b/libio/vtables.c
@@ -21,6 +21,496 @@
 #include <stdio.h>
 #include <ldsodefs.h>
 #include <pointer_guard.h>
+#include <libio-macros.h>
+
+const struct _IO_jump_t __io_vtables[] attribute_relro =
+{
+  /* _IO_str_jumps  */
+  [IO_STR_JUMPS] =
+  {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT(finish, _IO_str_finish),
+    JUMP_INIT(overflow, _IO_str_overflow),
+    JUMP_INIT(underflow, _IO_str_underflow),
+    JUMP_INIT(uflow, _IO_default_uflow),
+    JUMP_INIT(pbackfail, _IO_str_pbackfail),
+    JUMP_INIT(xsputn, _IO_default_xsputn),
+    JUMP_INIT(xsgetn, _IO_default_xsgetn),
+    JUMP_INIT(seekoff, _IO_str_seekoff),
+    JUMP_INIT(seekpos, _IO_default_seekpos),
+    JUMP_INIT(setbuf, _IO_default_setbuf),
+    JUMP_INIT(sync, _IO_default_sync),
+    JUMP_INIT(doallocate, _IO_default_doallocate),
+    JUMP_INIT(read, _IO_default_read),
+    JUMP_INIT(write, _IO_default_write),
+    JUMP_INIT(seek, _IO_default_seek),
+    JUMP_INIT(close, _IO_default_close),
+    JUMP_INIT(stat, _IO_default_stat),
+    JUMP_INIT(showmanyc, _IO_default_showmanyc),
+    JUMP_INIT(imbue, _IO_default_imbue)
+  },
+  /* _IO_wstr_jumps  */
+  [IO_WSTR_JUMPS] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT(finish, _IO_wstr_finish),
+    JUMP_INIT(overflow, (_IO_overflow_t) _IO_wstr_overflow),
+    JUMP_INIT(underflow, (_IO_underflow_t) _IO_wstr_underflow),
+    JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
+    JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
+    JUMP_INIT(xsputn, _IO_wdefault_xsputn),
+    JUMP_INIT(xsgetn, _IO_wdefault_xsgetn),
+    JUMP_INIT(seekoff, _IO_wstr_seekoff),
+    JUMP_INIT(seekpos, _IO_default_seekpos),
+    JUMP_INIT(setbuf, _IO_default_setbuf),
+    JUMP_INIT(sync, _IO_default_sync),
+    JUMP_INIT(doallocate, _IO_wdefault_doallocate),
+    JUMP_INIT(read, _IO_default_read),
+    JUMP_INIT(write, _IO_default_write),
+    JUMP_INIT(seek, _IO_default_seek),
+    JUMP_INIT(close, _IO_default_close),
+    JUMP_INIT(stat, _IO_default_stat),
+    JUMP_INIT(showmanyc, _IO_default_showmanyc),
+    JUMP_INIT(imbue, _IO_default_imbue)
+  },
+  /* _IO_strn_jumps  */
+  [IO_STRN_JUMPS] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT(finish, _IO_str_finish),
+    JUMP_INIT(overflow, _IO_strn_overflow),
+    JUMP_INIT(underflow, _IO_str_underflow),
+    JUMP_INIT(uflow, _IO_default_uflow),
+    JUMP_INIT(pbackfail, _IO_str_pbackfail),
+    JUMP_INIT(xsputn, _IO_default_xsputn),
+    JUMP_INIT(xsgetn, _IO_default_xsgetn),
+    JUMP_INIT(seekoff, _IO_str_seekoff),
+    JUMP_INIT(seekpos, _IO_default_seekpos),
+    JUMP_INIT(setbuf, _IO_default_setbuf),
+    JUMP_INIT(sync, _IO_default_sync),
+    JUMP_INIT(doallocate, _IO_default_doallocate),
+    JUMP_INIT(read, _IO_default_read),
+    JUMP_INIT(write, _IO_default_write),
+    JUMP_INIT(seek, _IO_default_seek),
+    JUMP_INIT(close, _IO_default_close),
+    JUMP_INIT(stat, _IO_default_stat),
+    JUMP_INIT(showmanyc, _IO_default_showmanyc),
+    JUMP_INIT(imbue, _IO_default_imbue)
+  },
+  /* _IO_wstrn_jumps  */
+  [IO_WSTRN_JUMPS] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT(finish, _IO_wstr_finish),
+    JUMP_INIT(overflow, (_IO_overflow_t) _IO_wstrn_overflow),
+    JUMP_INIT(underflow, (_IO_underflow_t) _IO_wstr_underflow),
+    JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
+    JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
+    JUMP_INIT(xsputn, _IO_wdefault_xsputn),
+    JUMP_INIT(xsgetn, _IO_wdefault_xsgetn),
+    JUMP_INIT(seekoff, _IO_wstr_seekoff),
+    JUMP_INIT(seekpos, _IO_default_seekpos),
+    JUMP_INIT(setbuf, _IO_default_setbuf),
+    JUMP_INIT(sync, _IO_default_sync),
+    JUMP_INIT(doallocate, _IO_wdefault_doallocate),
+    JUMP_INIT(read, _IO_default_read),
+    JUMP_INIT(write, _IO_default_write),
+    JUMP_INIT(seek, _IO_default_seek),
+    JUMP_INIT(close, _IO_default_close),
+    JUMP_INIT(stat, _IO_default_stat),
+    JUMP_INIT(showmanyc, _IO_default_showmanyc),
+    JUMP_INIT(imbue, _IO_default_imbue)
+  },
+  /* _IO_file_jumps  */
+  [IO_FILE_JUMPS] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT(finish, _IO_file_finish),
+    JUMP_INIT(overflow, _IO_file_overflow),
+    JUMP_INIT(underflow, _IO_file_underflow),
+    JUMP_INIT(uflow, _IO_default_uflow),
+    JUMP_INIT(pbackfail, _IO_default_pbackfail),
+    JUMP_INIT(xsputn, _IO_file_xsputn),
+    JUMP_INIT(xsgetn, _IO_file_xsgetn),
+    JUMP_INIT(seekoff, _IO_new_file_seekoff),
+    JUMP_INIT(seekpos, _IO_default_seekpos),
+    JUMP_INIT(setbuf, _IO_new_file_setbuf),
+    JUMP_INIT(sync, _IO_new_file_sync),
+    JUMP_INIT(doallocate, _IO_file_doallocate),
+    JUMP_INIT(read, _IO_file_read),
+    JUMP_INIT(write, _IO_new_file_write),
+    JUMP_INIT(seek, _IO_file_seek),
+    JUMP_INIT(close, _IO_file_close),
+    JUMP_INIT(stat, _IO_file_stat),
+    JUMP_INIT(showmanyc, _IO_default_showmanyc),
+    JUMP_INIT(imbue, _IO_default_imbue)
+  },
+  /* _IO_file_jumps_mmap  */
+  [IO_FILE_JUMPS_MMAP] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT(finish, _IO_file_finish),
+    JUMP_INIT(overflow, _IO_file_overflow),
+    JUMP_INIT(underflow, _IO_file_underflow_mmap),
+    JUMP_INIT(uflow, _IO_default_uflow),
+    JUMP_INIT(pbackfail, _IO_default_pbackfail),
+    JUMP_INIT(xsputn, _IO_new_file_xsputn),
+    JUMP_INIT(xsgetn, _IO_file_xsgetn_mmap),
+    JUMP_INIT(seekoff, _IO_file_seekoff_mmap),
+    JUMP_INIT(seekpos, _IO_default_seekpos),
+    JUMP_INIT(setbuf, (_IO_setbuf_t) _IO_file_setbuf_mmap),
+    JUMP_INIT(sync, _IO_file_sync_mmap),
+    JUMP_INIT(doallocate, _IO_file_doallocate),
+    JUMP_INIT(read, _IO_file_read),
+    JUMP_INIT(write, _IO_new_file_write),
+    JUMP_INIT(seek, _IO_file_seek),
+    JUMP_INIT(close, _IO_file_close_mmap),
+    JUMP_INIT(stat, _IO_file_stat),
+    JUMP_INIT(showmanyc, _IO_default_showmanyc),
+    JUMP_INIT(imbue, _IO_default_imbue)
+  },
+  /* _IO_file_jumps_maybe_mmap  */
+  [IO_FILE_JUMPS_MAYBE_MMAP] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT(finish, _IO_file_finish),
+    JUMP_INIT(overflow, _IO_file_overflow),
+    JUMP_INIT(underflow, _IO_file_underflow_maybe_mmap),
+    JUMP_INIT(uflow, _IO_default_uflow),
+    JUMP_INIT(pbackfail, _IO_default_pbackfail),
+    JUMP_INIT(xsputn, _IO_new_file_xsputn),
+    JUMP_INIT(xsgetn, _IO_file_xsgetn_maybe_mmap),
+    JUMP_INIT(seekoff, _IO_file_seekoff_maybe_mmap),
+    JUMP_INIT(seekpos, _IO_default_seekpos),
+    JUMP_INIT(setbuf, (_IO_setbuf_t) _IO_file_setbuf_mmap),
+    JUMP_INIT(sync, _IO_new_file_sync),
+    JUMP_INIT(doallocate, _IO_file_doallocate),
+    JUMP_INIT(read, _IO_file_read),
+    JUMP_INIT(write, _IO_new_file_write),
+    JUMP_INIT(seek, _IO_file_seek),
+    JUMP_INIT(close, _IO_file_close),
+    JUMP_INIT(stat, _IO_file_stat),
+    JUMP_INIT(showmanyc, _IO_default_showmanyc),
+    JUMP_INIT(imbue, _IO_default_imbue)
+  },
+  /* _IO_wfile_jumps  */
+  [IO_WFILE_JUMPS] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT(finish, _IO_new_file_finish),
+    JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
+    JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
+    JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
+    JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
+    JUMP_INIT(xsputn, _IO_wfile_xsputn),
+    JUMP_INIT(xsgetn, _IO_file_xsgetn),
+    JUMP_INIT(seekoff, _IO_wfile_seekoff),
+    JUMP_INIT(seekpos, _IO_default_seekpos),
+    JUMP_INIT(setbuf, _IO_new_file_setbuf),
+    JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
+    JUMP_INIT(doallocate, _IO_wfile_doallocate),
+    JUMP_INIT(read, _IO_file_read),
+    JUMP_INIT(write, _IO_new_file_write),
+    JUMP_INIT(seek, _IO_file_seek),
+    JUMP_INIT(close, _IO_file_close),
+    JUMP_INIT(stat, _IO_file_stat),
+    JUMP_INIT(showmanyc, _IO_default_showmanyc),
+    JUMP_INIT(imbue, _IO_default_imbue)
+  },
+  /* _IO_wfile_jumps_mmap  */
+  [IO_WFILE_JUMPS_MMAP] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT(finish, _IO_new_file_finish),
+    JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
+    JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_mmap),
+    JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
+    JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
+    JUMP_INIT(xsputn, _IO_wfile_xsputn),
+    JUMP_INIT(xsgetn, _IO_file_xsgetn),
+    JUMP_INIT(seekoff, _IO_wfile_seekoff),
+    JUMP_INIT(seekpos, _IO_default_seekpos),
+    JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
+    JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
+    JUMP_INIT(doallocate, _IO_wfile_doallocate),
+    JUMP_INIT(read, _IO_file_read),
+    JUMP_INIT(write, _IO_new_file_write),
+    JUMP_INIT(seek, _IO_file_seek),
+    JUMP_INIT(close, _IO_file_close_mmap),
+    JUMP_INIT(stat, _IO_file_stat),
+    JUMP_INIT(showmanyc, _IO_default_showmanyc),
+    JUMP_INIT(imbue, _IO_default_imbue)
+  },
+  /* _IO_wfile_jumps_maybe_mmap  */
+  [IO_WFILE_JUMPS_MAYBE_MMAP] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT(finish, _IO_new_file_finish),
+    JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
+    JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap),
+    JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
+    JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
+    JUMP_INIT(xsputn, _IO_wfile_xsputn),
+    JUMP_INIT(xsgetn, _IO_file_xsgetn),
+    JUMP_INIT(seekoff, _IO_wfile_seekoff),
+    JUMP_INIT(seekpos, _IO_default_seekpos),
+    JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
+    JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
+    JUMP_INIT(doallocate, _IO_wfile_doallocate),
+    JUMP_INIT(read, _IO_file_read),
+    JUMP_INIT(write, _IO_new_file_write),
+    JUMP_INIT(seek, _IO_file_seek),
+    JUMP_INIT(close, _IO_file_close),
+    JUMP_INIT(stat, _IO_file_stat),
+    JUMP_INIT(showmanyc, _IO_default_showmanyc),
+    JUMP_INIT(imbue, _IO_default_imbue)
+  },
+  /* _IO_cookie_jumps  */
+  [IO_COOKIE_JUMPS] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT(finish, _IO_file_finish),
+    JUMP_INIT(overflow, _IO_file_overflow),
+    JUMP_INIT(underflow, _IO_file_underflow),
+    JUMP_INIT(uflow, _IO_default_uflow),
+    JUMP_INIT(pbackfail, _IO_default_pbackfail),
+    JUMP_INIT(xsputn, _IO_file_xsputn),
+    JUMP_INIT(xsgetn, _IO_default_xsgetn),
+    JUMP_INIT(seekoff, _IO_cookie_seekoff),
+    JUMP_INIT(seekpos, _IO_default_seekpos),
+    JUMP_INIT(setbuf, _IO_file_setbuf),
+    JUMP_INIT(sync, _IO_file_sync),
+    JUMP_INIT(doallocate, _IO_file_doallocate),
+    JUMP_INIT(read, _IO_cookie_read),
+    JUMP_INIT(write, _IO_cookie_write),
+    JUMP_INIT(seek, _IO_cookie_seek),
+    JUMP_INIT(close, _IO_cookie_close),
+    JUMP_INIT(stat, _IO_default_stat),
+    JUMP_INIT(showmanyc, _IO_default_showmanyc),
+    JUMP_INIT(imbue, _IO_default_imbue),
+  },
+  /* _IO_proc_jumps  */
+  [IO_PROC_JUMPS] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT(finish, _IO_new_file_finish),
+    JUMP_INIT(overflow, _IO_new_file_overflow),
+    JUMP_INIT(underflow, _IO_new_file_underflow),
+    JUMP_INIT(uflow, _IO_default_uflow),
+    JUMP_INIT(pbackfail, _IO_default_pbackfail),
+    JUMP_INIT(xsputn, _IO_new_file_xsputn),
+    JUMP_INIT(xsgetn, _IO_default_xsgetn),
+    JUMP_INIT(seekoff, _IO_new_file_seekoff),
+    JUMP_INIT(seekpos, _IO_default_seekpos),
+    JUMP_INIT(setbuf, _IO_new_file_setbuf),
+    JUMP_INIT(sync, _IO_new_file_sync),
+    JUMP_INIT(doallocate, _IO_file_doallocate),
+    JUMP_INIT(read, _IO_file_read),
+    JUMP_INIT(write, _IO_new_file_write),
+    JUMP_INIT(seek, _IO_file_seek),
+    JUMP_INIT(close, _IO_new_proc_close),
+    JUMP_INIT(stat, _IO_file_stat),
+    JUMP_INIT(showmanyc, _IO_default_showmanyc),
+    JUMP_INIT(imbue, _IO_default_imbue)
+  },
+  /* _IO_str_chk_jumps  */
+  [IO_STR_CHK_JUMPS] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT(finish, _IO_str_finish),
+    JUMP_INIT(overflow, _IO_str_chk_overflow),
+    JUMP_INIT(underflow, _IO_str_underflow),
+    JUMP_INIT(uflow, _IO_default_uflow),
+    JUMP_INIT(pbackfail, _IO_str_pbackfail),
+    JUMP_INIT(xsputn, _IO_default_xsputn),
+    JUMP_INIT(xsgetn, _IO_default_xsgetn),
+    JUMP_INIT(seekoff, _IO_str_seekoff),
+    JUMP_INIT(seekpos, _IO_default_seekpos),
+    JUMP_INIT(setbuf, _IO_default_setbuf),
+    JUMP_INIT(sync, _IO_default_sync),
+    JUMP_INIT(doallocate, _IO_default_doallocate),
+    JUMP_INIT(read, _IO_default_read),
+    JUMP_INIT(write, _IO_default_write),
+    JUMP_INIT(seek, _IO_default_seek),
+    JUMP_INIT(close, _IO_default_close),
+    JUMP_INIT(stat, _IO_default_stat),
+    JUMP_INIT(showmanyc, _IO_default_showmanyc),
+    JUMP_INIT(imbue, _IO_default_imbue)
+  },
+  /* _IO_obstack_jumps  */
+  [IO_OBSTACK_JUMPS] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT(finish, NULL),
+    JUMP_INIT(overflow, __IO_obstack_overflow),
+    JUMP_INIT(underflow, NULL),
+    JUMP_INIT(uflow, NULL),
+    JUMP_INIT(pbackfail, NULL),
+    JUMP_INIT(xsputn, __IO_obstack_xsputn),
+    JUMP_INIT(xsgetn, NULL),
+    JUMP_INIT(seekoff, NULL),
+    JUMP_INIT(seekpos, NULL),
+    JUMP_INIT(setbuf, NULL),
+    JUMP_INIT(sync, NULL),
+    JUMP_INIT(doallocate, NULL),
+    JUMP_INIT(read, NULL),
+    JUMP_INIT(write, NULL),
+    JUMP_INIT(seek, NULL),
+    JUMP_INIT(close, NULL),
+    JUMP_INIT(stat, NULL),
+    JUMP_INIT(showmanyc, NULL),
+    JUMP_INIT(imbue, NULL)
+  },
+  /* _IO_helper_jumps  */
+  [IO_HELPER_JUMPS] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT (finish, _IO_wdefault_finish),
+    JUMP_INIT (overflow, _IO_helper_overflow),
+    JUMP_INIT (underflow, _IO_default_underflow),
+    JUMP_INIT (uflow, _IO_default_uflow),
+    JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
+    JUMP_INIT (xsputn, _IO_wdefault_xsputn),
+    JUMP_INIT (xsgetn, _IO_wdefault_xsgetn),
+    JUMP_INIT (seekoff, _IO_default_seekoff),
+    JUMP_INIT (seekpos, _IO_default_seekpos),
+    JUMP_INIT (setbuf, _IO_default_setbuf),
+    JUMP_INIT (sync, _IO_default_sync),
+    JUMP_INIT (doallocate, _IO_wdefault_doallocate),
+    JUMP_INIT (read, _IO_default_read),
+    JUMP_INIT (write, _IO_default_write),
+    JUMP_INIT (seek, _IO_default_seek),
+    JUMP_INIT (close, _IO_default_close),
+    JUMP_INIT (stat, _IO_default_stat)
+  },
+  /* _IO_whelper_jumps  */
+  [IO_WHELPER_JUMPS] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT (finish, _IO_default_finish),
+    JUMP_INIT (overflow, _IO_whelper_overflow),
+    JUMP_INIT (underflow, _IO_default_underflow),
+    JUMP_INIT (uflow, _IO_default_uflow),
+    JUMP_INIT (pbackfail, _IO_default_pbackfail),
+    JUMP_INIT (xsputn, _IO_default_xsputn),
+    JUMP_INIT (xsgetn, _IO_default_xsgetn),
+    JUMP_INIT (seekoff, _IO_default_seekoff),
+    JUMP_INIT (seekpos, _IO_default_seekpos),
+    JUMP_INIT (setbuf, _IO_default_setbuf),
+    JUMP_INIT (sync, _IO_default_sync),
+    JUMP_INIT (doallocate, _IO_default_doallocate),
+    JUMP_INIT (read, _IO_default_read),
+    JUMP_INIT (write, _IO_default_write),
+    JUMP_INIT (seek, _IO_default_seek),
+    JUMP_INIT (close, _IO_default_close),
+    JUMP_INIT (stat, _IO_default_stat)
+  },
+  /* _IO_mem_jumps  */
+  [IO_MEM_JUMPS] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT (finish, _IO_mem_finish),
+    JUMP_INIT (overflow, _IO_str_overflow),
+    JUMP_INIT (underflow, _IO_str_underflow),
+    JUMP_INIT (uflow, _IO_default_uflow),
+    JUMP_INIT (pbackfail, _IO_str_pbackfail),
+    JUMP_INIT (xsputn, _IO_default_xsputn),
+    JUMP_INIT (xsgetn, _IO_default_xsgetn),
+    JUMP_INIT (seekoff, _IO_str_seekoff),
+    JUMP_INIT (seekpos, _IO_default_seekpos),
+    JUMP_INIT (setbuf, _IO_default_setbuf),
+    JUMP_INIT (sync, _IO_mem_sync),
+    JUMP_INIT (doallocate, _IO_default_doallocate),
+    JUMP_INIT (read, _IO_default_read),
+    JUMP_INIT (write, _IO_default_write),
+    JUMP_INIT (seek, _IO_default_seek),
+    JUMP_INIT (close, _IO_default_close),
+    JUMP_INIT (stat, _IO_default_stat),
+    JUMP_INIT(showmanyc, _IO_default_showmanyc),
+    JUMP_INIT(imbue, _IO_default_imbue)
+  },
+  /* _IO_wmem_jumps  */
+  [IO_WMEM_JUMPS] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT (finish, _IO_wmem_finish),
+    JUMP_INIT (overflow, (_IO_overflow_t) _IO_wstr_overflow),
+    JUMP_INIT (underflow, (_IO_underflow_t) _IO_wstr_underflow),
+    JUMP_INIT (uflow, (_IO_underflow_t) _IO_wdefault_uflow),
+    JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
+    JUMP_INIT (xsputn, _IO_wdefault_xsputn),
+    JUMP_INIT (xsgetn, _IO_wdefault_xsgetn),
+    JUMP_INIT (seekoff, _IO_wstr_seekoff),
+    JUMP_INIT (seekpos, _IO_default_seekpos),
+    JUMP_INIT (setbuf, _IO_default_setbuf),
+    JUMP_INIT (sync, _IO_wmem_sync),
+    JUMP_INIT (doallocate, _IO_wdefault_doallocate),
+    JUMP_INIT (read, _IO_default_read),
+    JUMP_INIT (write, _IO_default_write),
+    JUMP_INIT (seek, _IO_default_seek),
+    JUMP_INIT (close, _IO_default_close),
+    JUMP_INIT (stat, _IO_default_stat),
+    JUMP_INIT (showmanyc, _IO_default_showmanyc),
+    JUMP_INIT (imbue, _IO_default_imbue)
+  },
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
+  /* _IO_old_file_jumps  */
+  [IO_OLD_FILE_JUMPS] {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT(finish, _IO_old_file_finish),
+    JUMP_INIT(overflow, _IO_old_file_overflow),
+    JUMP_INIT(underflow, _IO_old_file_underflow),
+    JUMP_INIT(uflow, _IO_default_uflow),
+    JUMP_INIT(pbackfail, _IO_default_pbackfail),
+    JUMP_INIT(xsputn, _IO_old_file_xsputn),
+    JUMP_INIT(xsgetn, _IO_default_xsgetn),
+    JUMP_INIT(seekoff, _IO_old_file_seekoff),
+    JUMP_INIT(seekpos, _IO_default_seekpos),
+    JUMP_INIT(setbuf, _IO_old_file_setbuf),
+    JUMP_INIT(sync, _IO_old_file_sync),
+    JUMP_INIT(doallocate, _IO_file_doallocate),
+    JUMP_INIT(read, _IO_file_read),
+    JUMP_INIT(write, _IO_old_file_write),
+    JUMP_INIT(seek, _IO_file_seek),
+    JUMP_INIT(close, _IO_file_close),
+    JUMP_INIT(stat, _IO_file_stat)
+  },
+  /*  _IO_old_proc_jumps  */
+  [IO_OLD_PROC_JUMPS] {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT(finish, _IO_old_file_finish),
+    JUMP_INIT(overflow, _IO_old_file_overflow),
+    JUMP_INIT(underflow, _IO_old_file_underflow),
+    JUMP_INIT(uflow, _IO_default_uflow),
+    JUMP_INIT(pbackfail, _IO_default_pbackfail),
+    JUMP_INIT(xsputn, _IO_old_file_xsputn),
+    JUMP_INIT(xsgetn, _IO_default_xsgetn),
+    JUMP_INIT(seekoff, _IO_old_file_seekoff),
+    JUMP_INIT(seekpos, _IO_default_seekpos),
+    JUMP_INIT(setbuf, _IO_old_file_setbuf),
+    JUMP_INIT(sync, _IO_old_file_sync),
+    JUMP_INIT(doallocate, _IO_file_doallocate),
+    JUMP_INIT(read, _IO_file_read),
+    JUMP_INIT(write, _IO_old_file_write),
+    JUMP_INIT(seek, _IO_file_seek),
+    JUMP_INIT(close, _IO_old_proc_close),
+    JUMP_INIT(stat, _IO_file_stat),
+    JUMP_INIT(showmanyc, _IO_default_showmanyc),
+    JUMP_INIT(imbue, _IO_default_imbue)
+  },
+#endif
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
+  /* _IO_old_cookie_jumps  */
+  [IO_OLD_COOKIED_JUMPS] = {
+    JUMP_INIT_DUMMY,
+    JUMP_INIT(finish, _IO_file_finish),
+    JUMP_INIT(overflow, _IO_file_overflow),
+    JUMP_INIT(underflow, _IO_file_underflow),
+    JUMP_INIT(uflow, _IO_default_uflow),
+    JUMP_INIT(pbackfail, _IO_default_pbackfail),
+    JUMP_INIT(xsputn, _IO_file_xsputn),
+    JUMP_INIT(xsgetn, _IO_default_xsgetn),
+    JUMP_INIT(seekoff, _IO_cookie_seekoff),
+    JUMP_INIT(seekpos, _IO_default_seekpos),
+    JUMP_INIT(setbuf, _IO_file_setbuf),
+    JUMP_INIT(sync, _IO_file_sync),
+    JUMP_INIT(doallocate, _IO_file_doallocate),
+    JUMP_INIT(read, _IO_cookie_read),
+    JUMP_INIT(write, _IO_cookie_write),
+    JUMP_INIT(seek, _IO_old_cookie_seek),
+    JUMP_INIT(close, _IO_cookie_close),
+    JUMP_INIT(stat, _IO_default_stat),
+    JUMP_INIT(showmanyc, _IO_default_showmanyc),
+    JUMP_INIT(imbue, _IO_default_imbue),
+  },
+#endif
+};
+const size_t __io_vtables_size attribute_relro = sizeof (__io_vtables);
 
 #ifdef SHARED
 
@@ -82,3 +572,15 @@ check_stdfiles_vtables (void)
     IO_set_accept_foreign_vtables (&_IO_vtable_check);
 }
 #endif
+
+#define STR(s)  XSTR(s)
+#define XSTR(s) #s
+
+#undef _IO_file_jumps
+#define _IO_file_jumps_alias  "__io_vtables + " STR(IO_FILE_JUMPS_OFFSET)
+declare_object_symbol_alias (_IO_file_jumps, _IO_file_jumps_alias,
+			     IO_JUMP_T_SIZE)
+#undef _IO_wfile_jumps
+#define _IO_wfile_jumps_alias  "__io_vtables + " STR(IO_WFILE_JUMPS_OFFSET)
+declare_object_symbol_alias (_IO_wfile_jumps, _IO_wfile_jumps_alias,
+			     IO_JUMP_T_SIZE)
diff --git a/libio/wfileops.c b/libio/wfileops.c
index b59a98881f..f92d9b42eb 100644
--- a/libio/wfileops.c
+++ b/libio/wfileops.c
@@ -328,7 +328,7 @@ _IO_wfile_underflow (FILE *fp)
 libc_hidden_def (_IO_wfile_underflow)
 
 
-static wint_t
+wint_t
 _IO_wfile_underflow_mmap (FILE *fp)
 {
   struct _IO_codecvt *cd;
@@ -389,7 +389,7 @@ _IO_wfile_underflow_mmap (FILE *fp)
   return WEOF;
 }
 
-static wint_t
+wint_t
 _IO_wfile_underflow_maybe_mmap (FILE *fp)
 {
   /* This is the first read attempt.  Doing the underflow will choose mmap
@@ -1017,78 +1017,3 @@ _IO_wfile_xsputn (FILE *f, const void *data, size_t n)
   return n - to_do;
 }
 libc_hidden_def (_IO_wfile_xsputn)
-
-
-const struct _IO_jump_t _IO_wfile_jumps libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_new_file_finish),
-  JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
-  JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow),
-  JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
-  JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
-  JUMP_INIT(xsputn, _IO_wfile_xsputn),
-  JUMP_INIT(xsgetn, _IO_file_xsgetn),
-  JUMP_INIT(seekoff, _IO_wfile_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_new_file_setbuf),
-  JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
-  JUMP_INIT(doallocate, _IO_wfile_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_new_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_file_close),
-  JUMP_INIT(stat, _IO_file_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-libc_hidden_data_def (_IO_wfile_jumps)
-
-
-const struct _IO_jump_t _IO_wfile_jumps_mmap libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_new_file_finish),
-  JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
-  JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_mmap),
-  JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
-  JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
-  JUMP_INIT(xsputn, _IO_wfile_xsputn),
-  JUMP_INIT(xsgetn, _IO_file_xsgetn),
-  JUMP_INIT(seekoff, _IO_wfile_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
-  JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
-  JUMP_INIT(doallocate, _IO_wfile_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_new_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_file_close_mmap),
-  JUMP_INIT(stat, _IO_file_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
-
-const struct _IO_jump_t _IO_wfile_jumps_maybe_mmap libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_new_file_finish),
-  JUMP_INIT(overflow, (_IO_overflow_t) _IO_wfile_overflow),
-  JUMP_INIT(underflow, (_IO_underflow_t) _IO_wfile_underflow_maybe_mmap),
-  JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
-  JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
-  JUMP_INIT(xsputn, _IO_wfile_xsputn),
-  JUMP_INIT(xsgetn, _IO_file_xsgetn),
-  JUMP_INIT(seekoff, _IO_wfile_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_file_setbuf_mmap),
-  JUMP_INIT(sync, (_IO_sync_t) _IO_wfile_sync),
-  JUMP_INIT(doallocate, _IO_wfile_doallocate),
-  JUMP_INIT(read, _IO_file_read),
-  JUMP_INIT(write, _IO_new_file_write),
-  JUMP_INIT(seek, _IO_file_seek),
-  JUMP_INIT(close, _IO_file_close),
-  JUMP_INIT(stat, _IO_file_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
diff --git a/libio/wmemstream.c b/libio/wmemstream.c
index e7f898c7fb..50ad1bdc86 100644
--- a/libio/wmemstream.c
+++ b/libio/wmemstream.c
@@ -30,34 +30,6 @@ struct _IO_FILE_wmemstream
 };
 
 
-static int _IO_wmem_sync (FILE* fp) __THROW;
-static void _IO_wmem_finish (FILE* fp, int) __THROW;
-
-
-static const struct _IO_jump_t _IO_wmem_jumps libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT (finish, _IO_wmem_finish),
-  JUMP_INIT (overflow, (_IO_overflow_t) _IO_wstr_overflow),
-  JUMP_INIT (underflow, (_IO_underflow_t) _IO_wstr_underflow),
-  JUMP_INIT (uflow, (_IO_underflow_t) _IO_wdefault_uflow),
-  JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
-  JUMP_INIT (xsputn, _IO_wdefault_xsputn),
-  JUMP_INIT (xsgetn, _IO_wdefault_xsgetn),
-  JUMP_INIT (seekoff, _IO_wstr_seekoff),
-  JUMP_INIT (seekpos, _IO_default_seekpos),
-  JUMP_INIT (setbuf, _IO_default_setbuf),
-  JUMP_INIT (sync, _IO_wmem_sync),
-  JUMP_INIT (doallocate, _IO_wdefault_doallocate),
-  JUMP_INIT (read, _IO_default_read),
-  JUMP_INIT (write, _IO_default_write),
-  JUMP_INIT (seek, _IO_default_seek),
-  JUMP_INIT (close, _IO_default_close),
-  JUMP_INIT (stat, _IO_default_stat),
-  JUMP_INIT (showmanyc, _IO_default_showmanyc),
-  JUMP_INIT (imbue, _IO_default_imbue)
-};
-
 /* Open a stream that writes into a malloc'd buffer that is expanded as
    necessary.  *BUFLOC and *SIZELOC are updated with the buffer's location
    and the number of characters written on fflush or fclose.  */
@@ -105,7 +77,7 @@ open_wmemstream (wchar_t **bufloc, size_t *sizeloc)
 }
 
 
-static int
+int
 _IO_wmem_sync (FILE *fp)
 {
   struct _IO_FILE_wmemstream *mp = (struct _IO_FILE_wmemstream *) fp;
@@ -124,7 +96,7 @@ _IO_wmem_sync (FILE *fp)
 }
 
 
-static void
+void
 _IO_wmem_finish (FILE *fp, int dummy)
 {
   struct _IO_FILE_wmemstream *mp = (struct _IO_FILE_wmemstream *) fp;
diff --git a/libio/wstrops.c b/libio/wstrops.c
index 2aec314937..ac7efe9f65 100644
--- a/libio/wstrops.c
+++ b/libio/wstrops.c
@@ -361,27 +361,3 @@ _IO_wstr_finish (FILE *fp, int dummy)
 
   _IO_wdefault_finish (fp, 0);
 }
-
-const struct _IO_jump_t _IO_wstr_jumps libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT(finish, _IO_wstr_finish),
-  JUMP_INIT(overflow, (_IO_overflow_t) _IO_wstr_overflow),
-  JUMP_INIT(underflow, (_IO_underflow_t) _IO_wstr_underflow),
-  JUMP_INIT(uflow, (_IO_underflow_t) _IO_wdefault_uflow),
-  JUMP_INIT(pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
-  JUMP_INIT(xsputn, _IO_wdefault_xsputn),
-  JUMP_INIT(xsgetn, _IO_wdefault_xsgetn),
-  JUMP_INIT(seekoff, _IO_wstr_seekoff),
-  JUMP_INIT(seekpos, _IO_default_seekpos),
-  JUMP_INIT(setbuf, _IO_default_setbuf),
-  JUMP_INIT(sync, _IO_default_sync),
-  JUMP_INIT(doallocate, _IO_wdefault_doallocate),
-  JUMP_INIT(read, _IO_default_read),
-  JUMP_INIT(write, _IO_default_write),
-  JUMP_INIT(seek, _IO_default_seek),
-  JUMP_INIT(close, _IO_default_close),
-  JUMP_INIT(stat, _IO_default_stat),
-  JUMP_INIT(showmanyc, _IO_default_showmanyc),
-  JUMP_INIT(imbue, _IO_default_imbue)
-};
diff --git a/stdio-common/vfprintf-internal.c b/stdio-common/vfprintf-internal.c
index fb94961f37..da284db349 100644
--- a/stdio-common/vfprintf-internal.c
+++ b/stdio-common/vfprintf-internal.c
@@ -1633,11 +1633,11 @@ struct helper_file
 #endif
   };
 
-static int
+#ifdef COMPILE_WPRINTF
+int
 _IO_helper_overflow (FILE *s, int c)
 {
   FILE *target = ((struct helper_file*) s)->_put_stream;
-#ifdef COMPILE_WPRINTF
   int used = s->_wide_data->_IO_write_ptr - s->_wide_data->_IO_write_base;
   if (used)
     {
@@ -1649,7 +1649,13 @@ _IO_helper_overflow (FILE *s, int c)
 		  used - written);
       s->_wide_data->_IO_write_ptr -= written;
     }
+  return PUTC (c, s);
+}
 #else
+int
+_IO_whelper_overflow (FILE *s, int c)
+{
+  FILE *target = ((struct helper_file*) s)->_put_stream;
   int used = s->_IO_write_ptr - s->_IO_write_base;
   if (used)
     {
@@ -1660,54 +1666,8 @@ _IO_helper_overflow (FILE *s, int c)
 	       used - written);
       s->_IO_write_ptr -= written;
     }
-#endif
   return PUTC (c, s);
 }
-
-#ifdef COMPILE_WPRINTF
-static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT (finish, _IO_wdefault_finish),
-  JUMP_INIT (overflow, _IO_helper_overflow),
-  JUMP_INIT (underflow, _IO_default_underflow),
-  JUMP_INIT (uflow, _IO_default_uflow),
-  JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wdefault_pbackfail),
-  JUMP_INIT (xsputn, _IO_wdefault_xsputn),
-  JUMP_INIT (xsgetn, _IO_wdefault_xsgetn),
-  JUMP_INIT (seekoff, _IO_default_seekoff),
-  JUMP_INIT (seekpos, _IO_default_seekpos),
-  JUMP_INIT (setbuf, _IO_default_setbuf),
-  JUMP_INIT (sync, _IO_default_sync),
-  JUMP_INIT (doallocate, _IO_wdefault_doallocate),
-  JUMP_INIT (read, _IO_default_read),
-  JUMP_INIT (write, _IO_default_write),
-  JUMP_INIT (seek, _IO_default_seek),
-  JUMP_INIT (close, _IO_default_close),
-  JUMP_INIT (stat, _IO_default_stat)
-};
-#else
-static const struct _IO_jump_t _IO_helper_jumps libio_vtable =
-{
-  JUMP_INIT_DUMMY,
-  JUMP_INIT (finish, _IO_default_finish),
-  JUMP_INIT (overflow, _IO_helper_overflow),
-  JUMP_INIT (underflow, _IO_default_underflow),
-  JUMP_INIT (uflow, _IO_default_uflow),
-  JUMP_INIT (pbackfail, _IO_default_pbackfail),
-  JUMP_INIT (xsputn, _IO_default_xsputn),
-  JUMP_INIT (xsgetn, _IO_default_xsgetn),
-  JUMP_INIT (seekoff, _IO_default_seekoff),
-  JUMP_INIT (seekpos, _IO_default_seekpos),
-  JUMP_INIT (setbuf, _IO_default_setbuf),
-  JUMP_INIT (sync, _IO_default_sync),
-  JUMP_INIT (doallocate, _IO_default_doallocate),
-  JUMP_INIT (read, _IO_default_read),
-  JUMP_INIT (write, _IO_default_write),
-  JUMP_INIT (seek, _IO_default_seek),
-  JUMP_INIT (close, _IO_default_close),
-  JUMP_INIT (stat, _IO_default_stat)
-};
 #endif
 
 static int
@@ -1742,7 +1702,11 @@ buffered_vfprintf (FILE *s, const CHAR_T *format, va_list args,
   hp->_lock = NULL;
 #endif
   hp->_flags2 = s->_flags2;
+#ifdef COMPILE_WPRINTF
   _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps;
+#else
+  _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_whelper_jumps;
+#endif
 
   /* Now print to helper instead.  */
   result = vfprintf (hp, format, args, mode_flags);
-- 
2.34.1


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

* [PATCH 6/7] Remove --with-default-link configure option
  2022-11-15 19:31 [PATCH 0/7] Fixing remaining lld issues Adhemerval Zanella via Libc-alpha
                   ` (4 preceding siblings ...)
  2022-11-15 19:31 ` [PATCH 5/7] libio: Remove the usage of __libc_IO_vtables Adhemerval Zanella via Libc-alpha
@ 2022-11-15 19:31 ` Adhemerval Zanella via Libc-alpha
  2022-11-15 19:31 ` [PATCH 7/7] Remove set-hooks.h from generic includes Adhemerval Zanella via Libc-alpha
  6 siblings, 0 replies; 25+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2022-11-15 19:31 UTC (permalink / raw)
  To: libc-alpha, Fangrui Song

Now that there is no need to use a special linker script to hardening
internal data structures, remove the --with-default-link configure
option and associated definitions.
---
 INSTALL                   |  6 ------
 Makerules                 | 21 ++++++---------------
 config.make.in            |  1 -
 configure                 | 13 -------------
 configure.ac              |  7 -------
 elf/Makefile              |  2 --
 iconvdata/extra-module.mk |  2 +-
 manual/install.texi       |  6 ------
 8 files changed, 7 insertions(+), 51 deletions(-)

diff --git a/INSTALL b/INSTALL
index 659f75a97f..f57c743d77 100644
--- a/INSTALL
+++ b/INSTALL
@@ -90,12 +90,6 @@ if 'CFLAGS' is specified it must enable optimization.  For example:
      library will still be usable, but functionality may be lost--for
      example, you can't build a shared libc with old binutils.
 
-'--with-default-link'
-     With '--with-default-link', the build system does not use a custom
-     linker script for linking shared objects.  The default is
-     '--without-default-link', because the custom linker script is
-     needed for full RELRO protection.
-
 '--with-nonshared-cflags=CFLAGS'
      Use additional compiler flags CFLAGS to build the parts of the
      library which are always statically linked into applications and
diff --git a/Makerules b/Makerules
index 41fc8db4ba..97864402fb 100644
--- a/Makerules
+++ b/Makerules
@@ -544,13 +544,8 @@ $(LINK.o) -shared -static-libgcc -Wl,-O1 $(sysdep-LDFLAGS) \
 	  -L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link)
 endef
 
-# If the linker is good enough, we can let it use its default linker script.
-# In the long term the custom linker script will be removed.
-shlib-lds =
-shlib-lds-flags =
-
 define build-shlib
-$(build-shlib-helper) -o $@ $(shlib-lds-flags) \
+$(build-shlib-helper) -o $@ \
 	  $(csu-objpfx)abi-note.o $(build-shlib-objlist)
 endef
 
@@ -569,12 +564,12 @@ endef
 # binutils only position loadable notes into the first page for binaries,
 # not for shared objects
 define build-module
-$(build-module-helper) -o $@ $(shlib-lds-flags) \
+$(build-module-helper) -o $@ \
 	  $(csu-objpfx)abi-note.o $(build-module-objlist) $(link-libc-args)
 $(call after-link,$@)
 endef
 define build-module-asneeded
-$(build-module-helper) -o $@ $(shlib-lds-flags) \
+$(build-module-helper) -o $@ \
 	  $(csu-objpfx)abi-note.o \
 	  -Wl,--as-needed $(build-module-objlist) -Wl,--no-as-needed \
 	  $(link-libc-args)
@@ -606,7 +601,6 @@ $(common-objpfx)libc_pic.os: $(common-objpfx)libc_pic.a
 	$(LINK.o) -nostdlib -nostartfiles -r -o $@ \
 	$(LDFLAGS-c_pic.os) $(whole-archive) $^ -o $@
 
-ifeq (,$(strip $(shlib-lds-flags)))
 # Generate a list of -R options to excise .gnu.glibc-stub.* sections.
 $(common-objpfx)libc_pic.opts: $(common-objpfx)libc_pic.os
 	$(OBJDUMP) -h $< | \
@@ -620,7 +614,6 @@ $(common-objpfx)libc_pic.os.clean: $(common-objpfx)libc_pic.opts \
 generated += libc_pic.opts libc_pic.os.clean
 
 libc_pic_clean := .clean
-endif
 
 # Build a possibly-modified version of libc_pic.a for use in building
 # linkobj/libc.so.
@@ -650,16 +643,14 @@ $(common-objpfx)linkobj/libc.so: link-libc-deps = # empty
 $(common-objpfx)libc.so: $(common-objpfx)libc_pic.os$(libc_pic_clean) \
 			 $(elf-objpfx)sofini.os \
 			 $(elf-objpfx)interp.os \
-			 $(elf-objpfx)ld.so \
-			 $(shlib-lds)
+			 $(elf-objpfx)ld.so
 	$(build-shlib)
 	$(call after-link,$@)
 
 $(common-objpfx)linkobj/libc.so: $(common-objpfx)linkobj/libc_pic.a \
 			 $(elf-objpfx)sofini.os \
 			 $(elf-objpfx)interp.os \
-			 $(elf-objpfx)ld.so \
-			 $(shlib-lds)
+			 $(elf-objpfx)ld.so
 	$(build-shlib)
 	$(call after-link,$@)
 
@@ -720,7 +711,7 @@ endif
 
 extra-modules-build := $(filter-out $(modules-names-nobuild),$(modules-names))
 $(extra-modules-build:%=$(objpfx)%.so): $(objpfx)%.so: \
-		$(objpfx)%.os $(shlib-lds) $(link-libs-deps)
+		$(objpfx)%.os $(link-libs-deps)
 	$(build-module)
 endif
 \f
diff --git a/config.make.in b/config.make.in
index d7c416cbea..befcc22625 100644
--- a/config.make.in
+++ b/config.make.in
@@ -69,7 +69,6 @@ have-libaudit = @have_libaudit@
 have-libcap = @have_libcap@
 have-cc-with-libunwind = @libc_cv_cc_with_libunwind@
 bind-now = @bindnow@
-use-default-link = @use_default_link@
 have-cxx-thread_local = @libc_cv_cxx_thread_local@
 have-loop-to-function = @libc_cv_cc_loop_to_function@
 have-textrel_ifunc = @libc_cv_textrel_ifunc@
diff --git a/configure b/configure
index 9a8acc4ef7..eff64601b4 100755
--- a/configure
+++ b/configure
@@ -679,7 +679,6 @@ hardcoded_path_in_tests
 enable_timezone_tools
 rtld_early_cflags
 extra_nonshared_cflags
-use_default_link
 sysheaders
 ac_ct_CXX
 CXXFLAGS
@@ -757,7 +756,6 @@ with_gd_lib
 with_binutils
 with_selinux
 with_headers
-with_default_link
 with_nonshared_cflags
 with_rtld_early_cflags
 with_timeoutfactor
@@ -1476,7 +1474,6 @@ Optional Packages:
   --with-selinux          if building with SELinux support
   --with-headers=PATH     location of system headers to use (for example
                           /usr/src/linux/include) [default=compiler default]
-  --with-default-link     do not use explicit linker scripts
   --with-nonshared-cflags=CFLAGS
                           build nonshared libraries with additional CFLAGS
   --with-rtld-early-cflags=CFLAGS
@@ -3460,16 +3457,6 @@ fi
 
 
 
-
-# Check whether --with-default-link was given.
-if test "${with_default_link+set}" = set; then :
-  withval=$with_default_link; use_default_link=$withval
-else
-  use_default_link=no
-fi
-
-
-
 # Check whether --with-nonshared-cflags was given.
 if test "${with_nonshared_cflags+set}" = set; then :
   withval=$with_nonshared_cflags; extra_nonshared_cflags=$withval
diff --git a/configure.ac b/configure.ac
index 5709c7a0cf..992d1f6937 100644
--- a/configure.ac
+++ b/configure.ac
@@ -149,13 +149,6 @@ AC_ARG_WITH([headers],
 	    [sysheaders=''])
 AC_SUBST(sysheaders)
 
-AC_SUBST(use_default_link)
-AC_ARG_WITH([default-link],
-	    AS_HELP_STRING([--with-default-link],
-			   [do not use explicit linker scripts]),
-	    [use_default_link=$withval],
-	    [use_default_link=no])
-
 dnl Additional build flags injection.
 AC_ARG_WITH([nonshared-cflags],
 	    AS_HELP_STRING([--with-nonshared-cflags=CFLAGS],
diff --git a/elf/Makefile b/elf/Makefile
index 8527e659dc..9e5bbb963b 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -1235,8 +1235,6 @@ endif
 # Command to link into a larger single relocatable object.
 reloc-link = $(LINK.o) -nostdlib -nostartfiles -r
 
-$(objpfx)sotruss-lib.so: $(shlib-lds)
-
 $(objpfx)dl-allobjs.os: $(all-rtld-routines:%=$(objpfx)%.os)
 	$(reloc-link) -o $@ $^
 
diff --git a/iconvdata/extra-module.mk b/iconvdata/extra-module.mk
index ecaf507624..a816659763 100644
--- a/iconvdata/extra-module.mk
+++ b/iconvdata/extra-module.mk
@@ -4,7 +4,7 @@ extra-modules-left := $(strip $(filter-out $(mod),$(extra-modules-left)))
 extra-objs := $(extra-objs) $(patsubst %,%.os,$($(mod)-routines))
 
 $(objpfx)$(mod).so: $(addprefix $(objpfx),$(addsuffix .os,$($(mod)-routines)))\
-		    $(shlib-lds) $(link-libc-deps)
+		    $(link-libc-deps)
 	$(build-module-asneeded)
 
 ifneq (,$(extra-modules-left))
diff --git a/manual/install.texi b/manual/install.texi
index c775005581..ba2231024b 100644
--- a/manual/install.texi
+++ b/manual/install.texi
@@ -117,12 +117,6 @@ problem and suppress these constructs, so that the library will still be
 usable, but functionality may be lost---for example, you can't build a
 shared libc with old binutils.
 
-@item --with-default-link
-With @code{--with-default-link}, the build system does not use a custom
-linker script for linking shared objects.  The default is
-@code{--without-default-link}, because the custom linker script is
-needed for full RELRO protection.
-
 @item --with-nonshared-cflags=@var{cflags}
 Use additional compiler flags @var{cflags} to build the parts of the
 library which are always statically linked into applications and
-- 
2.34.1


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

* [PATCH 7/7] Remove set-hooks.h from generic includes
  2022-11-15 19:31 [PATCH 0/7] Fixing remaining lld issues Adhemerval Zanella via Libc-alpha
                   ` (5 preceding siblings ...)
  2022-11-15 19:31 ` [PATCH 6/7] Remove --with-default-link configure option Adhemerval Zanella via Libc-alpha
@ 2022-11-15 19:31 ` Adhemerval Zanella via Libc-alpha
  6 siblings, 0 replies; 25+ messages in thread
From: Adhemerval Zanella via Libc-alpha @ 2022-11-15 19:31 UTC (permalink / raw)
  To: libc-alpha, Fangrui Song

The hooks mechanism uses symbol sets for running lists of functions,
which requires either extra linker directives to provide any hardening
(such RELRO) or additional code (such as pointer obfuscation via
mangling with random value).

Currently only hurd uses it and there multiple examples where using
direct function call provides both hardening and good code generation
without the need to extra link or code handling (for instance
nptl/nptlfreeres.c).
---
 {include => hurd}/set-hooks.h  | 0
 nptl/nptlfreeres.c             | 1 -
 sysdeps/mach/hurd/bits/errno.h | 1 -
 3 files changed, 2 deletions(-)
 rename {include => hurd}/set-hooks.h (100%)

diff --git a/include/set-hooks.h b/hurd/set-hooks.h
similarity index 100%
rename from include/set-hooks.h
rename to hurd/set-hooks.h
diff --git a/nptl/nptlfreeres.c b/nptl/nptlfreeres.c
index c67456d9d3..90b7b13287 100644
--- a/nptl/nptlfreeres.c
+++ b/nptl/nptlfreeres.c
@@ -16,7 +16,6 @@
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
 
-#include <set-hooks.h>
 #include <libc-symbols.h>
 #include <pthreadP.h>
 #include <nptl-stack.h>
-- 
2.34.1


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

* Re: [PATCH 3/7] stdlib: Move _IO_cleanup to call_function_static_weak
  2022-11-15 19:31 ` [PATCH 3/7] stdlib: Move _IO_cleanup to call_function_static_weak Adhemerval Zanella via Libc-alpha
@ 2022-12-12 10:52   ` Florian Weimer via Libc-alpha
  2022-12-13 16:52     ` Joseph Myers
  0 siblings, 1 reply; 25+ messages in thread
From: Florian Weimer via Libc-alpha @ 2022-12-12 10:52 UTC (permalink / raw)
  To: Adhemerval Zanella via Libc-alpha; +Cc: Fangrui Song, Adhemerval Zanella

* Adhemerval Zanella via Libc-alpha:

> ---
>  Makerules      | 3 ---
>  libio/genops.c | 2 --
>  stdlib/exit.c  | 6 ++----
>  3 files changed, 2 insertions(+), 9 deletions(-)
>
> diff --git a/Makerules b/Makerules
> index a41491429e..3226b7a12b 100644
> --- a/Makerules
> +++ b/Makerules
> @@ -568,9 +568,6 @@ $(common-objpfx)shlib.lds: $(common-objpfx)config.make $(..)Makerules
>  		 PROVIDE(__start___libc_subfreeres = .);\
>  		 __libc_subfreeres : { *(__libc_subfreeres) }\
>  		 PROVIDE(__stop___libc_subfreeres = .);\
> -		 PROVIDE(__start___libc_atexit = .);\
> -		 __libc_atexit : { *(__libc_atexit) }\
> -		 PROVIDE(__stop___libc_atexit = .);\
>  		 PROVIDE(__start___libc_IO_vtables = .);\
>  		 __libc_IO_vtables : { *(__libc_IO_vtables) }\
>  		 PROVIDE(__stop___libc_IO_vtables = .);\
> diff --git a/libio/genops.c b/libio/genops.c
> index 1b629eb695..8a7fc4f7c5 100644
> --- a/libio/genops.c
> +++ b/libio/genops.c
> @@ -1115,5 +1115,3 @@ _IO_list_resetlock (void)
>  #endif
>  }
>  libc_hidden_def (_IO_list_resetlock)
> -
> -text_set_element(__libc_atexit, _IO_cleanup);
> diff --git a/stdlib/exit.c b/stdlib/exit.c
> index 10c44e1449..98579fbda8 100644
> --- a/stdlib/exit.c
> +++ b/stdlib/exit.c
> @@ -20,11 +20,9 @@
>  #include <unistd.h>
>  #include <pointer_guard.h>
>  #include <libc-lock.h>
> +#include <libio/libioP.h>
>  #include "exit.h"
>  
> -#include "set-hooks.h"
> -DEFINE_HOOK (__libc_atexit, (void))
> -
>  /* Initialize the flag that indicates exit function processing
>     is complete. See concurrency notes in stdlib/exit.h where
>     __exit_funcs_lock is declared.  */
> @@ -128,7 +126,7 @@ __run_exit_handlers (int status, struct exit_function_list **listp,
>    __libc_lock_unlock (__exit_funcs_lock);
>  
>    if (run_list_atexit)
> -    RUN_HOOK (__libc_atexit, ());
> +    call_function_static_weak (_IO_cleanup);
>  
>    _exit (status);
>  }

This change looks okay to me.

Reviewed-by: Florian Weimer <fweimer@redhat.com>

Thanks,
Florian


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

* Re: [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions
  2022-11-15 19:31 ` [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions Adhemerval Zanella via Libc-alpha
@ 2022-12-12 10:55   ` Florian Weimer via Libc-alpha
  2022-12-12 13:14     ` Adhemerval Zanella Netto via Libc-alpha
  2022-12-12 10:58   ` Florian Weimer via Libc-alpha
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 25+ messages in thread
From: Florian Weimer via Libc-alpha @ 2022-12-12 10:55 UTC (permalink / raw)
  To: Adhemerval Zanella via Libc-alpha; +Cc: Fangrui Song, Adhemerval Zanella

* Adhemerval Zanella via Libc-alpha:

> diff --git a/crypt/md5-crypt.c b/crypt/md5-crypt.c
> index 7c4fb9fb97..9660cdd698 100644
> --- a/crypt/md5-crypt.c
> +++ b/crypt/md5-crypt.c
> @@ -299,10 +299,7 @@ __md5_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
>    return buffer;
>  }
>  
> -#ifndef _LIBC
> -# define libc_freeres_ptr(decl) decl
> -#endif
> -libc_freeres_ptr (static char *buffer);
> +static char *buffer;
>  
>  char *
>  __md5_crypt (const char *key, const char *salt)
> @@ -330,7 +327,10 @@ __md5_crypt (const char *key, const char *salt)
>  static void
>  __attribute__ ((__destructor__))
>  free_mem (void)
> +#else
> +void
> +__md5_crypt_freemem (void)
> +#endif
>  {
>    free (buffer);
>  }
> -#endif
> diff --git a/crypt/sha256-crypt.c b/crypt/sha256-crypt.c
> index a98a968a8b..75fd582429 100644
> --- a/crypt/sha256-crypt.c
> +++ b/crypt/sha256-crypt.c
> @@ -386,10 +386,7 @@ __sha256_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
>    return buffer;
>  }
>  
> -#ifndef _LIBC
> -# define libc_freeres_ptr(decl) decl
> -#endif
> -libc_freeres_ptr (static char *buffer);
> +static char *buffer;
>  
>  /* This entry point is equivalent to the `crypt' function in Unix
>     libcs.  */
> @@ -422,7 +419,10 @@ __sha256_crypt (const char *key, const char *salt)
>  static void
>  __attribute__ ((__destructor__))
>  free_mem (void)
> +#else
> +void
> +__sha256_crypt_freemem (void)
> +#endif
>  {
>    free (buffer);
>  }
> -#endif
> diff --git a/crypt/sha512-crypt.c b/crypt/sha512-crypt.c
> index ea13527c09..ae6ecaef16 100644
> --- a/crypt/sha512-crypt.c
> +++ b/crypt/sha512-crypt.c
> @@ -408,10 +408,7 @@ __sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
>    return buffer;
>  }
>  
> -#ifndef _LIBC
> -# define libc_freeres_ptr(decl) decl
> -#endif
> -libc_freeres_ptr (static char *buffer);
> +static char *buffer;
>  
>  /* This entry point is equivalent to the `crypt' function in Unix
>     libcs.  */
> @@ -444,7 +441,10 @@ __sha512_crypt (const char *key, const char *salt)
>  static void
>  __attribute__ ((__destructor__))
>  free_mem (void)
> +#else
> +void
> +__sha512_crypt_freemem (void)
> +#endif
>  {
>    free (buffer);
>  }
> -#endif

I think you should delete the entire deallocation logic, or make use of
the ELF destructor unconditional.  This wasn't linked into libc, so it
wasn't run from __libc_freeres, and the hook registration was a no-op.
(I believe, I haven't checked.)

Thanks,
Florian


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

* Re: [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions
  2022-11-15 19:31 ` [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions Adhemerval Zanella via Libc-alpha
  2022-12-12 10:55   ` Florian Weimer via Libc-alpha
@ 2022-12-12 10:58   ` Florian Weimer via Libc-alpha
  2022-12-12 13:16     ` Adhemerval Zanella Netto via Libc-alpha
  2022-12-12 11:00   ` Florian Weimer via Libc-alpha
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 25+ messages in thread
From: Florian Weimer via Libc-alpha @ 2022-12-12 10:58 UTC (permalink / raw)
  To: Adhemerval Zanella via Libc-alpha; +Cc: Fangrui Song, Adhemerval Zanella

* Adhemerval Zanella via Libc-alpha:

> diff --git a/elf/dl-libc.c b/elf/dl-libc.c
> index 266e068da6..06bce2f6dd 100644
> --- a/elf/dl-libc.c
> +++ b/elf/dl-libc.c
> @@ -228,7 +228,7 @@ __libc_dlclose (void *map)
>  }
>  
>  
> -static bool __libc_freeres_fn_section
> +static bool
>  free_slotinfo (struct dtv_slotinfo_list **elemp)
>  {
>    size_t cnt;
> @@ -256,7 +256,7 @@ free_slotinfo (struct dtv_slotinfo_list **elemp)
>  }
>  
>  
> -libc_freeres_fn (free_mem)
> +void __libc_freemem (void)
>  {
>    struct link_map *l;
>    struct r_search_path_elem *d;

I believe this should be called __dl_libc_freemem or something like
that, to point towards dl-libc.c as the implementing file.

Thanks,
Florian


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

* Re: [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions
  2022-11-15 19:31 ` [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions Adhemerval Zanella via Libc-alpha
  2022-12-12 10:55   ` Florian Weimer via Libc-alpha
  2022-12-12 10:58   ` Florian Weimer via Libc-alpha
@ 2022-12-12 11:00   ` Florian Weimer via Libc-alpha
  2022-12-12 13:49     ` Adhemerval Zanella Netto via Libc-alpha
  2022-12-12 11:05   ` Andreas Schwab via Libc-alpha
  2022-12-12 11:08   ` Florian Weimer via Libc-alpha
  4 siblings, 1 reply; 25+ messages in thread
From: Florian Weimer via Libc-alpha @ 2022-12-12 11:00 UTC (permalink / raw)
  To: Adhemerval Zanella via Libc-alpha; +Cc: Fangrui Song, Adhemerval Zanella

* Adhemerval Zanella via Libc-alpha:

> diff --git a/grp/fgetgrent.c b/grp/fgetgrent.c
> index fd2b4d32d6..df04530b04 100644
> --- a/grp/fgetgrent.c
> +++ b/grp/fgetgrent.c
> @@ -25,7 +25,7 @@
>  /* We need to protect the dynamic buffer handling.  */
>  __libc_lock_define_initialized (static, lock);
>  
> -libc_freeres_ptr (static char *buffer);
> +static char *buffer;
>  
>  /* Read one entry from the given stream.  */
>  struct group *
> @@ -82,3 +82,9 @@ fgetgrent (FILE *stream)
>  
>    return result;
>  }
> +
> +void
> +__libc_fgetgrent_freemem (void)
> +{
> +  free (buffer);
> +}
> diff --git a/gshadow/fgetsgent.c b/gshadow/fgetsgent.c
> index 02f9c7d643..4d9282e560 100644
> --- a/gshadow/fgetsgent.c
> +++ b/gshadow/fgetsgent.c
> @@ -28,7 +28,7 @@
>  /* We need to protect the dynamic buffer handling.  */
>  __libc_lock_define_initialized (static, lock);
>  
> -libc_freeres_ptr (static char *buffer);
> +static char *buffer;
>  
>  /* Read one shadow entry from the given stream.  */
>  struct sgrp *

Missing free function in the second patch.

I think you should consider introducing a call_free_static_weak that
does something like

  if (&ptr != NULL)
    free (ptr);

in the static case, and calls

  free (ptr);

unconditionally for the dynamic case.  And then add attribute_hidden
variable declarations to a suitable wrapper header under include/.

This avoids writing all these little helper functions.

Thanks,
Florian


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

* Re: [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions
  2022-11-15 19:31 ` [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions Adhemerval Zanella via Libc-alpha
                     ` (2 preceding siblings ...)
  2022-12-12 11:00   ` Florian Weimer via Libc-alpha
@ 2022-12-12 11:05   ` Andreas Schwab via Libc-alpha
  2022-12-12 13:49     ` Adhemerval Zanella Netto via Libc-alpha
  2022-12-12 11:08   ` Florian Weimer via Libc-alpha
  4 siblings, 1 reply; 25+ messages in thread
From: Andreas Schwab via Libc-alpha @ 2022-12-12 11:05 UTC (permalink / raw)
  To: Adhemerval Zanella via Libc-alpha; +Cc: Fangrui Song, Adhemerval Zanella

On Nov 15 2022, Adhemerval Zanella via Libc-alpha wrote:

> diff --git a/elf/dl-libc.c b/elf/dl-libc.c
> index 266e068da6..06bce2f6dd 100644
> --- a/elf/dl-libc.c
> +++ b/elf/dl-libc.c
> @@ -228,7 +228,7 @@ __libc_dlclose (void *map)
>  }
>  
>  
> -static bool __libc_freeres_fn_section
> +static bool
>  free_slotinfo (struct dtv_slotinfo_list **elemp)
>  {
>    size_t cnt;
> @@ -256,7 +256,7 @@ free_slotinfo (struct dtv_slotinfo_list **elemp)
>  }
>  
>  
> -libc_freeres_fn (free_mem)
> +void __libc_freemem (void)

Line break after return type.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

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

* Re: [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions
  2022-11-15 19:31 ` [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions Adhemerval Zanella via Libc-alpha
                     ` (3 preceding siblings ...)
  2022-12-12 11:05   ` Andreas Schwab via Libc-alpha
@ 2022-12-12 11:08   ` Florian Weimer via Libc-alpha
  2022-12-12 13:51     ` Adhemerval Zanella Netto via Libc-alpha
  4 siblings, 1 reply; 25+ messages in thread
From: Florian Weimer via Libc-alpha @ 2022-12-12 11:08 UTC (permalink / raw)
  To: Adhemerval Zanella via Libc-alpha; +Cc: Fangrui Song, Adhemerval Zanella

* Adhemerval Zanella via Libc-alpha:

> diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c
> index be8c2a35fc..ce5d010133 100644
> --- a/malloc/set-freeres.c
> +++ b/malloc/set-freeres.c
> @@ -15,32 +15,210 @@
>     License along with the GNU C Library; if not, see
>     <https://www.gnu.org/licenses/>.  */

> +/* Resource Freeing Hooks:
> +
> +   Normally a process exits and the OS cleans up any allocated
> +   memory.  However, when tooling like mtrace or valgrind is monitoring
> +   the process we need to free all resources that are part of the
> +   process in order to provide the consistency required to track
> +   memory leaks.
> +
> +   A single public API exists and is __libc_freeres(), and this is used
> +   by applications like valgrind to freee resouces.
> +
> +   Each free routines must be explicit listed below, with the care to define
> +   weak functions for external symbol if applicable.   */
> +
> +/* From libc.so.  */
> +extern void __libc_freemem (void) weak_function;
> +extern void __hdestroy (void) weak_function;
> +extern void __gconv_cache_freemem (void) weak_function;

These declarations should come from headers under include/, so that they
can be proper type-checked against the implementation.

> +static void (*__libc_freeres_funcs[])(void) attribute_relro =
> +{
> +  __libc_freemem,
> +  __hdestroy,
> +  __gconv_cache_freemem,

I think we can avoid these relocations for the dynamic case if we just
call these functions using call_function_static_weak, or directly free
the pointers using call_free_static_weak (see the other message).  The
latter has somewhat large code size, but I think that's the right
trade-off here.

Thanks,
Florian


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

* Re: [PATCH 5/7] libio: Remove the usage of __libc_IO_vtables
  2022-11-15 19:31 ` [PATCH 5/7] libio: Remove the usage of __libc_IO_vtables Adhemerval Zanella via Libc-alpha
@ 2022-12-12 11:40   ` Florian Weimer via Libc-alpha
  0 siblings, 0 replies; 25+ messages in thread
From: Florian Weimer via Libc-alpha @ 2022-12-12 11:40 UTC (permalink / raw)
  To: Adhemerval Zanella via Libc-alpha; +Cc: Fangrui Song, Adhemerval Zanella

* Adhemerval Zanella via Libc-alpha:

> The libio vtables are all moved to an array and the IO_validate_vtable
> checks if the vtable is within the array, instead of using special
> ELF section and linker scripts directives.
>
> To avoid static linking namespace issues and to pulling all vtables
> referenced objects, all function pointers are set to weak references.
> This also leads to slight small static objects that uses printf-like
> family.

I don't see a mechanism that pulls in, during a static link, functions
that are only referenced weakly through vtables that are referenced
strongly.  I think this causes static linking regressions in some cases.

We could merge my vfprintf factor first because it reduces the number of
vtables, and the amount of (eventually unnecessary) analysis needed.
> diff --git a/libio/libioP.h b/libio/libioP.h
> index 3a5498bd65..63d2145963 100644
> --- a/libio/libioP.h
> +++ b/libio/libioP.h
> @@ -431,57 +431,105 @@ libc_hidden_proto (_IO_enable_locks)

> +enum
> +{
> +  IO_STR_JUMPS              = 0,
> +  IO_WSTR_JUMPS             = 1,
> +  IO_STRN_JUMPS             = 2,
> +  IO_WSTRN_JUMPS            = 3,
> +  IO_FILE_JUMPS             = 4,
> +  IO_FILE_JUMPS_MMAP        = 5,
> +  IO_FILE_JUMPS_MAYBE_MMAP  = 6,
> +  IO_WFILE_JUMPS            = 7,
> +  IO_WFILE_JUMPS_MMAP       = 8,
> +  IO_WFILE_JUMPS_MAYBE_MMAP = 9,
> +  IO_COOKIE_JUMPS           = 10,
> +  IO_PROC_JUMPS             = 11,
> +  IO_STR_CHK_JUMPS          = 12,
> +  IO_OBSTACK_JUMPS          = 13,
> +  IO_HELPER_JUMPS           = 14,
> +  IO_WHELPER_JUMPS          = 15,
> +  IO_MEM_JUMPS              = 16,
> +  IO_WMEM_JUMPS             = 17,
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
> +  IO_OLD_FILE_JUMPS         = 18,
> +  IO_OLD_PROC_JUMPS         = 19,
> +#endif
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
> +  IO_OLD_COOKIED_JUMPS      = 20,
> +#endif
> +};
> +
> +extern const struct _IO_jump_t __io_vtables[] attribute_hidden;
> +extern const size_t __io_vtables_size attribute_hidden;

I think you should be able to compute that from the enum definitions
above.

Thanks,
Florian


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

* Re: [PATCH 2/7] elf: Do not assume symbol order on tst-audit25{a,b}
  2022-11-15 19:31 ` [PATCH 2/7] elf: Do not assume symbol order on tst-audit25{a,b} Adhemerval Zanella via Libc-alpha
@ 2022-12-12 12:36   ` Adhemerval Zanella Netto via Libc-alpha
  0 siblings, 0 replies; 25+ messages in thread
From: Adhemerval Zanella Netto via Libc-alpha @ 2022-12-12 12:36 UTC (permalink / raw)
  To: libc-alpha, Fangrui Song

If no one opposes it, I will commit this shortly.

On 15/11/22 16:31, Adhemerval Zanella wrote:
> The static linker might impose any order or internal function
> position, so change the test to check if the audit prints the
> symbol only once in any order.
> ---
>  elf/tst-audit25.h  | 46 ++++++++++++++++++++++++++++++++++++++++++++++
>  elf/tst-audit25a.c | 38 ++++++++++++++++++++++++--------------
>  elf/tst-audit25b.c | 39 +++++++++++++++++++++++++--------------
>  3 files changed, 95 insertions(+), 28 deletions(-)
>  create mode 100644 elf/tst-audit25.h
> 
> diff --git a/elf/tst-audit25.h b/elf/tst-audit25.h
> new file mode 100644
> index 0000000000..9b08c43c32
> --- /dev/null
> +++ b/elf/tst-audit25.h
> @@ -0,0 +1,46 @@
> +/* Check LD_AUDIT and LD_BIND_NOW.  Common definitions.
> +   Copyright (C) 2022 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
> +   <https://www.gnu.org/licenses/>.  */
> +
> +static void
> +compare_output (void *buffer, size_t length, const char *ref[], size_t reflen)
> +{
> +  FILE *in = fmemopen (buffer, length, "r");
> +  TEST_VERIFY_EXIT (in != NULL);
> +  char *line = NULL;
> +  size_t linelen = 0;
> +
> +  bool found[reflen];
> +  for (int i = 0; i < reflen; i++)
> +    found[i] = false;
> +
> +  while (xgetline (&line, &linelen, in))
> +    {
> +      for (int i = 0; i < reflen; i++)
> +	if (strcmp (line, ref[i]) == 0)
> +	  {
> +	    TEST_COMPARE (found[i], false);
> +	    found[i] = true;
> +	  }
> +    }
> +
> +  for (int i = 0; i < reflen; i++)
> +    TEST_COMPARE (found[i], true);
> +
> +  free (line);
> +  fclose (in);
> +}
> diff --git a/elf/tst-audit25a.c b/elf/tst-audit25a.c
> index c2cff8541b..9d2b316576 100644
> --- a/elf/tst-audit25a.c
> +++ b/elf/tst-audit25a.c
> @@ -29,6 +29,8 @@
>  #include <support/support.h>
>  #include <sys/auxv.h>
>  
> +#include "tst-audit25.h"
> +
>  static int restart;
>  #define CMDLINE_OPTIONS \
>    { "restart", no_argument, &restart, 1 },
> @@ -82,13 +84,17 @@ do_test (int argc, char *argv[])
>      /* tst-audit25a is build with -Wl,-z,lazy and tst-audit25mod1 with
>         -Wl,-z,now; so only tst_audit25mod3_func1 should be expected to
>         have LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT.  */
> -    TEST_COMPARE_STRING (result.err.buffer,
> -			 "la_symbind: tst_audit25mod3_func1 1\n"
> -			 "la_symbind: tst_audit25mod1_func1 0\n"
> -			 "la_symbind: tst_audit25mod1_func2 0\n"
> -			 "la_symbind: tst_audit25mod2_func1 0\n"
> -			 "la_symbind: tst_audit25mod4_func1 0\n"
> -			 "la_symbind: tst_audit25mod2_func2 0\n");
> +    const char *expected[] =
> +      {
> +	"la_symbind: tst_audit25mod1_func1 0\n",
> +	"la_symbind: tst_audit25mod1_func2 0\n",
> +	"la_symbind: tst_audit25mod2_func1 0\n",
> +	"la_symbind: tst_audit25mod2_func2 0\n",
> +	"la_symbind: tst_audit25mod3_func1 1\n",
> +	"la_symbind: tst_audit25mod4_func1 0\n",
> +      };
> +    compare_output (result.err.buffer, result.err.length,
> +		    expected, array_length(expected));
>  
>      support_capture_subprocess_free (&result);
>    }
> @@ -103,13 +109,17 @@ do_test (int argc, char *argv[])
>      /* With LD_BIND_NOW all symbols are expected to have
>         LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT.  Also the resolution
>         order is done in breadth-first order.  */
> -    TEST_COMPARE_STRING (result.err.buffer,
> -			 "la_symbind: tst_audit25mod4_func1 1\n"
> -			 "la_symbind: tst_audit25mod3_func1 1\n"
> -			 "la_symbind: tst_audit25mod1_func1 1\n"
> -			 "la_symbind: tst_audit25mod2_func1 1\n"
> -			 "la_symbind: tst_audit25mod1_func2 1\n"
> -			 "la_symbind: tst_audit25mod2_func2 1\n");
> +    const char *expected[] =
> +      {
> +	  "la_symbind: tst_audit25mod1_func1 1\n",
> +	  "la_symbind: tst_audit25mod1_func2 1\n",
> +	  "la_symbind: tst_audit25mod2_func1 1\n",
> +	  "la_symbind: tst_audit25mod2_func2 1\n",
> +	  "la_symbind: tst_audit25mod3_func1 1\n",
> +	  "la_symbind: tst_audit25mod4_func1 1\n",
> +      };
> +    compare_output (result.err.buffer, result.err.length,
> +		    expected, array_length(expected));
>  
>      support_capture_subprocess_free (&result);
>    }
> diff --git a/elf/tst-audit25b.c b/elf/tst-audit25b.c
> index 46391770fd..e1422049b1 100644
> --- a/elf/tst-audit25b.c
> +++ b/elf/tst-audit25b.c
> @@ -16,6 +16,7 @@
>     License along with the GNU C Library; if not, see
>     <https://www.gnu.org/licenses/>.  */
>  
> +#include <array_length.h>
>  #include <errno.h>
>  #include <getopt.h>
>  #include <limits.h>
> @@ -28,6 +29,8 @@
>  #include <support/support.h>
>  #include <sys/auxv.h>
>  
> +#include "tst-audit25.h"
> +
>  static int restart;
>  #define CMDLINE_OPTIONS \
>    { "restart", no_argument, &restart, 1 },
> @@ -81,13 +84,17 @@ do_test (int argc, char *argv[])
>         tst-audit25mod2 is built with -Wl,-z,lazy.  So only
>         tst_audit25mod4_func1 (called by tst_audit25mod2_func1) should not
>         have LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT.  */
> -    TEST_COMPARE_STRING (result.err.buffer,
> -			 "la_symbind: tst_audit25mod3_func1 1\n"
> -			 "la_symbind: tst_audit25mod1_func1 1\n"
> -			 "la_symbind: tst_audit25mod2_func1 1\n"
> -			 "la_symbind: tst_audit25mod1_func2 1\n"
> -			 "la_symbind: tst_audit25mod2_func2 1\n"
> -			 "la_symbind: tst_audit25mod4_func1 0\n");
> +    const char *expected[] =
> +      {
> +	"la_symbind: tst_audit25mod3_func1 1\n",
> +	"la_symbind: tst_audit25mod1_func1 1\n",
> +	"la_symbind: tst_audit25mod2_func1 1\n",
> +	"la_symbind: tst_audit25mod1_func2 1\n",
> +	"la_symbind: tst_audit25mod2_func2 1\n",
> +	"la_symbind: tst_audit25mod4_func1 0\n",
> +      };
> +    compare_output (result.err.buffer, result.err.length,
> +		    expected, array_length(expected));
>  
>      support_capture_subprocess_free (&result);
>    }
> @@ -102,13 +109,17 @@ do_test (int argc, char *argv[])
>      /* With LD_BIND_NOW all symbols are expected to have
>         LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT.  Also the resolution
>         order is done in breadth-first order.  */
> -    TEST_COMPARE_STRING (result.err.buffer,
> -			 "la_symbind: tst_audit25mod4_func1 1\n"
> -			 "la_symbind: tst_audit25mod3_func1 1\n"
> -			 "la_symbind: tst_audit25mod1_func1 1\n"
> -			 "la_symbind: tst_audit25mod2_func1 1\n"
> -			 "la_symbind: tst_audit25mod1_func2 1\n"
> -			 "la_symbind: tst_audit25mod2_func2 1\n");
> +    const char *expected[] =
> +      {
> +	"la_symbind: tst_audit25mod4_func1 1\n",
> +	"la_symbind: tst_audit25mod3_func1 1\n",
> +	"la_symbind: tst_audit25mod1_func1 1\n",
> +	"la_symbind: tst_audit25mod2_func1 1\n",
> +	"la_symbind: tst_audit25mod1_func2 1\n",
> +	"la_symbind: tst_audit25mod2_func2 1\n",
> +      };
> +    compare_output (result.err.buffer, result.err.length,
> +		    expected, array_length(expected));
>  
>      support_capture_subprocess_free (&result);
>    }

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

* Re: [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions
  2022-12-12 10:55   ` Florian Weimer via Libc-alpha
@ 2022-12-12 13:14     ` Adhemerval Zanella Netto via Libc-alpha
  0 siblings, 0 replies; 25+ messages in thread
From: Adhemerval Zanella Netto via Libc-alpha @ 2022-12-12 13:14 UTC (permalink / raw)
  To: Florian Weimer, Adhemerval Zanella via Libc-alpha; +Cc: Fangrui Song



On 12/12/22 07:55, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
> 
>> diff --git a/crypt/md5-crypt.c b/crypt/md5-crypt.c
>> index 7c4fb9fb97..9660cdd698 100644
>> --- a/crypt/md5-crypt.c
>> +++ b/crypt/md5-crypt.c
>> @@ -299,10 +299,7 @@ __md5_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
>>    return buffer;
>>  }
>>  
>> -#ifndef _LIBC
>> -# define libc_freeres_ptr(decl) decl
>> -#endif
>> -libc_freeres_ptr (static char *buffer);
>> +static char *buffer;
>>  
>>  char *
>>  __md5_crypt (const char *key, const char *salt)
>> @@ -330,7 +327,10 @@ __md5_crypt (const char *key, const char *salt)
>>  static void
>>  __attribute__ ((__destructor__))
>>  free_mem (void)
>> +#else
>> +void
>> +__md5_crypt_freemem (void)
>> +#endif
>>  {
>>    free (buffer);
>>  }
>> -#endif
>> diff --git a/crypt/sha256-crypt.c b/crypt/sha256-crypt.c
>> index a98a968a8b..75fd582429 100644
>> --- a/crypt/sha256-crypt.c
>> +++ b/crypt/sha256-crypt.c
>> @@ -386,10 +386,7 @@ __sha256_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
>>    return buffer;
>>  }
>>  
>> -#ifndef _LIBC
>> -# define libc_freeres_ptr(decl) decl
>> -#endif
>> -libc_freeres_ptr (static char *buffer);
>> +static char *buffer;
>>  
>>  /* This entry point is equivalent to the `crypt' function in Unix
>>     libcs.  */
>> @@ -422,7 +419,10 @@ __sha256_crypt (const char *key, const char *salt)
>>  static void
>>  __attribute__ ((__destructor__))
>>  free_mem (void)
>> +#else
>> +void
>> +__sha256_crypt_freemem (void)
>> +#endif
>>  {
>>    free (buffer);
>>  }
>> -#endif
>> diff --git a/crypt/sha512-crypt.c b/crypt/sha512-crypt.c
>> index ea13527c09..ae6ecaef16 100644
>> --- a/crypt/sha512-crypt.c
>> +++ b/crypt/sha512-crypt.c
>> @@ -408,10 +408,7 @@ __sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
>>    return buffer;
>>  }
>>  
>> -#ifndef _LIBC
>> -# define libc_freeres_ptr(decl) decl
>> -#endif
>> -libc_freeres_ptr (static char *buffer);
>> +static char *buffer;
>>  
>>  /* This entry point is equivalent to the `crypt' function in Unix
>>     libcs.  */
>> @@ -444,7 +441,10 @@ __sha512_crypt (const char *key, const char *salt)
>>  static void
>>  __attribute__ ((__destructor__))
>>  free_mem (void)
>> +#else
>> +void
>> +__sha512_crypt_freemem (void)
>> +#endif
>>  {
>>    free (buffer);
>>  }
>> -#endif
> 
> I think you should delete the entire deallocation logic, or make use of
> the ELF destructor unconditional.  This wasn't linked into libc, so it
> wasn't run from __libc_freeres, and the hook registration was a no-op.
> (I believe, I haven't checked.)

Indeed you are right and for modern systems is highly unlikely that glibc
libcrypto will be used anyways (at least for system I usually check libxcrypt
is used instead). I will just remove it.

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

* Re: [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions
  2022-12-12 10:58   ` Florian Weimer via Libc-alpha
@ 2022-12-12 13:16     ` Adhemerval Zanella Netto via Libc-alpha
  0 siblings, 0 replies; 25+ messages in thread
From: Adhemerval Zanella Netto via Libc-alpha @ 2022-12-12 13:16 UTC (permalink / raw)
  To: Florian Weimer, Adhemerval Zanella via Libc-alpha; +Cc: Fangrui Song



On 12/12/22 07:58, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
> 
>> diff --git a/elf/dl-libc.c b/elf/dl-libc.c
>> index 266e068da6..06bce2f6dd 100644
>> --- a/elf/dl-libc.c
>> +++ b/elf/dl-libc.c
>> @@ -228,7 +228,7 @@ __libc_dlclose (void *map)
>>  }
>>  
>>  
>> -static bool __libc_freeres_fn_section
>> +static bool
>>  free_slotinfo (struct dtv_slotinfo_list **elemp)
>>  {
>>    size_t cnt;
>> @@ -256,7 +256,7 @@ free_slotinfo (struct dtv_slotinfo_list **elemp)
>>  }
>>  
>>  
>> -libc_freeres_fn (free_mem)
>> +void __libc_freemem (void)
>>  {
>>    struct link_map *l;
>>    struct r_search_path_elem *d;
> 
> I believe this should be called __dl_libc_freemem or something like
> that, to point towards dl-libc.c as the implementing file.

Alright, I will rename it.

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

* Re: [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions
  2022-12-12 11:00   ` Florian Weimer via Libc-alpha
@ 2022-12-12 13:49     ` Adhemerval Zanella Netto via Libc-alpha
  2022-12-12 14:05       ` Florian Weimer via Libc-alpha
  0 siblings, 1 reply; 25+ messages in thread
From: Adhemerval Zanella Netto via Libc-alpha @ 2022-12-12 13:49 UTC (permalink / raw)
  To: Florian Weimer, Adhemerval Zanella via Libc-alpha; +Cc: Fangrui Song



On 12/12/22 08:00, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
> 
>> diff --git a/grp/fgetgrent.c b/grp/fgetgrent.c
>> index fd2b4d32d6..df04530b04 100644
>> --- a/grp/fgetgrent.c
>> +++ b/grp/fgetgrent.c
>> @@ -25,7 +25,7 @@
>>  /* We need to protect the dynamic buffer handling.  */
>>  __libc_lock_define_initialized (static, lock);
>>  
>> -libc_freeres_ptr (static char *buffer);
>> +static char *buffer;
>>  
>>  /* Read one entry from the given stream.  */
>>  struct group *
>> @@ -82,3 +82,9 @@ fgetgrent (FILE *stream)
>>  
>>    return result;
>>  }
>> +
>> +void
>> +__libc_fgetgrent_freemem (void)
>> +{
>> +  free (buffer);
>> +}
>> diff --git a/gshadow/fgetsgent.c b/gshadow/fgetsgent.c
>> index 02f9c7d643..4d9282e560 100644
>> --- a/gshadow/fgetsgent.c
>> +++ b/gshadow/fgetsgent.c
>> @@ -28,7 +28,7 @@
>>  /* We need to protect the dynamic buffer handling.  */
>>  __libc_lock_define_initialized (static, lock);
>>  
>> -libc_freeres_ptr (static char *buffer);
>> +static char *buffer;
>>  
>>  /* Read one shadow entry from the given stream.  */
>>  struct sgrp *
> 
> Missing free function in the second patch.
> 
> I think you should consider introducing a call_free_static_weak that
> does something like
> 
>   if (&ptr != NULL)
>     free (ptr);
> 
> in the static case, and calls
> 
>   free (ptr);
> 
> unconditionally for the dynamic case.  And then add attribute_hidden
> variable declarations to a suitable wrapper header under include/.
> 
> This avoids writing all these little helper functions.

We already have call_free_static_weak function that does exactly that,
maybe you are proposing a something like:

# ifdef SHARED
#  define declare_libc_freeres (name, ptr) \
static void name (void) { free (ptr); }
# else 
#  define declare_libc_freeres (name, ptr) \
static void name (void) { if (ptr != NULL) free (ptr); }
# endif

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

* Re: [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions
  2022-12-12 11:05   ` Andreas Schwab via Libc-alpha
@ 2022-12-12 13:49     ` Adhemerval Zanella Netto via Libc-alpha
  0 siblings, 0 replies; 25+ messages in thread
From: Adhemerval Zanella Netto via Libc-alpha @ 2022-12-12 13:49 UTC (permalink / raw)
  To: Andreas Schwab, Adhemerval Zanella via Libc-alpha; +Cc: Fangrui Song



On 12/12/22 08:05, Andreas Schwab wrote:
> On Nov 15 2022, Adhemerval Zanella via Libc-alpha wrote:
> 
>> diff --git a/elf/dl-libc.c b/elf/dl-libc.c
>> index 266e068da6..06bce2f6dd 100644
>> --- a/elf/dl-libc.c
>> +++ b/elf/dl-libc.c
>> @@ -228,7 +228,7 @@ __libc_dlclose (void *map)
>>  }
>>  
>>  
>> -static bool __libc_freeres_fn_section
>> +static bool
>>  free_slotinfo (struct dtv_slotinfo_list **elemp)
>>  {
>>    size_t cnt;
>> @@ -256,7 +256,7 @@ free_slotinfo (struct dtv_slotinfo_list **elemp)
>>  }
>>  
>>  
>> -libc_freeres_fn (free_mem)
>> +void __libc_freemem (void)
> 
> Line break after return type.
> 

Ack.

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

* Re: [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions
  2022-12-12 11:08   ` Florian Weimer via Libc-alpha
@ 2022-12-12 13:51     ` Adhemerval Zanella Netto via Libc-alpha
  0 siblings, 0 replies; 25+ messages in thread
From: Adhemerval Zanella Netto via Libc-alpha @ 2022-12-12 13:51 UTC (permalink / raw)
  To: Florian Weimer, Adhemerval Zanella via Libc-alpha; +Cc: Fangrui Song



On 12/12/22 08:08, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
> 
>> diff --git a/malloc/set-freeres.c b/malloc/set-freeres.c
>> index be8c2a35fc..ce5d010133 100644
>> --- a/malloc/set-freeres.c
>> +++ b/malloc/set-freeres.c
>> @@ -15,32 +15,210 @@
>>     License along with the GNU C Library; if not, see
>>     <https://www.gnu.org/licenses/>.  */
> 
>> +/* Resource Freeing Hooks:
>> +
>> +   Normally a process exits and the OS cleans up any allocated
>> +   memory.  However, when tooling like mtrace or valgrind is monitoring
>> +   the process we need to free all resources that are part of the
>> +   process in order to provide the consistency required to track
>> +   memory leaks.
>> +
>> +   A single public API exists and is __libc_freeres(), and this is used
>> +   by applications like valgrind to freee resouces.
>> +
>> +   Each free routines must be explicit listed below, with the care to define
>> +   weak functions for external symbol if applicable.   */
>> +
>> +/* From libc.so.  */
>> +extern void __libc_freemem (void) weak_function;
>> +extern void __hdestroy (void) weak_function;
>> +extern void __gconv_cache_freemem (void) weak_function;
> 
> These declarations should come from headers under include/, so that they
> can be proper type-checked against the implementation.

Ack.

> 
>> +static void (*__libc_freeres_funcs[])(void) attribute_relro =
>> +{
>> +  __libc_freemem,
>> +  __hdestroy,
>> +  __gconv_cache_freemem,
> 
> I think we can avoid these relocations for the dynamic case if we just
> call these functions using call_function_static_weak, or directly free
> the pointers using call_free_static_weak (see the other message).  The
> latter has somewhat large code size, but I think that's the right
> trade-off here.

I used a function pointer array mainly because it tends to generate less
code on some ABIs compare to a chain of call_function_static_weak, but I
did not take in consideration the relocation time spent.  I don't have
a strong opinion in fact, I will change to direct call using
call_free_static_weak.

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

* Re: [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions
  2022-12-12 13:49     ` Adhemerval Zanella Netto via Libc-alpha
@ 2022-12-12 14:05       ` Florian Weimer via Libc-alpha
  2022-12-12 14:16         ` Adhemerval Zanella Netto via Libc-alpha
  0 siblings, 1 reply; 25+ messages in thread
From: Florian Weimer via Libc-alpha @ 2022-12-12 14:05 UTC (permalink / raw)
  To: Adhemerval Zanella Netto; +Cc: Adhemerval Zanella via Libc-alpha, Fangrui Song

* Adhemerval Zanella Netto:

>> I think you should consider introducing a call_free_static_weak that
>> does something like
>> 
>>   if (&ptr != NULL)
>>     free (ptr);
>> 
>> in the static case, and calls
>> 
>>   free (ptr);
>> 
>> unconditionally for the dynamic case.  And then add attribute_hidden
>> variable declarations to a suitable wrapper header under include/.
>> 
>> This avoids writing all these little helper functions.
>
> We already have call_free_static_weak function that does exactly that,

I don't see call_free_static_weak?

> maybe you are proposing a something like:
>
> # ifdef SHARED
> #  define declare_libc_freeres (name, ptr) \
> static void name (void) { free (ptr); }
> # else 
> #  define declare_libc_freeres (name, ptr) \
> static void name (void) { if (ptr != NULL) free (ptr); }
> # endif

It has to be &ptr != NULL for the weak case, and you also need to create
a weak alias.

Thanks,
Florian


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

* Re: [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions
  2022-12-12 14:05       ` Florian Weimer via Libc-alpha
@ 2022-12-12 14:16         ` Adhemerval Zanella Netto via Libc-alpha
  2022-12-12 15:39           ` Florian Weimer via Libc-alpha
  0 siblings, 1 reply; 25+ messages in thread
From: Adhemerval Zanella Netto via Libc-alpha @ 2022-12-12 14:16 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Adhemerval Zanella via Libc-alpha, Fangrui Song



On 12/12/22 11:05, Florian Weimer wrote:
> * Adhemerval Zanella Netto:
> 
>>> I think you should consider introducing a call_free_static_weak that
>>> does something like
>>>
>>>   if (&ptr != NULL)
>>>     free (ptr);
>>>
>>> in the static case, and calls
>>>
>>>   free (ptr);
>>>
>>> unconditionally for the dynamic case.  And then add attribute_hidden
>>> variable declarations to a suitable wrapper header under include/.
>>>
>>> This avoids writing all these little helper functions.
>>
>> We already have call_free_static_weak function that does exactly that,
> 
> I don't see call_free_static_weak?
> 
>> maybe you are proposing a something like:
>>
>> # ifdef SHARED
>> #  define declare_libc_freeres (name, ptr) \
>> static void name (void) { free (ptr); }
>> # else 
>> #  define declare_libc_freeres (name, ptr) \
>> static void name (void) { if (ptr != NULL) free (ptr); }
>> # endif
> 
> It has to be &ptr != NULL for the weak case, and you also need to create
> a weak alias.

Right, and do we really need a weak_alias in this fact? Wouldn't weak_function
suffice in this case for !SHARED?


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

* Re: [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions
  2022-12-12 14:16         ` Adhemerval Zanella Netto via Libc-alpha
@ 2022-12-12 15:39           ` Florian Weimer via Libc-alpha
  0 siblings, 0 replies; 25+ messages in thread
From: Florian Weimer via Libc-alpha @ 2022-12-12 15:39 UTC (permalink / raw)
  To: Adhemerval Zanella Netto; +Cc: Adhemerval Zanella via Libc-alpha, Fangrui Song

* Adhemerval Zanella Netto:

>> It has to be &ptr != NULL for the weak case, and you also need to create
>> a weak alias.
>
> Right, and do we really need a weak_alias in this fact? Wouldn't weak_function
> suffice in this case for !SHARED?

weak_function is active for shared builds, and I don't think we want it
there because it obscures bugs that would otherwise lead to link
failures.

Thanks,
Florian


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

* Re: [PATCH 3/7] stdlib: Move _IO_cleanup to call_function_static_weak
  2022-12-12 10:52   ` Florian Weimer via Libc-alpha
@ 2022-12-13 16:52     ` Joseph Myers
  0 siblings, 0 replies; 25+ messages in thread
From: Joseph Myers @ 2022-12-13 16:52 UTC (permalink / raw)
  To: Florian Weimer
  Cc: Adhemerval Zanella via Libc-alpha, Fangrui Song,
	Adhemerval Zanella, caiyinyu, xry111

This commit has exposed a LoongArch linker bug (affecting several IFUNC 
testcases); I don't know why.

https://sourceware.org/pipermail/libc-testresults/2022q4/010595.html

collect2: fatal error: ld terminated with signal 11 [Segmentation fault], core dumped
compilation terminated.
make[3]: *** [../Rules:301: /scratch/jmyers/glibc/many12/build/glibcs/loongarch64-linux-gnu-lp64d/glibc/elf/ifuncmain1static] Error 1

Maybe the LoongArch people could investigate to see if there is some fix 
that could be applied to binutils 2.39 branch?  (At least in combination 
with GCC mainline, this doesn't appear with binutils mainline, so it will 
probably also be resolved when we move build-many-glibcs.py to binutils 
2.40 branch after 2.40 is released in mid-January, if not fixed before 
then.)

-- 
Joseph S. Myers
joseph@codesourcery.com

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

end of thread, other threads:[~2022-12-13 16:53 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-15 19:31 [PATCH 0/7] Fixing remaining lld issues Adhemerval Zanella via Libc-alpha
2022-11-15 19:31 ` [PATCH 1/7] configure: Move locale tools early Adhemerval Zanella via Libc-alpha
2022-11-15 19:31 ` [PATCH 2/7] elf: Do not assume symbol order on tst-audit25{a,b} Adhemerval Zanella via Libc-alpha
2022-12-12 12:36   ` Adhemerval Zanella Netto via Libc-alpha
2022-11-15 19:31 ` [PATCH 3/7] stdlib: Move _IO_cleanup to call_function_static_weak Adhemerval Zanella via Libc-alpha
2022-12-12 10:52   ` Florian Weimer via Libc-alpha
2022-12-13 16:52     ` Joseph Myers
2022-11-15 19:31 ` [PATCH 4/7] Move libc_freeres_ptrs and libc_subfreeres to weak functions Adhemerval Zanella via Libc-alpha
2022-12-12 10:55   ` Florian Weimer via Libc-alpha
2022-12-12 13:14     ` Adhemerval Zanella Netto via Libc-alpha
2022-12-12 10:58   ` Florian Weimer via Libc-alpha
2022-12-12 13:16     ` Adhemerval Zanella Netto via Libc-alpha
2022-12-12 11:00   ` Florian Weimer via Libc-alpha
2022-12-12 13:49     ` Adhemerval Zanella Netto via Libc-alpha
2022-12-12 14:05       ` Florian Weimer via Libc-alpha
2022-12-12 14:16         ` Adhemerval Zanella Netto via Libc-alpha
2022-12-12 15:39           ` Florian Weimer via Libc-alpha
2022-12-12 11:05   ` Andreas Schwab via Libc-alpha
2022-12-12 13:49     ` Adhemerval Zanella Netto via Libc-alpha
2022-12-12 11:08   ` Florian Weimer via Libc-alpha
2022-12-12 13:51     ` Adhemerval Zanella Netto via Libc-alpha
2022-11-15 19:31 ` [PATCH 5/7] libio: Remove the usage of __libc_IO_vtables Adhemerval Zanella via Libc-alpha
2022-12-12 11:40   ` Florian Weimer via Libc-alpha
2022-11-15 19:31 ` [PATCH 6/7] Remove --with-default-link configure option Adhemerval Zanella via Libc-alpha
2022-11-15 19:31 ` [PATCH 7/7] Remove set-hooks.h from generic includes Adhemerval Zanella via Libc-alpha

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).