[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[glibc] 01/06: debian/patches/git-updates.diff: update from upstream stable branch.



This is an automated email from the git hooks/post-receive script.

aurel32 pushed a commit to branch glibc-2.25
in repository glibc.

commit d2fb01e9d70db03247badbeec3b46918497d7fb3
Author: Aurelien Jarno <aurelien@aurel32.net>
Date:   Tue Nov 14 21:35:47 2017 +0100

    debian/patches/git-updates.diff: update from upstream stable branch.
---
 debian/changelog                |    1 +
 debian/patches/git-updates.diff | 6240 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 6010 insertions(+), 231 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index d1c439e..f9abcc2 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -9,6 +9,7 @@ glibc (2.25-0experimental4) UNRELEASED; urgency=medium
   * sysdeps/hurd.mk: Enable stack-protector on the Hurd.
 
   [ Aurelien Jarno ]
+  * debian/patches/git-updates.diff: update from upstream stable branch.
   * Replace debian/patches/mips/submitted-syscalls5-7-unbound-stack.diff
     by the final version git/submitted-syscalls5-7-unbound-stack.diff.
 
diff --git a/debian/patches/git-updates.diff b/debian/patches/git-updates.diff
index fe337be..55fd207 100644
--- a/debian/patches/git-updates.diff
+++ b/debian/patches/git-updates.diff
@@ -1,10 +1,194 @@
 GIT update of git://sourceware.org/git/glibc.git/release/2.25/master from glibc-2.25
 
 diff --git a/ChangeLog b/ChangeLog
-index f140ee67de..de780da83c 100644
+index f140ee67de..687fd20c46 100644
 --- a/ChangeLog
 +++ b/ChangeLog
-@@ -1,3 +1,392 @@
+@@ -1,3 +1,576 @@
++2017-10-13  James Clarke  <jrtc27@jrtc27.com>
++
++	* sysdeps/powerpc/powerpc32/dl-machine.h (elf_machine_rela):
++	Assign sym_map to be map for local symbols, as TLS relocations
++	use sym_map to determine whether the symbol is defined and to
++	extract the TLS information.
++	* sysdeps/sparc/sparc32/dl-machine.h (elf_machine_rela): Likewise.
++	* sysdeps/sparc/sparc64/dl-machine.h (elf_machine_rela): Likewise.
++
++2017-10-19  Joseph Myers  <joseph@codesourcery.com>
++
++	[BZ #22322]
++	* sysdeps/mips/bits/long-double.h: Move to ....
++	* sysdeps/mips/ieee754/bits/long-double.h: ... here.
++
++2017-10-22  H.J. Lu  <hongjiu.lu@intel.com>
++
++	[BZ #21265]
++	* sysdeps/x86/cpu-features-offsets.sym (XSAVE_STATE_SIZE_OFFSET):
++	New.
++	* sysdeps/x86/cpu-features.c: Include <libc-internal.h>.
++	(get_common_indeces): Set xsave_state_size and
++	bit_arch_XSAVEC_Usable if needed.
++	(init_cpu_features): Remove bit_arch_Use_dl_runtime_resolve_slow
++	and bit_arch_Use_dl_runtime_resolve_opt.
++	* sysdeps/x86/cpu-features.h (bit_arch_Use_dl_runtime_resolve_opt):
++	Removed.
++	(bit_arch_Use_dl_runtime_resolve_slow): Likewise.
++	(bit_arch_Prefer_No_AVX512): Updated.
++	(bit_arch_MathVec_Prefer_No_AVX512): Likewise.
++	(bit_arch_XSAVEC_Usable): New.
++	(STATE_SAVE_OFFSET): Likewise.
++	(STATE_SAVE_MASK): Likewise.
++	[__ASSEMBLER__]: Include <cpu-features-offsets.h>.
++	(cpu_features): Add xsave_state_size.
++	(index_arch_Use_dl_runtime_resolve_opt): Removed.
++	(index_arch_Use_dl_runtime_resolve_slow): Likewise.
++	(index_arch_XSAVEC_Usable): New.
++	* sysdeps/x86_64/dl-machine.h (elf_machine_runtime_setup):
++	Replace _dl_runtime_resolve_sse, _dl_runtime_resolve_avx,
++	_dl_runtime_resolve_avx_slow, _dl_runtime_resolve_avx_opt,
++	_dl_runtime_resolve_avx512 and _dl_runtime_resolve_avx512_opt
++	with _dl_runtime_resolve_fxsave, _dl_runtime_resolve_xsave and
++	_dl_runtime_resolve_xsavec.
++	* sysdeps/x86_64/dl-trampoline.S (DL_RUNTIME_UNALIGNED_VEC_SIZE):
++	Removed.
++	(DL_RUNTIME_RESOLVE_REALIGN_STACK): Check STATE_SAVE_ALIGNMENT
++	instead of VEC_SIZE.
++	(REGISTER_SAVE_BND0): Removed.
++	(REGISTER_SAVE_BND1): Likewise.
++	(REGISTER_SAVE_BND3): Likewise.
++	(REGISTER_SAVE_RAX): Always defined to 0.
++	(VMOV): Removed.
++	(_dl_runtime_resolve_avx): Likewise.
++	(_dl_runtime_resolve_avx_slow): Likewise.
++	(_dl_runtime_resolve_avx_opt): Likewise.
++	(_dl_runtime_resolve_avx512): Likewise.
++	(_dl_runtime_resolve_avx512_opt): Likewise.
++	(_dl_runtime_resolve_sse): Likewise.
++	(_dl_runtime_resolve_sse_vex): Likewise.
++	(USE_FXSAVE): New.
++	(_dl_runtime_resolve_fxsave): Likewise.
++	(USE_XSAVE): Likewise.
++	(_dl_runtime_resolve_xsave): Likewise.
++	(USE_XSAVEC): Likewise.
++	(_dl_runtime_resolve_xsavec): Likewise.
++	* sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_avx512):
++	Removed.
++	(_dl_runtime_resolve_avx512_opt): Likewise.
++	(_dl_runtime_resolve_avx): Likewise.
++	(_dl_runtime_resolve_avx_opt): Likewise.
++	(_dl_runtime_resolve_sse): Likewise.
++	(_dl_runtime_resolve_sse_vex): Likewise.
++	(_dl_runtime_resolve_fxsave): New.
++	(_dl_runtime_resolve_xsave): Likewise.
++	(_dl_runtime_resolve_xsavec): Likewise.
++
++2017-10-19  H.J. Lu  <hongjiu.lu@intel.com>
++
++	* sysdeps/x86_64/Makefile (tests): Add tst-sse, tst-avx and
++	tst-avx512.
++	(test-extras): Add tst-avx-aux and tst-avx512-aux.
++	(extra-test-objs): Add tst-avx-aux.o and tst-avx512-aux.o.
++	(modules-names): Add tst-ssemod, tst-avxmod and tst-avx512mod.
++	($(objpfx)tst-sse): New rule.
++	($(objpfx)tst-avx): Likewise.
++	($(objpfx)tst-avx512): Likewise.
++	(CFLAGS-tst-avx-aux.c): New.
++	(CFLAGS-tst-avxmod.c): Likewise.
++	(CFLAGS-tst-avx512-aux.c): Likewise.
++	(CFLAGS-tst-avx512mod.c): Likewise.
++	* sysdeps/x86_64/tst-avx-aux.c: New file.
++	* sysdeps/x86_64/tst-avx.c: Likewise.
++	* sysdeps/x86_64/tst-avx512-aux.c: Likewise.
++	* sysdeps/x86_64/tst-avx512.c: Likewise.
++	* sysdeps/x86_64/tst-avx512mod.c: Likewise.
++	* sysdeps/x86_64/tst-avxmod.c: Likewise.
++	* sysdeps/x86_64/tst-sse.c: Likewise.
++	* sysdeps/x86_64/tst-ssemod.c: Likewise.
++
++2017-07-19  DJ Delorie  <dj@delorie.com>
++
++	[BZ #21654]
++	* grp/grp-merge.c (libc_hidden_def): Fix cast-after-dereference.
++
++2017-07-14  DJ Delorie  <dj@redhat.com>
++
++	[BZ #21654]
++	* grp/grp_merge.c (__copy_grp): Align char** to minimum pointer
++	alignment not char alignment.
++	(__merge_grp): Likewise.
++
++2017-08-22  Joseph Myers  <joseph@codesourcery.com>
++
++	[BZ #21987]
++	* sysdeps/unix/sysv/linux/sparc/bits/long-double.h: Remove file
++	and copy to ...
++	* sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h:
++	... here.
++	* sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h:
++	... and here.
++
++2017-09-11  H.J. Lu  <hongjiu.lu@intel.com>
++	    Florian Weimer <fweimer@redhat.com>
++
++	* configure.ac (find_cxx_header): Suppress compiler error message.
++	* configure: Regenerated.
++
++	[BZ #21573]
++	* Makerules [$(c++-bits-std_abs-h) != ""] (before-compile): Add
++	$(common-objpfx)bits/std_abs.h.
++	[$(c++-bits-std_abs-h) != ""] ($(common-objpfx)bits/std_abs.h):
++	New target.
++	* config.make.in (c++-bits-std_abs-h): New.
++	* configure.ac (find_cxx_header): Use "\,$1," with sed.
++	(CXX_BITS_STD_ABS_H): New.
++	(AC_SUBST(CXX_BITS_STD_ABS_H)): Likewise.
++	* configure: Regenerated.
++
++2017-09-11  H.J. Lu  <hongjiu.lu@intel.com>
++
++	[BZ #21982]
++	* string/stratcliff.c (do_test): Declare size, nchars, inner,
++	middle and outer with size_t instead of int.  Repleace %d and
++	%Zd with %zu in printf.  Update "MAX (0, nchars - 128)" and
++	"MAX (outer, nchars - 64)" to support unsigned outer and
++	nchars.  Also exit loop when outer == 0.
++
++2017-09-07  H.J. Lu  <hongjiu.lu@intel.com>
++
++	* resolv/tst-resolv-qtypes.c (domain): Changed to
++	"const char domain[] =".
++
++2017-08-31  H.J. Lu  <hongjiu.lu@intel.com>
++
++	[BZ #22051]
++	* Makerules (build-module-helper-objlist): Filter out
++	$(elf-objpfx)sofini.os.
++	(build-shlib-objlist): Append $(elf-objpfx)sofini.os if it is
++	needed.
++
++2017-07-29  Torvald Riegel  <triegel@redhat.com>
++	    Carlos O'Donell  <carlos@redhat.com>
++
++	[BZ 21778]
++	* nptl/pthread_mutex_timedlock.c (__pthread_mutex_timedlock): Update
++	oldval if the CAS fails.
++	* nptl/pthread_mutex_lock.c (__pthread_mutex_lock_full): Likewise.
++	* nptl/tst-mutex7.c: Add comments explaining template test.
++	(ROBUST, DELAY_NSEC, ROUNDS, N): New.
++	(tf, do_test): Use them.
++	* nptl/tst-mutex7robust.c: New file.
++	* nptl/Makefile (tests): Add new test.
++
++2017-07-28  Torvald Riegel  <triegel@redhat.com>
++	    Carlos O'Donell  <carlos@redhat.com>
++
++	[BZ #21298]
++	* nptl/Makefile (tests): Add tst-rwlock20.
++	* nptl/pthread_rwlock_common.c (__pthread_rwlock_rdlock_full): Fix
++	explicit hand-over.
++	(__pthread_rwlock_wrlock_full): Likewise.
++	* nptl/tst-rwlock20.c: New file.
++
 +2017-08-21  Florian Weimer  <fweimer@redhat.com>
 +
 +	[BZ #21972]
@@ -433,10 +617,25 @@ index 97a15b569e..1c815113b9 100644
  # This is invoked with $(call after-link,...), so it should operate on
  # the file $1.  This can be set to do some sort of post-processing on
 diff --git a/Makerules b/Makerules
-index e9194e54cf..7f0eef8096 100644
+index e9194e54cf..43343f03ee 100644
 --- a/Makerules
 +++ b/Makerules
-@@ -588,7 +588,7 @@ $(LINK.o) -shared -static-libgcc -Wl,-O1 $(sysdep-LDFLAGS) \
+@@ -127,6 +127,14 @@ $(common-objpfx)cstdlib: $(c++-cstdlib-header)
+ $(common-objpfx)cmath: $(c++-cmath-header)
+ 	$(INSTALL_DATA) $< $@T
+ 	$(move-if-change) $@T $@
++ifneq (,$(c++-bits-std_abs-h))
++# Also make a copy of <bits/std_abs.h> from GCC 7 to prevent it from
++# including /usr/include/stdlib.h.
++before-compile := $(common-objpfx)bits/std_abs.h $(before-compile)
++$(common-objpfx)bits/std_abs.h: $(c++-bits-std_abs-h)
++	$(INSTALL_DATA) $< $@T
++	$(move-if-change) $@T $@
++endif
+ endif
+ 
+ before-compile := $(common-objpfx)libc-abis.h $(before-compile)
+@@ -588,7 +596,7 @@ $(LINK.o) -shared -static-libgcc -Wl,-O1 $(sysdep-LDFLAGS) \
  	  $(extra-B-$(@F:lib%.so=%).so) -B$(csu-objpfx) \
  	  $(extra-B-$(@F:lib%.so=%).so) $(load-map-file) \
  	  -Wl,-soname=lib$(libprefix)$(@F:lib%.so=%).so$($(@F)-version) \
@@ -445,7 +644,26 @@ index e9194e54cf..7f0eef8096 100644
  	  -L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link)
  endef
  
-@@ -686,10 +686,6 @@ LDFLAGS-c.so = -nostdlib -nostartfiles
+@@ -669,14 +677,17 @@ $(build-module-helper) -o $@ $(shlib-lds-flags) \
+ $(call after-link,$@)
+ endef
+ 
++# sofini.os must be placed last since it terminates .eh_frame section.
+ build-module-helper-objlist = \
+ 	$(patsubst %_pic.a,$(whole-archive) %_pic.a $(no-whole-archive),\
+ 		   $(filter-out %.lds $(map-file) $(+preinit) $(+postinit) \
++				$(elf-objpfx)sofini.os \
+ 				$(link-libc-deps),$^))
+ 
+ build-module-objlist = $(build-module-helper-objlist) $(LDLIBS-$(@F:%.so=%).so)
+ build-shlib-objlist = $(build-module-helper-objlist) \
+-		      $(LDLIBS-$(@F:lib%.so=%).so)
++		      $(LDLIBS-$(@F:lib%.so=%).so) \
++		      $(filter $(elf-objpfx)sofini.os,$^)
+ 
+ # Don't try to use -lc when making libc.so itself.
+ # Also omits crti.o and crtn.o, which we do not want
+@@ -686,10 +697,6 @@ LDFLAGS-c.so = -nostdlib -nostartfiles
  LDLIBS-c.so += $(libc.so-gnulib)
  # Give libc.so an entry point and make it directly runnable itself.
  LDFLAGS-c.so += -e __libc_main
@@ -456,7 +674,7 @@ index e9194e54cf..7f0eef8096 100644
  # Pre-link the objects of libc_pic.a so that we can locally resolve
  # COMMON symbols before we link against ld.so.  This is because ld.so
  # contains some of libc_pic.a already, which will prevent the COMMONs
-@@ -1104,7 +1100,8 @@ $(common-objpfx)format.lds: $(..)scripts/output-format.sed \
+@@ -1104,7 +1111,8 @@ $(common-objpfx)format.lds: $(..)scripts/output-format.sed \
  ifneq (unknown,$(output-format))
  	echo > $@.new 'OUTPUT_FORMAT($(output-format))'
  else
@@ -467,10 +685,10 @@ index e9194e54cf..7f0eef8096 100644
  	| sed -n -f $< > $@.new
  	test -s $@.new
 diff --git a/NEWS b/NEWS
-index ec15dde761..6abe9022a7 100644
+index ec15dde761..1879b735e6 100644
 --- a/NEWS
 +++ b/NEWS
-@@ -5,6 +5,26 @@ See the end for copying conditions.
+@@ -5,6 +5,31 @@ See the end for copying conditions.
  Please send GNU C library bug reports via <http://sourceware.org/bugzilla/>
  using `glibc' in the "product" field.
  
@@ -489,10 +707,15 @@ index ec15dde761..6abe9022a7 100644
 +  [21115] sunrpc: Use-after-free in error path in clntudp_call
 +  [21209] Ignore and remove LD_HWCAP_MASK for AT_SECURE programs
 +  [21242] assert: Suppress pedantic warning caused by statement expression
++  [21265] x86-64: Use fxsave/xsave/xsavec in _dl_runtime_resolve
 +  [21289] Fix symbol redirect for fts_set
++  [21298] rwlock can deadlock on frequent reader/writer phase switching
 +  [21386] Assertion in fork for distinct parent PID is incorrect
 +  [21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366)
++  [21654] nss: Fix invalid cast in group merging
++  [21778] Robust mutex may deadlock
 +  [21972] assert macro requires operator== (int) for its argument type
++  [22322] libc: [mips64] wrong bits/long-double.h installed
 +
  Version 2.25
  
@@ -673,6 +896,71 @@ index 0000000000..8c06402825
 +   <http://www.gnu.org/licenses/>.  */
 +
 +#include <tst-assert-c++.cc>
+diff --git a/config.make.in b/config.make.in
+index 5836b32a72..709527da4f 100644
+--- a/config.make.in
++++ b/config.make.in
+@@ -47,6 +47,7 @@ sysincludes = @SYSINCLUDES@
+ c++-sysincludes = @CXX_SYSINCLUDES@
+ c++-cstdlib-header = @CXX_CSTDLIB_HEADER@
+ c++-cmath-header = @CXX_CMATH_HEADER@
++c++-bits-std_abs-h = @CXX_BITS_STD_ABS_H@
+ all-warnings = @all_warnings@
+ enable-werror = @enable_werror@
+ 
+diff --git a/configure b/configure
+index eecd0ace74..ee637a7caf 100755
+--- a/configure
++++ b/configure
+@@ -634,6 +634,7 @@ BISON
+ INSTALL_INFO
+ PERL
+ BASH_SHELL
++CXX_BITS_STD_ABS_H
+ CXX_CMATH_HEADER
+ CXX_CSTDLIB_HEADER
+ CXX_SYSINCLUDES
+@@ -5318,14 +5319,17 @@ fi
+ # copy of those headers in Makerules.
+ if test -n "$CXX"; then
+   find_cxx_header () {
+-    echo "#include <$1>" | $CXX -M -MP -x c++ - | sed -n "/$1:/{s/:\$//;p}"
++    echo "#include <$1>" | $CXX -M -MP -x c++ - 2>/dev/null \
++	 | sed -n "\,$1:,{s/:\$//;p}"
+   }
+   CXX_CSTDLIB_HEADER="$(find_cxx_header cstdlib)"
+   CXX_CMATH_HEADER="$(find_cxx_header cmath)"
++  CXX_BITS_STD_ABS_H="$(find_cxx_header bits/std_abs.h)"
+ fi
+ 
+ 
+ 
++
+ # Test if LD_LIBRARY_PATH contains the notation for the current directory
+ # since this would lead to problems installing/building glibc.
+ # LD_LIBRARY_PATH contains the current directory if one of the following
+diff --git a/configure.ac b/configure.ac
+index 4a77411b71..d288ff43cd 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1176,13 +1176,16 @@ AC_SUBST(CXX_SYSINCLUDES)
+ # copy of those headers in Makerules.
+ if test -n "$CXX"; then
+   find_cxx_header () {
+-    echo "#include <$1>" | $CXX -M -MP -x c++ - | sed -n "/$1:/{s/:\$//;p}"
++    echo "#include <$1>" | $CXX -M -MP -x c++ - 2>/dev/null \
++	 | sed -n "\,$1:,{s/:\$//;p}"
+   }
+   CXX_CSTDLIB_HEADER="$(find_cxx_header cstdlib)"
+   CXX_CMATH_HEADER="$(find_cxx_header cmath)"
++  CXX_BITS_STD_ABS_H="$(find_cxx_header bits/std_abs.h)"
+ fi
+ AC_SUBST(CXX_CSTDLIB_HEADER)
+ AC_SUBST(CXX_CMATH_HEADER)
++AC_SUBST(CXX_BITS_STD_ABS_H)
+ 
+ # Test if LD_LIBRARY_PATH contains the notation for the current directory
+ # since this would lead to problems installing/building glibc.
 diff --git a/elf/Makefile b/elf/Makefile
 index 61abeb59ee..cc4aeb25b6 100644
 --- a/elf/Makefile
@@ -1057,6 +1345,49 @@ index 6ec3fa5874..eec408eb5d 100644
    return 0;
  }
  #endif
+diff --git a/grp/grp-merge.c b/grp/grp-merge.c
+index 77c494d159..035e7a604b 100644
+--- a/grp/grp-merge.c
++++ b/grp/grp-merge.c
+@@ -85,6 +85,14 @@ __copy_grp (const struct group srcgrp, const size_t buflen,
+     }
+   members[i] = NULL;
+ 
++  /* Align for pointers.  We can't simply align C because we need to
++     align destbuf[c].  */
++  if ((((uintptr_t)destbuf + c) & (__alignof__(char **) - 1)) != 0)
++    {
++      uintptr_t mis_align = ((uintptr_t)destbuf + c) & (__alignof__(char **) - 1);
++      c += __alignof__(char **) - mis_align;
++    }
++
+   /* Copy the pointers from the members array into the buffer and assign them
+      to the gr_mem member of destgrp.  */
+   destgrp->gr_mem = (char **) &destbuf[c];
+@@ -129,7 +137,7 @@ __merge_grp (struct group *savedgrp, char *savedbuf, char *savedend,
+ 
+   /* Get the count of group members from the last sizeof (size_t) bytes in the
+      mergegrp buffer.  */
+-  savedmemcount = (size_t) *(savedend - sizeof (size_t));
++  savedmemcount = *(size_t *) (savedend - sizeof (size_t));
+ 
+   /* Get the count of new members to add.  */
+   for (memcount = 0; mergegrp->gr_mem[memcount]; memcount++)
+@@ -168,6 +176,14 @@ __merge_grp (struct group *savedgrp, char *savedbuf, char *savedend,
+   /* Add the NULL-terminator.  */
+   members[savedmemcount + memcount] = NULL;
+ 
++  /* Align for pointers.  We can't simply align C because we need to
++     align savedbuf[c].  */
++  if ((((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1)) != 0)
++    {
++      uintptr_t mis_align = ((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1);
++      c += __alignof__(char **) - mis_align;
++    }
++
+   /* Copy the member array back into the buffer after the member list and free
+      the member array.  */
+   savedgrp->gr_mem = (char **) &savedbuf[c];
 diff --git a/iconvdata/Makefile b/iconvdata/Makefile
 index 04157b25c5..e4845871f5 100644
 --- a/iconvdata/Makefile
@@ -1741,6 +2072,27 @@ index 19d76c0c37..eaea7c3b89 100644
  compat_symbol (libc, locs, locs, GLIBC_2_0);
  
  
+diff --git a/nptl/Makefile b/nptl/Makefile
+index 6d48c0cfc8..24067768ed 100644
+--- a/nptl/Makefile
++++ b/nptl/Makefile
+@@ -224,6 +224,7 @@ tests = tst-typesizes \
+ 	tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
+ 	tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \
+ 	tst-mutex7 tst-mutex8 tst-mutex9 tst-mutex5a tst-mutex7a \
++	tst-mutex7robust \
+ 	tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \
+ 	tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a tst-mutexpi8 \
+ 	tst-mutexpi9 \
+@@ -241,7 +242,7 @@ tests = tst-typesizes \
+ 	tst-rwlock4 tst-rwlock5 tst-rwlock6 tst-rwlock7 tst-rwlock8 \
+ 	tst-rwlock9 tst-rwlock10 tst-rwlock11 tst-rwlock12 tst-rwlock13 \
+ 	tst-rwlock14 tst-rwlock15 tst-rwlock16 tst-rwlock17 tst-rwlock18 \
+-	tst-rwlock19 \
++	tst-rwlock19 tst-rwlock20 \
+ 	tst-once1 tst-once2 tst-once3 tst-once4 tst-once5 \
+ 	tst-key1 tst-key2 tst-key3 tst-key4 \
+ 	tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 \
 diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
 index 8a228ab254..368fe3c36b 100644
 --- a/nptl/allocatestack.c
@@ -1762,6 +2114,850 @@ index 8a228ab254..368fe3c36b 100644
  	    goto mprot_error;
  #endif
  
+diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c
+index dc9ca4c476..4425927c30 100644
+--- a/nptl/pthread_mutex_lock.c
++++ b/nptl/pthread_mutex_lock.c
+@@ -197,11 +197,14 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex)
+ 	{
+ 	  /* Try to acquire the lock through a CAS from 0 (not acquired) to
+ 	     our TID | assume_other_futex_waiters.  */
+-	  if (__glibc_likely ((oldval == 0)
+-			      && (atomic_compare_and_exchange_bool_acq
+-				  (&mutex->__data.__lock,
+-				   id | assume_other_futex_waiters, 0) == 0)))
+-	      break;
++	  if (__glibc_likely (oldval == 0))
++	    {
++	      oldval
++	        = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
++	            id | assume_other_futex_waiters, 0);
++	      if (__glibc_likely (oldval == 0))
++		break;
++	    }
+ 
+ 	  if ((oldval & FUTEX_OWNER_DIED) != 0)
+ 	    {
+diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c
+index a4beb7b0dc..dd88cc4ec9 100644
+--- a/nptl/pthread_mutex_timedlock.c
++++ b/nptl/pthread_mutex_timedlock.c
+@@ -154,11 +154,14 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex,
+ 	{
+ 	  /* Try to acquire the lock through a CAS from 0 (not acquired) to
+ 	     our TID | assume_other_futex_waiters.  */
+-	  if (__glibc_likely ((oldval == 0)
+-			      && (atomic_compare_and_exchange_bool_acq
+-				  (&mutex->__data.__lock,
+-				   id | assume_other_futex_waiters, 0) == 0)))
+-	      break;
++	  if (__glibc_likely (oldval == 0))
++	    {
++	      oldval
++	        = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
++	            id | assume_other_futex_waiters, 0);
++	      if (__glibc_likely (oldval == 0))
++		break;
++	    }
+ 
+ 	  if ((oldval & FUTEX_OWNER_DIED) != 0)
+ 	    {
+diff --git a/nptl/pthread_rwlock_common.c b/nptl/pthread_rwlock_common.c
+index 256508ca2a..846687e1cf 100644
+--- a/nptl/pthread_rwlock_common.c
++++ b/nptl/pthread_rwlock_common.c
+@@ -55,7 +55,6 @@
+    lock acquisition attempts, so that new incoming readers do not prolong a
+    phase in which readers have acquired the lock.
+ 
+-
+    The main components of the rwlock are a writer-only lock that allows only
+    one of the concurrent writers to be the primary writer, and a
+    single-writer-multiple-readers lock that decides between read phases, in
+@@ -70,15 +69,16 @@
+    ---------------------------
+    #1    0   0   0   0   Lock is idle (and in a read phase).
+    #2    0   0   >0  0   Readers have acquired the lock.
+-   #3    0   1   0   0   Lock is not acquired; a writer is waiting for a write
+-			 phase to start or will try to start one.
++   #3    0   1   0   0   Lock is not acquired; a writer will try to start a
++			 write phase.
+    #4    0   1   >0  0   Readers have acquired the lock; a writer is waiting
+ 			 and explicit hand-over to the writer is required.
+    #4a   0   1   >0  1   Same as #4 except that there are further readers
+ 			 waiting because the writer is to be preferred.
+    #5    1   0   0   0   Lock is idle (and in a write phase).
+-   #6    1   0   >0  0   Write phase; readers are waiting for a read phase to
+-			 start or will try to start one.
++   #6    1   0   >0  0   Write phase; readers will try to start a read phase
++			 (requires explicit hand-over to all readers that
++			 do not start the read phase).
+    #7    1   1   0   0   Lock is acquired by a writer.
+    #8    1   1   >0  0   Lock acquired by a writer and readers are waiting;
+ 			 explicit hand-over to the readers is required.
+@@ -375,9 +375,9 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
+      complexity.  */
+   if (__glibc_likely ((r & PTHREAD_RWLOCK_WRPHASE) == 0))
+     return 0;
+-
+-  /* If there is no primary writer but we are in a write phase, we can try
+-     to install a read phase ourself.  */
++  /* Otherwise, if we were in a write phase (states #6 or #8), we must wait
++     for explicit hand-over of the read phase; the only exception is if we
++     can start a read phase if there is no primary writer currently.  */
+   while (((r & PTHREAD_RWLOCK_WRPHASE) != 0)
+       && ((r & PTHREAD_RWLOCK_WRLOCKED) == 0))
+     {
+@@ -390,15 +390,18 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
+ 	{
+ 	  /* We started the read phase, so we are also responsible for
+ 	     updating the write-phase futex.  Relaxed MO is sufficient.
+-	     Note that there can be no other reader that we have to wake
+-	     because all other readers will see the read phase started by us
+-	     (or they will try to start it themselves); if a writer started
+-	     the read phase, we cannot have started it.  Furthermore, we
+-	     cannot discard a PTHREAD_RWLOCK_FUTEX_USED flag because we will
+-	     overwrite the value set by the most recent writer (or the readers
+-	     before it in case of explicit hand-over) and we know that there
+-	     are no waiting readers.  */
+-	  atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0);
++	     We have to do the same steps as a writer would when handing
++	     over the read phase to us because other readers cannot
++	     distinguish between us and the writer; this includes
++	     explicit hand-over and potentially having to wake other readers
++	     (but we can pretend to do the setting and unsetting of WRLOCKED
++	     atomically, and thus can skip this step).  */
++	  if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0)
++	      & PTHREAD_RWLOCK_FUTEX_USED) != 0)
++	    {
++	      int private = __pthread_rwlock_get_private (rwlock);
++	      futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private);
++	    }
+ 	  return 0;
+ 	}
+       else
+@@ -407,102 +410,98 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock,
+ 	}
+     }
+ 
+-  if ((r & PTHREAD_RWLOCK_WRPHASE) != 0)
++  /* We were in a write phase but did not install the read phase.  We cannot
++     distinguish between a writer and another reader starting the read phase,
++     so we must wait for explicit hand-over via __wrphase_futex.
++     However, __wrphase_futex might not have been set to 1 yet (either
++     because explicit hand-over to the writer is still ongoing, or because
++     the writer has started the write phase but has not yet updated
++     __wrphase_futex).  The least recent value of __wrphase_futex we can
++     read from here is the modification of the last read phase (because
++     we synchronize with the last reader in this read phase through
++     __readers; see the use of acquire MO on the fetch_add above).
++     Therefore, if we observe a value of 0 for __wrphase_futex, we need
++     to subsequently check that __readers now indicates a read phase; we
++     need to use acquire MO for this so that if we observe a read phase,
++     we will also see the modification of __wrphase_futex by the previous
++     writer.  We then need to load __wrphase_futex again and continue to
++     wait if it is not 0, so that we do not skip explicit hand-over.
++     Relaxed MO is sufficient for the load from __wrphase_futex because
++     we just use it as an indicator for when we can proceed; we use
++     __readers and the acquire MO accesses to it to eventually read from
++     the proper stores to __wrphase_futex.  */
++  unsigned int wpf;
++  bool ready = false;
++  for (;;)
+     {
+-      /* We are in a write phase, and there must be a primary writer because
+-	 of the previous loop.  Block until the primary writer gives up the
+-	 write phase.  This case requires explicit hand-over using
+-	 __wrphase_futex.
+-	 However, __wrphase_futex might not have been set to 1 yet (either
+-	 because explicit hand-over to the writer is still ongoing, or because
+-	 the writer has started the write phase but does not yet have updated
+-	 __wrphase_futex).  The least recent value of __wrphase_futex we can
+-	 read from here is the modification of the last read phase (because
+-	 we synchronize with the last reader in this read phase through
+-	 __readers; see the use of acquire MO on the fetch_add above).
+-	 Therefore, if we observe a value of 0 for __wrphase_futex, we need
+-	 to subsequently check that __readers now indicates a read phase; we
+-	 need to use acquire MO for this so that if we observe a read phase,
+-	 we will also see the modification of __wrphase_futex by the previous
+-	 writer.  We then need to load __wrphase_futex again and continue to
+-	 wait if it is not 0, so that we do not skip explicit hand-over.
+-	 Relaxed MO is sufficient for the load from __wrphase_futex because
+-	 we just use it as an indicator for when we can proceed; we use
+-	 __readers and the acquire MO accesses to it to eventually read from
+-	 the proper stores to __wrphase_futex.  */
+-      unsigned int wpf;
+-      bool ready = false;
+-      for (;;)
++      while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
++	  | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED))
+ 	{
+-	  while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
+-	      | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED))
++	  int private = __pthread_rwlock_get_private (rwlock);
++	  if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0)
++	      && !atomic_compare_exchange_weak_relaxed
++		  (&rwlock->__data.__wrphase_futex,
++		   &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED))
++	    continue;
++	  int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
++	      1 | PTHREAD_RWLOCK_FUTEX_USED, abstime, private);
++	  if (err == ETIMEDOUT)
+ 	    {
+-	      int private = __pthread_rwlock_get_private (rwlock);
+-	      if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0)
+-		  && !atomic_compare_exchange_weak_relaxed
+-		      (&rwlock->__data.__wrphase_futex,
+-		       &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED))
+-		continue;
+-	      int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
+-		  1 | PTHREAD_RWLOCK_FUTEX_USED, abstime, private);
+-	      if (err == ETIMEDOUT)
++	      /* If we timed out, we need to unregister.  If no read phase
++		 has been installed while we waited, we can just decrement
++		 the number of readers.  Otherwise, we just acquire the
++		 lock, which is allowed because we give no precise timing
++		 guarantees, and because the timeout is only required to
++		 be in effect if we would have had to wait for other
++		 threads (e.g., if futex_wait would time-out immediately
++		 because the given absolute time is in the past).  */
++	      r = atomic_load_relaxed (&rwlock->__data.__readers);
++	      while ((r & PTHREAD_RWLOCK_WRPHASE) != 0)
+ 		{
+-		  /* If we timed out, we need to unregister.  If no read phase
+-		     has been installed while we waited, we can just decrement
+-		     the number of readers.  Otherwise, we just acquire the
+-		     lock, which is allowed because we give no precise timing
+-		     guarantees, and because the timeout is only required to
+-		     be in effect if we would have had to wait for other
+-		     threads (e.g., if futex_wait would time-out immediately
+-		     because the given absolute time is in the past).  */
+-		  r = atomic_load_relaxed (&rwlock->__data.__readers);
+-		  while ((r & PTHREAD_RWLOCK_WRPHASE) != 0)
+-		    {
+-		      /* We don't need to make anything else visible to
+-			 others besides unregistering, so relaxed MO is
+-			 sufficient.  */
+-		      if (atomic_compare_exchange_weak_relaxed
+-			  (&rwlock->__data.__readers, &r,
+-			   r - (1 << PTHREAD_RWLOCK_READER_SHIFT)))
+-			return ETIMEDOUT;
+-		      /* TODO Back-off.  */
+-		    }
+-		  /* Use the acquire MO fence to mirror the steps taken in the
+-		     non-timeout case.  Note that the read can happen both
+-		     in the atomic_load above as well as in the failure case
+-		     of the CAS operation.  */
+-		  atomic_thread_fence_acquire ();
+-		  /* We still need to wait for explicit hand-over, but we must
+-		     not use futex_wait anymore because we would just time out
+-		     in this case and thus make the spin-waiting we need
+-		     unnecessarily expensive.  */
+-		  while ((atomic_load_relaxed (&rwlock->__data.__wrphase_futex)
+-		      | PTHREAD_RWLOCK_FUTEX_USED)
+-		      == (1 | PTHREAD_RWLOCK_FUTEX_USED))
+-		    {
+-		      /* TODO Back-off?  */
+-		    }
+-		  ready = true;
+-		  break;
++		  /* We don't need to make anything else visible to
++		     others besides unregistering, so relaxed MO is
++		     sufficient.  */
++		  if (atomic_compare_exchange_weak_relaxed
++		      (&rwlock->__data.__readers, &r,
++		       r - (1 << PTHREAD_RWLOCK_READER_SHIFT)))
++		    return ETIMEDOUT;
++		  /* TODO Back-off.  */
+ 		}
+-	      /* If we got interrupted (EINTR) or the futex word does not have the
+-		 expected value (EAGAIN), retry.  */
++	      /* Use the acquire MO fence to mirror the steps taken in the
++		 non-timeout case.  Note that the read can happen both
++		 in the atomic_load above as well as in the failure case
++		 of the CAS operation.  */
++	      atomic_thread_fence_acquire ();
++	      /* We still need to wait for explicit hand-over, but we must
++		 not use futex_wait anymore because we would just time out
++		 in this case and thus make the spin-waiting we need
++		 unnecessarily expensive.  */
++	      while ((atomic_load_relaxed (&rwlock->__data.__wrphase_futex)
++		  | PTHREAD_RWLOCK_FUTEX_USED)
++		  == (1 | PTHREAD_RWLOCK_FUTEX_USED))
++		{
++		  /* TODO Back-off?  */
++		}
++	      ready = true;
++	      break;
+ 	    }
+-	  if (ready)
+-	    /* See below.  */
+-	    break;
+-	  /* We need acquire MO here so that we synchronize with the lock
+-	     release of the writer, and so that we observe a recent value of
+-	     __wrphase_futex (see below).  */
+-	  if ((atomic_load_acquire (&rwlock->__data.__readers)
+-	      & PTHREAD_RWLOCK_WRPHASE) == 0)
+-	    /* We are in a read phase now, so the least recent modification of
+-	       __wrphase_futex we can read from is the store by the writer
+-	       with value 1.  Thus, only now we can assume that if we observe
+-	       a value of 0, explicit hand-over is finished. Retry the loop
+-	       above one more time.  */
+-	    ready = true;
++	  /* If we got interrupted (EINTR) or the futex word does not have the
++	     expected value (EAGAIN), retry.  */
+ 	}
++      if (ready)
++	/* See below.  */
++	break;
++      /* We need acquire MO here so that we synchronize with the lock
++	 release of the writer, and so that we observe a recent value of
++	 __wrphase_futex (see below).  */
++      if ((atomic_load_acquire (&rwlock->__data.__readers)
++	  & PTHREAD_RWLOCK_WRPHASE) == 0)
++	/* We are in a read phase now, so the least recent modification of
++	   __wrphase_futex we can read from is the store by the writer
++	   with value 1.  Thus, only now we can assume that if we observe
++	   a value of 0, explicit hand-over is finished. Retry the loop
++	   above one more time.  */
++	ready = true;
+     }
+ 
+   return 0;
+@@ -741,10 +740,23 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
+ 	  r = atomic_load_relaxed (&rwlock->__data.__readers);
+ 	}
+       /* Our snapshot of __readers is up-to-date at this point because we
+-	 either set WRLOCKED using a CAS or were handed over WRLOCKED from
++	 either set WRLOCKED using a CAS (and update r accordingly below,
++	 which was used as expected value for the CAS) or got WRLOCKED from
+ 	 another writer whose snapshot of __readers we inherit.  */
++      r |= PTHREAD_RWLOCK_WRLOCKED;
+     }
+ 
++  /* We are the primary writer; enable blocking on __writers_futex.  Relaxed
++     MO is sufficient for futex words; acquire MO on the previous
++     modifications of __readers ensures that this store happens after the
++     store of value 0 by the previous primary writer.  */
++  atomic_store_relaxed (&rwlock->__data.__writers_futex,
++      1 | (may_share_futex_used_flag ? PTHREAD_RWLOCK_FUTEX_USED : 0));
++
++  /* If we are in a write phase, we have acquired the lock.  */
++  if ((r & PTHREAD_RWLOCK_WRPHASE) != 0)
++    goto done;
++
+   /* If we are in a read phase and there are no readers, try to start a write
+      phase.  */
+   while (((r & PTHREAD_RWLOCK_WRPHASE) == 0)
+@@ -758,166 +770,156 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock,
+ 	  &r, r | PTHREAD_RWLOCK_WRPHASE))
+ 	{
+ 	  /* We have started a write phase, so need to enable readers to wait.
+-	     See the similar case in__pthread_rwlock_rdlock_full.  */
++	     See the similar case in __pthread_rwlock_rdlock_full.  Unlike in
++	     that similar case, we are the (only) primary writer and so do
++	     not need to wake another writer.  */
+ 	  atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1);
+-	  /* Make sure we fall through to the end of the function.  */
+-	  r |= PTHREAD_RWLOCK_WRPHASE;
+-	  break;
++
++	  goto done;
+ 	}
+       /* TODO Back-off.  */
+     }
+ 
+-  /* We are the primary writer; enable blocking on __writers_futex.  Relaxed
+-     MO is sufficient for futex words; acquire MO on the previous
+-     modifications of __readers ensures that this store happens after the
+-     store of value 0 by the previous primary writer.  */
+-  atomic_store_relaxed (&rwlock->__data.__writers_futex,
+-      1 | (may_share_futex_used_flag ? PTHREAD_RWLOCK_FUTEX_USED : 0));
+-
+-  if (__glibc_unlikely ((r & PTHREAD_RWLOCK_WRPHASE) == 0))
++  /* We became the primary writer in a read phase and there were readers when
++     we did (because of the previous loop).  Thus, we have to wait for
++     explicit hand-over from one of these readers.
++     We basically do the same steps as for the similar case in
++     __pthread_rwlock_rdlock_full, except that we additionally might try
++     to directly hand over to another writer and need to wake up
++     other writers or waiting readers (i.e., PTHREAD_RWLOCK_RWAITING).  */
++  unsigned int wpf;
++  bool ready = false;
++  for (;;)
+     {
+-      /* We are not in a read phase and there are readers (because of the
+-	 previous loop).  Thus, we have to wait for explicit hand-over from
+-	 one of these readers.
+-	 We basically do the same steps as for the similar case in
+-	 __pthread_rwlock_rdlock_full, except that we additionally might try
+-	 to directly hand over to another writer and need to wake up
+-	 other writers or waiting readers (i.e., PTHREAD_RWLOCK_RWAITING).  */
+-      unsigned int wpf;
+-      bool ready = false;
+-      for (;;)
++      while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
++	  | PTHREAD_RWLOCK_FUTEX_USED) == PTHREAD_RWLOCK_FUTEX_USED)
+ 	{
+-	  while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex))
+-	      | PTHREAD_RWLOCK_FUTEX_USED) == PTHREAD_RWLOCK_FUTEX_USED)
++	  int private = __pthread_rwlock_get_private (rwlock);
++	  if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0)
++	      && !atomic_compare_exchange_weak_relaxed
++		  (&rwlock->__data.__wrphase_futex, &wpf,
++		   PTHREAD_RWLOCK_FUTEX_USED))
++	    continue;
++	  int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
++	      PTHREAD_RWLOCK_FUTEX_USED, abstime, private);
++	  if (err == ETIMEDOUT)
+ 	    {
+-	      int private = __pthread_rwlock_get_private (rwlock);
+-	      if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0)
+-		  && !atomic_compare_exchange_weak_relaxed
+-		      (&rwlock->__data.__wrphase_futex, &wpf,
+-		       PTHREAD_RWLOCK_FUTEX_USED))
+-		continue;
+-	      int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex,
+-		  PTHREAD_RWLOCK_FUTEX_USED, abstime, private);
+-	      if (err == ETIMEDOUT)
++	      if (rwlock->__data.__flags
++		  != PTHREAD_RWLOCK_PREFER_READER_NP)
+ 		{
+-		  if (rwlock->__data.__flags
+-		      != PTHREAD_RWLOCK_PREFER_READER_NP)
+-		    {
+-		      /* We try writer--writer hand-over.  */
+-		      unsigned int w = atomic_load_relaxed
+-			  (&rwlock->__data.__writers);
+-		      if (w != 0)
+-			{
+-			  /* We are about to hand over WRLOCKED, so we must
+-			     release __writers_futex too; otherwise, we'd have
+-			     a pending store, which could at least prevent
+-			     other threads from waiting using the futex
+-			     because it could interleave with the stores
+-			     by subsequent writers.  In turn, this means that
+-			     we have to clean up when we do not hand over
+-			     WRLOCKED.
+-			     Release MO so that another writer that gets
+-			     WRLOCKED from us can take over our view of
+-			     __readers.  */
+-			  unsigned int wf = atomic_exchange_relaxed
+-			      (&rwlock->__data.__writers_futex, 0);
+-			  while (w != 0)
+-			    {
+-			      if (atomic_compare_exchange_weak_release
+-				  (&rwlock->__data.__writers, &w,
+-				      w | PTHREAD_RWLOCK_WRHANDOVER))
+-				{
+-				  /* Wake other writers.  */
+-				  if ((wf & PTHREAD_RWLOCK_FUTEX_USED) != 0)
+-				    futex_wake
+-					(&rwlock->__data.__writers_futex, 1,
+-					 private);
+-				  return ETIMEDOUT;
+-				}
+-			      /* TODO Back-off.  */
+-			    }
+-			  /* We still own WRLOCKED and someone else might set
+-			     a write phase concurrently, so enable waiting
+-			     again.  Make sure we don't loose the flag that
+-			     signals whether there are threads waiting on
+-			     this futex.  */
+-			  atomic_store_relaxed
+-			      (&rwlock->__data.__writers_futex, wf);
+-			}
+-		    }
+-		  /* If we timed out and we are not in a write phase, we can
+-		     just stop being a primary writer.  Otherwise, we just
+-		     acquire the lock.  */
+-		  r = atomic_load_relaxed (&rwlock->__data.__readers);
+-		  if ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
++		  /* We try writer--writer hand-over.  */
++		  unsigned int w = atomic_load_relaxed
++		      (&rwlock->__data.__writers);
++		  if (w != 0)
+ 		    {
+-		      /* We are about to release WRLOCKED, so we must release
+-			 __writers_futex too; see the handling of
+-			 writer--writer hand-over above.  */
++		      /* We are about to hand over WRLOCKED, so we must
++			 release __writers_futex too; otherwise, we'd have
++			 a pending store, which could at least prevent
++			 other threads from waiting using the futex
++			 because it could interleave with the stores
++			 by subsequent writers.  In turn, this means that
++			 we have to clean up when we do not hand over
++			 WRLOCKED.
++			 Release MO so that another writer that gets
++			 WRLOCKED from us can take over our view of
++			 __readers.  */
+ 		      unsigned int wf = atomic_exchange_relaxed
+ 			  (&rwlock->__data.__writers_futex, 0);
+-		      while ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
++		      while (w != 0)
+ 			{
+-			  /* While we don't need to make anything from a
+-			     caller's critical section visible to other
+-			     threads, we need to ensure that our changes to
+-			     __writers_futex are properly ordered.
+-			     Therefore, use release MO to synchronize with
+-			     subsequent primary writers.  Also wake up any
+-			     waiting readers as they are waiting because of
+-			     us.  */
+ 			  if (atomic_compare_exchange_weak_release
+-			      (&rwlock->__data.__readers, &r,
+-			       (r ^ PTHREAD_RWLOCK_WRLOCKED)
+-			       & ~(unsigned int) PTHREAD_RWLOCK_RWAITING))
++			      (&rwlock->__data.__writers, &w,
++				  w | PTHREAD_RWLOCK_WRHANDOVER))
+ 			    {
+ 			      /* Wake other writers.  */
+ 			      if ((wf & PTHREAD_RWLOCK_FUTEX_USED) != 0)
+ 				futex_wake (&rwlock->__data.__writers_futex,
+-				    1, private);
+-			      /* Wake waiting readers.  */
+-			      if ((r & PTHREAD_RWLOCK_RWAITING) != 0)
+-				futex_wake (&rwlock->__data.__readers,
+-				    INT_MAX, private);
++					    1, private);
+ 			      return ETIMEDOUT;
+ 			    }
++			  /* TODO Back-off.  */
+ 			}
+-		      /* We still own WRLOCKED and someone else might set a
+-			 write phase concurrently, so enable waiting again.
+-			 Make sure we don't loose the flag that signals
+-			 whether there are threads waiting on this futex.  */
+-		      atomic_store_relaxed (&rwlock->__data.__writers_futex,
+-			  wf);
++		      /* We still own WRLOCKED and someone else might set
++			 a write phase concurrently, so enable waiting
++			 again.  Make sure we don't loose the flag that
++			 signals whether there are threads waiting on
++			 this futex.  */
++		      atomic_store_relaxed
++			  (&rwlock->__data.__writers_futex, wf);
+ 		    }
+-		  /* Use the acquire MO fence to mirror the steps taken in the
+-		     non-timeout case.  Note that the read can happen both
+-		     in the atomic_load above as well as in the failure case
+-		     of the CAS operation.  */
+-		  atomic_thread_fence_acquire ();
+-		  /* We still need to wait for explicit hand-over, but we must
+-		     not use futex_wait anymore.  */
+-		  while ((atomic_load_relaxed
+-		      (&rwlock->__data.__wrphase_futex)
+-		       | PTHREAD_RWLOCK_FUTEX_USED)
+-		      == PTHREAD_RWLOCK_FUTEX_USED)
++		}
++	      /* If we timed out and we are not in a write phase, we can
++		 just stop being a primary writer.  Otherwise, we just
++		 acquire the lock.  */
++	      r = atomic_load_relaxed (&rwlock->__data.__readers);
++	      if ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
++		{
++		  /* We are about to release WRLOCKED, so we must release
++		     __writers_futex too; see the handling of
++		     writer--writer hand-over above.  */
++		  unsigned int wf = atomic_exchange_relaxed
++		      (&rwlock->__data.__writers_futex, 0);
++		  while ((r & PTHREAD_RWLOCK_WRPHASE) == 0)
+ 		    {
+-		      /* TODO Back-off.  */
++		      /* While we don't need to make anything from a
++			 caller's critical section visible to other
++			 threads, we need to ensure that our changes to
++			 __writers_futex are properly ordered.
++			 Therefore, use release MO to synchronize with
++			 subsequent primary writers.  Also wake up any
++			 waiting readers as they are waiting because of
++			 us.  */
++		      if (atomic_compare_exchange_weak_release
++			  (&rwlock->__data.__readers, &r,
++			   (r ^ PTHREAD_RWLOCK_WRLOCKED)
++			   & ~(unsigned int) PTHREAD_RWLOCK_RWAITING))
++			{
++			  /* Wake other writers.  */
++			  if ((wf & PTHREAD_RWLOCK_FUTEX_USED) != 0)
++			    futex_wake (&rwlock->__data.__writers_futex,
++				1, private);
++			  /* Wake waiting readers.  */
++			  if ((r & PTHREAD_RWLOCK_RWAITING) != 0)
++			    futex_wake (&rwlock->__data.__readers,
++				INT_MAX, private);
++			  return ETIMEDOUT;
++			}
+ 		    }
+-		  ready = true;
+-		  break;
++		  /* We still own WRLOCKED and someone else might set a
++		     write phase concurrently, so enable waiting again.
++		     Make sure we don't loose the flag that signals
++		     whether there are threads waiting on this futex.  */
++		  atomic_store_relaxed (&rwlock->__data.__writers_futex, wf);
+ 		}
+-	      /* If we got interrupted (EINTR) or the futex word does not have
+-		 the expected value (EAGAIN), retry.  */
++	      /* Use the acquire MO fence to mirror the steps taken in the
++		 non-timeout case.  Note that the read can happen both
++		 in the atomic_load above as well as in the failure case
++		 of the CAS operation.  */
++	      atomic_thread_fence_acquire ();
++	      /* We still need to wait for explicit hand-over, but we must
++		 not use futex_wait anymore.  */
++	      while ((atomic_load_relaxed
++		  (&rwlock->__data.__wrphase_futex)
++		   | PTHREAD_RWLOCK_FUTEX_USED)
++		  == PTHREAD_RWLOCK_FUTEX_USED)
++		{
++		  /* TODO Back-off.  */
++		}
++	      ready = true;
++	      break;
+ 	    }
+-	  /* See pthread_rwlock_rdlock_full.  */
+-	  if (ready)
+-	    break;
+-	  if ((atomic_load_acquire (&rwlock->__data.__readers)
+-	      & PTHREAD_RWLOCK_WRPHASE) != 0)
+-	    ready = true;
++	  /* If we got interrupted (EINTR) or the futex word does not have
++	     the expected value (EAGAIN), retry.  */
+ 	}
++      /* See pthread_rwlock_rdlock_full.  */
++      if (ready)
++	break;
++      if ((atomic_load_acquire (&rwlock->__data.__readers)
++	  & PTHREAD_RWLOCK_WRPHASE) != 0)
++	ready = true;
+     }
+ 
++ done:
+   atomic_store_relaxed (&rwlock->__data.__cur_writer,
+       THREAD_GETMEM (THREAD_SELF, tid));
+   return 0;
+diff --git a/nptl/tst-mutex7.c b/nptl/tst-mutex7.c
+index a11afdba5e..08fe251eeb 100644
+--- a/nptl/tst-mutex7.c
++++ b/nptl/tst-mutex7.c
+@@ -22,25 +22,41 @@
+ #include <stdlib.h>
+ #include <time.h>
+ 
+-
++/* This test is a template for other tests to use.  Other tests define
++   the following macros to change the behaviour of the template test.
++   The test is very simple, it configures N threads given the parameters
++   below and then proceeds to go through mutex lock and unlock
++   operations in each thread as described before for the thread
++   function.  */
+ #ifndef TYPE
+ # define TYPE PTHREAD_MUTEX_DEFAULT
+ #endif
+-
++#ifndef ROBUST
++# define ROBUST PTHREAD_MUTEX_STALLED
++#endif
++#ifndef DELAY_NSEC
++# define DELAY_NSEC 11000
++#endif
++#ifndef ROUNDS
++# define ROUNDS 1000
++#endif
++#ifndef N
++# define N 100
++#endif
+ 
+ static pthread_mutex_t lock;
+ 
+-
+-#define ROUNDS 1000
+-#define N 100
+-
+-
++/* Each thread locks and the subsequently unlocks the lock, yielding
++   the smallest critical section possible.  After the unlock the thread
++   waits DELAY_NSEC nanoseconds before doing the lock and unlock again.
++   Every thread does this ROUNDS times.  The lock and unlock are
++   checked for errors.  */
+ static void *
+ tf (void *arg)
+ {
+   int nr = (long int) arg;
+   int cnt;
+-  struct timespec ts = { .tv_sec = 0, .tv_nsec = 11000 };
++  struct timespec ts = { .tv_sec = 0, .tv_nsec = DELAY_NSEC };
+ 
+   for (cnt = 0; cnt < ROUNDS; ++cnt)
+     {
+@@ -56,13 +72,16 @@ tf (void *arg)
+ 	  return (void *) 1l;
+ 	}
+ 
+-      nanosleep (&ts, NULL);
++      if ((ts.tv_sec > 0) || (ts.tv_nsec > 0))
++	nanosleep (&ts, NULL);
+     }
+ 
+   return NULL;
+ }
+ 
+-
++/* Setup and run N threads, where each thread does as described
++   in the above thread function.  The threads are given a minimal 1MiB
++   stack since they don't do anything between the lock and unlock.  */
+ static int
+ do_test (void)
+ {
+@@ -80,6 +99,12 @@ do_test (void)
+       exit (1);
+     }
+ 
++  if (pthread_mutexattr_setrobust (&a, ROBUST) != 0)
++    {
++      puts ("mutexattr_setrobust failed");
++      exit (1);
++    }
++
+ #ifdef ENABLE_PI
+   if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
+     {
+diff --git a/nptl/tst-mutex7robust.c b/nptl/tst-mutex7robust.c
+new file mode 100644
+index 0000000000..8221a61d29
+--- /dev/null
++++ b/nptl/tst-mutex7robust.c
+@@ -0,0 +1,7 @@
++/* Bug 21778: Fix oversight in robust mutex lock acquisition.  */
++#define TYPE PTHREAD_MUTEX_NORMAL
++#define ROBUST PTHREAD_MUTEX_ROBUST
++#define DELAY_NSEC 0
++#define ROUNDS 1000
++#define N 32
++#include "tst-mutex7.c"
+diff --git a/nptl/tst-rwlock20.c b/nptl/tst-rwlock20.c
+new file mode 100644
+index 0000000000..4aeea2b8f5
+--- /dev/null
++++ b/nptl/tst-rwlock20.c
+@@ -0,0 +1,116 @@
++/* Test program for a read-phase / write-phase explicit hand-over.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++
++   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; see the file COPYING.LIB.  If
++   not, see <http://www.gnu.org/licenses/>.  */
++
++#include <errno.h>
++#include <error.h>
++#include <pthread.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <stdint.h>
++#include <time.h>
++#include <atomic.h>
++#include <support/xthread.h>
++
++/* We realy want to set threads to 2 to reproduce this issue. The goal
++   is to have one primary writer and a single reader, and to hit the
++   bug that happens in the interleaving of those two phase transitions.
++   However, on most hardware, adding a second writer seems to help the
++   interleaving happen slightly more often, say 20% of the time.  On a
++   16 core ppc64 machine this fails 100% of the time with an unpatched
++   glibc.  On a 8 core x86_64 machine this fails ~93% of the time, but
++   it doesn't fail at all on a 4 core system, so having available
++   unloaded cores makes a big difference in reproducibility.  On an 8
++   core qemu/kvm guest the reproducer reliability drops to ~10%.  */
++#define THREADS 3
++
++#define KIND PTHREAD_RWLOCK_PREFER_READER_NP
++
++static pthread_rwlock_t lock;
++static int done = 0;
++
++static void*
++tf (void* arg)
++{
++  while (atomic_load_relaxed (&done) == 0)
++    {
++      int rcnt = 0;
++      int wcnt = 100;
++      if ((uintptr_t) arg == 0)
++	{
++	  rcnt = 1;
++	  wcnt = 1;
++	}
++
++      do
++	{
++	  if (wcnt)
++	    {
++	      xpthread_rwlock_wrlock (&lock);
++	      xpthread_rwlock_unlock (&lock);
++	      wcnt--;
++	  }
++	  if (rcnt)
++	    {
++	      xpthread_rwlock_rdlock (&lock);
++	      xpthread_rwlock_unlock (&lock);
++	      rcnt--;
++	  }
++	}
++      while ((atomic_load_relaxed (&done) == 0) && (rcnt + wcnt > 0));
++
++    }
++    return NULL;
++}
++
++
++
++static int
++do_test (void)
++{
++  pthread_t thr[THREADS];
++  int n;
++  pthread_rwlockattr_t attr;
++
++  xpthread_rwlockattr_init (&attr);
++  xpthread_rwlockattr_setkind_np (&attr, KIND);
++
++  xpthread_rwlock_init (&lock, &attr);
++
++  /* Make standard error the same as standard output.  */
++  dup2 (1, 2);
++
++  /* Make sure we see all message, even those on stdout.  */
++  setvbuf (stdout, NULL, _IONBF, 0);
++
++  for (n = 0; n < THREADS; ++n)
++    thr[n] = xpthread_create (NULL, tf, (void *) (uintptr_t) n);
++
++  struct timespec delay;
++  delay.tv_sec = 10;
++  delay.tv_nsec = 0;
++  nanosleep (&delay, NULL);
++  atomic_store_relaxed (&done, 1);
++
++  /* Wait for all the threads.  */
++  for (n = 0; n < THREADS; ++n)
++    xpthread_join (thr[n]);
++
++  return 0;
++}
++
++#include <support/test-driver.c>
 diff --git a/posix/globtest.sh b/posix/globtest.sh
 index f9cc80b4b5..73f7ae31cc 100755
 --- a/posix/globtest.sh
@@ -2448,6 +3644,135 @@ index 0000000000..f17dbc3450
 +}
 +
 +#include <support/test-driver.c>
+diff --git a/resolv/tst-resolv-qtypes.c b/resolv/tst-resolv-qtypes.c
+index dcb39e505e..da3325f80c 100644
+--- a/resolv/tst-resolv-qtypes.c
++++ b/resolv/tst-resolv-qtypes.c
+@@ -50,7 +50,7 @@ response (const struct resolv_response_context *ctx,
+   resolv_response_close_record (b);
+ }
+ 
+-static const const char *domain = "www.example.com";
++static const char domain[] = "www.example.com";
+ 
+ static int
+ wrap_res_query (int type, unsigned char *answer, int answer_length)
+diff --git a/scripts/backport-support.sh b/scripts/backport-support.sh
+new file mode 100644
+index 0000000000..2ece7ce575
+--- /dev/null
++++ b/scripts/backport-support.sh
+@@ -0,0 +1,110 @@
++#!/bin/bash
++# Create a patch which backports the support/ subdirectory.
++# Copyright (C) 2017 Free Software Foundation, Inc.
++# This file is part of the GNU C Library.
++
++# The GNU C Library is free software; you can redistribute it and/or
++# modify it under the terms of the GNU Lesser General Public
++# License as published by the Free Software Foundation; either
++# version 2.1 of the License, or (at your option) any later version.
++
++# The GNU C Library is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++# Lesser General Public License for more details.
++
++# You should have received a copy of the GNU Lesser General Public
++# License along with the GNU C Library; if not, see
++# <http://www.gnu.org/licenses/>.
++
++# This script does not backport the Makefile tweaks outside the
++# support/ directory (which need to be backported separately), or the
++# changes to test-skeleton.c (which should not be backported).
++
++set -e
++
++export LC_ALL=C
++export GIT_CONFIG=/dev/null
++export GTT_CONFIG_NOSYSTEM=0
++export GIT_PAGER=
++
++usage () {
++    cat >&2 <<EOF
++usage: $0 {patch|commit}
++EOF
++    exit 1
++}
++
++if test $# -ne 1 ; then
++    usage
++fi
++
++command="$1"
++
++case "$command" in
++    patch|commit)
++    ;;
++    *)
++	usage
++	;;
++esac
++
++# The upstream branch to work on.
++branch=origin/master
++
++# The commit which added the support/ directory.
++initial_commit=c23de0aacbeaa7a091609b35764bed931475a16d
++
++# We backport the support directory and this script.  Directories need
++# to end in a /.
++patch_targets="support/ scripts/backport-support.sh"
++
++latest_commit="$(git log --max-count=1 --pretty=format:%H "$branch" -- \
++  $patch_targets)"
++
++# Simplify the branch name somewhat for reporting.
++branch_name="$(echo "$branch" | sed s,^origin/,,)"
++
++command_patch () {
++    cat <<EOF
++This patch creates the contents of the support/ directory up to this
++upstream commit on the $branch_name branch:
++
++EOF
++    git log --max-count=1 "$latest_commit"
++    echo
++    git diff "$initial_commit"^.."$latest_commit" $patch_targets
++    echo "# Before applying the patch, run this command:" >&2
++    echo "# rm -rf $patch_targets" >&2
++}
++
++command_commit () {
++    git status --porcelain | while read line ; do
++	echo "error: working copy is not clean, cannot commit" >&2
++	exit 1
++    done
++    for path in $patch_targets; do
++	echo "# Processing $path" >&2
++	case "$path" in
++	    [a-zA-Z0-9]*/)
++		# Directory.
++		git rm --cached --ignore-unmatch -r "$path"
++		rm -rf "$path"
++		git read-tree --prefix="$path" "$latest_commit":"$path"
++		git checkout "$path"
++		;;
++	    *)
++		# File.
++		git show "$latest_commit":"$path" > "$path"
++		git add "$path"
++	esac
++    done
++    git commit -m "Synchronize support/ infrastructure with $branch_name
++
++This commit updates the support/ subdirectory to
++commit $latest_commit
++on the $branch_name branch.
++"
++}
++
++command_$command
 diff --git a/stdlib/getentropy.c b/stdlib/getentropy.c
 index a71d4cd8f5..a88bbf8de3 100644
 --- a/stdlib/getentropy.c
@@ -2461,77 +3786,686 @@ index a71d4cd8f5..a88bbf8de3 100644
  getentropy (void *buffer, size_t length)
  {
    __set_errno (ENOSYS);
-diff --git a/string/test-memchr.c b/string/test-memchr.c
-index d62889ff8f..6431605c7e 100644
---- a/string/test-memchr.c
-+++ b/string/test-memchr.c
-@@ -208,6 +208,12 @@ test_main (void)
-       do_test (0, i, i + 1, i + 1, 0);
+diff --git a/string/stratcliff.c b/string/stratcliff.c
+index e672644888..2cd8686082 100644
+--- a/string/stratcliff.c
++++ b/string/stratcliff.c
+@@ -58,8 +58,8 @@
+ static int
+ do_test (void)
+ {
+-  int size = sysconf (_SC_PAGESIZE);
+-  int nchars = size / sizeof (CHAR);
++  size_t size = sysconf (_SC_PAGESIZE);
++  size_t nchars = size / sizeof (CHAR);
+   CHAR *adr;
+   CHAR *dest;
+   int result = 0;
+@@ -80,7 +80,17 @@ do_test (void)
      }
- 
-+  /* BZ#21182 - wrong overflow calculation for i686 implementation
-+     with address near end of the page.  */
-+  for (i = 2; i < 16; ++i)
-+    /* page_size is in fact getpagesize() * 2.  */
-+    do_test (page_size / 2 - i, i, i, 1, 0x9B);
+   else
+     {
+-      int inner, middle, outer;
++      size_t inner, middle, outer, nchars64, max128;
 +
-   do_random_tests ();
-   return ret;
- }
-diff --git a/sunrpc/Makefile b/sunrpc/Makefile
-index 0c1e6124ff..7e5d2955a0 100644
---- a/sunrpc/Makefile
-+++ b/sunrpc/Makefile
-@@ -93,11 +93,12 @@ rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \
- extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs))
- others += rpcgen
- 
--tests = tst-xdrmem tst-xdrmem2 test-rpcent
-+tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error tst-udp-timeout \
-+  tst-udp-nonblocking
- xtests := tst-getmyaddr
- 
- ifeq ($(have-thread-library),yes)
--xtests += thrsvc
-+xtests += thrsvc tst-udp-garbage
- endif
++      if (nchars > 64)
++	nchars64 = nchars - 64;
++      else
++	nchars64 = 0;
++
++      if (nchars > 128)
++	max128 = nchars - 128;
++      else
++	max128 = 0;
  
- ifeq ($(run-built-tests),yes)
-@@ -155,6 +156,7 @@ BUILD_CPPFLAGS += $(sunrpc-CPPFLAGS)
- $(objpfx)tst-getmyaddr: $(common-objpfx)linkobj/libc.so
- $(objpfx)tst-xdrmem: $(common-objpfx)linkobj/libc.so
- $(objpfx)tst-xdrmem2: $(common-objpfx)linkobj/libc.so
-+$(objpfx)tst-udp-error: $(common-objpfx)linkobj/libc.so
+       mprotect (adr, size, PROT_NONE);
+       mprotect (adr + 2 * nchars, size, PROT_NONE);
+@@ -93,59 +103,65 @@ do_test (void)
+       MEMSET (adr, L('T'), nchars);
  
- $(objpfx)rpcgen: $(addprefix $(objpfx),$(rpcgen-objs))
+       /* strlen/wcslen test */
+-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
++      for (outer = nchars - 1; outer >= max128; --outer)
+ 	{
+-	  for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner)
++	  for (inner = MAX (outer, nchars64); inner < nchars; ++inner)
+ 	    {
+ 	      adr[inner] = L('\0');
  
-@@ -234,3 +236,8 @@ $(rpcgen-tests): $(objpfx)%.out: %.x $(objpfx)rpcgen
- 	$(built-program-cmd) -c $< -o $@; \
- 	$(evaluate-test)
- endif
-+
-+$(objpfx)tst-udp-timeout: $(common-objpfx)linkobj/libc.so
-+$(objpfx)tst-udp-nonblocking: $(common-objpfx)linkobj/libc.so
-+$(objpfx)tst-udp-garbage: \
-+  $(common-objpfx)linkobj/libc.so $(shared-thread-library)
-diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c
-index 4d9acb1e6a..6ce16eb298 100644
---- a/sunrpc/clnt_udp.c
-+++ b/sunrpc/clnt_udp.c
-@@ -55,6 +55,7 @@
- #endif
+ 	      if (STRLEN (&adr[outer]) != (size_t) (inner - outer))
+ 		{
+-		  printf ("%s flunked for outer = %d, inner = %d\n",
++		  printf ("%s flunked for outer = %zu, inner = %zu\n",
+ 			  STRINGIFY (STRLEN), outer, inner);
+ 		  result = 1;
+ 		}
  
- #include <kernel-features.h>
-+#include <inet/net-internal.h>
+ 	      adr[inner] = L('T');
+ 	    }
++	  if (outer == 0)
++	    break;
+ 	}
  
- extern u_long _create_xid (void);
+       /* strnlen/wcsnlen test */
+-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
++      for (outer = nchars; outer >= max128; --outer)
+ 	{
+-	  for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner)
++	  for (inner = MAX (outer, nchars64); inner < nchars; ++inner)
+ 	    {
+ 	      adr[inner] = L('\0');
  
-@@ -80,7 +81,9 @@ static const struct clnt_ops udp_ops =
- };
+ 	      if (STRNLEN (&adr[outer], inner - outer + 1)
+ 		  != (size_t) (inner - outer))
+ 		{
+-		  printf ("%s flunked for outer = %d, inner = %d\n",
++		  printf ("%s flunked for outer = %zu, inner = %zu\n",
+ 			  STRINGIFY (STRNLEN), outer, inner);
+ 		  result = 1;
+ 		}
  
- /*
-- * Private data kept per client handle
-+ * Private data kept per client handle.  This private struct is
+ 	      adr[inner] = L('T');
+ 	    }
++	  if (outer == 0)
++	    break;
+ 	}
+-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
++      for (outer = nchars; outer >= max128; --outer)
+ 	{
+-	  for (inner = MAX (outer, nchars - 64); inner <= nchars; ++inner)
++	  for (inner = MAX (outer, nchars64); inner <= nchars; ++inner)
+ 	    {
+ 	      if (STRNLEN (&adr[outer], inner - outer)
+ 		  != (size_t) (inner - outer))
+ 		{
+-		  printf ("%s flunked bounded for outer = %d, inner = %d\n",
++		  printf ("%s flunked bounded for outer = %zu, inner = %zu\n",
+ 			  STRINGIFY (STRNLEN), outer, inner);
+ 		  result = 1;
+ 		}
+ 	    }
++	  if (outer == 0)
++	    break;
+ 	}
+ 
+       /* strchr/wcschr test */
+-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
++      for (outer = nchars - 1; outer >= max128; --outer)
+ 	{
+-	  for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle)
++	  for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
+ 	    {
+ 	      for (inner = middle; inner < nchars; ++inner)
+ 		{
+@@ -158,8 +174,8 @@ do_test (void)
+ 		      || (inner != middle
+ 			  && (cp - &adr[outer]) != middle - outer))
+ 		    {
+-		      printf ("%s flunked for outer = %d, middle = %d, "
+-			      "inner = %d\n",
++		      printf ("%s flunked for outer = %zu, middle = %zu, "
++			      "inner = %zu\n",
+ 			      STRINGIFY (STRCHR), outer, middle, inner);
+ 		      result = 1;
+ 		    }
+@@ -168,6 +184,8 @@ do_test (void)
+ 		  adr[middle] = L('T');
+ 		}
+ 	    }
++	  if (outer == 0)
++	    break;
+ 	}
+ 
+       /* Special test.  */
+@@ -180,9 +198,9 @@ do_test (void)
+ 	}
+ 
+       /* strrchr/wcsrchr test */
+-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
++      for (outer = nchars - 1; outer >= max128; --outer)
+ 	{
+-	  for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle)
++	  for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
+ 	    {
+ 	      for (inner = middle; inner < nchars; ++inner)
+ 		{
+@@ -195,8 +213,8 @@ do_test (void)
+ 		      || (inner != middle
+ 			  && (cp - &adr[outer]) != middle - outer))
+ 		    {
+-		      printf ("%s flunked for outer = %d, middle = %d, "
+-			      "inner = %d\n",
++		      printf ("%s flunked for outer = %zu, middle = %zu, "
++			      "inner = %zu\n",
+ 			      STRINGIFY (STRRCHR), outer, middle, inner);
+ 		      result = 1;
+ 		    }
+@@ -205,12 +223,14 @@ do_test (void)
+ 		  adr[middle] = L('T');
+ 		}
+ 	    }
++	  if (outer == 0)
++	    break;
+ 	}
+ 
+       /* memchr test */
+-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
++      for (outer = nchars - 1; outer >= max128; --outer)
+ 	{
+-	  for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle)
++	  for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
+ 	    {
+ 	      adr[middle] = L('V');
+ 
+@@ -218,32 +238,36 @@ do_test (void)
+ 
+ 	      if (cp - &adr[outer] != middle - outer)
+ 		{
+-		  printf ("%s flunked for outer = %d, middle = %d\n",
++		  printf ("%s flunked for outer = %zu, middle = %zu\n",
+ 			  STRINGIFY (MEMCHR), outer, middle);
+ 		  result = 1;
+ 		}
+ 
+ 	      adr[middle] = L('T');
+ 	    }
++	  if (outer == 0)
++	    break;
+ 	}
+-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
++      for (outer = nchars; outer >= max128; --outer)
+ 	{
+ 	  CHAR *cp = MEMCHR (&adr[outer], L('V'), nchars - outer);
+ 
+ 	  if (cp != NULL)
+ 	    {
+-	      printf ("%s flunked for outer = %d\n",
++	      printf ("%s flunked for outer = %zu\n",
+ 		      STRINGIFY (MEMCHR), outer);
+ 	      result = 1;
+ 	    }
++	  if (outer == 0)
++	    break;
+ 	}
+ 
+       /* These functions only exist for single-byte characters.  */
+ #ifndef WCSTEST
+       /* rawmemchr test */
+-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
++      for (outer = nchars - 1; outer >= max128; --outer)
+ 	{
+-	  for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle)
++	  for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
+ 	    {
+ 	      adr[middle] = L('V');
+ 
+@@ -251,19 +275,21 @@ do_test (void)
+ 
+ 	      if (cp - &adr[outer] != middle - outer)
+ 		{
+-		  printf ("%s flunked for outer = %d, middle = %d\n",
++		  printf ("%s flunked for outer = %zu, middle = %zu\n",
+ 			  STRINGIFY (rawmemchr), outer, middle);
+ 		  result = 1;
+ 		}
+ 
+ 	      adr[middle] = L('T');
+ 	    }
++	  if (outer == 0)
++	    break;
+ 	}
+ 
+       /* memrchr test */
+-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
++      for (outer = nchars - 1; outer >= max128; --outer)
+ 	{
+-	  for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle)
++	  for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
+ 	    {
+ 	      adr[middle] = L('V');
+ 
+@@ -271,44 +297,50 @@ do_test (void)
+ 
+ 	      if (cp - &adr[outer] != middle - outer)
+ 		{
+-		  printf ("%s flunked for outer = %d, middle = %d\n",
++		  printf ("%s flunked for outer = %zu, middle = %zu\n",
+ 			  STRINGIFY (memrchr), outer, middle);
+ 		  result = 1;
+ 		}
+ 
+ 	      adr[middle] = L('T');
+ 	    }
++	  if (outer == 0)
++	    break;
+ 	}
+-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
++      for (outer = nchars; outer >= max128; --outer)
+ 	{
+ 	  CHAR *cp = memrchr (&adr[outer], L('V'), nchars - outer);
+ 
+ 	  if (cp != NULL)
+ 	    {
+-	      printf ("%s flunked for outer = %d\n",
++	      printf ("%s flunked for outer = %zu\n",
+ 		      STRINGIFY (memrchr), outer);
+ 	      result = 1;
+ 	    }
++	  if (outer == 0)
++	    break;
+ 	}
+ #endif
+ 
+       /* strcpy/wcscpy test */
+-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
++      for (outer = nchars - 1; outer >= max128; --outer)
+ 	{
+-	  for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner)
++	  for (inner = MAX (outer, nchars64); inner < nchars; ++inner)
+ 	    {
+ 	      adr[inner] = L('\0');
+ 
+ 	      if (STRCPY (dest, &adr[outer]) != dest
+ 		  || STRLEN (dest) != (size_t) (inner - outer))
+ 		{
+-		  printf ("%s flunked for outer = %d, inner = %d\n",
++		  printf ("%s flunked for outer = %zu, inner = %zu\n",
+ 			  STRINGIFY (STRCPY), outer, inner);
+ 		  result = 1;
+ 		}
+ 
+ 	      adr[inner] = L('T');
+ 	    }
++	  if (outer == 0)
++	    break;
+ 	}
+ 
+       /* strcmp/wcscmp tests */
+@@ -322,14 +354,14 @@ do_test (void)
+ 
+ 	    if (STRCMP (adr + middle, dest + nchars - outer) <= 0)
+ 	      {
+-		printf ("%s 1 flunked for outer = %d, middle = %d\n",
++		printf ("%s 1 flunked for outer = %zu, middle = %zu\n",
+ 			STRINGIFY (STRCMP), outer, middle);
+ 		result = 1;
+ 	      }
+ 
+ 	    if (STRCMP (dest + nchars - outer, adr + middle) >= 0)
+ 	      {
+-		printf ("%s 2 flunked for outer = %d, middle = %d\n",
++		printf ("%s 2 flunked for outer = %zu, middle = %zu\n",
+ 			STRINGIFY (STRCMP), outer, middle);
+ 		result = 1;
+ 	      }
+@@ -348,16 +380,16 @@ do_test (void)
+ 	      {
+ 		if (STRNCMP (adr + middle, dest + nchars - outer, inner) != 0)
+ 		  {
+-		    printf ("%s 1 flunked for outer = %d, middle = %d, "
+-			    "inner = %d\n",
++		    printf ("%s 1 flunked for outer = %zu, middle = %zu, "
++			    "inner = %zu\n",
+ 			    STRINGIFY (STRNCMP), outer, middle, inner);
+ 		    result = 1;
+ 		  }
+ 
+ 		if (STRNCMP (dest + nchars - outer, adr + middle, inner) != 0)
+ 		  {
+-		    printf ("%s 2 flunked for outer = %d, middle = %d, "
+-			    "inner = %d\n",
++		    printf ("%s 2 flunked for outer = %zu, middle = %zu, "
++			    "inner = %zu\n",
+ 			    STRINGIFY (STRNCMP), outer, middle, inner);
+ 		    result = 1;
+ 		  }
+@@ -365,14 +397,14 @@ do_test (void)
+ 
+ 	    if (STRNCMP (adr + middle, dest + nchars - outer, outer) >= 0)
+ 	      {
+-		printf ("%s 1 flunked for outer = %d, middle = %d, full\n",
++		printf ("%s 1 flunked for outer = %zu, middle = %zu, full\n",
+ 			STRINGIFY (STRNCMP), outer, middle);
+ 		result = 1;
+ 	      }
+ 
+ 	    if (STRNCMP (dest + nchars - outer, adr + middle, outer) <= 0)
+ 	      {
+-		printf ("%s 2 flunked for outer = %d, middle = %d, full\n",
++		printf ("%s 2 flunked for outer = %zu, middle = %zu, full\n",
+ 			STRINGIFY (STRNCMP), outer, middle);
+ 		result = 1;
+ 	      }
+@@ -380,7 +412,7 @@ do_test (void)
+ 
+       /* strncpy/wcsncpy tests */
+       adr[nchars - 1] = L('T');
+-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
++      for (outer = nchars; outer >= max128; --outer)
+ 	{
+ 	  size_t len;
+ 
+@@ -389,17 +421,19 @@ do_test (void)
+ 	      if (STRNCPY (dest, &adr[outer], len) != dest
+ 		  || MEMCMP (dest, &adr[outer], len) != 0)
+ 		{
+-		  printf ("outer %s flunked for outer = %d, len = %Zd\n",
++		  printf ("outer %s flunked for outer = %zu, len = %zu\n",
+ 			  STRINGIFY (STRNCPY), outer, len);
+ 		  result = 1;
+ 		}
+ 	    }
++	  if (outer == 0)
++	    break;
+ 	}
+       adr[nchars - 1] = L('\0');
+ 
+-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
++      for (outer = nchars - 1; outer >= max128; --outer)
+ 	{
+-	  for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner)
++	  for (inner = MAX (outer, nchars64); inner < nchars; ++inner)
+ 	    {
+ 	      size_t len;
+ 
+@@ -413,8 +447,8 @@ do_test (void)
+ 		      || (inner - outer < len
+ 			  && STRLEN (dest) != (inner - outer)))
+ 		    {
+-		      printf ("%s flunked for outer = %d, inner = %d, "
+-			      "len = %Zd\n",
++		      printf ("%s flunked for outer = %zu, inner = %zu, "
++			      "len = %zu\n",
+ 			      STRINGIFY (STRNCPY), outer, inner, len);
+ 		      result = 1;
+ 		    }
+@@ -424,8 +458,8 @@ do_test (void)
+ 		      || (inner - outer < len
+ 			  && STRLEN (dest + 1) != (inner - outer)))
+ 		    {
+-		      printf ("%s+1 flunked for outer = %d, inner = %d, "
+-			      "len = %Zd\n",
++		      printf ("%s+1 flunked for outer = %zu, inner = %zu, "
++			      "len = %zu\n",
+ 			      STRINGIFY (STRNCPY), outer, inner, len);
+ 		      result = 1;
+ 		    }
+@@ -433,29 +467,33 @@ do_test (void)
+ 
+ 	      adr[inner] = L('T');
+ 	    }
++	  if (outer == 0)
++	    break;
+ 	}
+ 
+       /* stpcpy/wcpcpy test */
+-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
++      for (outer = nchars - 1; outer >= max128; --outer)
+ 	{
+-	  for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner)
++	  for (inner = MAX (outer, nchars64); inner < nchars; ++inner)
+ 	    {
+ 	      adr[inner] = L('\0');
+ 
+ 	      if ((STPCPY (dest, &adr[outer]) - dest) != inner - outer)
+ 		{
+-		  printf ("%s flunked for outer = %d, inner = %d\n",
++		  printf ("%s flunked for outer = %zu, inner = %zu\n",
+ 			  STRINGIFY (STPCPY), outer, inner);
+ 		  result = 1;
+ 		}
+ 
+ 	      adr[inner] = L('T');
+ 	    }
++	  if (outer == 0)
++	    break;
+ 	}
+ 
+       /* stpncpy/wcpncpy test */
+       adr[nchars - 1] = L('T');
+-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
++      for (outer = nchars; outer >= max128; --outer)
+ 	{
+ 	  size_t len;
+ 
+@@ -464,17 +502,19 @@ do_test (void)
+ 	      if (STPNCPY (dest, &adr[outer], len) != dest + len
+ 		  || MEMCMP (dest, &adr[outer], len) != 0)
+ 		{
+-		  printf ("outer %s flunked for outer = %d, len = %Zd\n",
++		  printf ("outer %s flunked for outer = %zu, len = %zu\n",
+ 			  STRINGIFY (STPNCPY), outer, len);
+ 		  result = 1;
+ 		}
+ 	    }
++	  if (outer == 0)
++	    break;
+ 	}
+       adr[nchars - 1] = L('\0');
+ 
+-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
++      for (outer = nchars - 1; outer >= max128; --outer)
+ 	{
+-	  for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle)
++	  for (middle = MAX (outer, nchars64); middle < nchars; ++middle)
+ 	    {
+ 	      adr[middle] = L('\0');
+ 
+@@ -483,8 +523,8 @@ do_test (void)
+ 		  if ((STPNCPY (dest, &adr[outer], inner) - dest)
+ 		      != MIN (inner, middle - outer))
+ 		    {
+-		      printf ("%s flunked for outer = %d, middle = %d, "
+-			      "inner = %d\n",
++		      printf ("%s flunked for outer = %zu, middle = %zu, "
++			      "inner = %zu\n",
+ 			      STRINGIFY (STPNCPY), outer, middle, inner);
+ 		      result = 1;
+ 		    }
+@@ -492,66 +532,84 @@ do_test (void)
+ 
+ 	      adr[middle] = L('T');
+ 	    }
++	  if (outer == 0)
++	    break;
+ 	}
+ 
+       /* memcpy/wmemcpy test */
+-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
+-	for (inner = 0; inner < nchars - outer; ++inner)
+-	  if (MEMCPY (dest, &adr[outer], inner) !=  dest)
+-	    {
+-	      printf ("%s flunked for outer = %d, inner = %d\n",
+-		      STRINGIFY (MEMCPY), outer, inner);
+-	      result = 1;
+-	    }
++      for (outer = nchars; outer >= max128; --outer)
++	{
++	  for (inner = 0; inner < nchars - outer; ++inner)
++	    if (MEMCPY (dest, &adr[outer], inner) !=  dest)
++	      {
++		printf ("%s flunked for outer = %zu, inner = %zu\n",
++			STRINGIFY (MEMCPY), outer, inner);
++		result = 1;
++	      }
++	  if (outer == 0)
++	    break;
++	}
+ 
+       /* mempcpy/wmempcpy test */
+-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
+-	for (inner = 0; inner < nchars - outer; ++inner)
+-	  if (MEMPCPY (dest, &adr[outer], inner) !=  dest + inner)
+-	    {
+-	      printf ("%s flunked for outer = %d, inner = %d\n",
+-		      STRINGIFY (MEMPCPY), outer, inner);
+-	      result = 1;
+-	    }
++      for (outer = nchars; outer >= max128; --outer)
++	{
++	  for (inner = 0; inner < nchars - outer; ++inner)
++	    if (MEMPCPY (dest, &adr[outer], inner) !=  dest + inner)
++	      {
++		printf ("%s flunked for outer = %zu, inner = %zu\n",
++			STRINGIFY (MEMPCPY), outer, inner);
++		result = 1;
++	      }
++	  if (outer == 0)
++	    break;
++	}
+ 
+       /* This function only exists for single-byte characters.  */
+ #ifndef WCSTEST
+       /* memccpy test */
+       memset (adr, '\0', nchars);
+-      for (outer = nchars; outer >= MAX (0, nchars - 128); --outer)
+-	for (inner = 0; inner < nchars - outer; ++inner)
+-	  if (memccpy (dest, &adr[outer], L('\1'), inner) != NULL)
+-	    {
+-	      printf ("memccpy flunked full copy for outer = %d, inner = %d\n",
+-		      outer, inner);
+-	      result = 1;
+-	    }
+-      for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer)
+-	for (middle = 0; middle < nchars - outer; ++middle)
+-	  {
+-	    memset (dest, L('\2'), middle + 1);
+-	    for (inner = 0; inner < middle; ++inner)
++      for (outer = nchars; outer >= max128; --outer)
++	{
++	  for (inner = 0; inner < nchars - outer; ++inner)
++	    if (memccpy (dest, &adr[outer], L('\1'), inner) != NULL)
+ 	      {
+-		adr[outer + inner] = L('\1');
+-
+-		if (memccpy (dest, &adr[outer], '\1', middle + 128)
+-		    !=  dest + inner + 1)
+-		  {
+-		    printf ("\
+-memccpy flunked partial copy for outer = %d, middle = %d, inner = %d\n",
+-			    outer, middle, inner);
+-		    result = 1;
+-		  }
+-		else if (dest[inner + 1] != L('\2'))
+-		  {
+-		    printf ("\
+-memccpy copied too much for outer = %d, middle = %d, inner = %d\n",
+-			    outer, middle, inner);
+-		    result = 1;
+-		  }
+-		adr[outer + inner] = L('\0');
++		printf ("memccpy flunked full copy for outer = %zu, inner = %zu\n",
++			outer, inner);
++		result = 1;
+ 	      }
+-	  }
++	  if (outer == 0)
++	    break;
++	}
++      for (outer = nchars - 1; outer >= max128; --outer)
++	{
++	  for (middle = 0; middle < nchars - outer; ++middle)
++	    {
++	      memset (dest, L('\2'), middle + 1);
++	      for (inner = 0; inner < middle; ++inner)
++		{
++		  adr[outer + inner] = L('\1');
++
++		  if (memccpy (dest, &adr[outer], '\1', middle + 128)
++		      !=  dest + inner + 1)
++		    {
++		      printf ("\
++			      memccpy flunked partial copy for outer = %zu, middle = %zu, inner = %zu\n",
++			      outer, middle, inner);
++		      result = 1;
++		    }
++		  else if (dest[inner + 1] != L('\2'))
++		    {
++		      printf ("\
++			      memccpy copied too much for outer = %zu, middle = %zu, inner = %zu\n",
++			      outer, middle, inner);
++		      result = 1;
++		    }
++		  adr[outer + inner] = L('\0');
++		}
++	    }
++	  if (outer == 0)
++	    break;
++	}
+ #endif
+     }
+ 
+diff --git a/string/test-memchr.c b/string/test-memchr.c
+index d62889ff8f..6431605c7e 100644
+--- a/string/test-memchr.c
++++ b/string/test-memchr.c
+@@ -208,6 +208,12 @@ test_main (void)
+       do_test (0, i, i + 1, i + 1, 0);
+     }
+ 
++  /* BZ#21182 - wrong overflow calculation for i686 implementation
++     with address near end of the page.  */
++  for (i = 2; i < 16; ++i)
++    /* page_size is in fact getpagesize() * 2.  */
++    do_test (page_size / 2 - i, i, i, 1, 0x9B);
++
+   do_random_tests ();
+   return ret;
+ }
+diff --git a/sunrpc/Makefile b/sunrpc/Makefile
+index 0c1e6124ff..7e5d2955a0 100644
+--- a/sunrpc/Makefile
++++ b/sunrpc/Makefile
+@@ -93,11 +93,12 @@ rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \
+ extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs))
+ others += rpcgen
+ 
+-tests = tst-xdrmem tst-xdrmem2 test-rpcent
++tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error tst-udp-timeout \
++  tst-udp-nonblocking
+ xtests := tst-getmyaddr
+ 
+ ifeq ($(have-thread-library),yes)
+-xtests += thrsvc
++xtests += thrsvc tst-udp-garbage
+ endif
+ 
+ ifeq ($(run-built-tests),yes)
+@@ -155,6 +156,7 @@ BUILD_CPPFLAGS += $(sunrpc-CPPFLAGS)
+ $(objpfx)tst-getmyaddr: $(common-objpfx)linkobj/libc.so
+ $(objpfx)tst-xdrmem: $(common-objpfx)linkobj/libc.so
+ $(objpfx)tst-xdrmem2: $(common-objpfx)linkobj/libc.so
++$(objpfx)tst-udp-error: $(common-objpfx)linkobj/libc.so
+ 
+ $(objpfx)rpcgen: $(addprefix $(objpfx),$(rpcgen-objs))
+ 
+@@ -234,3 +236,8 @@ $(rpcgen-tests): $(objpfx)%.out: %.x $(objpfx)rpcgen
+ 	$(built-program-cmd) -c $< -o $@; \
+ 	$(evaluate-test)
+ endif
++
++$(objpfx)tst-udp-timeout: $(common-objpfx)linkobj/libc.so
++$(objpfx)tst-udp-nonblocking: $(common-objpfx)linkobj/libc.so
++$(objpfx)tst-udp-garbage: \
++  $(common-objpfx)linkobj/libc.so $(shared-thread-library)
+diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c
+index 4d9acb1e6a..6ce16eb298 100644
+--- a/sunrpc/clnt_udp.c
++++ b/sunrpc/clnt_udp.c
+@@ -55,6 +55,7 @@
+ #endif
+ 
+ #include <kernel-features.h>
++#include <inet/net-internal.h>
+ 
+ extern u_long _create_xid (void);
+ 
+@@ -80,7 +81,9 @@ static const struct clnt_ops udp_ops =
+ };
+ 
+ /*
+- * Private data kept per client handle
++ * Private data kept per client handle.  This private struct is
 + * unfortunately part of the ABI; ypbind contains a copy of it and
 + * accesses it through CLIENT::cl_private field.
   */
@@ -3647,28 +5581,302 @@ index 0000000000..db9943a03e
 +/* The minimum run time is around 17 seconds.  */
 +#define TIMEOUT 25
 +#include <support/test-driver.c>
-diff --git a/support/resolv_test.c b/support/resolv_test.c
-index 2d0ea3c17c..6b3554f1ce 100644
---- a/support/resolv_test.c
-+++ b/support/resolv_test.c
-@@ -428,6 +428,7 @@ struct query_info
-   char qname[MAXDNAME];
-   uint16_t qclass;
-   uint16_t qtype;
-+  struct resolv_edns_info edns;
- };
+diff --git a/support/Makefile b/support/Makefile
+index 2ace559ae0..027a663000 100644
+--- a/support/Makefile
++++ b/support/Makefile
+@@ -35,7 +35,12 @@ libsupport-routines = \
+   oom_error \
+   resolv_test \
+   set_fortify_handler \
++  support-xstat \
+   support_become_root \
++  support_can_chroot \
++  support_capture_subprocess \
++  support_capture_subprocess_check \
++  support_chroot \
+   support_enter_network_namespace \
+   support_format_address_family \
+   support_format_addrinfo \
+@@ -43,17 +48,25 @@ libsupport-routines = \
+   support_format_herrno \
+   support_format_hostent \
+   support_format_netent \
++  support_isolate_in_subprocess \
+   support_record_failure \
+   support_run_diff \
++  support_shared_allocate \
++  support_write_file_string \
+   support_test_main \
+   support_test_verify_impl \
+   temp_file \
+   write_message \
+   xaccept \
++  xaccept4 \
+   xasprintf \
+   xbind \
+   xcalloc \
++  xchroot \
++  xclose \
+   xconnect \
++  xdlfcn \
++  xdup2 \
+   xfclose \
+   xfopen \
+   xfork \
+@@ -61,13 +74,18 @@ libsupport-routines = \
+   xlisten \
+   xmalloc \
+   xmemstream \
++  xmkdir \
+   xmmap \
++  xmprotect \
+   xmunmap \
++  xopen \
++  xpipe \
+   xpoll \
+   xpthread_attr_destroy \
+   xpthread_attr_init \
+   xpthread_attr_setdetachstate \
+   xpthread_attr_setstacksize \
++  xpthread_attr_setguardsize \
+   xpthread_barrier_destroy \
+   xpthread_barrier_init \
+   xpthread_barrier_wait \
+@@ -89,6 +107,12 @@ libsupport-routines = \
+   xpthread_mutexattr_setrobust \
+   xpthread_mutexattr_settype \
+   xpthread_once \
++  xpthread_rwlock_init \
++  xpthread_rwlock_rdlock \
++  xpthread_rwlock_wrlock \
++  xpthread_rwlock_unlock \
++  xpthread_rwlockattr_init \
++  xpthread_rwlockattr_setkind_np \
+   xpthread_sigmask \
+   xpthread_spin_lock \
+   xpthread_spin_unlock \
+@@ -111,6 +135,8 @@ endif
+ tests = \
+   README-testing \
+   tst-support-namespace \
++  tst-support_capture_subprocess \
++  tst-support_format_dns_packet \
+   tst-support_record_failure \
  
- /* Update *INFO from the specified DNS packet.  */
-@@ -435,10 +436,26 @@ static void
- parse_query (struct query_info *info,
-              const unsigned char *buffer, size_t length)
- {
--  if (length < 12)
-+  HEADER hd;
-+  _Static_assert (sizeof (hd) == 12, "DNS header size");
-+  if (length < sizeof (hd))
-     FAIL_EXIT1 ("malformed DNS query: too short: %zu bytes", length);
--
+ ifeq ($(run-built-tests),yes)
+@@ -125,4 +151,6 @@ $(objpfx)tst-support_record_failure-2.out: tst-support_record_failure-2.sh \
+ 	$(evaluate-test)
+ endif
+ 
++$(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so
++
+ include ../Rules
+diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h
+new file mode 100644
+index 0000000000..43caf9bce4
+--- /dev/null
++++ b/support/capture_subprocess.h
+@@ -0,0 +1,61 @@
++/* Capture output from a subprocess.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#ifndef SUPPORT_CAPTURE_SUBPROCESS_H
++#define SUPPORT_CAPTURE_SUBPROCESS_H
++
++#include <support/xmemstream.h>
++
++struct support_capture_subprocess
++{
++  struct xmemstream out;
++  struct xmemstream err;
++  int status;
++};
++
++/* Invoke CALLBACK (CLOSURE) in a subprocess and capture standard
++   output, standard error, and the exit status.  The out.buffer and
++   err.buffer members in the result are null-terminated strings which
++   can be examined by the caller (out.out and err.out are NULL).  */
++struct support_capture_subprocess support_capture_subprocess
++  (void (*callback) (void *), void *closure);
++
++/* Deallocate the subprocess data captured by
++   support_capture_subprocess.  */
++void support_capture_subprocess_free (struct support_capture_subprocess *);
++
++enum support_capture_allow
++{
++  /* No output is allowed.  */
++  sc_allow_none = 0x01,
++  /* Output to stdout is permitted.  */
++  sc_allow_stdout = 0x02,
++  /* Output to standard error is permitted.  */
++  sc_allow_stderr = 0x04,
++};
++
++/* Check that the subprocess exited with STATUS and that only the
++   allowed outputs happened.  ALLOWED is a combination of
++   support_capture_allow flags.  Report errors under the CONTEXT
++   message.  */
++void support_capture_subprocess_check (struct support_capture_subprocess *,
++                                       const char *context, int status,
++                                       int allowed)
++  __attribute__ ((nonnull (1, 2)));
++
++#endif /* SUPPORT_CAPTURE_SUBPROCESS_H */
+diff --git a/support/check.h b/support/check.h
+index 1d244a3557..bdcd12952a 100644
+--- a/support/check.h
++++ b/support/check.h
+@@ -51,7 +51,7 @@ __BEGIN_DECLS
+     if (expr)                                                   \
+       ;                                                         \
+     else                                                        \
+-      support_test_verify_impl (-1, __FILE__, __LINE__, #expr); \
++      support_test_verify_impl (__FILE__, __LINE__, #expr);     \
+   })
+ 
+ /* Record a test failure and exit if EXPR evaluates to false.  */
+@@ -60,7 +60,8 @@ __BEGIN_DECLS
+     if (expr)                                                   \
+       ;                                                         \
+     else                                                        \
+-      support_test_verify_impl (1, __FILE__, __LINE__, #expr);  \
++      support_test_verify_exit_impl                             \
++        (1, __FILE__, __LINE__, #expr);                         \
+   })
+ 
+ int support_print_failure_impl (const char *file, int line,
+@@ -70,8 +71,11 @@ void support_exit_failure_impl (int exit_status,
+                                 const char *file, int line,
+                                 const char *format, ...)
+   __attribute__ ((noreturn, nonnull (2), format (printf, 4, 5)));
+-void support_test_verify_impl (int status, const char *file, int line,
++void support_test_verify_impl (const char *file, int line,
+                                const char *expr);
++void support_test_verify_exit_impl (int status, const char *file, int line,
++                                    const char *expr)
++  __attribute__ ((noreturn));
+ 
+ /* Record a test failure.  This function returns and does not
+    terminate the process.  The failure counter is stored in a shared
+diff --git a/support/namespace.h b/support/namespace.h
+index 6bc82d619b..9eddb1a0e9 100644
+--- a/support/namespace.h
++++ b/support/namespace.h
+@@ -35,6 +35,13 @@ __BEGIN_DECLS
+    single-threaded processes.  */
+ bool support_become_root (void);
+ 
++/* Return true if this process can perform a chroot operation.  In
++   general, this is only possible if support_become_root has been
++   called.  Note that the actual test is performed in a subprocess,
++   after fork, so that the file system root of the original process is
++   not changed.  */
++bool support_can_chroot (void);
++
+ /* Enter a network namespace (and a UTS namespace if possible) and
+    configure the loopback interface.  Return true if a network
+    namespace could be created.  Print diagnostics to standard output.
+@@ -48,6 +55,48 @@ bool support_enter_network_namespace (void);
+    UTS namespace.  */
+ bool support_in_uts_namespace (void);
+ 
++/* Invoke CALLBACK (CLOSURE) in a subprocess created using fork.
++   Terminate the calling process if the subprocess exits with a
++   non-zero exit status.  */
++void support_isolate_in_subprocess (void (*callback) (void *), void *closure);
++
++/* Describe the setup of a chroot environment, for
++   support_chroot_create below.  */
++struct support_chroot_configuration
++{
++  /* File contents.  The files are not created if the field is
++     NULL.  */
++  const char *resolv_conf;      /* /etc/resolv.conf.  */
++  const char *hosts;            /* /etc/hosts.  */
++  const char *host_conf;        /* /etc/host.conf.  */
++};
++
++/* The result of the creation of a chroot.  */
++struct support_chroot
++{
++  /* Path information.  All these paths are relative to the parent
++     chroot.  */
++
++  /* Path to the chroot directory.  */
++  char *path_chroot;
++
++  /* Paths to files in the chroot.  These are absolute and outside of
++     the chroot.  */
++  char *path_resolv_conf;       /* /etc/resolv.conf.  */
++  char *path_hosts;             /* /etc/hosts.  */
++  char *path_host_conf;         /* /etc/host.conf.  */
++};
++
++/* Create a chroot environment.  The returned data should be freed
++   using support_chroot_free below.  The files will be deleted when
++   the process exits.  This function does not enter the chroot.  */
++struct support_chroot *support_chroot_create
++  (struct support_chroot_configuration);
++
++/* Deallocate the chroot information created by
++   support_chroot_create.  */
++void support_chroot_free (struct support_chroot *);
++
+ __END_DECLS
+ 
+ #endif
+diff --git a/support/resolv_test.c b/support/resolv_test.c
+index 2d0ea3c17c..1625dcf43a 100644
+--- a/support/resolv_test.c
++++ b/support/resolv_test.c
+@@ -32,9 +32,11 @@
+ #include <support/test-driver.h>
+ #include <support/xsocket.h>
+ #include <support/xthread.h>
++#include <support/xunistd.h>
++#include <sys/uio.h>
+ #include <unistd.h>
+ 
+-/* Response builder. */
++/* Response builder.  */
+ 
+ enum
+   {
+@@ -428,6 +430,7 @@ struct query_info
+   char qname[MAXDNAME];
+   uint16_t qclass;
+   uint16_t qtype;
++  struct resolv_edns_info edns;
+ };
+ 
+ /* Update *INFO from the specified DNS packet.  */
+@@ -435,10 +438,26 @@ static void
+ parse_query (struct query_info *info,
+              const unsigned char *buffer, size_t length)
+ {
+-  if (length < 12)
++  HEADER hd;
++  _Static_assert (sizeof (hd) == 12, "DNS header size");
++  if (length < sizeof (hd))
+     FAIL_EXIT1 ("malformed DNS query: too short: %zu bytes", length);
+-
 -  int ret = dn_expand (buffer, buffer + length, buffer + 12,
 +  memcpy (&hd, buffer, sizeof (hd));
 +
@@ -3685,93 +5893,2365 @@ index 2d0ea3c17c..6b3554f1ce 100644
 +    FAIL_EXIT1 ("malformed DNS query: wrong additional count: %d",
 +                (int) ntohs (hd.arcount));
 +
-+  int ret = dn_expand (buffer, buffer + length, buffer + sizeof (hd),
-                        info->qname, sizeof (info->qname));
-   if (ret < 0)
-     FAIL_EXIT1 ("malformed DNS query: cannot uncompress QNAME");
-@@ -456,6 +473,37 @@ parse_query (struct query_info *info,
-   memcpy (&qtype_qclass, buffer + 12 + ret, sizeof (qtype_qclass));
-   info->qclass = ntohs (qtype_qclass.qclass);
-   info->qtype = ntohs (qtype_qclass.qtype);
++  int ret = dn_expand (buffer, buffer + length, buffer + sizeof (hd),
+                        info->qname, sizeof (info->qname));
+   if (ret < 0)
+     FAIL_EXIT1 ("malformed DNS query: cannot uncompress QNAME");
+@@ -456,6 +475,37 @@ parse_query (struct query_info *info,
+   memcpy (&qtype_qclass, buffer + 12 + ret, sizeof (qtype_qclass));
+   info->qclass = ntohs (qtype_qclass.qclass);
+   info->qtype = ntohs (qtype_qclass.qtype);
++
++  memset (&info->edns, 0, sizeof (info->edns));
++  if (ntohs (hd.arcount) > 0)
++    {
++      /* Parse EDNS record.  */
++      struct __attribute__ ((packed, aligned (1)))
++      {
++        uint8_t root;
++        uint16_t rtype;
++        uint16_t payload;
++        uint8_t edns_extended_rcode;
++        uint8_t edns_version;
++        uint16_t flags;
++        uint16_t rdatalen;
++      } rr;
++      _Static_assert (sizeof (rr) == 11, "EDNS record size");
++
++      if (remaining < 4 + sizeof (rr))
++        FAIL_EXIT1 ("mailformed DNS query: no room for EDNS record");
++      memcpy (&rr, buffer + 12 + ret + 4, sizeof (rr));
++      if (rr.root != 0)
++        FAIL_EXIT1 ("malformed DNS query: invalid OPT RNAME: %d\n", rr.root);
++      if (rr.rtype != htons (41))
++        FAIL_EXIT1 ("malformed DNS query: invalid OPT type: %d\n",
++                    ntohs (rr.rtype));
++      info->edns.active = true;
++      info->edns.extended_rcode = rr.edns_extended_rcode;
++      info->edns.version = rr.edns_version;
++      info->edns.flags = ntohs (rr.flags);
++      info->edns.payload_size = ntohs (rr.payload);
++    }
+ }
+ 
+ 
+@@ -585,6 +635,7 @@ server_thread_udp_process_one (struct resolv_test *obj, int server_index)
+       .query_length = length,
+       .server_index = server_index,
+       .tcp = false,
++      .edns = qinfo.edns,
+     };
+   struct resolv_response_builder *b = response_builder_allocate (query, length);
+   obj->config.response_callback
+@@ -820,6 +871,7 @@ server_thread_tcp_client (void *arg)
+           .query_length = query_length,
+           .server_index = closure->server_index,
+           .tcp = true,
++          .edns = qinfo.edns,
+         };
+       struct resolv_response_builder *b = response_builder_allocate
+         (query_buffer, query_length);
+@@ -860,7 +912,7 @@ server_thread_tcp_client (void *arg)
+         break;
+     }
+ 
+-  close (closure->client_socket);
++  xclose (closure->client_socket);
+   free (closure);
+   return NULL;
+ }
+@@ -881,7 +933,7 @@ server_thread_tcp (struct resolv_test *obj, int server_index)
+       if (obj->termination_requested)
+         {
+           xpthread_mutex_unlock (&obj->lock);
+-          close (client_socket);
++          xclose (client_socket);
+           break;
+         }
+       xpthread_mutex_unlock (&obj->lock);
+@@ -941,8 +993,8 @@ make_server_sockets (struct resolv_test_server *server)
+              next local UDP address randomly.  */
+           if (errno == EADDRINUSE)
+             {
+-              close (server->socket_udp);
+-              close (server->socket_tcp);
++              xclose (server->socket_udp);
++              xclose (server->socket_tcp);
+               continue;
+             }
+           FAIL_EXIT1 ("TCP bind: %m");
+@@ -952,6 +1004,29 @@ make_server_sockets (struct resolv_test_server *server)
+     }
+ }
+ 
++/* Like make_server_sockets, but the caller supplies the address to
++   use.  */
++static void
++make_server_sockets_for_address (struct resolv_test_server *server,
++                                 const struct sockaddr *addr)
++{
++  server->socket_udp = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
++  server->socket_tcp = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
++
++  if (addr->sa_family == AF_INET)
++    server->address = *(const struct sockaddr_in *) addr;
++  else
++    /* We cannot store the server address in the socket.  This should
++       not matter if disable_redirect is used.  */
++    server->address = (struct sockaddr_in) { .sin_family = 0, };
++
++  xbind (server->socket_udp,
++         (struct sockaddr *)&server->address, sizeof (server->address));
++  xbind (server->socket_tcp,
++         (struct sockaddr *)&server->address, sizeof (server->address));
++  xlisten (server->socket_tcp, 5);
++}
++
+ /* One-time initialization of NSS.  */
+ static void
+ resolv_redirect_once (void)
+@@ -1012,11 +1087,17 @@ resolv_test_start (struct resolv_redirect_config config)
+     .lock = PTHREAD_MUTEX_INITIALIZER,
+   };
+ 
+-  resolv_test_init ();
++  if (!config.disable_redirect)
++    resolv_test_init ();
+ 
+   /* Create all the servers, to reserve the necessary ports.  */
+   for (int server_index = 0; server_index < config.nscount; ++server_index)
+-    make_server_sockets (obj->servers + server_index);
++    if (config.disable_redirect && config.server_address_overrides != NULL)
++      make_server_sockets_for_address
++        (obj->servers + server_index,
++         config.server_address_overrides[server_index]);
++    else
++      make_server_sockets (obj->servers + server_index);
+ 
+   /* Start server threads.  Disable the server ports, as
+      requested.  */
+@@ -1025,7 +1106,7 @@ resolv_test_start (struct resolv_redirect_config config)
+       struct resolv_test_server *server = obj->servers + server_index;
+       if (config.servers[server_index].disable_udp)
+         {
+-          close (server->socket_udp);
++          xclose (server->socket_udp);
+           server->socket_udp = -1;
+         }
+       else if (!config.single_thread_udp)
+@@ -1033,7 +1114,7 @@ resolv_test_start (struct resolv_redirect_config config)
+                                                   server_thread_udp);
+       if (config.servers[server_index].disable_tcp)
+         {
+-          close (server->socket_tcp);
++          xclose (server->socket_tcp);
+           server->socket_tcp = -1;
+         }
+       else
+@@ -1043,6 +1124,9 @@ resolv_test_start (struct resolv_redirect_config config)
+   if (config.single_thread_udp)
+     start_server_thread_udp_single (obj);
+ 
++  if (config.disable_redirect)
++    return obj;
++
+   int timeout = 1;
+ 
+   /* Initialize libresolv.  */
+@@ -1077,6 +1161,7 @@ resolv_test_start (struct resolv_redirect_config config)
+     }
+   for (int server_index = 0; server_index < config.nscount; ++server_index)
+     {
++      TEST_VERIFY_EXIT (obj->servers[server_index].address.sin_port != 0);
+       _res.nsaddr_list[server_index] = obj->servers[server_index].address;
+       if (test_verbose)
+         {
+@@ -1114,7 +1199,7 @@ resolv_test_end (struct resolv_test *obj)
+           xsendto (sock, "", 1, 0,
+                    (struct sockaddr *) &obj->servers[server_index].address,
+                    sizeof (obj->servers[server_index].address));
+-          close (sock);
++          xclose (sock);
+         }
+       if (!obj->config.servers[server_index].disable_tcp)
+         {
+@@ -1122,7 +1207,7 @@ resolv_test_end (struct resolv_test *obj)
+           xconnect (sock,
+                     (struct sockaddr *) &obj->servers[server_index].address,
+                     sizeof (obj->servers[server_index].address));
+-          close (sock);
++          xclose (sock);
+         }
+     }
+ 
+@@ -1137,12 +1222,12 @@ resolv_test_end (struct resolv_test *obj)
+         {
+           if (!obj->config.single_thread_udp)
+             xpthread_join (obj->servers[server_index].thread_udp);
+-          close (obj->servers[server_index].socket_udp);
++          xclose (obj->servers[server_index].socket_udp);
+         }
+       if (!obj->config.servers[server_index].disable_tcp)
+         {
+           xpthread_join (obj->servers[server_index].thread_tcp);
+-          close (obj->servers[server_index].socket_tcp);
++          xclose (obj->servers[server_index].socket_tcp);
+         }
+     }
+ 
+diff --git a/support/resolv_test.h b/support/resolv_test.h
+index 7a9f1f7ae8..b953dc1200 100644
+--- a/support/resolv_test.h
++++ b/support/resolv_test.h
+@@ -25,6 +25,16 @@
+ 
+ __BEGIN_DECLS
+ 
++/* Information about EDNS properties of a DNS query.  */
++struct resolv_edns_info
++{
++  bool active;
++  uint8_t extended_rcode;
++  uint8_t version;
++  uint16_t flags;
++  uint16_t payload_size;
++};
++
+ /* This struct provides context information when the response callback
+    specified in struct resolv_redirect_config is invoked. */
+ struct resolv_response_context
+@@ -33,6 +43,7 @@ struct resolv_response_context
+   size_t query_length;
+   int server_index;
+   bool tcp;
++  struct resolv_edns_info edns;
+ };
+ 
+ /* This opaque struct is used to construct responses from within the
+@@ -82,6 +93,16 @@ struct resolv_redirect_config
+      may results in more predictable ordering of queries and
+      responses.  */
+   bool single_thread_udp;
++
++  /* Do not rewrite the _res variable or change NSS defaults.  Use
++     server_address_overrides below to tell the testing framework on
++     which addresses to create the servers.  */
++  bool disable_redirect;
++
++  /* Use these addresses for creating the DNS servers.  The array must
++     have ns_count (or resolv_max_test_servers) sockaddr * elements if
++     not NULL.  */
++  const struct sockaddr *const *server_address_overrides;
+ };
+ 
+ /* Configure NSS to use, nss_dns only for aplicable databases, and try
+diff --git a/support/support-xstat.c b/support/support-xstat.c
+new file mode 100644
+index 0000000000..86a81ec601
+--- /dev/null
++++ b/support/support-xstat.c
+@@ -0,0 +1,30 @@
++/* stat64 with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++/* NB: Non-standard file name to avoid sysdeps override for xstat.  */
++
++#include <support/check.h>
++#include <support/xunistd.h>
++#include <sys/stat.h>
++
++void
++xstat (const char *path, struct stat64 *result)
++{
++  if (stat64 (path, result) != 0)
++    FAIL_EXIT1 ("stat64 (\"%s\"): %m", path);
++}
+diff --git a/support/support.h b/support/support.h
+index 7292e2a564..4b5f04c2cc 100644
+--- a/support/support.h
++++ b/support/support.h
+@@ -44,6 +44,21 @@ void set_fortify_handler (void (*handler) (int sig));
+ void oom_error (const char *function, size_t size)
+   __attribute__ ((nonnull (1)));
+ 
++/* Return a pointer to a memory region of SIZE bytes.  The memory is
++   initialized to zero and will be shared with subprocesses (across
++   fork).  The returned pointer must be freed using
++   support_shared_free; it is not compatible with the malloc
++   functions.  */
++void *support_shared_allocate (size_t size);
++
++/* Deallocate a pointer returned by support_shared_allocate.  */
++void support_shared_free (void *);
++
++/* Write CONTENTS to the file PATH.  Create or truncate the file as
++   needed.  The file mode is 0666 masked by the umask.  Terminate the
++   process on error.  */
++void support_write_file_string (const char *path, const char *contents);
++
+ /* Error-checking wrapper functions which terminate the process on
+    error.  */
+ 
+diff --git a/support/support_can_chroot.c b/support/support_can_chroot.c
+new file mode 100644
+index 0000000000..0dfd2deb54
+--- /dev/null
++++ b/support/support_can_chroot.c
+@@ -0,0 +1,65 @@
++/* Return true if the process can perform a chroot operation.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <errno.h>
++#include <stdio.h>
++#include <support/check.h>
++#include <support/namespace.h>
++#include <support/support.h>
++#include <sys/stat.h>
++#include <unistd.h>
++#include <xunistd.h>
++
++static void
++callback (void *closure)
++{
++  int *result = closure;
++  struct stat64 before;
++  xstat ("/dev", &before);
++  if (chroot ("/dev") != 0)
++    {
++      *result = errno;
++      return;
++    }
++  struct stat64 after;
++  xstat ("/", &after);
++  TEST_VERIFY (before.st_dev == after.st_dev);
++  TEST_VERIFY (before.st_ino == after.st_ino);
++  *result = 0;
++}
++
++bool
++support_can_chroot (void)
++{
++  int *result = support_shared_allocate (sizeof (*result));
++  *result = 0;
++  support_isolate_in_subprocess (callback, result);
++  bool ok = *result == 0;
++  if (!ok)
++    {
++      static bool already_warned;
++      if (!already_warned)
++        {
++          already_warned = true;
++          errno = *result;
++          printf ("warning: this process does not support chroot: %m\n");
++        }
++    }
++  support_shared_free (result);
++  return ok;
++}
+diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
+new file mode 100644
+index 0000000000..030f124252
+--- /dev/null
++++ b/support/support_capture_subprocess.c
+@@ -0,0 +1,108 @@
++/* Capture output from a subprocess.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/capture_subprocess.h>
++
++#include <errno.h>
++#include <stdlib.h>
++#include <support/check.h>
++#include <support/xunistd.h>
++#include <support/xsocket.h>
++
++static void
++transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
++{
++  if (pfd->revents != 0)
++    {
++      char buf[1024];
++      ssize_t ret = TEMP_FAILURE_RETRY (read (pfd->fd, buf, sizeof (buf)));
++      if (ret < 0)
++        {
++          support_record_failure ();
++          printf ("error: reading from subprocess %s: %m", what);
++          pfd->events = 0;
++          pfd->revents = 0;
++        }
++      else if (ret == 0)
++        {
++          /* EOF reached.  Stop listening.  */
++          pfd->events = 0;
++          pfd->revents = 0;
++        }
++      else
++        /* Store the data just read.   */
++        TEST_VERIFY (fwrite (buf, ret, 1, stream->out) == 1);
++    }
++}
++
++struct support_capture_subprocess
++support_capture_subprocess (void (*callback) (void *), void *closure)
++{
++  struct support_capture_subprocess result;
++  xopen_memstream (&result.out);
++  xopen_memstream (&result.err);
++
++  int stdout_pipe[2];
++  xpipe (stdout_pipe);
++  int stderr_pipe[2];
++  xpipe (stderr_pipe);
++
++  TEST_VERIFY (fflush (stdout) == 0);
++  TEST_VERIFY (fflush (stderr) == 0);
++
++  pid_t pid = xfork ();
++  if (pid == 0)
++    {
++      xclose (stdout_pipe[0]);
++      xclose (stderr_pipe[0]);
++      xdup2 (stdout_pipe[1], STDOUT_FILENO);
++      xdup2 (stderr_pipe[1], STDERR_FILENO);
++      callback (closure);
++      _exit (0);
++    }
++  xclose (stdout_pipe[1]);
++  xclose (stderr_pipe[1]);
++
++  struct pollfd fds[2] =
++    {
++      { .fd = stdout_pipe[0], .events = POLLIN },
++      { .fd = stderr_pipe[0], .events = POLLIN },
++    };
++
++  do
++    {
++      xpoll (fds, 2, -1);
++      transfer ("stdout", &fds[0], &result.out);
++      transfer ("stderr", &fds[1], &result.err);
++    }
++  while (fds[0].events != 0 || fds[1].events != 0);
++  xclose (stdout_pipe[0]);
++  xclose (stderr_pipe[0]);
++
++  xfclose_memstream (&result.out);
++  xfclose_memstream (&result.err);
++  xwaitpid (pid, &result.status, 0);
++  return result;
++}
++
++void
++support_capture_subprocess_free (struct support_capture_subprocess *p)
++{
++  free (p->out.buffer);
++  free (p->err.buffer);
++}
+diff --git a/support/support_capture_subprocess_check.c b/support/support_capture_subprocess_check.c
+new file mode 100644
+index 0000000000..e1cf73b6a5
+--- /dev/null
++++ b/support/support_capture_subprocess_check.c
+@@ -0,0 +1,67 @@
++/* Verify capture output from a subprocess.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <stdbool.h>
++#include <stdio.h>
++#include <support/capture_subprocess.h>
++#include <support/check.h>
++
++static void
++print_context (const char *context, bool *failed)
++{
++  if (*failed)
++    /* Do not duplicate message.  */
++    return;
++  support_record_failure ();
++  printf ("error: subprocess failed: %s\n", context);
++}
++
++void
++support_capture_subprocess_check (struct support_capture_subprocess *proc,
++                                  const char *context, int status,
++                                  int allowed)
++{
++  TEST_VERIFY ((allowed & sc_allow_none)
++               || (allowed & sc_allow_stdout)
++               || (allowed & sc_allow_stderr));
++  TEST_VERIFY (!((allowed & sc_allow_none)
++                 && ((allowed & sc_allow_stdout)
++                     || (allowed & sc_allow_stderr))));
++
++  bool failed = false;
++  if (proc->status != status)
++    {
++      print_context (context, &failed);
++      printf ("error:   expected exit status: %d\n", status);
++      printf ("error:   actual exit status:   %d\n", proc->status);
++    }
++  if (!(allowed & sc_allow_stdout) && proc->out.length != 0)
++    {
++      print_context (context, &failed);
++      printf ("error:   unexpected output from subprocess\n");
++      fwrite (proc->out.buffer, proc->out.length, 1, stdout);
++      puts ("\n");
++    }
++  if (!(allowed & sc_allow_stderr) && proc->err.length != 0)
++    {
++      print_context (context, &failed);
++      printf ("error:   unexpected error output from subprocess\n");
++      fwrite (proc->err.buffer, proc->err.length, 1, stdout);
++      puts ("\n");
++    }
++}
+diff --git a/support/support_chroot.c b/support/support_chroot.c
+new file mode 100644
+index 0000000000..f3ef551b05
+--- /dev/null
++++ b/support/support_chroot.c
+@@ -0,0 +1,85 @@
++/* Setup a chroot environment for use within tests.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <stdlib.h>
++#include <support/check.h>
++#include <support/namespace.h>
++#include <support/support.h>
++#include <support/temp_file.h>
++#include <support/test-driver.h>
++#include <support/xunistd.h>
++
++/* If CONTENTS is not NULL, write it to the file at DIRECTORY/RELPATH,
++   and store the name in *ABSPATH.  If CONTENTS is NULL, store NULL in
++   *ABSPATH.  */
++static void
++write_file (const char *directory, const char *relpath, const char *contents,
++            char **abspath)
++{
++  if (contents != NULL)
++    {
++      *abspath = xasprintf ("%s/%s", directory, relpath);
++      add_temp_file (*abspath);
++      support_write_file_string (*abspath, contents);
++    }
++  else
++    *abspath = NULL;
++}
++
++struct support_chroot *
++support_chroot_create (struct support_chroot_configuration conf)
++{
++  struct support_chroot *chroot = xmalloc (sizeof (*chroot));
++
++  chroot->path_chroot = xasprintf ("%s/tst-resolv-res_init-XXXXXX", test_dir);
++  if (mkdtemp (chroot->path_chroot) == NULL)
++    FAIL_EXIT1 ("mkdtemp (\"%s\"): %m", chroot->path_chroot);
++  add_temp_file (chroot->path_chroot);
++
++  /* Create the /etc directory in the chroot environment.  */
++  char *path_etc = xasprintf ("%s/etc", chroot->path_chroot);
++  xmkdir (path_etc, 0777);
++  add_temp_file (path_etc);
++
++  write_file (path_etc, "resolv.conf", conf.resolv_conf,
++              &chroot->path_resolv_conf);
++  write_file (path_etc, "hosts", conf.hosts, &chroot->path_hosts);
++  write_file (path_etc, "host.conf", conf.host_conf, &chroot->path_host_conf);
++
++  free (path_etc);
++
++  /* valgrind needs a temporary directory in the chroot.  */
++  {
++    char *path_tmp = xasprintf ("%s/tmp", chroot->path_chroot);
++    xmkdir (path_tmp, 0777);
++    add_temp_file (path_tmp);
++    free (path_tmp);
++  }
++
++  return chroot;
++}
++
++void
++support_chroot_free (struct support_chroot *chroot)
++{
++  free (chroot->path_chroot);
++  free (chroot->path_resolv_conf);
++  free (chroot->path_hosts);
++  free (chroot->path_host_conf);
++  free (chroot);
++}
+diff --git a/support/support_enter_network_namespace.c b/support/support_enter_network_namespace.c
+index d2e78fe560..28b0ee29cf 100644
+--- a/support/support_enter_network_namespace.c
++++ b/support/support_enter_network_namespace.c
+@@ -23,9 +23,10 @@
+ #include <stdio.h>
+ #include <string.h>
+ #include <support/check.h>
++#include <support/xsocket.h>
++#include <support/xunistd.h>
+ #include <sys/ioctl.h>
+ #include <unistd.h>
+-#include <xsocket.h>
+ 
+ static bool in_uts_namespace;
+ 
+@@ -58,7 +59,7 @@ support_enter_network_namespace (void)
+           req.ifr_flags |= IFF_UP | IFF_RUNNING;
+           TEST_VERIFY_EXIT (ioctl (fd, SIOCSIFFLAGS, &req) == 0);
+         }
+-      close (fd);
++      xclose (fd);
+ 
+       return !already_up;
+     }
+diff --git a/support/support_format_addrinfo.c b/support/support_format_addrinfo.c
+index 262e0df737..eedb030591 100644
+--- a/support/support_format_addrinfo.c
++++ b/support/support_format_addrinfo.c
+@@ -39,8 +39,8 @@ socket_address_length (int family)
+ }
+ 
+ static void
+-format_ai_flags (FILE *out, struct addrinfo *ai, int flag, const char *name,
+-                 int * flags_printed)
++format_ai_flags_1 (FILE *out, struct addrinfo *ai, int flag, const char *name,
++                   int * flags_printed)
+ {
+   if ((ai->ai_flags & flag) != 0)
+     fprintf (out, " %s", name);
+@@ -48,14 +48,16 @@ format_ai_flags (FILE *out, struct addrinfo *ai, int flag, const char *name,
+ }
+ 
+ static void
+-format_ai_one (FILE *out, struct addrinfo *ai, int *flags)
++format_ai_flags (FILE *out, struct addrinfo *ai)
+ {
+-  /* ai_flags */
+-  if (ai->ai_flags != *flags)
++  if (ai == NULL)
++    return;
++
++  if (ai->ai_flags != 0)
+     {
+       fprintf (out, "flags:");
+       int flags_printed = 0;
+-#define FLAG(flag) format_ai_flags (out, ai, flag, #flag, &flags_printed)
++#define FLAG(flag) format_ai_flags_1 (out, ai, flag, #flag, &flags_printed)
+       FLAG (AI_PASSIVE);
+       FLAG (AI_CANONNAME);
+       FLAG (AI_NUMERICHOST);
+@@ -72,9 +74,47 @@ format_ai_one (FILE *out, struct addrinfo *ai, int *flags)
+       if (remaining != 0)
+         fprintf (out, " %08x", remaining);
+       fprintf (out, "\n");
+-      *flags = ai->ai_flags;
+     }
+ 
++  /* Report flag mismatches within the list.  */
++  int flags = ai->ai_flags;
++  int index = 1;
++  ai = ai->ai_next;
++  while (ai != NULL)
++    {
++      if (ai->ai_flags != flags)
++        fprintf (out, "error: flags at %d: 0x%x expected, 0x%x actual\n",
++                 index, flags, ai->ai_flags);
++      ai = ai->ai_next;
++      ++index;
++    }
++}
++
++static void
++format_ai_canonname (FILE *out, struct addrinfo *ai)
++{
++  if (ai == NULL)
++    return;
++  if (ai->ai_canonname != NULL)
++    fprintf (out, "canonname: %s\n", ai->ai_canonname);
++
++  /* Report incorrectly set ai_canonname fields on subsequent list
++     entries.  */
++  int index = 1;
++  ai = ai->ai_next;
++  while (ai != NULL)
++    {
++      if (ai->ai_canonname != NULL)
++        fprintf (out, "error: canonname set at %d: %s\n",
++                 index, ai->ai_canonname);
++      ai = ai->ai_next;
++      ++index;
++    }
++}
++
++static void
++format_ai_one (FILE *out, struct addrinfo *ai)
++{
+   {
+     char type_buf[32];
+     const char *type_str;
+@@ -156,20 +196,16 @@ format_ai_one (FILE *out, struct addrinfo *ai, int *flags)
+     else
+       fprintf (out, " %s %u\n", buf, ntohs (port));
+   }
+-
+-  /* ai_canonname */
+-  if (ai->ai_canonname != NULL)
+-    fprintf (out, "canonname: %s\n", ai->ai_canonname);
+ }
+ 
+ /* Format all the addresses in one address family.  */
+ static void
+-format_ai_family (FILE *out, struct addrinfo *ai, int family, int *flags)
++format_ai_family (FILE *out, struct addrinfo *ai, int family)
+ {
+   while (ai)
+     {
+       if (ai->ai_family == family)
+-        format_ai_one (out, ai, flags);
++        format_ai_one (out, ai);
+       ai = ai->ai_next;
+     }
+ }
+@@ -192,9 +228,10 @@ support_format_addrinfo (struct addrinfo *ai, int ret)
+     }
+   else
+     {
+-      int flags = 0;
+-      format_ai_family (mem.out, ai, AF_INET, &flags);
+-      format_ai_family (mem.out, ai, AF_INET6, &flags);
++      format_ai_flags (mem.out, ai);
++      format_ai_canonname (mem.out, ai);
++      format_ai_family (mem.out, ai, AF_INET);
++      format_ai_family (mem.out, ai, AF_INET6);
+     }
+ 
+   xfclose_memstream (&mem);
+diff --git a/support/support_format_dns_packet.c b/support/support_format_dns_packet.c
+index 21fe7e5c8d..2992c57971 100644
+--- a/support/support_format_dns_packet.c
++++ b/support/support_format_dns_packet.c
+@@ -174,7 +174,7 @@ support_format_dns_packet (const unsigned char *buffer, size_t length)
+           goto out;
+         }
+       /* Skip non-matching record types.  */
+-      if (rtype != qtype || rclass != qclass)
++      if ((rtype != qtype && rtype != T_CNAME) || rclass != qclass)
+         continue;
+       switch (rtype)
+         {
+@@ -186,22 +186,29 @@ support_format_dns_packet (const unsigned char *buffer, size_t length)
+                        rdata.data[2],
+                        rdata.data[3]);
+           else
+-            fprintf (mem.out, "error: A record of size %d: %s\n", rdlen, rname.name);
++            fprintf (mem.out, "error: A record of size %d: %s\n",
++                     rdlen, rname.name);
+           break;
+         case T_AAAA:
+           {
+-            char buf[100];
+-            if (inet_ntop (AF_INET6, rdata.data, buf, sizeof (buf)) == NULL)
+-              fprintf (mem.out, "error: AAAA record decoding failed: %m\n");
++            if (rdlen == 16)
++              {
++                char buf[100];
++                if (inet_ntop (AF_INET6, rdata.data, buf, sizeof (buf)) == NULL)
++                  fprintf (mem.out, "error: AAAA record decoding failed: %m\n");
++                else
++                  fprintf (mem.out, "address: %s\n", buf);
++              }
+             else
+-              fprintf (mem.out, "address: %s\n", buf);
++              fprintf (mem.out, "error: AAAA record of size %d: %s\n",
++                       rdlen, rname.name);
+           }
+           break;
+         case T_CNAME:
+         case T_PTR:
+           {
+             struct dname name;
+-            if (extract_name (full, &in, &name))
++            if (extract_name (full, &rdata, &name))
+               fprintf (mem.out, "name: %s\n", name.name);
+             else
+               fprintf (mem.out, "error: malformed CNAME/PTR record\n");
+diff --git a/support/support_format_hostent.c b/support/support_format_hostent.c
+index 5b5f26082e..88c85ec1f1 100644
+--- a/support/support_format_hostent.c
++++ b/support/support_format_hostent.c
+@@ -19,6 +19,7 @@
+ #include <support/format_nss.h>
+ 
+ #include <arpa/inet.h>
++#include <errno.h>
+ #include <stdio.h>
+ #include <support/support.h>
+ #include <support/xmemstream.h>
+@@ -41,10 +42,15 @@ support_format_hostent (struct hostent *h)
+ {
+   if (h == NULL)
+     {
+-      char *value = support_format_herrno (h_errno);
+-      char *result = xasprintf ("error: %s\n", value);
+-      free (value);
+-      return result;
++      if (h_errno == NETDB_INTERNAL)
++        return xasprintf ("error: NETDB_INTERNAL (errno %d, %m)\n", errno);
++      else
++        {
++          char *value = support_format_herrno (h_errno);
++          char *result = xasprintf ("error: %s\n", value);
++          free (value);
++          return result;
++        }
+     }
+ 
+   struct xmemstream mem;
+diff --git a/support/support_isolate_in_subprocess.c b/support/support_isolate_in_subprocess.c
+new file mode 100644
+index 0000000000..cf48614383
+--- /dev/null
++++ b/support/support_isolate_in_subprocess.c
+@@ -0,0 +1,38 @@
++/* Run a function in a subprocess.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/check.h>
++#include <support/xunistd.h>
++
++void
++support_isolate_in_subprocess (void (*callback) (void *), void *closure)
++{
++  pid_t pid = xfork ();
++  if (pid == 0)
++    {
++      /* Child process.  */
++      callback (closure);
++      _exit (0);
++    }
++
++  /* Parent process.  */
++  int status;
++  xwaitpid (pid, &status, 0);
++  if (status != 0)
++    FAIL_EXIT1 ("child process exited with status %d", status);
++}
+diff --git a/support/support_run_diff.c b/support/support_run_diff.c
+index 3085037a69..f5155de727 100644
+--- a/support/support_run_diff.c
++++ b/support/support_run_diff.c
+@@ -24,8 +24,8 @@
+ #include <support/check.h>
+ #include <support/support.h>
+ #include <support/temp_file.h>
++#include <support/xunistd.h>
+ #include <sys/wait.h>
+-#include <xunistd.h>
+ 
+ static char *
+ write_to_temp_file (const char *prefix, const char *str)
+@@ -36,7 +36,7 @@ write_to_temp_file (const char *prefix, const char *str)
+   TEST_VERIFY_EXIT (fd >= 0);
+   free (template);
+   xwrite (fd, str, strlen (str));
+-  TEST_VERIFY_EXIT (close (fd) == 0);
++  xclose (fd);
+   return name;
+ }
+ 
+diff --git a/support/support_shared_allocate.c b/support/support_shared_allocate.c
+new file mode 100644
+index 0000000000..61d088e8cf
+--- /dev/null
++++ b/support/support_shared_allocate.c
+@@ -0,0 +1,57 @@
++/* Allocate a memory region shared across processes.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <errno.h>
++#include <stddef.h>
++#include <support/support.h>
++#include <support/xunistd.h>
++#include <sys/mman.h>
++
++/* Header for the allocation.  It contains the size of the allocation
++   for subsequent unmapping.  */
++struct header
++{
++  size_t total_size;
++  char data[] __attribute__ ((aligned (__alignof__ (max_align_t))));
++};
++
++void *
++support_shared_allocate (size_t size)
++{
++  size_t total_size = size + offsetof (struct header, data);
++  if (total_size < size)
++    {
++      errno = ENOMEM;
++      oom_error (__func__, size);
++      return NULL;
++    }
++  else
++    {
++      struct header *result = xmmap (NULL, total_size, PROT_READ | PROT_WRITE,
++                                     MAP_ANONYMOUS | MAP_SHARED, -1);
++      result->total_size = total_size;
++      return &result->data;
++    }
++}
++
++void
++support_shared_free (void *data)
++{
++  struct header *header = data - offsetof (struct header, data);
++  xmunmap (header, header->total_size);
++}
+diff --git a/support/support_test_main.c b/support/support_test_main.c
+index 914d64f603..3c411a467b 100644
+--- a/support/support_test_main.c
++++ b/support/support_test_main.c
+@@ -211,7 +211,8 @@ support_test_main (int argc, char **argv, const struct test_config *config)
+         mallopt (M_PERTURB, 42);
+     }
+ 
+-  while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1)
++  while ((opt = getopt_long (argc, argv, config->optstring, options, NULL))
++	 != -1)
+     switch (opt)
+       {
+       case '?':
+diff --git a/support/support_test_verify_impl.c b/support/support_test_verify_impl.c
+index 5bae38f8b1..55ab2111b3 100644
+--- a/support/support_test_verify_impl.c
++++ b/support/support_test_verify_impl.c
+@@ -22,12 +22,16 @@
+ #include <stdlib.h>
+ 
+ void
+-support_test_verify_impl (int status, const char *file, int line,
+-                          const char *expr)
++support_test_verify_impl (const char *file, int line, const char *expr)
+ {
+   support_record_failure ();
+   printf ("error: %s:%d: not true: %s\n", file, line, expr);
+-  if (status >= 0)
+-    exit (status);
++}
+ 
++void
++support_test_verify_exit_impl (int status, const char *file, int line,
++                               const char *expr)
++{
++  support_test_verify_impl (file, line, expr);
++  exit (status);
+ }
+diff --git a/support/support_write_file_string.c b/support/support_write_file_string.c
+new file mode 100644
+index 0000000000..48e89597f3
+--- /dev/null
++++ b/support/support_write_file_string.c
+@@ -0,0 +1,39 @@
++/* Write a string to a file.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <fcntl.h>
++#include <string.h>
++#include <support/check.h>
++#include <xunistd.h>
++
++void
++support_write_file_string (const char *path, const char *contents)
++{
++  int fd = xopen (path, O_CREAT | O_TRUNC | O_WRONLY, 0666);
++  const char *end = contents + strlen (contents);
++  for (const char *p = contents; p < end; )
++    {
++      ssize_t ret = write (fd, p, end - p);
++      if (ret < 0)
++        FAIL_EXIT1 ("cannot write to \"%s\": %m", path);
++      if (ret == 0)
++        FAIL_EXIT1 ("zero-length write to \"%s\"", path);
++      p += ret;
++    }
++  xclose (fd);
++}
+diff --git a/support/temp_file.c b/support/temp_file.c
+index f06647a467..fdb2477ab9 100644
+--- a/support/temp_file.c
++++ b/support/temp_file.c
+@@ -25,16 +25,17 @@
+ #include <support/support.h>
+ 
+ #include <paths.h>
+-#include <search.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <unistd.h>
+ 
+ /* List of temporary files.  */
+ static struct temp_name_list
+ {
+-  struct qelem q;
++  struct temp_name_list *next;
+   char *name;
++  pid_t owner;
+ } *temp_name_list;
+ 
+ /* Location of the temporary files.  Set by the test skeleton via
+@@ -50,10 +51,9 @@ add_temp_file (const char *name)
+   if (newname != NULL)
+     {
+       newp->name = newname;
+-      if (temp_name_list == NULL)
+-	temp_name_list = (struct temp_name_list *) &newp->q;
+-      else
+-	insque (newp, temp_name_list);
++      newp->next = temp_name_list;
++      newp->owner = getpid ();
++      temp_name_list = newp;
+     }
+   else
+     free (newp);
+@@ -97,13 +97,22 @@ support_set_test_dir (const char *path)
+ void
+ support_delete_temp_files (void)
+ {
++  pid_t pid = getpid ();
+   while (temp_name_list != NULL)
+     {
+-      remove (temp_name_list->name);
++      /* Only perform the removal if the path was registed in the same
++	 process, as identified by the PID.  (This assumes that the
++	 parent process which registered the temporary file sticks
++	 around, to prevent PID reuse.)  */
++      if (temp_name_list->owner == pid)
++	{
++	  if (remove (temp_name_list->name) != 0)
++	    printf ("warning: could not remove temporary file: %s: %m\n",
++		    temp_name_list->name);
++	}
+       free (temp_name_list->name);
+ 
+-      struct temp_name_list *next
+-	= (struct temp_name_list *) temp_name_list->q.q_forw;
++      struct temp_name_list *next = temp_name_list->next;
+       free (temp_name_list);
+       temp_name_list = next;
+     }
+@@ -116,9 +125,7 @@ support_print_temp_files (FILE *f)
+     {
+       struct temp_name_list *n;
+       fprintf (f, "temp_files=(\n");
+-      for (n = temp_name_list;
+-           n != NULL;
+-           n = (struct temp_name_list *) n->q.q_forw)
++      for (n = temp_name_list; n != NULL; n = n->next)
+         fprintf (f, "  '%s'\n", n->name);
+       fprintf (f, ")\n");
+     }
+diff --git a/support/test-driver.c b/support/test-driver.c
+index 482066dbeb..47c387c2b4 100644
+--- a/support/test-driver.c
++++ b/support/test-driver.c
+@@ -93,6 +93,10 @@
+    has this type:
+ 
+      void CMDLINE_PROCESS (int);
++
++   If the program also to process custom default short command line
++   argument (similar to getopt) it must define CMDLINE_OPTSTRING
++   with the expected options (for instance "vb").
+ */
+ 
+ #include <support/test-driver.h>
+@@ -151,6 +155,11 @@ main (int argc, char **argv)
+ #ifdef CMDLINE_PROCESS
+   test_config.cmdline_function = CMDLINE_PROCESS;
+ #endif
++#ifdef CMDLINE_OPTSTRING
++  test_config.optstring = "+" CMDLINE_OPTSTRING;
++#else
++  test_config.optstring = "+";
++#endif
+ 
+   return support_test_main (argc, argv, &test_config);
+ }
+diff --git a/support/test-driver.h b/support/test-driver.h
+index af1971a9ca..a8fe9c3565 100644
+--- a/support/test-driver.h
++++ b/support/test-driver.h
+@@ -35,6 +35,7 @@ struct test_config
+   int expected_status;   /* Expected exit status.  */
+   int expected_signal;   /* If non-zero, expect termination by signal.  */
+   char no_mallopt;       /* Boolean flag to disable mallopt.  */
++  const char *optstring; /* Short command line options.  */
+ };
+ 
+ enum
+diff --git a/support/tst-support-namespace.c b/support/tst-support-namespace.c
+index a50b074f5e..dbe7cc07c8 100644
+--- a/support/tst-support-namespace.c
++++ b/support/tst-support-namespace.c
+@@ -16,18 +16,98 @@
+    License along with the GNU C Library; if not, see
+    <http://www.gnu.org/licenses/>.  */
+ 
++#include <errno.h>
++#include <netdb.h>
+ #include <stdio.h>
++#include <support/check.h>
+ #include <support/namespace.h>
++#include <support/xsocket.h>
++#include <support/xunistd.h>
++
++/* Check that the loopback interface provides multiple addresses which
++   can be used to run independent servers.  */
++static void
++test_localhost_bind (void)
++{
++  printf ("info: testing loopback interface with multiple addresses\n");
++
++  /* Create the two server addresses.  */
++  static const struct addrinfo hints =
++    {
++      .ai_family = AF_INET,
++      .ai_socktype = SOCK_DGRAM,
++      .ai_protocol = IPPROTO_UDP,
++    };
++  struct addrinfo *ai[3];
++  TEST_VERIFY_EXIT (getaddrinfo ("127.0.0.1", "53", &hints, ai + 0) == 0);
++  TEST_VERIFY_EXIT (getaddrinfo ("127.0.0.2", "53", &hints, ai + 1) == 0);
++  TEST_VERIFY_EXIT (getaddrinfo ("127.0.0.3", "53", &hints, ai + 2) == 0);
++
++  /* Create the server scokets and bind them to these addresses.  */
++  int sockets[3];
++  for (int i = 0; i < 3; ++i)
++    {
++      sockets[i] = xsocket
++        (ai[i]->ai_family, ai[i]->ai_socktype, ai[i]->ai_protocol);
++      xbind (sockets[i], ai[i]->ai_addr, ai[i]->ai_addrlen);
++    }
++
++  /* Send two packets to each server.  */
++  int client = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
++  for (int i = 0; i < 3; ++i)
++    {
++      TEST_VERIFY (sendto (client, &i, sizeof (i), 0,
++                           ai[i]->ai_addr, ai[i]->ai_addrlen) == sizeof (i));
++      int j = i + 256;
++      TEST_VERIFY (sendto (client, &j, sizeof (j), 0,
++                           ai[i]->ai_addr, ai[i]->ai_addrlen) == sizeof (j));
++    }
++
++  /* Check that the packets can be received with the expected
++     contents.  Note that the receive calls interleave differently,
++     which hopefully proves that the sockets are, indeed,
++     independent.  */
++  for (int i = 0; i < 3; ++i)
++    {
++      int buf;
++      TEST_VERIFY (recv (sockets[i], &buf, sizeof (buf), 0) == sizeof (buf));
++      TEST_VERIFY (buf == i);
++    }
++  for (int i = 0; i < 3; ++i)
++    {
++      int buf;
++      TEST_VERIFY (recv (sockets[i], &buf, sizeof (buf), 0) == sizeof (buf));
++      TEST_VERIFY (buf == i + 256);
++      /* Check that there is no more data to receive.  */
++      TEST_VERIFY (recv (sockets[i], &buf, sizeof (buf), MSG_DONTWAIT) == -1);
++      TEST_VERIFY (errno == EWOULDBLOCK || errno == EAGAIN);
++    }
++
++  /* Close all sockets and free the addresses.  */
++  for (int i = 0; i < 3; ++i)
++    {
++      freeaddrinfo (ai[i]);
++      xclose (sockets[i]);
++    }
++  xclose (client);
++}
++
+ 
+ static int
+ do_test (void)
+ {
+-  if (support_become_root ())
++  bool root = support_become_root ();
++  if (root)
+     printf ("info: acquired root-like privileges\n");
+-  if (support_enter_network_namespace ())
++  bool netns = support_enter_network_namespace ();
++  if (netns)
+     printf ("info: entered network namespace\n");
+   if (support_in_uts_namespace ())
+     printf ("info: also entered UTS namespace\n");
++
++  if (root && netns)
++    test_localhost_bind ();
++
+   return 0;
+ }
+ 
+diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c
+new file mode 100644
+index 0000000000..5672fba0f7
+--- /dev/null
++++ b/support/tst-support_capture_subprocess.c
+@@ -0,0 +1,188 @@
++/* Test capturing output from a subprocess.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <stdbool.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <support/capture_subprocess.h>
++#include <support/check.h>
++#include <support/support.h>
++#include <sys/wait.h>
++#include <unistd.h>
++
++/* Write one byte at *P to FD and advance *P.  Do nothing if *P is
++   '\0'.  */
++static void
++transfer (const unsigned char **p, int fd)
++{
++  if (**p != '\0')
++    {
++      TEST_VERIFY (write (fd, *p, 1) == 1);
++      ++*p;
++    }
++}
++
++/* Determine the order in which stdout and stderr are written.  */
++enum write_mode { out_first, err_first, interleave,
++                  write_mode_last =  interleave };
++
++/* Describe what to write in the subprocess.  */
++struct test
++{
++  char *out;
++  char *err;
++  enum write_mode write_mode;
++  int signal;
++  int status;
++};
++
++/* For use with support_capture_subprocess.  */
++static void
++callback (void *closure)
++{
++  const struct test *test = closure;
++  bool mode_ok = false;
++  switch (test->write_mode)
++    {
++    case out_first:
++      TEST_VERIFY (fputs (test->out, stdout) >= 0);
++      TEST_VERIFY (fflush (stdout) == 0);
++      TEST_VERIFY (fputs (test->err, stderr) >= 0);
++      TEST_VERIFY (fflush (stderr) == 0);
++      mode_ok = true;
++      break;
++    case err_first:
++      TEST_VERIFY (fputs (test->err, stderr) >= 0);
++      TEST_VERIFY (fflush (stderr) == 0);
++      TEST_VERIFY (fputs (test->out, stdout) >= 0);
++      TEST_VERIFY (fflush (stdout) == 0);
++      mode_ok = true;
++      break;
++    case interleave:
++      {
++        const unsigned char *pout = (const unsigned char *) test->out;
++        const unsigned char *perr = (const unsigned char *) test->err;
++        do
++          {
++            transfer (&pout, STDOUT_FILENO);
++            transfer (&perr, STDERR_FILENO);
++          }
++        while (*pout != '\0' || *perr != '\0');
++      }
++      mode_ok = true;
++      break;
++    }
++  TEST_VERIFY (mode_ok);
++
++  if (test->signal != 0)
++    raise (test->signal);
++  exit (test->status);
++}
++
++/* Create a heap-allocated random string of letters.  */
++static char *
++random_string (size_t length)
++{
++  char *result = xmalloc (length + 1);
++  for (size_t i = 0; i < length; ++i)
++    result[i] = 'a' + (rand () % 26);
++  result[length] = '\0';
++  return result;
++}
++
++/* Check that the specific stream from the captured subprocess matches
++   expectations.  */
++static void
++check_stream (const char *what, const struct xmemstream *stream,
++              const char *expected)
++{
++  if (strcmp (stream->buffer, expected) != 0)
++    {
++      support_record_failure ();
++      printf ("error: captured %s data incorrect\n"
++              "  expected: %s\n"
++              "  actual:   %s\n",
++              what, expected, stream->buffer);
++    }
++  if (stream->length != strlen (expected))
++    {
++      support_record_failure ();
++      printf ("error: captured %s data length incorrect\n"
++              "  expected: %zu\n"
++              "  actual:   %zu\n",
++              what, strlen (expected), stream->length);
++    }
++}
++
++static int
++do_test (void)
++{
++  const int lengths[] = {0, 1, 17, 512, 20000, -1};
++
++  /* Test multiple combinations of support_capture_subprocess.
++
++     length_idx_stdout: Index into the lengths array above,
++       controls how many bytes are written by the subprocess to
++       standard output.
++     length_idx_stderr: Same for standard error.
++     write_mode: How standard output and standard error writes are
++       ordered.
++     signal: Exit with no signal if zero, with SIGTERM if one.
++     status: Process exit status: 0 if zero, 3 if one.  */
++  for (int length_idx_stdout = 0; lengths[length_idx_stdout] >= 0;
++       ++length_idx_stdout)
++    for (int length_idx_stderr = 0; lengths[length_idx_stderr] >= 0;
++         ++length_idx_stderr)
++      for (int write_mode = 0; write_mode < write_mode_last; ++write_mode)
++        for (int signal = 0; signal < 2; ++signal)
++          for (int status = 0; status < 2; ++status)
++            {
++              struct test test =
++                {
++                  .out = random_string (lengths[length_idx_stdout]),
++                  .err = random_string (lengths[length_idx_stderr]),
++                  .write_mode = write_mode,
++                  .signal = signal * SIGTERM, /* 0 or SIGTERM.  */
++                  .status = status * 3,       /* 0 or 3.  */
++                };
++              TEST_VERIFY (strlen (test.out) == lengths[length_idx_stdout]);
++              TEST_VERIFY (strlen (test.err) == lengths[length_idx_stderr]);
++
++              struct support_capture_subprocess result
++                = support_capture_subprocess (callback, &test);
++              check_stream ("stdout", &result.out, test.out);
++              check_stream ("stderr", &result.err, test.err);
++              if (test.signal != 0)
++                {
++                  TEST_VERIFY (WIFSIGNALED (result.status));
++                  TEST_VERIFY (WTERMSIG (result.status) == test.signal);
++                }
++              else
++                {
++                  TEST_VERIFY (WIFEXITED (result.status));
++                  TEST_VERIFY (WEXITSTATUS (result.status) == test.status);
++                }
++              support_capture_subprocess_free (&result);
++              free (test.out);
++              free (test.err);
++            }
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/support/tst-support_format_dns_packet.c b/support/tst-support_format_dns_packet.c
+new file mode 100644
+index 0000000000..9c8589c09c
+--- /dev/null
++++ b/support/tst-support_format_dns_packet.c
+@@ -0,0 +1,101 @@
++/* Tests for the support_format_dns_packet function.
++   Copyright (C) 2016-2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/check.h>
++#include <support/format_nss.h>
++#include <support/run_diff.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++static void
++check_packet (const void *buffer, size_t length,
++              const char *name, const char *expected)
++{
++  char *actual = support_format_dns_packet (buffer, length);
++  if (strcmp (actual, expected) != 0)
++    {
++      support_record_failure ();
++      printf ("error: formatted packet does not match: %s\n", name);
++      support_run_diff ("expected", expected,
++                        "actual", actual);
++    }
++  free (actual);
++}
++
++static void
++test_aaaa_length (void)
++{
++  static const char packet[] =
++    /* Header: Response with two records.  */
++    "\x12\x34\x80\x00\x00\x01\x00\x02\x00\x00\x00\x00"
++    /* Question section.  www.example/IN/AAAA.  */
++    "\x03www\x07""example\x00\x00\x1c\x00\x01"
++    /* Answer section.  www.example AAAA [corrupted].  */
++    "\xc0\x0c"
++    "\x00\x1c\x00\x01\x00\x00\x00\x00\x00\x10"
++    "\x20\x01\x0d\xb8\x05\x06\x07\x08"
++    "\x11\x12\x13\x14\x15\x16\x17\x18"
++    /* www.example AAAA [corrupted].  */
++    "\xc0\x0c"
++    "\x00\x1c\x00\x01\x00\x00\x00\x00\x00\x11"
++    "\x01\x02\x03\x04\x05\x06\x07\x08"
++    "\x11\x12\x13\x14\x15\x16\x17\x18" "\xff";
++  check_packet (packet, sizeof (packet) - 1, __func__,
++                "name: www.example\n"
++                "address: 2001:db8:506:708:1112:1314:1516:1718\n"
++                "error: AAAA record of size 17: www.example\n");
++}
++
++static void
++test_multiple_cnames (void)
++{
++  static const char packet[] =
++    /* Header: Response with three records.  */
++    "\x12\x34\x80\x00\x00\x01\x00\x03\x00\x00\x00\x00"
++    /* Question section.  www.example/IN/A.  */
++    "\x03www\x07""example\x00\x00\x01\x00\x01"
++    /* Answer section.  www.example CNAME www1.example.  */
++    "\xc0\x0c"
++    "\x00\x05\x00\x01\x00\x00\x00\x00\x00\x07"
++    "\x04www1\xc0\x10"
++    /* www1 CNAME www2.  */
++    "\x04www1\xc0\x10"
++    "\x00\x05\x00\x01\x00\x00\x00\x00\x00\x07"
++    "\x04www2\xc0\x10"
++    /* www2 A 192.0.2.1.  */
++    "\x04www2\xc0\x10"
++    "\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04"
++    "\xc0\x00\x02\x01";
++  check_packet (packet, sizeof (packet) - 1, __func__,
++                "name: www.example\n"
++                "name: www1.example\n"
++                "name: www2.example\n"
++                "address: 192.0.2.1\n");
++}
++
++static int
++do_test (void)
++{
++  test_aaaa_length ();
++  test_multiple_cnames ();
++  return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/support/tst-support_record_failure-2.sh b/support/tst-support_record_failure-2.sh
+index 175137780a..2c9372cc29 100644
+--- a/support/tst-support_record_failure-2.sh
++++ b/support/tst-support_record_failure-2.sh
+@@ -37,7 +37,7 @@ run_test () {
+     set -e
+     echo "  exit status: $status"
+     if test "$output" != "$expected_output" ; then
+-	echo "error: unexpected ouput: $output"
++	echo "error: unexpected output: $output"
+ 	exit 1
+     fi
+     if test "$status" -ne "$expected_status" ; then
+@@ -52,9 +52,9 @@ different_status () {
+     run_test 1 "error: 1 test failures" $direct --status=1
+     run_test 2 "error: 1 test failures" $direct --status=2
+     run_test 1 "error: 1 test failures" $direct --status=77
+-    run_test 2 "error: tst-support_record_failure.c:108: not true: false
++    run_test 2 "error: tst-support_record_failure.c:109: not true: false
+ error: 1 test failures" $direct --test-verify
+-    run_test 2 "error: tst-support_record_failure.c:108: not true: false
++    run_test 2 "error: tst-support_record_failure.c:109: not true: false
+ info: execution passed failed TEST_VERIFY
+ error: 1 test failures" $direct --test-verify --verbose
+ }
+@@ -62,8 +62,8 @@ error: 1 test failures" $direct --test-verify --verbose
+ different_status
+ different_status --direct
+ 
+-run_test 1 "error: tst-support_record_failure.c:115: not true: false
++run_test 1 "error: tst-support_record_failure.c:116: not true: false
+ error: 1 test failures" --test-verify-exit
+ # --direct does not print the summary error message if exit is called.
+-run_test 1 "error: tst-support_record_failure.c:115: not true: false" \
++run_test 1 "error: tst-support_record_failure.c:116: not true: false" \
+ 	 --direct --test-verify-exit
+diff --git a/support/tst-support_record_failure.c b/support/tst-support_record_failure.c
+index 62d8e1f057..e739e739c3 100644
+--- a/support/tst-support_record_failure.c
++++ b/support/tst-support_record_failure.c
+@@ -25,6 +25,7 @@
+ #include <stdbool.h>
+ #include <stdlib.h>
+ #include <stdio.h>
++#include <string.h>
+ 
+ static int exit_status_with_failure = -1;
+ static bool test_verify;
+diff --git a/support/xaccept4.c b/support/xaccept4.c
+new file mode 100644
+index 0000000000..67dd95e9fb
+--- /dev/null
++++ b/support/xaccept4.c
+@@ -0,0 +1,32 @@
++/* accept4 with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/xsocket.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <support/check.h>
++
++int
++xaccept4 (int fd, struct sockaddr *sa, socklen_t *salen, int flags)
++{
++  int clientfd = accept4 (fd, sa, salen, flags);
++  if (clientfd < 0)
++    FAIL_EXIT1 ("accept4 (%d, 0x%x): %m", fd, flags);
++  return clientfd;
++}
+diff --git a/support/xchroot.c b/support/xchroot.c
+new file mode 100644
+index 0000000000..abcc299e00
+--- /dev/null
++++ b/support/xchroot.c
+@@ -0,0 +1,28 @@
++/* chroot with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/check.h>
++#include <support/xunistd.h>
++#include <sys/stat.h>
++
++void
++xchroot (const char *path)
++{
++  if (chroot (path) != 0)
++    FAIL_EXIT1 ("chroot (\"%s\"): %m", path);
++}
+diff --git a/support/xclose.c b/support/xclose.c
+new file mode 100644
+index 0000000000..c931e08421
+--- /dev/null
++++ b/support/xclose.c
+@@ -0,0 +1,28 @@
++/* close with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/xunistd.h>
++#include <support/check.h>
++#include <errno.h>
++
++void
++xclose (int fd)
++{
++  if (close (fd) < 0 && errno != EINTR)
++    FAIL_EXIT1 ("close of descriptor %d failed: %m", fd);
++}
+diff --git a/support/xdlfcn.c b/support/xdlfcn.c
+new file mode 100644
+index 0000000000..6e3979983d
+--- /dev/null
++++ b/support/xdlfcn.c
+@@ -0,0 +1,58 @@
++/* Support functionality for using dlopen/dlclose/dlsym.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/check.h>
++#include <support/xdlfcn.h>
++
++void *
++xdlopen (const char *filename, int flags)
++{
++  void *dso = dlopen (filename, flags);
++
++  if (dso == NULL)
++    FAIL_EXIT1 ("error: dlopen: %s\n", dlerror ());
++
++  /* Clear any errors.  */
++  dlerror ();
++
++  return dso;
++}
++
++void *
++xdlsym (void *handle, const char *symbol)
++{
++  void *sym = dlsym (handle, symbol);
++
++  if (sym == NULL)
++    FAIL_EXIT1 ("error: dlsym: %s\n", dlerror ());
++
++  /* Clear any errors.  */
++  dlerror ();
++
++  return sym;
++}
++
++void
++xdlclose (void *handle)
++{
++  if (dlclose (handle) != 0)
++    FAIL_EXIT1 ("error: dlclose: %s\n", dlerror ());
++
++  /* Clear any errors.  */
++  dlerror ();
++}
+diff --git a/support/xdlfcn.h b/support/xdlfcn.h
+new file mode 100644
+index 0000000000..9bdcb38d3e
+--- /dev/null
++++ b/support/xdlfcn.h
+@@ -0,0 +1,34 @@
++/* Support functionality for using dlopen/dlclose/dlsym.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#ifndef SUPPORT_DLOPEN_H
++#define SUPPORT_DLOPEN_H
++
++#include <dlfcn.h>
++
++__BEGIN_DECLS
++
++/* Each of these terminates process on failure with relevant error message.  */
++void *xdlopen (const char *filename, int flags);
++void *xdlsym (void *handle, const char *symbol);
++void xdlclose (void *handle);
++
++
++__END_DECLS
++
++#endif /* SUPPORT_DLOPEN_H */
+diff --git a/support/xdup2.c b/support/xdup2.c
+new file mode 100644
+index 0000000000..dc08c94518
+--- /dev/null
++++ b/support/xdup2.c
+@@ -0,0 +1,28 @@
++/* dup2 with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/xunistd.h>
++
++#include <support/check.h>
++
++void
++xdup2 (int from, int to)
++{
++  if (dup2 (from, to) < 0)
++    FAIL_EXIT1 ("dup2 (%d, %d): %m", from, to);
++}
+diff --git a/support/xmkdir.c b/support/xmkdir.c
+new file mode 100644
+index 0000000000..ea17d49391
+--- /dev/null
++++ b/support/xmkdir.c
+@@ -0,0 +1,28 @@
++/* mkdir with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/check.h>
++#include <support/xunistd.h>
++#include <sys/stat.h>
++
++void
++xmkdir (const char *path, mode_t mode)
++{
++  if (mkdir (path, mode) != 0)
++    FAIL_EXIT1 ("mkdir (\"%s\", 0%o): %m", path, mode);
++}
+diff --git a/support/xmprotect.c b/support/xmprotect.c
+new file mode 100644
+index 0000000000..9410251c32
+--- /dev/null
++++ b/support/xmprotect.c
+@@ -0,0 +1,28 @@
++/* mprotect with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/check.h>
++#include <support/xunistd.h>
++#include <sys/mman.h>
++
++void
++xmprotect (void *addr, size_t length, int prot)
++{
++  if (mprotect (addr, length, prot) != 0)
++    FAIL_EXIT1 ("mprotect (%p, %zu, 0x%x): %m", addr, length, prot);
++}
+diff --git a/support/xopen.c b/support/xopen.c
+new file mode 100644
+index 0000000000..7f033a03a7
+--- /dev/null
++++ b/support/xopen.c
+@@ -0,0 +1,30 @@
++/* open64 with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/check.h>
++#include <support/xunistd.h>
++#include <fcntl.h>
++
++int
++xopen (const char *path, int flags, mode_t mode)
++{
++  int ret = open64 (path, flags, mode);
++  if (ret < 0)
++    FAIL_EXIT1 ("open64 (\"%s\", 0x%x, 0%o): %m", path, flags, mode);
++  return ret;
++}
+diff --git a/support/xpipe.c b/support/xpipe.c
+new file mode 100644
+index 0000000000..89a64a55c1
+--- /dev/null
++++ b/support/xpipe.c
+@@ -0,0 +1,28 @@
++/* pipe with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/xunistd.h>
++
++#include <support/check.h>
++
++void
++xpipe (int fds[2])
++{
++  if (pipe (fds) < 0)
++    FAIL_EXIT1 ("pipe: %m");
++}
+diff --git a/support/xpthread_attr_setguardsize.c b/support/xpthread_attr_setguardsize.c
+new file mode 100644
+index 0000000000..35fed5d9ec
+--- /dev/null
++++ b/support/xpthread_attr_setguardsize.c
+@@ -0,0 +1,26 @@
++/* pthread_attr_setguardsize with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/xthread.h>
++
++void
++xpthread_attr_setguardsize (pthread_attr_t *attr, size_t guardsize)
++{
++  xpthread_check_return ("pthread_attr_setguardize",
++			 pthread_attr_setguardsize (attr, guardsize));
++}
+diff --git a/support/xpthread_rwlock_init.c b/support/xpthread_rwlock_init.c
+new file mode 100644
+index 0000000000..824288c90e
+--- /dev/null
++++ b/support/xpthread_rwlock_init.c
+@@ -0,0 +1,27 @@
++/* pthread_rwlock_init with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/xthread.h>
++
++void
++xpthread_rwlock_init (pthread_rwlock_t *rwlock,
++		      const pthread_rwlockattr_t *attr)
++{
++  xpthread_check_return ("pthread_rwlock_init",
++                         pthread_rwlock_init (rwlock, attr));
++}
+diff --git a/support/xpthread_rwlock_rdlock.c b/support/xpthread_rwlock_rdlock.c
+new file mode 100644
+index 0000000000..96330a5637
+--- /dev/null
++++ b/support/xpthread_rwlock_rdlock.c
+@@ -0,0 +1,26 @@
++/* pthread_rwlock_rdlock with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/xthread.h>
++
++void
++xpthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
++{
++  xpthread_check_return ("pthread_rwlock_rdlock",
++			 pthread_rwlock_rdlock (rwlock));
++}
+diff --git a/support/xpthread_rwlock_unlock.c b/support/xpthread_rwlock_unlock.c
+new file mode 100644
+index 0000000000..eaa136b3ec
+--- /dev/null
++++ b/support/xpthread_rwlock_unlock.c
+@@ -0,0 +1,26 @@
++/* pthread_rwlock_unlock with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/xthread.h>
++
++void
++xpthread_rwlock_unlock (pthread_rwlock_t *rwlock)
++{
++  xpthread_check_return ("pthread_rwlock_unlock",
++			 pthread_rwlock_unlock (rwlock));
++}
+diff --git a/support/xpthread_rwlock_wrlock.c b/support/xpthread_rwlock_wrlock.c
+new file mode 100644
+index 0000000000..8d25d5b818
+--- /dev/null
++++ b/support/xpthread_rwlock_wrlock.c
+@@ -0,0 +1,26 @@
++/* pthread_rwlock_wrlock with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/xthread.h>
++
++void
++xpthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
++{
++  xpthread_check_return ("pthread_rwlock_wrlock",
++			 pthread_rwlock_wrlock (rwlock));
++}
+diff --git a/support/xpthread_rwlockattr_init.c b/support/xpthread_rwlockattr_init.c
+new file mode 100644
+index 0000000000..48baf247f3
+--- /dev/null
++++ b/support/xpthread_rwlockattr_init.c
+@@ -0,0 +1,26 @@
++/* pthread_rwlockattr_init with error checking.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <support/xthread.h>
++
++void
++xpthread_rwlockattr_init (pthread_rwlockattr_t *attr)
++{
++  xpthread_check_return ("pthread_rwlockattr_init",
++                         pthread_rwlockattr_init (attr));
++}
+diff --git a/support/xpthread_rwlockattr_setkind_np.c b/support/xpthread_rwlockattr_setkind_np.c
+new file mode 100644
+index 0000000000..958aace9f6
+--- /dev/null
++++ b/support/xpthread_rwlockattr_setkind_np.c
+@@ -0,0 +1,27 @@
++/* pthread_rwlockattr_setkind_np with error checking.
++   Copyright (C) 2017 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.
 +
-+  memset (&info->edns, 0, sizeof (info->edns));
-+  if (ntohs (hd.arcount) > 0)
-+    {
-+      /* Parse EDNS record.  */
-+      struct __attribute__ ((packed, aligned (1)))
-+      {
-+        uint8_t root;
-+        uint16_t rtype;
-+        uint16_t payload;
-+        uint8_t edns_extended_rcode;
-+        uint8_t edns_version;
-+        uint16_t flags;
-+        uint16_t rdatalen;
-+      } rr;
-+      _Static_assert (sizeof (rr) == 11, "EDNS record size");
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
 +
-+      if (remaining < 4 + sizeof (rr))
-+        FAIL_EXIT1 ("mailformed DNS query: no room for EDNS record");
-+      memcpy (&rr, buffer + 12 + ret + 4, sizeof (rr));
-+      if (rr.root != 0)
-+        FAIL_EXIT1 ("malformed DNS query: invalid OPT RNAME: %d\n", rr.root);
-+      if (rr.rtype != htons (41))
-+        FAIL_EXIT1 ("malformed DNS query: invalid OPT type: %d\n",
-+                    ntohs (rr.rtype));
-+      info->edns.active = true;
-+      info->edns.extended_rcode = rr.edns_extended_rcode;
-+      info->edns.version = rr.edns_version;
-+      info->edns.flags = ntohs (rr.flags);
-+      info->edns.payload_size = ntohs (rr.payload);
-+    }
- }
- 
++#include <support/xthread.h>
++
++void
++xpthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr,
++				int pref)
++{
++  xpthread_check_return ("pthread_rwlockattr_setkind_np",
++                         pthread_rwlockattr_setkind_np (attr, pref));
++}
+diff --git a/support/xsocket.h b/support/xsocket.h
+index 0dbf13ace9..d6724948d8 100644
+--- a/support/xsocket.h
++++ b/support/xsocket.h
+@@ -30,6 +30,7 @@ void xconnect (int, const struct sockaddr *, socklen_t);
+ void xbind (int, const struct sockaddr *, socklen_t);
+ void xlisten (int, int);
+ int xaccept (int, struct sockaddr *, socklen_t *);
++int xaccept4 (int, struct sockaddr *, socklen_t *, int);
+ void xsendto (int, const void *, size_t, int,
+               const struct sockaddr *, socklen_t);
+ size_t xrecvfrom (int, void *, size_t, int, struct sockaddr *, socklen_t *);
+diff --git a/support/xthread.h b/support/xthread.h
+index 6dd7e709be..472763ebe8 100644
+--- a/support/xthread.h
++++ b/support/xthread.h
+@@ -67,11 +67,21 @@ void xpthread_attr_setdetachstate (pthread_attr_t *attr,
+ 				   int detachstate);
+ void xpthread_attr_setstacksize (pthread_attr_t *attr,
+ 				 size_t stacksize);
++void xpthread_attr_setguardsize (pthread_attr_t *attr,
++				 size_t guardsize);
+ 
+ /* This function returns non-zero if pthread_barrier_wait returned
+    PTHREAD_BARRIER_SERIAL_THREAD.  */
+ int xpthread_barrier_wait (pthread_barrier_t *barrier);
+ 
++void xpthread_rwlock_init (pthread_rwlock_t *rwlock,
++			  const pthread_rwlockattr_t *attr);
++void xpthread_rwlockattr_init (pthread_rwlockattr_t *attr);
++void xpthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref);
++void xpthread_rwlock_wrlock (pthread_rwlock_t *rwlock);
++void xpthread_rwlock_rdlock (pthread_rwlock_t *rwlock);
++void xpthread_rwlock_unlock (pthread_rwlock_t *rwlock);
++
+ __END_DECLS
  
-@@ -585,6 +633,7 @@ server_thread_udp_process_one (struct resolv_test *obj, int server_index)
-       .query_length = length,
-       .server_index = server_index,
-       .tcp = false,
-+      .edns = qinfo.edns,
-     };
-   struct resolv_response_builder *b = response_builder_allocate (query, length);
-   obj->config.response_callback
-@@ -820,6 +869,7 @@ server_thread_tcp_client (void *arg)
-           .query_length = query_length,
-           .server_index = closure->server_index,
-           .tcp = true,
-+          .edns = qinfo.edns,
-         };
-       struct resolv_response_builder *b = response_builder_allocate
-         (query_buffer, query_length);
-diff --git a/support/resolv_test.h b/support/resolv_test.h
-index 7a9f1f7ae8..6498751569 100644
---- a/support/resolv_test.h
-+++ b/support/resolv_test.h
-@@ -25,6 +25,16 @@
+ #endif /* SUPPORT_THREAD_H */
+diff --git a/support/xunistd.h b/support/xunistd.h
+index a83b1f4541..c947bfd8fb 100644
+--- a/support/xunistd.h
++++ b/support/xunistd.h
+@@ -22,20 +22,33 @@
+ #ifndef SUPPORT_XUNISTD_H
+ #define SUPPORT_XUNISTD_H
+ 
+-#include <unistd.h>
+ #include <sys/cdefs.h>
++#include <sys/types.h>
++#include <unistd.h>
  
  __BEGIN_DECLS
  
-+/* Information about EDNS properties of a DNS query.  */
-+struct resolv_edns_info
-+{
-+  bool active;
-+  uint8_t extended_rcode;
-+  uint8_t version;
-+  uint16_t flags;
-+  uint16_t payload_size;
-+};
++struct stat64;
 +
- /* This struct provides context information when the response callback
-    specified in struct resolv_redirect_config is invoked. */
- struct resolv_response_context
-@@ -33,6 +43,7 @@ struct resolv_response_context
-   size_t query_length;
-   int server_index;
-   bool tcp;
-+  struct resolv_edns_info edns;
- };
+ pid_t xfork (void);
+ pid_t xwaitpid (pid_t, int *status, int flags);
++void xpipe (int[2]);
++void xdup2 (int, int);
++int xopen (const char *path, int flags, mode_t);
++void xstat (const char *path, struct stat64 *);
++void xmkdir (const char *path, mode_t);
++void xchroot (const char *path);
++
++/* Close the file descriptor.  Ignore EINTR errors, but terminate the
++   process on other errors.  */
++void xclose (int);
  
- /* This opaque struct is used to construct responses from within the
+ /* Write the buffer.  Retry on short writes.  */
+ void xwrite (int, const void *, size_t);
+ 
+ /* Invoke mmap with a zero file offset.  */
+ void *xmmap (void *addr, size_t length, int prot, int flags, int fd);
+-
++void xmprotect (void *addr, size_t length, int prot);
+ void xmunmap (void *addr, size_t length);
+ 
+ __END_DECLS
 diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h
 index 84b8aecfb8..6067a1d8a0 100644
 --- a/sysdeps/aarch64/dl-machine.h
@@ -4182,6 +8662,64 @@ index 7760b966e2..6742a35d41 100644
 +#if IS_IN (libc)
 +# include <sysdeps/x86_64/multiarch/varshift.c>
 +#endif
+diff --git a/sysdeps/mips/bits/long-double.h b/sysdeps/mips/bits/long-double.h
+deleted file mode 100644
+index 604188e181..0000000000
+--- a/sysdeps/mips/bits/long-double.h
++++ /dev/null
+@@ -1,23 +0,0 @@
+-/* Properties of long double type.  MIPS version.
+-   Copyright (C) 2016-2017 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  published by the Free Software Foundation; either
+-   version 2.1 of the License, or (at your option) any later version.
+-
+-   The GNU C Library is distributed in the hope that it will be useful,
+-   but WITHOUT ANY WARRANTY; without even the implied warranty of
+-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+-   Lesser General Public License for more details.
+-
+-   You should have received a copy of the GNU Lesser General Public
+-   License along with the GNU C Library; if not, see
+-   <http://www.gnu.org/licenses/>.  */
+-
+-#include <sgidefs.h>
+-
+-#if !defined __NO_LONG_DOUBLE_MATH && _MIPS_SIM == _ABIO32
+-# define __NO_LONG_DOUBLE_MATH	1
+-#endif
+diff --git a/sysdeps/mips/ieee754/bits/long-double.h b/sysdeps/mips/ieee754/bits/long-double.h
+new file mode 100644
+index 0000000000..604188e181
+--- /dev/null
++++ b/sysdeps/mips/ieee754/bits/long-double.h
+@@ -0,0 +1,23 @@
++/* Properties of long double type.  MIPS version.
++   Copyright (C) 2016-2017 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  published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <sgidefs.h>
++
++#if !defined __NO_LONG_DOUBLE_MATH && _MIPS_SIM == _ABIO32
++# define __NO_LONG_DOUBLE_MATH	1
++#endif
 diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c
 index db6d721fce..4bb87e2331 100644
 --- a/sysdeps/nptl/fork.c
@@ -4263,6 +8801,46 @@ index f7ecbd105a..3ae383a831 100644
      }
    /* Test to avoid logb_downward (0.0) == -0.0.  */
    return ret == -0.0 ? 0.0 : ret;
+diff --git a/sysdeps/powerpc/powerpc32/dl-machine.h b/sysdeps/powerpc/powerpc32/dl-machine.h
+index 28eb50f92d..9b5a99fcc7 100644
+--- a/sysdeps/powerpc/powerpc32/dl-machine.h
++++ b/sysdeps/powerpc/powerpc32/dl-machine.h
+@@ -309,7 +309,10 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
+      against local symbols.  */
+   if (__builtin_expect (ELF32_ST_BIND (sym->st_info) == STB_LOCAL, 0)
+       && sym->st_shndx != SHN_UNDEF)
+-    value = map->l_addr;
++    {
++      sym_map = map;
++      value = map->l_addr;
++    }
+   else
+     {
+       sym_map = RESOLVE_MAP (&sym, version, r_type);
+diff --git a/sysdeps/sparc/sparc32/dl-machine.h b/sysdeps/sparc/sparc32/dl-machine.h
+index cf7272f359..3e03fd091c 100644
+--- a/sysdeps/sparc/sparc32/dl-machine.h
++++ b/sysdeps/sparc/sparc32/dl-machine.h
+@@ -375,6 +375,7 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
+   if (__builtin_expect (ELF32_ST_BIND (sym->st_info) == STB_LOCAL, 0)
+       && sym->st_shndx != SHN_UNDEF)
+     {
++      sym_map = map;
+       value = map->l_addr;
+     }
+   else
+diff --git a/sysdeps/sparc/sparc64/dl-machine.h b/sysdeps/sparc/sparc64/dl-machine.h
+index 99c00f493d..0694ac1362 100644
+--- a/sysdeps/sparc/sparc64/dl-machine.h
++++ b/sysdeps/sparc/sparc64/dl-machine.h
+@@ -402,6 +402,7 @@ elf_machine_rela (struct link_map *map, const Elf64_Rela *reloc,
+   if (__builtin_expect (ELF64_ST_BIND (sym->st_info) == STB_LOCAL, 0)
+       && sym->st_shndx != SHN_UNDEF)
+     {
++      sym_map = map;
+       value = map->l_addr;
+     }
+   else
 diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data
 index cca17f1e34..1f0e3b494e 100644
 --- a/sysdeps/unix/sysv/linux/alpha/localplt.data
@@ -5055,6 +9633,102 @@ index 2c2584956d..8ea4333846 100644
  # The main malloc is interposed into the dynamic linker, for
  # allocations after the initial link (when dlopen is used).
  ld.so: malloc + REL R_386_GLOB_DAT
+diff --git a/sysdeps/unix/sysv/linux/sparc/bits/long-double.h b/sysdeps/unix/sysv/linux/sparc/bits/long-double.h
+deleted file mode 100644
+index 094e05124b..0000000000
+--- a/sysdeps/unix/sysv/linux/sparc/bits/long-double.h
++++ /dev/null
+@@ -1,26 +0,0 @@
+-/* Properties of long double type.  SPARC version.
+-   Copyright (C) 2016-2017 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  published by the Free Software Foundation; either
+-   version 2.1 of the License, or (at your option) any later version.
+-
+-   The GNU C Library is distributed in the hope that it will be useful,
+-   but WITHOUT ANY WARRANTY; without even the implied warranty of
+-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+-   Lesser General Public License for more details.
+-
+-   You should have received a copy of the GNU Lesser General Public
+-   License along with the GNU C Library; if not, see
+-   <http://www.gnu.org/licenses/>.  */
+-
+-#include <bits/wordsize.h>
+-
+-#if !defined __NO_LONG_DOUBLE_MATH && __WORDSIZE == 32
+-# define __LONG_DOUBLE_MATH_OPTIONAL   1
+-# ifndef __LONG_DOUBLE_128__
+-#  define __NO_LONG_DOUBLE_MATH        1
+-# endif
+-#endif
+diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h b/sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h
+new file mode 100644
+index 0000000000..094e05124b
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h
+@@ -0,0 +1,26 @@
++/* Properties of long double type.  SPARC version.
++   Copyright (C) 2016-2017 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  published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <bits/wordsize.h>
++
++#if !defined __NO_LONG_DOUBLE_MATH && __WORDSIZE == 32
++# define __LONG_DOUBLE_MATH_OPTIONAL   1
++# ifndef __LONG_DOUBLE_128__
++#  define __NO_LONG_DOUBLE_MATH        1
++# endif
++#endif
+diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h b/sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h
+new file mode 100644
+index 0000000000..094e05124b
+--- /dev/null
++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h
+@@ -0,0 +1,26 @@
++/* Properties of long double type.  SPARC version.
++   Copyright (C) 2016-2017 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  published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <bits/wordsize.h>
++
++#if !defined __NO_LONG_DOUBLE_MATH && __WORDSIZE == 32
++# define __LONG_DOUBLE_MATH_OPTIONAL   1
++# ifndef __LONG_DOUBLE_128__
++#  define __NO_LONG_DOUBLE_MATH        1
++# endif
++#endif
 diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
 index 2daf0c5ef0..29d8f25ab5 100644
 --- a/sysdeps/unix/sysv/linux/spawni.c
@@ -5095,11 +9769,103 @@ index 2daf0c5ef0..29d8f25ab5 100644
    size_t stack_size = ALIGN_UP (argv_size, GLRO(dl_pagesize));
    void *stack = __mmap (NULL, stack_size, prot,
  			MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
+diff --git a/sysdeps/x86/cpu-features-offsets.sym b/sysdeps/x86/cpu-features-offsets.sym
+index f6739fae81..33dd094e37 100644
+--- a/sysdeps/x86/cpu-features-offsets.sym
++++ b/sysdeps/x86/cpu-features-offsets.sym
+@@ -15,6 +15,7 @@ CPUID_ECX_OFFSET	offsetof (struct cpuid_registers, ecx)
+ CPUID_EDX_OFFSET	offsetof (struct cpuid_registers, edx)
+ FAMILY_OFFSET		offsetof (struct cpu_features, family)
+ MODEL_OFFSET		offsetof (struct cpu_features, model)
++XSAVE_STATE_SIZE_OFFSET	offsetof (struct cpu_features, xsave_state_size)
+ FEATURE_OFFSET		offsetof (struct cpu_features, feature)
+ FEATURE_SIZE		sizeof (unsigned int)
+ 
 diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
-index 1c714a4017..5019f156c8 100644
+index 1c714a4017..38012912be 100644
 --- a/sysdeps/x86/cpu-features.c
 +++ b/sysdeps/x86/cpu-features.c
-@@ -139,8 +139,6 @@ init_cpu_features (struct cpu_features *cpu_features)
+@@ -18,6 +18,7 @@
+ 
+ #include <cpuid.h>
+ #include <cpu-features.h>
++#include <libc-internal.h>
+ 
+ static void
+ get_common_indeces (struct cpu_features *cpu_features,
+@@ -93,6 +94,71 @@ get_common_indeces (struct cpu_features *cpu_features,
+ 		}
+ 	    }
+ 	}
++
++      /* For _dl_runtime_resolve, set xsave_state_size to xsave area
++	 size + integer register save size and align it to 64 bytes.  */
++      if (cpu_features->max_cpuid >= 0xd)
++	{
++	  unsigned int eax, ebx, ecx, edx;
++
++	  __cpuid_count (0xd, 0, eax, ebx, ecx, edx);
++	  if (ebx != 0)
++	    {
++	      cpu_features->xsave_state_size
++		= ALIGN_UP (ebx + STATE_SAVE_OFFSET, 64);
++
++	      __cpuid_count (0xd, 1, eax, ebx, ecx, edx);
++
++	      /* Check if XSAVEC is available.  */
++	      if ((eax & (1 << 1)) != 0)
++		{
++		  unsigned int xstate_comp_offsets[32];
++		  unsigned int xstate_comp_sizes[32];
++		  unsigned int i;
++
++		  xstate_comp_offsets[0] = 0;
++		  xstate_comp_offsets[1] = 160;
++		  xstate_comp_offsets[2] = 576;
++		  xstate_comp_sizes[0] = 160;
++		  xstate_comp_sizes[1] = 256;
++
++		  for (i = 2; i < 32; i++)
++		    {
++		      if ((STATE_SAVE_MASK & (1 << i)) != 0)
++			{
++			  __cpuid_count (0xd, i, eax, ebx, ecx, edx);
++			  xstate_comp_sizes[i] = eax;
++			}
++		      else
++			{
++			  ecx = 0;
++			  xstate_comp_sizes[i] = 0;
++			}
++
++		      if (i > 2)
++			{
++			  xstate_comp_offsets[i]
++			    = (xstate_comp_offsets[i - 1]
++			       + xstate_comp_sizes[i -1]);
++			  if ((ecx & (1 << 1)) != 0)
++			    xstate_comp_offsets[i]
++			      = ALIGN_UP (xstate_comp_offsets[i], 64);
++			}
++		    }
++
++		  /* Use XSAVEC.  */
++		  unsigned int size
++		    = xstate_comp_offsets[31] + xstate_comp_sizes[31];
++		  if (size)
++		    {
++		      cpu_features->xsave_state_size
++			= ALIGN_UP (size + STATE_SAVE_OFFSET, 64);
++		      cpu_features->feature[index_arch_XSAVEC_Usable]
++			|= bit_arch_XSAVEC_Usable;
++		    }
++		}
++	    }
++	}
+     }
+ }
+ 
+@@ -139,8 +205,6 @@ init_cpu_features (struct cpu_features *cpu_features)
  
  	    case 0x57:
  	      /* Knights Landing.  Enable Silvermont optimizations.  */
@@ -5108,10 +9874,23 @@ index 1c714a4017..5019f156c8 100644
  
  	    case 0x5c:
  	    case 0x5f:
-@@ -226,11 +224,24 @@ init_cpu_features (struct cpu_features *cpu_features)
+@@ -226,19 +290,15 @@ init_cpu_features (struct cpu_features *cpu_features)
  	cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load]
  	  |= bit_arch_AVX_Fast_Unaligned_Load;
  
+-      /* To avoid SSE transition penalty, use _dl_runtime_resolve_slow.
+-         If XGETBV suports ECX == 1, use _dl_runtime_resolve_opt.  */
+-      cpu_features->feature[index_arch_Use_dl_runtime_resolve_slow]
+-	|= bit_arch_Use_dl_runtime_resolve_slow;
+-      if (cpu_features->max_cpuid >= 0xd)
+-	{
+-	  unsigned int eax;
+-
+-	  __cpuid_count (0xd, 1, eax, ebx, ecx, edx);
+-	  if ((eax & (1 << 2)) != 0)
+-	    cpu_features->feature[index_arch_Use_dl_runtime_resolve_opt]
+-	      |= bit_arch_Use_dl_runtime_resolve_opt;
+-	}
 +      /* Since AVX512ER is unique to Xeon Phi, set Prefer_No_VZEROUPPER
 +         if AVX512ER is available.  Don't use AVX512 to avoid lower CPU
 +	 frequency if AVX512ER isn't available.  */
@@ -5121,33 +9900,25 @@ index 1c714a4017..5019f156c8 100644
 +      else
 +	cpu_features->feature[index_arch_Prefer_No_AVX512]
 +	  |= bit_arch_Prefer_No_AVX512;
-+
-       /* To avoid SSE transition penalty, use _dl_runtime_resolve_slow.
--         If XGETBV suports ECX == 1, use _dl_runtime_resolve_opt.  */
-+         If XGETBV suports ECX == 1, use _dl_runtime_resolve_opt.
-+	 Use _dl_runtime_resolve_opt only with AVX512F since it is
-+	 slower than _dl_runtime_resolve_slow with AVX.  */
-       cpu_features->feature[index_arch_Use_dl_runtime_resolve_slow]
- 	|= bit_arch_Use_dl_runtime_resolve_slow;
--      if (cpu_features->max_cpuid >= 0xd)
-+      if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable)
-+	  && cpu_features->max_cpuid >= 0xd)
- 	{
- 	  unsigned int eax;
- 
+     }
+   /* This spells out "AuthenticAMD".  */
+   else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65)
 diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h
-index 95f0fcff87..a409db67d8 100644
+index 95f0fcff87..af83a28512 100644
 --- a/sysdeps/x86/cpu-features.h
 +++ b/sysdeps/x86/cpu-features.h
-@@ -39,6 +39,7 @@
+@@ -37,8 +37,8 @@
+ #define bit_arch_Prefer_No_VZEROUPPER		(1 << 17)
+ #define bit_arch_Fast_Unaligned_Copy		(1 << 18)
  #define bit_arch_Prefer_ERMS			(1 << 19)
- #define bit_arch_Use_dl_runtime_resolve_opt	(1 << 20)
- #define bit_arch_Use_dl_runtime_resolve_slow	(1 << 21)
-+#define bit_arch_Prefer_No_AVX512		(1 << 22)
+-#define bit_arch_Use_dl_runtime_resolve_opt	(1 << 20)
+-#define bit_arch_Use_dl_runtime_resolve_slow	(1 << 21)
++#define bit_arch_Prefer_No_AVX512		(1 << 20)
++#define bit_arch_XSAVEC_Usable			(1 << 21)
  
  /* CPUID Feature flags.  */
  
-@@ -62,6 +63,11 @@
+@@ -62,6 +62,11 @@
  #define bit_cpu_AVX2		(1 << 5)
  #define bit_cpu_AVX512F		(1 << 16)
  #define bit_cpu_AVX512DQ	(1 << 17)
@@ -5159,7 +9930,23 @@ index 95f0fcff87..a409db67d8 100644
  
  /* XCR0 Feature flags.  */
  #define bit_XMM_state		(1 << 1)
-@@ -111,6 +117,7 @@
+@@ -76,6 +81,15 @@
+ /* The current maximum size of the feature integer bit array.  */
+ #define FEATURE_INDEX_MAX 1
+ 
++/* Offset for fxsave/xsave area used by _dl_runtime_resolve.  Also need
++   space to preserve RCX, RDX, RSI, RDI, R8, R9 and RAX.  It must be
++   aligned to 16 bytes for fxsave and 64 bytes for xsave.  */
++#define STATE_SAVE_OFFSET (8 * 7 + 8)
++
++/* Save SSE, AVX, AVX512, mask and bound registers.  */
++#define STATE_SAVE_MASK \
++  ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 5) | (1 << 6) | (1 << 7))
++
+ #ifdef	__ASSEMBLER__
+ 
+ # include <cpu-features-offsets.h>
+@@ -111,6 +125,7 @@
  # define index_arch_Prefer_ERMS		FEATURE_INDEX_1*FEATURE_SIZE
  # define index_arch_Use_dl_runtime_resolve_opt FEATURE_INDEX_1*FEATURE_SIZE
  # define index_arch_Use_dl_runtime_resolve_slow FEATURE_INDEX_1*FEATURE_SIZE
@@ -5167,7 +9954,20 @@ index 95f0fcff87..a409db67d8 100644
  
  
  # if defined (_LIBC) && !IS_IN (nonlib)
-@@ -236,6 +243,11 @@ extern const struct cpu_features *__get_cpu_features (void)
+@@ -199,6 +214,12 @@ struct cpu_features
+   } cpuid[COMMON_CPUID_INDEX_MAX];
+   unsigned int family;
+   unsigned int model;
++  /* The type must be unsigned long int so that we use
++
++	sub xsave_state_size_offset(%rip) %RSP_LP
++
++     in _dl_runtime_resolve.  */
++  unsigned long int xsave_state_size;
+   unsigned int feature[FEATURE_INDEX_MAX];
+ };
+ 
+@@ -236,6 +257,11 @@ extern const struct cpu_features *__get_cpu_features (void)
  # define index_cpu_AVX2		COMMON_CPUID_INDEX_7
  # define index_cpu_AVX512F	COMMON_CPUID_INDEX_7
  # define index_cpu_AVX512DQ	COMMON_CPUID_INDEX_7
@@ -5179,7 +9979,7 @@ index 95f0fcff87..a409db67d8 100644
  # define index_cpu_ERMS		COMMON_CPUID_INDEX_7
  # define index_cpu_RTM		COMMON_CPUID_INDEX_7
  # define index_cpu_FMA		COMMON_CPUID_INDEX_1
-@@ -254,6 +266,11 @@ extern const struct cpu_features *__get_cpu_features (void)
+@@ -254,6 +280,11 @@ extern const struct cpu_features *__get_cpu_features (void)
  # define reg_AVX2		ebx
  # define reg_AVX512F		ebx
  # define reg_AVX512DQ		ebx
@@ -5191,11 +9991,14 @@ index 95f0fcff87..a409db67d8 100644
  # define reg_ERMS		ebx
  # define reg_RTM		ebx
  # define reg_FMA		ecx
-@@ -283,6 +300,7 @@ extern const struct cpu_features *__get_cpu_features (void)
+@@ -281,8 +312,8 @@ extern const struct cpu_features *__get_cpu_features (void)
+ # define index_arch_Prefer_No_VZEROUPPER FEATURE_INDEX_1
+ # define index_arch_Fast_Unaligned_Copy	FEATURE_INDEX_1
  # define index_arch_Prefer_ERMS		FEATURE_INDEX_1
- # define index_arch_Use_dl_runtime_resolve_opt FEATURE_INDEX_1
- # define index_arch_Use_dl_runtime_resolve_slow FEATURE_INDEX_1
+-# define index_arch_Use_dl_runtime_resolve_opt FEATURE_INDEX_1
+-# define index_arch_Use_dl_runtime_resolve_slow FEATURE_INDEX_1
 +# define index_arch_Prefer_No_AVX512	FEATURE_INDEX_1
++# define index_arch_XSAVEC_Usable	FEATURE_INDEX_1
  
  #endif	/* !__ASSEMBLER__ */
  
@@ -5260,7 +10063,7 @@ index 5043b32563..95282a3ac7 100644
    TEST_VEC_LOOP (r_loc, VEC_LEN/4);				\
    TEST_VEC_LOOP (r1_loc, VEC_LEN/4);				\
 diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile
-index 5f25893dc9..c896e22568 100644
+index 5f25893dc9..132470d9cb 100644
 --- a/sysdeps/x86_64/Makefile
 +++ b/sysdeps/x86_64/Makefile
 @@ -27,7 +27,7 @@ ifeq ($(subdir),elf)
@@ -5272,13 +10075,120 @@ index 5f25893dc9..c896e22568 100644
  
  tests += ifuncmain8
  modules-names += ifuncmod8
-@@ -108,5 +108,5 @@ endif
+@@ -52,9 +52,12 @@ $(objpfx)tst-quad2pie: $(objpfx)tst-quadmod2pie.o
+ CFLAGS-tst-quad1pie.c = $(PIE-ccflag)
+ CFLAGS-tst-quad2pie.c = $(PIE-ccflag)
+ 
+-tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 tst-audit10
+-test-extras += tst-audit4-aux tst-audit10-aux
+-extra-test-objs += tst-audit4-aux.o tst-audit10-aux.o
++tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 \
++	 tst-audit10 tst-sse tst-avx tst-avx512
++test-extras += tst-audit4-aux tst-audit10-aux \
++	       tst-avx-aux tst-avx512-aux
++extra-test-objs += tst-audit4-aux.o tst-audit10-aux.o \
++		   tst-avx-aux.o tst-avx512-aux.o
+ 
+ tests += tst-split-dynreloc
+ LDFLAGS-tst-split-dynreloc = -Wl,-T,$(..)sysdeps/x86_64/tst-split-dynreloc.lds
+@@ -65,7 +68,8 @@ modules-names += tst-auditmod3a tst-auditmod3b \
+ 		tst-auditmod5a tst-auditmod5b \
+ 		tst-auditmod6a tst-auditmod6b tst-auditmod6c \
+ 		tst-auditmod7a tst-auditmod7b \
+-		tst-auditmod10a tst-auditmod10b
++		tst-auditmod10a tst-auditmod10b \
++		tst-ssemod tst-avxmod tst-avx512mod
+ 
+ $(objpfx)tst-audit3: $(objpfx)tst-auditmod3a.so
+ $(objpfx)tst-audit3.out: $(objpfx)tst-auditmod3b.so
+@@ -92,6 +96,10 @@ $(objpfx)tst-audit10: $(objpfx)tst-audit10-aux.o $(objpfx)tst-auditmod10a.so
+ $(objpfx)tst-audit10.out: $(objpfx)tst-auditmod10b.so
+ tst-audit10-ENV = LD_AUDIT=$(objpfx)tst-auditmod10b.so
+ 
++$(objpfx)tst-sse: $(objpfx)tst-ssemod.so
++$(objpfx)tst-avx: $(objpfx)tst-avx-aux.o $(objpfx)tst-avxmod.so
++$(objpfx)tst-avx512: $(objpfx)tst-avx512-aux.o $(objpfx)tst-avx512mod.so
++
+ AVX-CFLAGS=-mavx -mno-vzeroupper
+ CFLAGS-tst-audit4-aux.c += $(AVX-CFLAGS)
+ CFLAGS-tst-auditmod4a.c += $(AVX-CFLAGS)
+@@ -99,14 +107,18 @@ CFLAGS-tst-auditmod4b.c += $(AVX-CFLAGS)
+ CFLAGS-tst-auditmod6b.c += $(AVX-CFLAGS)
+ CFLAGS-tst-auditmod6c.c += $(AVX-CFLAGS)
+ CFLAGS-tst-auditmod7b.c += $(AVX-CFLAGS)
++CFLAGS-tst-avx-aux.c += $(AVX-CFLAGS)
++CFLAGS-tst-avxmod.c += $(AVX-CFLAGS)
+ ifeq (yes,$(config-cflags-avx512))
+ AVX512-CFLAGS = -mavx512f
+ CFLAGS-tst-audit10-aux.c += $(AVX512-CFLAGS)
+ CFLAGS-tst-auditmod10a.c += $(AVX512-CFLAGS)
+ CFLAGS-tst-auditmod10b.c += $(AVX512-CFLAGS)
++CFLAGS-tst-avx512-aux.c += $(AVX512-CFLAGS)
++CFLAGS-tst-avx512mod.c += $(AVX512-CFLAGS)
+ endif
  endif
  
  ifeq ($(subdir),csu)
 -gen-as-const-headers += tlsdesc.sym
 +gen-as-const-headers += tlsdesc.sym rtld-offsets.sym
  endif
+diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
+index daf4d8c070..be0b8616ea 100644
+--- a/sysdeps/x86_64/dl-machine.h
++++ b/sysdeps/x86_64/dl-machine.h
+@@ -66,12 +66,9 @@ static inline int __attribute__ ((unused, always_inline))
+ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
+ {
+   Elf64_Addr *got;
+-  extern void _dl_runtime_resolve_sse (ElfW(Word)) attribute_hidden;
+-  extern void _dl_runtime_resolve_avx (ElfW(Word)) attribute_hidden;
+-  extern void _dl_runtime_resolve_avx_slow (ElfW(Word)) attribute_hidden;
+-  extern void _dl_runtime_resolve_avx_opt (ElfW(Word)) attribute_hidden;
+-  extern void _dl_runtime_resolve_avx512 (ElfW(Word)) attribute_hidden;
+-  extern void _dl_runtime_resolve_avx512_opt (ElfW(Word)) attribute_hidden;
++  extern void _dl_runtime_resolve_fxsave (ElfW(Word)) attribute_hidden;
++  extern void _dl_runtime_resolve_xsave (ElfW(Word)) attribute_hidden;
++  extern void _dl_runtime_resolve_xsavec (ElfW(Word)) attribute_hidden;
+   extern void _dl_runtime_profile_sse (ElfW(Word)) attribute_hidden;
+   extern void _dl_runtime_profile_avx (ElfW(Word)) attribute_hidden;
+   extern void _dl_runtime_profile_avx512 (ElfW(Word)) attribute_hidden;
+@@ -120,29 +117,14 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
+ 	  /* This function will get called to fix up the GOT entry
+ 	     indicated by the offset on the stack, and then jump to
+ 	     the resolved address.  */
+-	  if (HAS_ARCH_FEATURE (AVX512F_Usable))
+-	    {
+-	      if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_opt))
+-		*(ElfW(Addr) *) (got + 2)
+-		  = (ElfW(Addr)) &_dl_runtime_resolve_avx512_opt;
+-	      else
+-		*(ElfW(Addr) *) (got + 2)
+-		  = (ElfW(Addr)) &_dl_runtime_resolve_avx512;
+-	    }
+-	  else if (HAS_ARCH_FEATURE (AVX_Usable))
+-	    {
+-	      if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_opt))
+-		*(ElfW(Addr) *) (got + 2)
+-		  = (ElfW(Addr)) &_dl_runtime_resolve_avx_opt;
+-	      else if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_slow))
+-		*(ElfW(Addr) *) (got + 2)
+-		  = (ElfW(Addr)) &_dl_runtime_resolve_avx_slow;
+-	      else
+-		*(ElfW(Addr) *) (got + 2)
+-		  = (ElfW(Addr)) &_dl_runtime_resolve_avx;
+-	    }
++	  if (GLRO(dl_x86_cpu_features).xsave_state_size != 0)
++	    *(ElfW(Addr) *) (got + 2)
++	      = (HAS_ARCH_FEATURE (XSAVEC_Usable)
++		 ? (ElfW(Addr)) &_dl_runtime_resolve_xsavec
++		 : (ElfW(Addr)) &_dl_runtime_resolve_xsave);
+ 	  else
+-	    *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_resolve_sse;
++	    *(ElfW(Addr) *) (got + 2)
++	      = (ElfW(Addr)) &_dl_runtime_resolve_fxsave;
+ 	}
+     }
+ 
 diff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c
 new file mode 100644
 index 0000000000..3584805c8e
@@ -5359,56 +10269,487 @@ index 4a59d2a924..c2fb56c0a1 100644
 +
 +#endif /* _X86_64_DL_TLS_H */
 diff --git a/sysdeps/x86_64/dl-trampoline.S b/sysdeps/x86_64/dl-trampoline.S
-index 33d7fcf7d0..c14c61aa58 100644
+index 33d7fcf7d0..a645572e44 100644
 --- a/sysdeps/x86_64/dl-trampoline.S
 +++ b/sysdeps/x86_64/dl-trampoline.S
-@@ -87,11 +87,9 @@
+@@ -34,41 +34,24 @@
+ # define DL_STACK_ALIGNMENT 8
+ #endif
+ 
+-#ifndef DL_RUNTIME_UNALIGNED_VEC_SIZE
+-/* The maximum size in bytes of unaligned vector load and store in the
+-   dynamic linker.  Since SSE optimized memory/string functions with
+-   aligned SSE register load and store are used in the dynamic linker,
+-   we must set this to 8 so that _dl_runtime_resolve_sse will align the
+-   stack before calling _dl_fixup.  */
+-# define DL_RUNTIME_UNALIGNED_VEC_SIZE 8
+-#endif
+-
+-/* True if _dl_runtime_resolve should align stack to VEC_SIZE bytes.  */
++/* True if _dl_runtime_resolve should align stack for STATE_SAVE or align
++   stack to 16 bytes before calling _dl_fixup.  */
+ #define DL_RUNTIME_RESOLVE_REALIGN_STACK \
+-  (VEC_SIZE > DL_STACK_ALIGNMENT \
+-   && VEC_SIZE > DL_RUNTIME_UNALIGNED_VEC_SIZE)
+-
+-/* Align vector register save area to 16 bytes.  */
+-#define REGISTER_SAVE_VEC_OFF	0
++  (STATE_SAVE_ALIGNMENT > DL_STACK_ALIGNMENT \
++   || 16 > DL_STACK_ALIGNMENT)
+ 
+ /* Area on stack to save and restore registers used for parameter
+    passing when calling _dl_fixup.  */
+ #ifdef __ILP32__
+-# define REGISTER_SAVE_RAX	(REGISTER_SAVE_VEC_OFF + VEC_SIZE * 8)
+ # define PRESERVE_BND_REGS_PREFIX
+ #else
+-/* Align bound register save area to 16 bytes.  */
+-# define REGISTER_SAVE_BND0	(REGISTER_SAVE_VEC_OFF + VEC_SIZE * 8)
+-# define REGISTER_SAVE_BND1	(REGISTER_SAVE_BND0 + 16)
+-# define REGISTER_SAVE_BND2	(REGISTER_SAVE_BND1 + 16)
+-# define REGISTER_SAVE_BND3	(REGISTER_SAVE_BND2 + 16)
+-# define REGISTER_SAVE_RAX	(REGISTER_SAVE_BND3 + 16)
+ # ifdef HAVE_MPX_SUPPORT
+ #  define PRESERVE_BND_REGS_PREFIX bnd
+ # else
+ #  define PRESERVE_BND_REGS_PREFIX .byte 0xf2
+ # endif
  #endif
++#define REGISTER_SAVE_RAX	0
+ #define REGISTER_SAVE_RCX	(REGISTER_SAVE_RAX + 8)
+ #define REGISTER_SAVE_RDX	(REGISTER_SAVE_RCX + 8)
+ #define REGISTER_SAVE_RSI	(REGISTER_SAVE_RDX + 8)
+@@ -80,69 +63,56 @@
+ 
+ #define VEC_SIZE		64
+ #define VMOVA			vmovdqa64
+-#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT
+-# define VMOV			vmovdqa64
+-#else
+-# define VMOV			vmovdqu64
+-#endif
  #define VEC(i)			zmm##i
- #define _dl_runtime_resolve	_dl_runtime_resolve_avx512
+-#define _dl_runtime_resolve	_dl_runtime_resolve_avx512
 -#define _dl_runtime_resolve_opt	_dl_runtime_resolve_avx512_opt
  #define _dl_runtime_profile	_dl_runtime_profile_avx512
  #include "dl-trampoline.h"
- #undef _dl_runtime_resolve
+-#undef _dl_runtime_resolve
+-#undef _dl_runtime_resolve_opt
+ #undef _dl_runtime_profile
+ #undef VEC
+-#undef VMOV
+ #undef VMOVA
+ #undef VEC_SIZE
+ 
+ #define VEC_SIZE		32
+ #define VMOVA			vmovdqa
+-#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT
+-# define VMOV			vmovdqa
+-#else
+-# define VMOV			vmovdqu
+-#endif
+ #define VEC(i)			ymm##i
+-#define _dl_runtime_resolve	_dl_runtime_resolve_avx
+-#define _dl_runtime_resolve_opt	_dl_runtime_resolve_avx_opt
+ #define _dl_runtime_profile	_dl_runtime_profile_avx
+ #include "dl-trampoline.h"
+-#undef _dl_runtime_resolve
 -#undef _dl_runtime_resolve_opt
  #undef _dl_runtime_profile
  #undef VEC
- #undef VMOV
-@@ -145,4 +143,5 @@
- # define VMOV			vmovdqu
- #endif
- #define _dl_runtime_resolve	_dl_runtime_resolve_sse_vex
-+#define _dl_runtime_resolve_opt	_dl_runtime_resolve_avx512_opt
+-#undef VMOV
+ #undef VMOVA
+ #undef VEC_SIZE
+ 
+ /* movaps/movups is 1-byte shorter.  */
+ #define VEC_SIZE		16
+ #define VMOVA			movaps
+-#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT
+-# define VMOV			movaps
+-#else
+-# define VMOV			movups
+-#endif
+ #define VEC(i)			xmm##i
+-#define _dl_runtime_resolve	_dl_runtime_resolve_sse
+ #define _dl_runtime_profile	_dl_runtime_profile_sse
+ #undef RESTORE_AVX
  #include "dl-trampoline.h"
+-#undef _dl_runtime_resolve
+ #undef _dl_runtime_profile
+-#undef VMOV
++#undef VEC
+ #undef VMOVA
++#undef VEC_SIZE
+ 
+-/* Used by _dl_runtime_resolve_avx_opt/_dl_runtime_resolve_avx512_opt
+-   to preserve the full vector registers with zero upper bits.  */
+-#define VMOVA			vmovdqa
+-#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT
+-# define VMOV			vmovdqa
+-#else
+-# define VMOV			vmovdqu
+-#endif
+-#define _dl_runtime_resolve	_dl_runtime_resolve_sse_vex
++#define USE_FXSAVE
++#define STATE_SAVE_ALIGNMENT	16
++#define _dl_runtime_resolve	_dl_runtime_resolve_fxsave
++#include "dl-trampoline.h"
++#undef _dl_runtime_resolve
++#undef USE_FXSAVE
++#undef STATE_SAVE_ALIGNMENT
++
++#define USE_XSAVE
++#define STATE_SAVE_ALIGNMENT	64
++#define _dl_runtime_resolve	_dl_runtime_resolve_xsave
++#include "dl-trampoline.h"
++#undef _dl_runtime_resolve
++#undef USE_XSAVE
++#undef STATE_SAVE_ALIGNMENT
++
++#define USE_XSAVEC
++#define STATE_SAVE_ALIGNMENT	64
++#define _dl_runtime_resolve	_dl_runtime_resolve_xsavec
+ #include "dl-trampoline.h"
++#undef _dl_runtime_resolve
++#undef USE_XSAVEC
++#undef STATE_SAVE_ALIGNMENT
 diff --git a/sysdeps/x86_64/dl-trampoline.h b/sysdeps/x86_64/dl-trampoline.h
-index b27fa06974..8db24c16ac 100644
+index b27fa06974..9ddaafee17 100644
 --- a/sysdeps/x86_64/dl-trampoline.h
 +++ b/sysdeps/x86_64/dl-trampoline.h
-@@ -129,19 +129,20 @@ _dl_runtime_resolve_opt:
- 	# YMM state isn't in use.
- 	PRESERVE_BND_REGS_PREFIX
- 	jz _dl_runtime_resolve_sse_vex
+@@ -16,139 +16,47 @@
+    License along with the GNU C Library; if not, see
+    <http://www.gnu.org/licenses/>.  */
+ 
+-#undef REGISTER_SAVE_AREA_RAW
+-#ifdef __ILP32__
+-/* X32 saves RCX, RDX, RSI, RDI, R8 and R9 plus RAX as well as VEC0 to
+-   VEC7.  */
+-# define REGISTER_SAVE_AREA_RAW	(8 * 7 + VEC_SIZE * 8)
+-#else
+-/* X86-64 saves RCX, RDX, RSI, RDI, R8 and R9 plus RAX as well as
+-   BND0, BND1, BND2, BND3 and VEC0 to VEC7. */
+-# define REGISTER_SAVE_AREA_RAW	(8 * 7 + 16 * 4 + VEC_SIZE * 8)
+-#endif
++	.text
++#ifdef _dl_runtime_resolve
+ 
+-#undef REGISTER_SAVE_AREA
+-#undef LOCAL_STORAGE_AREA
+-#undef BASE
+-#if DL_RUNTIME_RESOLVE_REALIGN_STACK
+-# define REGISTER_SAVE_AREA	(REGISTER_SAVE_AREA_RAW + 8)
+-/* Local stack area before jumping to function address: RBX.  */
+-# define LOCAL_STORAGE_AREA	8
+-# define BASE			rbx
+-# if (REGISTER_SAVE_AREA % VEC_SIZE) != 0
+-#  error REGISTER_SAVE_AREA must be multples of VEC_SIZE
+-# endif
+-#else
+-# define REGISTER_SAVE_AREA	REGISTER_SAVE_AREA_RAW
+-/* Local stack area before jumping to function address:  All saved
+-   registers.  */
+-# define LOCAL_STORAGE_AREA	REGISTER_SAVE_AREA
+-# define BASE			rsp
+-# if (REGISTER_SAVE_AREA % 16) != 8
+-#  error REGISTER_SAVE_AREA must be odd multples of 8
++# undef REGISTER_SAVE_AREA
++# undef LOCAL_STORAGE_AREA
++# undef BASE
++
++# if (STATE_SAVE_ALIGNMENT % 16) != 0
++#  error STATE_SAVE_ALIGNMENT must be multples of 16
+ # endif
+-#endif
+ 
+-	.text
+-#ifdef _dl_runtime_resolve_opt
+-/* Use the smallest vector registers to preserve the full YMM/ZMM
+-   registers to avoid SSE transition penalty.  */
+-
+-# if VEC_SIZE == 32
+-/* Check if the upper 128 bits in %ymm0 - %ymm7 registers are non-zero
+-   and preserve %xmm0 - %xmm7 registers with the zero upper bits.  Since
+-   there is no SSE transition penalty on AVX512 processors which don't
+-   support XGETBV with ECX == 1, _dl_runtime_resolve_avx512_slow isn't
+-   provided.   */
+-	.globl _dl_runtime_resolve_avx_slow
+-	.hidden _dl_runtime_resolve_avx_slow
+-	.type _dl_runtime_resolve_avx_slow, @function
+-	.align 16
+-_dl_runtime_resolve_avx_slow:
+-	cfi_startproc
+-	cfi_adjust_cfa_offset(16) # Incorporate PLT
+-	vorpd %ymm0, %ymm1, %ymm8
+-	vorpd %ymm2, %ymm3, %ymm9
+-	vorpd %ymm4, %ymm5, %ymm10
+-	vorpd %ymm6, %ymm7, %ymm11
+-	vorpd %ymm8, %ymm9, %ymm9
+-	vorpd %ymm10, %ymm11, %ymm10
+-	vpcmpeqd %xmm8, %xmm8, %xmm8
+-	vorpd %ymm9, %ymm10, %ymm10
+-	vptest %ymm10, %ymm8
+-	# Preserve %ymm0 - %ymm7 registers if the upper 128 bits of any
+-	# %ymm0 - %ymm7 registers aren't zero.
+-	PRESERVE_BND_REGS_PREFIX
+-	jnc _dl_runtime_resolve_avx
+-	# Use vzeroupper to avoid SSE transition penalty.
+-	vzeroupper
+-	# Preserve %xmm0 - %xmm7 registers with the zero upper 128 bits
+-	# when the upper 128 bits of %ymm0 - %ymm7 registers are zero.
+-	PRESERVE_BND_REGS_PREFIX
+-	jmp _dl_runtime_resolve_sse_vex
+-	cfi_adjust_cfa_offset(-16) # Restore PLT adjustment
+-	cfi_endproc
+-	.size _dl_runtime_resolve_avx_slow, .-_dl_runtime_resolve_avx_slow
++# if (STATE_SAVE_OFFSET % STATE_SAVE_ALIGNMENT) != 0
++#  error STATE_SAVE_OFFSET must be multples of STATE_SAVE_ALIGNMENT
+ # endif
+ 
+-/* Use XGETBV with ECX == 1 to check which bits in vector registers are
+-   non-zero and only preserve the non-zero lower bits with zero upper
+-   bits.  */
+-	.globl _dl_runtime_resolve_opt
+-	.hidden _dl_runtime_resolve_opt
+-	.type _dl_runtime_resolve_opt, @function
+-	.align 16
+-_dl_runtime_resolve_opt:
+-	cfi_startproc
+-	cfi_adjust_cfa_offset(16) # Incorporate PLT
+-	pushq %rax
+-	cfi_adjust_cfa_offset(8)
+-	cfi_rel_offset(%rax, 0)
+-	pushq %rcx
+-	cfi_adjust_cfa_offset(8)
+-	cfi_rel_offset(%rcx, 0)
+-	pushq %rdx
+-	cfi_adjust_cfa_offset(8)
+-	cfi_rel_offset(%rdx, 0)
+-	movl $1, %ecx
+-	xgetbv
+-	movl %eax, %r11d
+-	popq %rdx
+-	cfi_adjust_cfa_offset(-8)
+-	cfi_restore (%rdx)
+-	popq %rcx
+-	cfi_adjust_cfa_offset(-8)
+-	cfi_restore (%rcx)
+-	popq %rax
+-	cfi_adjust_cfa_offset(-8)
+-	cfi_restore (%rax)
+-# if VEC_SIZE == 32
+-	# For YMM registers, check if YMM state is in use.
+-	andl $bit_YMM_state, %r11d
+-	# Preserve %xmm0 - %xmm7 registers with the zero upper 128 bits if
+-	# YMM state isn't in use.
+-	PRESERVE_BND_REGS_PREFIX
+-	jz _dl_runtime_resolve_sse_vex
 -# elif VEC_SIZE == 64
-+# elif VEC_SIZE == 16
- 	# For ZMM registers, check if YMM state and ZMM state are in
- 	# use.
- 	andl $(bit_YMM_state | bit_ZMM0_15_state), %r11d
- 	cmpl $bit_YMM_state, %r11d
+-	# For ZMM registers, check if YMM state and ZMM state are in
+-	# use.
+-	andl $(bit_YMM_state | bit_ZMM0_15_state), %r11d
+-	cmpl $bit_YMM_state, %r11d
 -	# Preserve %xmm0 - %xmm7 registers with the zero upper 384 bits if
 -	# neither YMM state nor ZMM state are in use.
-+	# Preserve %zmm0 - %zmm7 registers if ZMM state is in use.
- 	PRESERVE_BND_REGS_PREFIX
+-	PRESERVE_BND_REGS_PREFIX
 -	jl _dl_runtime_resolve_sse_vex
-+	jg _dl_runtime_resolve_avx512
- 	# Preserve %ymm0 - %ymm7 registers with the zero upper 256 bits if
- 	# ZMM state isn't in use.
- 	PRESERVE_BND_REGS_PREFIX
- 	je _dl_runtime_resolve_avx
-+	# Preserve %xmm0 - %xmm7 registers with the zero upper 384 bits if
-+	# neither YMM state nor ZMM state are in use.
+-	# Preserve %ymm0 - %ymm7 registers with the zero upper 256 bits if
+-	# ZMM state isn't in use.
+-	PRESERVE_BND_REGS_PREFIX
+-	je _dl_runtime_resolve_avx
++# if DL_RUNTIME_RESOLVE_REALIGN_STACK
++/* Local stack area before jumping to function address: RBX.  */
++#  define LOCAL_STORAGE_AREA	8
++#  define BASE			rbx
++#  ifdef USE_FXSAVE
++/* Use fxsave to save XMM registers.  */
++#   define REGISTER_SAVE_AREA	(512 + STATE_SAVE_OFFSET)
++#   if (REGISTER_SAVE_AREA % 16) != 0
++#    error REGISTER_SAVE_AREA must be multples of 16
++#   endif
++#  endif
+ # else
+-#  error Unsupported VEC_SIZE!
++#  ifndef USE_FXSAVE
++#   error USE_FXSAVE must be defined
++#  endif
++/* Use fxsave to save XMM registers.  */
++#  define REGISTER_SAVE_AREA	(512 + STATE_SAVE_OFFSET + 8)
++/* Local stack area before jumping to function address:  All saved
++   registers.  */
++#  define LOCAL_STORAGE_AREA	REGISTER_SAVE_AREA
++#  define BASE			rsp
++#  if (REGISTER_SAVE_AREA % 16) != 8
++#   error REGISTER_SAVE_AREA must be odd multples of 8
++#  endif
+ # endif
+-	cfi_adjust_cfa_offset(-16) # Restore PLT adjustment
+-	cfi_endproc
+-	.size _dl_runtime_resolve_opt, .-_dl_runtime_resolve_opt
+-#endif
++
+ 	.globl _dl_runtime_resolve
+ 	.hidden _dl_runtime_resolve
+ 	.type _dl_runtime_resolve, @function
+@@ -156,21 +64,30 @@ _dl_runtime_resolve_opt:
+ 	cfi_startproc
+ _dl_runtime_resolve:
+ 	cfi_adjust_cfa_offset(16) # Incorporate PLT
+-#if DL_RUNTIME_RESOLVE_REALIGN_STACK
+-# if LOCAL_STORAGE_AREA != 8
+-#  error LOCAL_STORAGE_AREA must be 8
+-# endif
++# if DL_RUNTIME_RESOLVE_REALIGN_STACK
++#  if LOCAL_STORAGE_AREA != 8
++#   error LOCAL_STORAGE_AREA must be 8
++#  endif
+ 	pushq %rbx			# push subtracts stack by 8.
+ 	cfi_adjust_cfa_offset(8)
+ 	cfi_rel_offset(%rbx, 0)
+ 	mov %RSP_LP, %RBX_LP
+ 	cfi_def_cfa_register(%rbx)
+-	and $-VEC_SIZE, %RSP_LP
+-#endif
++	and $-STATE_SAVE_ALIGNMENT, %RSP_LP
++# endif
++# ifdef REGISTER_SAVE_AREA
+ 	sub $REGISTER_SAVE_AREA, %RSP_LP
+-#if !DL_RUNTIME_RESOLVE_REALIGN_STACK
++#  if !DL_RUNTIME_RESOLVE_REALIGN_STACK
+ 	cfi_adjust_cfa_offset(REGISTER_SAVE_AREA)
+-#endif
++#  endif
++# else
++	# Allocate stack space of the required size to save the state.
++#  if IS_IN (rtld)
++	sub _rtld_local_ro+RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET+XSAVE_STATE_SIZE_OFFSET(%rip), %RSP_LP
++#  else
++	sub _dl_x86_cpu_features+XSAVE_STATE_SIZE_OFFSET(%rip), %RSP_LP
++#  endif
++# endif
+ 	# Preserve registers otherwise clobbered.
+ 	movq %rax, REGISTER_SAVE_RAX(%rsp)
+ 	movq %rcx, REGISTER_SAVE_RCX(%rsp)
+@@ -179,59 +96,42 @@ _dl_runtime_resolve:
+ 	movq %rdi, REGISTER_SAVE_RDI(%rsp)
+ 	movq %r8, REGISTER_SAVE_R8(%rsp)
+ 	movq %r9, REGISTER_SAVE_R9(%rsp)
+-	VMOV %VEC(0), (REGISTER_SAVE_VEC_OFF)(%rsp)
+-	VMOV %VEC(1), (REGISTER_SAVE_VEC_OFF + VEC_SIZE)(%rsp)
+-	VMOV %VEC(2), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 2)(%rsp)
+-	VMOV %VEC(3), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 3)(%rsp)
+-	VMOV %VEC(4), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 4)(%rsp)
+-	VMOV %VEC(5), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 5)(%rsp)
+-	VMOV %VEC(6), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 6)(%rsp)
+-	VMOV %VEC(7), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 7)(%rsp)
+-#ifndef __ILP32__
+-	# We also have to preserve bound registers.  These are nops if
+-	# Intel MPX isn't available or disabled.
+-# ifdef HAVE_MPX_SUPPORT
+-	bndmov %bnd0, REGISTER_SAVE_BND0(%rsp)
+-	bndmov %bnd1, REGISTER_SAVE_BND1(%rsp)
+-	bndmov %bnd2, REGISTER_SAVE_BND2(%rsp)
+-	bndmov %bnd3, REGISTER_SAVE_BND3(%rsp)
++# ifdef USE_FXSAVE
++	fxsave STATE_SAVE_OFFSET(%rsp)
+ # else
+-#  if REGISTER_SAVE_BND0 == 0
+-	.byte 0x66,0x0f,0x1b,0x04,0x24
++	movl $STATE_SAVE_MASK, %eax
++	xorl %edx, %edx
++	# Clear the XSAVE Header.
++#  ifdef USE_XSAVE
++	movq %rdx, (STATE_SAVE_OFFSET + 512)(%rsp)
++	movq %rdx, (STATE_SAVE_OFFSET + 512 + 8)(%rsp)
++#  endif
++	movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 2)(%rsp)
++	movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 3)(%rsp)
++	movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 4)(%rsp)
++	movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 5)(%rsp)
++	movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 6)(%rsp)
++	movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 7)(%rsp)
++#  ifdef USE_XSAVE
++	xsave STATE_SAVE_OFFSET(%rsp)
+ #  else
+-	.byte 0x66,0x0f,0x1b,0x44,0x24,REGISTER_SAVE_BND0
++	xsavec STATE_SAVE_OFFSET(%rsp)
+ #  endif
+-	.byte 0x66,0x0f,0x1b,0x4c,0x24,REGISTER_SAVE_BND1
+-	.byte 0x66,0x0f,0x1b,0x54,0x24,REGISTER_SAVE_BND2
+-	.byte 0x66,0x0f,0x1b,0x5c,0x24,REGISTER_SAVE_BND3
+ # endif
+-#endif
+ 	# Copy args pushed by PLT in register.
+ 	# %rdi: link_map, %rsi: reloc_index
+ 	mov (LOCAL_STORAGE_AREA + 8)(%BASE), %RSI_LP
+ 	mov LOCAL_STORAGE_AREA(%BASE), %RDI_LP
+ 	call _dl_fixup		# Call resolver.
+ 	mov %RAX_LP, %R11_LP	# Save return value
+-#ifndef __ILP32__
+-	# Restore bound registers.  These are nops if Intel MPX isn't
+-	# avaiable or disabled.
+-# ifdef HAVE_MPX_SUPPORT
+-	bndmov REGISTER_SAVE_BND3(%rsp), %bnd3
+-	bndmov REGISTER_SAVE_BND2(%rsp), %bnd2
+-	bndmov REGISTER_SAVE_BND1(%rsp), %bnd1
+-	bndmov REGISTER_SAVE_BND0(%rsp), %bnd0
++	# Get register content back.
++# ifdef USE_FXSAVE
++	fxrstor STATE_SAVE_OFFSET(%rsp)
  # else
- #  error Unsupported VEC_SIZE!
+-	.byte 0x66,0x0f,0x1a,0x5c,0x24,REGISTER_SAVE_BND3
+-	.byte 0x66,0x0f,0x1a,0x54,0x24,REGISTER_SAVE_BND2
+-	.byte 0x66,0x0f,0x1a,0x4c,0x24,REGISTER_SAVE_BND1
+-#  if REGISTER_SAVE_BND0 == 0
+-	.byte 0x66,0x0f,0x1a,0x04,0x24
+-#  else
+-	.byte 0x66,0x0f,0x1a,0x44,0x24,REGISTER_SAVE_BND0
+-#  endif
++	movl $STATE_SAVE_MASK, %eax
++	xorl %edx, %edx
++	xrstor STATE_SAVE_OFFSET(%rsp)
  # endif
+-#endif
+-	# Get register content back.
+ 	movq REGISTER_SAVE_R9(%rsp), %r9
+ 	movq REGISTER_SAVE_R8(%rsp), %r8
+ 	movq REGISTER_SAVE_RDI(%rsp), %rdi
+@@ -239,20 +139,12 @@ _dl_runtime_resolve:
+ 	movq REGISTER_SAVE_RDX(%rsp), %rdx
+ 	movq REGISTER_SAVE_RCX(%rsp), %rcx
+ 	movq REGISTER_SAVE_RAX(%rsp), %rax
+-	VMOV (REGISTER_SAVE_VEC_OFF)(%rsp), %VEC(0)
+-	VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE)(%rsp), %VEC(1)
+-	VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 2)(%rsp), %VEC(2)
+-	VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 3)(%rsp), %VEC(3)
+-	VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 4)(%rsp), %VEC(4)
+-	VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 5)(%rsp), %VEC(5)
+-	VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 6)(%rsp), %VEC(6)
+-	VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 7)(%rsp), %VEC(7)
+-#if DL_RUNTIME_RESOLVE_REALIGN_STACK
++# if DL_RUNTIME_RESOLVE_REALIGN_STACK
+ 	mov %RBX_LP, %RSP_LP
+ 	cfi_def_cfa_register(%rsp)
+ 	movq (%rsp), %rbx
+ 	cfi_restore(%rbx)
+-#endif
++# endif
+ 	# Adjust stack(PLT did 2 pushes)
+ 	add $(LOCAL_STORAGE_AREA + 16), %RSP_LP
+ 	cfi_adjust_cfa_offset(-(LOCAL_STORAGE_AREA + 16))
+@@ -261,11 +153,9 @@ _dl_runtime_resolve:
+ 	jmp *%r11		# Jump to function address.
+ 	cfi_endproc
+ 	.size _dl_runtime_resolve, .-_dl_runtime_resolve
++#endif
+ 
+ 
+-/* To preserve %xmm0 - %xmm7 registers, dl-trampoline.h is included
+-   twice, for _dl_runtime_resolve_sse and _dl_runtime_resolve_sse_vex.
+-   But we don't need another _dl_runtime_profile for XMM registers.  */
+ #if !defined PROF && defined _dl_runtime_profile
+ # if (LR_VECTOR_OFFSET % VEC_SIZE) != 0
+ #  error LR_VECTOR_OFFSET must be multples of VEC_SIZE
 diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data
 index 014a9f4554..a1840cff31 100644
 --- a/sysdeps/x86_64/localplt.data
@@ -5629,3 +10970,440 @@ index 33854975d0..fc897ab4b5 100644
 +
 +TI_MODULE_OFFSET 		offsetof(tls_index, ti_module)
 +TI_OFFSET_OFFSET 		offsetof(tls_index, ti_offset)
+diff --git a/sysdeps/x86_64/tst-avx-aux.c b/sysdeps/x86_64/tst-avx-aux.c
+new file mode 100644
+index 0000000000..e3807de7bb
+--- /dev/null
++++ b/sysdeps/x86_64/tst-avx-aux.c
+@@ -0,0 +1,47 @@
++/* Test case for preserved AVX registers in dynamic linker, -mavx part.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <immintrin.h>
++#include <stdlib.h>
++#include <string.h>
++
++int
++tst_avx_aux (void)
++{
++#ifdef __AVX__
++  extern __m256i avx_test (__m256i, __m256i, __m256i, __m256i,
++			   __m256i, __m256i, __m256i, __m256i);
++
++  __m256i ymm0 = _mm256_set1_epi32 (0);
++  __m256i ymm1 = _mm256_set1_epi32 (1);
++  __m256i ymm2 = _mm256_set1_epi32 (2);
++  __m256i ymm3 = _mm256_set1_epi32 (3);
++  __m256i ymm4 = _mm256_set1_epi32 (4);
++  __m256i ymm5 = _mm256_set1_epi32 (5);
++  __m256i ymm6 = _mm256_set1_epi32 (6);
++  __m256i ymm7 = _mm256_set1_epi32 (7);
++  __m256i ret = avx_test (ymm0, ymm1, ymm2, ymm3,
++			  ymm4, ymm5, ymm6, ymm7);
++  ymm0 =  _mm256_set1_epi32 (0x12349876);
++  if (memcmp (&ymm0, &ret, sizeof (ret)))
++    abort ();
++  return 0;
++#else  /* __AVX__ */
++  return 77;
++#endif  /* __AVX__ */
++}
+diff --git a/sysdeps/x86_64/tst-avx.c b/sysdeps/x86_64/tst-avx.c
+new file mode 100644
+index 0000000000..ec2e3a79ff
+--- /dev/null
++++ b/sysdeps/x86_64/tst-avx.c
+@@ -0,0 +1,49 @@
++/* Test case for preserved AVX registers in dynamic linker.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <cpuid.h>
++
++int tst_avx_aux (void);
++
++static int
++avx_enabled (void)
++{
++  unsigned int eax, ebx, ecx, edx;
++
++  if (__get_cpuid (1, &eax, &ebx, &ecx, &edx) == 0
++      || (ecx & (bit_AVX | bit_OSXSAVE)) != (bit_AVX | bit_OSXSAVE))
++    return 0;
++
++  /* Check the OS has AVX and SSE saving enabled.  */
++  asm ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (0));
++
++  return (eax & 6) == 6;
++}
++
++static int
++do_test (void)
++{
++  /* Run AVX test only if AVX is supported.  */
++  if (avx_enabled ())
++    return tst_avx_aux ();
++  else
++    return 77;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../../test-skeleton.c"
+diff --git a/sysdeps/x86_64/tst-avx512-aux.c b/sysdeps/x86_64/tst-avx512-aux.c
+new file mode 100644
+index 0000000000..6cebc523f2
+--- /dev/null
++++ b/sysdeps/x86_64/tst-avx512-aux.c
+@@ -0,0 +1,48 @@
++/* Test case for preserved AVX512 registers in dynamic linker,
++   -mavx512 part.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <immintrin.h>
++#include <stdlib.h>
++#include <string.h>
++
++int
++tst_avx512_aux (void)
++{
++#ifdef __AVX512F__
++  extern __m512i avx512_test (__m512i, __m512i, __m512i, __m512i,
++			      __m512i, __m512i, __m512i, __m512i);
++
++  __m512i zmm0 = _mm512_set1_epi32 (0);
++  __m512i zmm1 = _mm512_set1_epi32 (1);
++  __m512i zmm2 = _mm512_set1_epi32 (2);
++  __m512i zmm3 = _mm512_set1_epi32 (3);
++  __m512i zmm4 = _mm512_set1_epi32 (4);
++  __m512i zmm5 = _mm512_set1_epi32 (5);
++  __m512i zmm6 = _mm512_set1_epi32 (6);
++  __m512i zmm7 = _mm512_set1_epi32 (7);
++  __m512i ret = avx512_test (zmm0, zmm1, zmm2, zmm3,
++			     zmm4, zmm5, zmm6, zmm7);
++  zmm0 =  _mm512_set1_epi32 (0x12349876);
++  if (memcmp (&zmm0, &ret, sizeof (ret)))
++    abort ();
++  return 0;
++#else  /* __AVX512F__ */
++  return 77;
++#endif  /* __AVX512F__ */
++}
+diff --git a/sysdeps/x86_64/tst-avx512.c b/sysdeps/x86_64/tst-avx512.c
+new file mode 100644
+index 0000000000..a8e42ef553
+--- /dev/null
++++ b/sysdeps/x86_64/tst-avx512.c
+@@ -0,0 +1,57 @@
++/* Test case for preserved AVX512 registers in dynamic linker.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <cpuid.h>
++
++int tst_avx512_aux (void);
++
++static int
++avx512_enabled (void)
++{
++#ifdef bit_AVX512F
++  unsigned int eax, ebx, ecx, edx;
++
++  if (__get_cpuid (1, &eax, &ebx, &ecx, &edx) == 0
++      || (ecx & (bit_AVX | bit_OSXSAVE)) != (bit_AVX | bit_OSXSAVE))
++    return 0;
++
++  __cpuid_count (7, 0, eax, ebx, ecx, edx);
++  if (!(ebx & bit_AVX512F))
++    return 0;
++
++  asm ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (0));
++
++  /* Verify that ZMM, YMM and XMM states are enabled.  */
++  return (eax & 0xe6) == 0xe6;
++#else
++  return 0;
++#endif
++}
++
++static int
++do_test (void)
++{
++  /* Run AVX512 test only if AVX512 is supported.  */
++  if (avx512_enabled ())
++    return tst_avx512_aux ();
++  else
++    return 77;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../../test-skeleton.c"
+diff --git a/sysdeps/x86_64/tst-avx512mod.c b/sysdeps/x86_64/tst-avx512mod.c
+new file mode 100644
+index 0000000000..4cfb3a2c3d
+--- /dev/null
++++ b/sysdeps/x86_64/tst-avx512mod.c
+@@ -0,0 +1,48 @@
++/* Test case for x86-64 preserved AVX512 registers in dynamic linker.  */
++
++#ifdef __AVX512F__
++#include <stdlib.h>
++#include <string.h>
++#include <immintrin.h>
++
++__m512i
++avx512_test (__m512i x0, __m512i x1, __m512i x2, __m512i x3,
++	     __m512i x4, __m512i x5, __m512i x6, __m512i x7)
++{
++  __m512i zmm;
++
++  zmm = _mm512_set1_epi32 (0);
++  if (memcmp (&zmm, &x0, sizeof (zmm)))
++    abort ();
++
++  zmm = _mm512_set1_epi32 (1);
++  if (memcmp (&zmm, &x1, sizeof (zmm)))
++    abort ();
++
++  zmm = _mm512_set1_epi32 (2);
++  if (memcmp (&zmm, &x2, sizeof (zmm)))
++    abort ();
++
++  zmm = _mm512_set1_epi32 (3);
++  if (memcmp (&zmm, &x3, sizeof (zmm)))
++    abort ();
++
++  zmm = _mm512_set1_epi32 (4);
++  if (memcmp (&zmm, &x4, sizeof (zmm)))
++    abort ();
++
++  zmm = _mm512_set1_epi32 (5);
++  if (memcmp (&zmm, &x5, sizeof (zmm)))
++    abort ();
++
++  zmm = _mm512_set1_epi32 (6);
++  if (memcmp (&zmm, &x6, sizeof (zmm)))
++    abort ();
++
++  zmm = _mm512_set1_epi32 (7);
++  if (memcmp (&zmm, &x7, sizeof (zmm)))
++    abort ();
++
++  return _mm512_set1_epi32 (0x12349876);
++}
++#endif
+diff --git a/sysdeps/x86_64/tst-avxmod.c b/sysdeps/x86_64/tst-avxmod.c
+new file mode 100644
+index 0000000000..6e5b154997
+--- /dev/null
++++ b/sysdeps/x86_64/tst-avxmod.c
+@@ -0,0 +1,48 @@
++/* Test case for x86-64 preserved AVX registers in dynamic linker.  */
++
++#ifdef __AVX__
++#include <stdlib.h>
++#include <string.h>
++#include <immintrin.h>
++
++__m256i
++avx_test (__m256i x0, __m256i x1, __m256i x2, __m256i x3,
++	  __m256i x4, __m256i x5, __m256i x6, __m256i x7)
++{
++  __m256i ymm;
++
++  ymm = _mm256_set1_epi32 (0);
++  if (memcmp (&ymm, &x0, sizeof (ymm)))
++    abort ();
++
++  ymm = _mm256_set1_epi32 (1);
++  if (memcmp (&ymm, &x1, sizeof (ymm)))
++    abort ();
++
++  ymm = _mm256_set1_epi32 (2);
++  if (memcmp (&ymm, &x2, sizeof (ymm)))
++    abort ();
++
++  ymm = _mm256_set1_epi32 (3);
++  if (memcmp (&ymm, &x3, sizeof (ymm)))
++    abort ();
++
++  ymm = _mm256_set1_epi32 (4);
++  if (memcmp (&ymm, &x4, sizeof (ymm)))
++    abort ();
++
++  ymm = _mm256_set1_epi32 (5);
++  if (memcmp (&ymm, &x5, sizeof (ymm)))
++    abort ();
++
++  ymm = _mm256_set1_epi32 (6);
++  if (memcmp (&ymm, &x6, sizeof (ymm)))
++    abort ();
++
++  ymm = _mm256_set1_epi32 (7);
++  if (memcmp (&ymm, &x7, sizeof (ymm)))
++    abort ();
++
++  return _mm256_set1_epi32 (0x12349876);
++}
++#endif
+diff --git a/sysdeps/x86_64/tst-sse.c b/sysdeps/x86_64/tst-sse.c
+new file mode 100644
+index 0000000000..dd1537cf27
+--- /dev/null
++++ b/sysdeps/x86_64/tst-sse.c
+@@ -0,0 +1,46 @@
++/* Test case for preserved SSE registers in dynamic linker.
++   Copyright (C) 2017 Free Software Foundation, Inc.
++   This file is part of the GNU C Library.
++
++   The GNU C Library is free software; you can redistribute it and/or
++   modify it under the terms of the GNU Lesser General Public
++   License as published by the Free Software Foundation; either
++   version 2.1 of the License, or (at your option) any later version.
++
++   The GNU C Library is distributed in the hope that it will be useful,
++   but WITHOUT ANY WARRANTY; without even the implied warranty of
++   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++   Lesser General Public License for more details.
++
++   You should have received a copy of the GNU Lesser General Public
++   License along with the GNU C Library; if not, see
++   <http://www.gnu.org/licenses/>.  */
++
++#include <immintrin.h>
++#include <stdlib.h>
++#include <string.h>
++
++extern __m128i sse_test (__m128i, __m128i, __m128i, __m128i,
++			 __m128i, __m128i, __m128i, __m128i);
++
++static int
++do_test (void)
++{
++  __m128i xmm0 = _mm_set1_epi32 (0);
++  __m128i xmm1 = _mm_set1_epi32 (1);
++  __m128i xmm2 = _mm_set1_epi32 (2);
++  __m128i xmm3 = _mm_set1_epi32 (3);
++  __m128i xmm4 = _mm_set1_epi32 (4);
++  __m128i xmm5 = _mm_set1_epi32 (5);
++  __m128i xmm6 = _mm_set1_epi32 (6);
++  __m128i xmm7 = _mm_set1_epi32 (7);
++  __m128i ret = sse_test (xmm0, xmm1, xmm2, xmm3,
++			  xmm4, xmm5, xmm6, xmm7);
++  xmm0 =  _mm_set1_epi32 (0x12349876);
++  if (memcmp (&xmm0, &ret, sizeof (ret)))
++    abort ();
++  return 0;
++}
++
++#define TEST_FUNCTION do_test ()
++#include "../../test-skeleton.c"
+diff --git a/sysdeps/x86_64/tst-ssemod.c b/sysdeps/x86_64/tst-ssemod.c
+new file mode 100644
+index 0000000000..907a64c69e
+--- /dev/null
++++ b/sysdeps/x86_64/tst-ssemod.c
+@@ -0,0 +1,46 @@
++/* Test case for x86-64 preserved SSE registers in dynamic linker.  */
++
++#include <stdlib.h>
++#include <string.h>
++#include <immintrin.h>
++
++__m128i
++sse_test (__m128i x0, __m128i x1, __m128i x2, __m128i x3,
++	  __m128i x4, __m128i x5, __m128i x6, __m128i x7)
++{
++  __m128i xmm;
++
++  xmm = _mm_set1_epi32 (0);
++  if (memcmp (&xmm, &x0, sizeof (xmm)))
++    abort ();
++
++  xmm = _mm_set1_epi32 (1);
++  if (memcmp (&xmm, &x1, sizeof (xmm)))
++    abort ();
++
++  xmm = _mm_set1_epi32 (2);
++  if (memcmp (&xmm, &x2, sizeof (xmm)))
++    abort ();
++
++  xmm = _mm_set1_epi32 (3);
++  if (memcmp (&xmm, &x3, sizeof (xmm)))
++    abort ();
++
++  xmm = _mm_set1_epi32 (4);
++  if (memcmp (&xmm, &x4, sizeof (xmm)))
++    abort ();
++
++  xmm = _mm_set1_epi32 (5);
++  if (memcmp (&xmm, &x5, sizeof (xmm)))
++    abort ();
++
++  xmm = _mm_set1_epi32 (6);
++  if (memcmp (&xmm, &x6, sizeof (xmm)))
++    abort ();
++
++  xmm = _mm_set1_epi32 (7);
++  if (memcmp (&xmm, &x7, sizeof (xmm)))
++    abort ();
++
++  return _mm_set1_epi32 (0x12349876);
++}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-glibc/glibc.git


Reply to: