[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: